diff --git a/osaca/data/skx.yml b/osaca/data/skx.yml index 22c86b4..faf38a2 100644 --- a/osaca/data/skx.yml +++ b/osaca/data/skx.yml @@ -2836,6 +2836,12 @@ instruction_forms: port_pressure: [] throughput: 0.0 uops: 1 +- name: JA + operands: + - class: identifier + throughput: 0.0 + latency: 0.0 + port_pressure: [] - name: WRMSR operands: [] latency: ~ @@ -36881,14 +36887,3 @@ instruction_forms: port_pressure: [[1, '01']] throughput: 0.5 uops: 2 -- name: vfmadd132pd - operands: - - class: register - name: ymm - - class: register - name: ymm - - class: register - name: ymm - throughput: 0.5 - latency: 4.0 # 1*p01 - port_pressure: [[1, '01']] diff --git a/osaca/parser/parser_AArch64v81.py b/osaca/parser/parser_AArch64v81.py index 56abb98..6d7b46e 100755 --- a/osaca/parser/parser_AArch64v81.py +++ b/osaca/parser/parser_AArch64v81.py @@ -178,7 +178,7 @@ class ParserAArch64v81(BaseParser): instruction_form = AttrDict( { self.INSTRUCTION_ID: None, - self.OPERANDS_ID: None, + self.OPERANDS_ID: [], self.DIRECTIVE_ID: None, self.COMMENT_ID: None, self.LABEL_ID: None, diff --git a/osaca/parser/parser_x86att.py b/osaca/parser/parser_x86att.py index 7063721..d7489ea 100755 --- a/osaca/parser/parser_x86att.py +++ b/osaca/parser/parser_x86att.py @@ -123,7 +123,7 @@ class ParserX86ATT(BaseParser): instruction_form = AttrDict( { self.INSTRUCTION_ID: None, - self.OPERANDS_ID: None, + self.OPERANDS_ID: [], self.DIRECTIVE_ID: None, self.COMMENT_ID: None, self.LABEL_ID: None, diff --git a/osaca/semantics/arch_semantics.py b/osaca/semantics/arch_semantics.py index 0e4af4c..ba7c19e 100755 --- a/osaca/semantics/arch_semantics.py +++ b/osaca/semantics/arch_semantics.py @@ -182,13 +182,13 @@ class ArchSemantics(ISASemantics): assign_unknown = False reg_types = [ self._parser.get_reg_type(op['register']) - for op in operands['operand_list'] + for op in operands if 'register' in op ] load_port_uops = self._machine_model.get_load_throughput( [ x['memory'] - for x in instruction_form['operands']['source'] + for x in instruction_form['semantic_operands']['source'] if 'memory' in x ][0] ) @@ -243,36 +243,9 @@ class ArchSemantics(ISASemantics): instruction_form['latency_lcd'] = 0 def substitute_mem_address(self, operands): - regs = [op for op in operands['operand_list'] if 'register' in op] - if ( - len(regs) > 1 - and len(set([self._parser.get_reg_type(x['register']) for x in regs])) != 1 - ): - warnings.warn('Load type could not be identified clearly.') - reg_type = self._parser.get_reg_type(regs[0]['register']) - - source = [ - operand if 'memory' not in operand else self.convert_mem_to_reg(operand, reg_type) - for operand in operands['source'] - ] - destination = [ - operand if 'memory' not in operand else self.convert_mem_to_reg(operand, reg_type) - for operand in operands['destination'] - ] - src_dst = [ - operand if 'memory' not in operand else self.convert_mem_to_reg(operand, reg_type) - for operand in operands['destination'] - ] - operand_list = [ - operand if 'memory' not in operand else self.convert_mem_to_reg(operand, reg_type) - for operand in operands['operand_list'] - ] - return { - 'source': source, - 'destination': destination, - 'src_dst': src_dst, - 'operand_list': operand_list, - } + reg_ops = [op for op in operands if 'register' in op] + reg_type = self._parser.get_reg_type(reg_ops[0]['register']) + return [self.convert_mem_to_reg(op, reg_type) for op in operands] def convert_mem_to_reg(self, memory, reg_type, reg_id='0'): if self._isa == 'x86': diff --git a/osaca/semantics/hw_model.py b/osaca/semantics/hw_model.py index 08bc989..7c4441f 100755 --- a/osaca/semantics/hw_model.py +++ b/osaca/semantics/hw_model.py @@ -228,8 +228,6 @@ class MachineModel(object): return False def _match_operands(self, i_operands, operands): - if isinstance(operands, dict): - operands = operands['operand_list'] operands_ok = True if len(operands) != len(i_operands): return False diff --git a/osaca/semantics/isa_semantics.py b/osaca/semantics/isa_semantics.py index fc8a7f8..3856d88 100755 --- a/osaca/semantics/isa_semantics.py +++ b/osaca/semantics/isa_semantics.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from itertools import chain from osaca import utils from osaca.parser import AttrDict, ParserAArch64v81, ParserX86ATT @@ -39,9 +40,11 @@ class ISASemantics(object): # - destination # - source/destination def assign_src_dst(self, instruction_form): - """Update instruction form dictionary with source and destination information.""" + """Update instruction form dictionary with source, destination and flag information.""" # if the instruction form doesn't have operands, there's nothing to do if instruction_form['operands'] is None: + instruction_form['semantic_operands'] = AttrDict( + {'source': [], 'destination': [], 'src_dst': []}) return # check if instruction form is in ISA yaml, otherwise apply standard operand assignment # (one dest, others source) @@ -71,8 +74,7 @@ class ISASemantics(object): op_dict['destination'].append(operands[i]) continue # store operand list in dict and reassign operand key/value pair - op_dict['operand_list'] = operands - instruction_form['operands'] = AttrDict.convert_dict(op_dict) + instruction_form['semantic_operands'] = AttrDict.convert_dict(op_dict) # assign LD/ST flags instruction_form['flags'] = ( instruction_form['flags'] if 'flags' in instruction_form else [] @@ -83,17 +85,15 @@ class ISASemantics(object): instruction_form['flags'] += [INSTR_FLAGS.HAS_ST] def _has_load(self, instruction_form): - for operand in ( - instruction_form['operands']['source'] + instruction_form['operands']['src_dst'] - ): + for operand in chain(instruction_form['semantic_operands']['source'], + instruction_form['semantic_operands']['src_dst']): if 'memory' in operand: return True return False def _has_store(self, instruction_form): - for operand in ( - instruction_form['operands']['destination'] + instruction_form['operands']['src_dst'] - ): + for operand in chain(instruction_form['semantic_operands']['destination'], + instruction_form['semantic_operands']['src_dst']): if 'memory' in operand: return True return False @@ -101,13 +101,9 @@ class ISASemantics(object): def _get_regular_source_operands(self, instruction_form): if self._isa == 'x86': # return all but last operand - return [ - op for op in instruction_form['operands'][0:len(instruction_form['operands']) - 1] - ] + return [op for op in instruction_form['operands'][0:-1]] elif self._isa == 'aarch64': - return [ - op for op in instruction_form['operands'][1:len(instruction_form['operands'])] - ] + return [op for op in instruction_form['operands'][1:]] else: raise ValueError("Unsupported ISA {}.".format(self._isa)) diff --git a/osaca/semantics/kernel_dg.py b/osaca/semantics/kernel_dg.py index 1047e86..3e41579 100755 --- a/osaca/semantics/kernel_dg.py +++ b/osaca/semantics/kernel_dg.py @@ -149,9 +149,10 @@ class KernelDG(nx.DiGraph): raise NotImplementedError('Kernel is cyclic.') def find_depending(self, instruction_form, kernel, include_write=False): - if instruction_form.operands is None: + if instruction_form.semantic_operands is None: return - for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: + for dst in chain(instruction_form.semantic_operands.destination, + instruction_form.semantic_operands.src_dst): if 'register' in dst: # Check for read of register until overwrite for instr_form in kernel: @@ -199,9 +200,10 @@ class KernelDG(nx.DiGraph): def is_read(self, register, instruction_form): is_read = False - if instruction_form.operands is None: + if instruction_form.semantic_operands is None: return is_read - for src in instruction_form.operands.source + instruction_form.operands.src_dst: + for src in chain(instruction_form.semantic_operands.source, + instruction_form.semantic_operands.src_dst): if 'register' in src: is_read = self.parser.is_reg_dependend_of(register, src.register) or is_read if 'memory' in src: @@ -212,7 +214,8 @@ class KernelDG(nx.DiGraph): self.parser.is_reg_dependend_of(register, src.memory.index) or is_read ) # Check also if read in destination memory address - for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: + for dst in chain(instruction_form.semantic_operands.destination, + instruction_form.semantic_operands.src_dst): if 'memory' in dst: if dst.memory.base is not None: is_read = self.parser.is_reg_dependend_of(register, dst.memory.base) or is_read @@ -224,9 +227,10 @@ class KernelDG(nx.DiGraph): def is_written(self, register, instruction_form): is_written = False - if instruction_form.operands is None: + if instruction_form.semantic_operands is None: return is_written - for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: + for dst in chain(instruction_form.semantic_operands.destination, + instruction_form.semantic_operands.src_dst): if 'register' in dst: is_written = self.parser.is_reg_dependend_of(register, dst.register) or is_written if 'memory' in dst: @@ -235,7 +239,8 @@ class KernelDG(nx.DiGraph): self.parser.is_reg_dependend_of(register, dst.memory.base) or is_written ) # Check also for possible pre- or post-indexing in memory addresses - for src in instruction_form.operands.source + instruction_form.operands.src_dst: + for src in chain(instruction_form.semantic_operands.source, + instruction_form.semantic_operands.src_dst): if 'memory' in src: if 'pre_indexed' in src.memory or 'post_indexed' in src.memory: is_written = ( diff --git a/osaca/semantics/marker_utils.py b/osaca/semantics/marker_utils.py index d5a6aab..77d0eb1 100755 --- a/osaca/semantics/marker_utils.py +++ b/osaca/semantics/marker_utils.py @@ -67,6 +67,7 @@ def get_marker(isa): def find_marked_section(lines, parser, mov_instr, mov_reg, mov_vals, nop_bytes, reverse=False): + # TODO match to instructions returned by get_marker index_start = -1 index_end = -1 for i, line in enumerate(lines): diff --git a/tests/test_parser_AArch64v81.py b/tests/test_parser_AArch64v81.py index 9dd03b0..bf87534 100755 --- a/tests/test_parser_AArch64v81.py +++ b/tests/test_parser_AArch64v81.py @@ -122,7 +122,8 @@ class TestParserAArch64v81(unittest.TestCase): self.assertEqual(parsed_5.operands[0].register.name, '0') self.assertEqual(parsed_5.operands[0].register.prefix, 'x') self.assertEqual(parsed_5.operands[1].memory.offset.identifier.name, 'q2c') - self.assertEqual(parsed_5.operands[1].memory.offset.identifier.relocation, ':got_lo12:') + self.assertEqual(parsed_5.operands[1].memory.offset.identifier.relocation, + ':got_lo12:') self.assertEqual(parsed_5.operands[1].memory.base.name, '0') self.assertEqual(parsed_5.operands[1].memory.base.prefix, 'x') self.assertIsNone(parsed_5.operands[1].memory.index) @@ -139,7 +140,8 @@ class TestParserAArch64v81(unittest.TestCase): self.assertEqual(parsed_7.operands[0].register.prefix, 'v') self.assertEqual(parsed_7.operands[0].register.lanes, '2') self.assertEqual(parsed_7.operands[0].register.shape, 'd') - self.assertEqual(self.parser.get_full_reg_name(parsed_7.operands[2].register), 'v1.2d') + self.assertEqual(self.parser.get_full_reg_name(parsed_7.operands[2].register), + 'v1.2d') def test_parse_line(self): line_comment = '// -- Begin main' @@ -152,7 +154,7 @@ class TestParserAArch64v81(unittest.TestCase): instruction_form_1 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': None, 'comment': '-- Begin main', 'label': None, @@ -162,7 +164,7 @@ class TestParserAArch64v81(unittest.TestCase): instruction_form_2 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': None, 'comment': '=>This Inner Loop Header: Depth=1', 'label': '.LBB0_1', @@ -171,7 +173,7 @@ class TestParserAArch64v81(unittest.TestCase): } instruction_form_3 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': {'name': 'cfi_def_cfa', 'parameters': ['w29', '-16']}, 'comment': None, 'label': None, diff --git a/tests/test_parser_x86att.py b/tests/test_parser_x86att.py index 7545f1e..16d43c8 100755 --- a/tests/test_parser_x86att.py +++ b/tests/test_parser_x86att.py @@ -136,7 +136,7 @@ class TestParserX86ATT(unittest.TestCase): instruction_form_1 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': None, 'comment': '-- Begin main', 'label': None, @@ -145,7 +145,7 @@ class TestParserX86ATT(unittest.TestCase): } instruction_form_2 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': None, 'comment': 'Preds ..B1.6', 'label': '..B1.7', @@ -154,7 +154,7 @@ class TestParserX86ATT(unittest.TestCase): } instruction_form_3 = { 'instruction': None, - 'operands': None, + 'operands': [], 'directive': {'name': 'quad', 'parameters': ['.2.3_2__kmpc_loc_pack.2']}, 'comment': 'qed', 'label': None, diff --git a/tests/test_semantics.py b/tests/test_semantics.py index f5c5a8b..7ff495a 100755 --- a/tests/test_semantics.py +++ b/tests/test_semantics.py @@ -73,18 +73,18 @@ class TestSemanticTools(unittest.TestCase): def test_src_dst_assignment_x86(self): for instruction_form in self.kernel_x86: with self.subTest(instruction_form=instruction_form): - if instruction_form['operands'] is not None: - self.assertTrue('source' in instruction_form['operands']) - self.assertTrue('destination' in instruction_form['operands']) - self.assertTrue('src_dst' in instruction_form['operands']) + if instruction_form['semantic_operands'] is not None: + self.assertTrue('source' in instruction_form['semantic_operands']) + self.assertTrue('destination' in instruction_form['semantic_operands']) + self.assertTrue('src_dst' in instruction_form['semantic_operands']) def test_src_dst_assignment_AArch64(self): for instruction_form in self.kernel_AArch64: with self.subTest(instruction_form=instruction_form): - if instruction_form['operands'] is not None: - self.assertTrue('source' in instruction_form['operands']) - self.assertTrue('destination' in instruction_form['operands']) - self.assertTrue('src_dst' in instruction_form['operands']) + if instruction_form['semantic_operands'] is not None: + self.assertTrue('source' in instruction_form['semantic_operands']) + self.assertTrue('destination' in instruction_form['semantic_operands']) + self.assertTrue('src_dst' in instruction_form['semantic_operands']) def test_tp_lt_assignment_x86(self): self.assertTrue('ports' in self.machine_model_csx)