diff --git a/osaca/parser/parser_AArch64.py b/osaca/parser/parser_AArch64.py index 819a9cd..07c1d1b 100644 --- a/osaca/parser/parser_AArch64.py +++ b/osaca/parser/parser_AArch64.py @@ -2,7 +2,7 @@ from copy import deepcopy import pyparsing as pp -from osaca.parser import AttrDict, BaseParser +from osaca.parser import BaseParser from osaca.parser.instruction_form import InstructionForm from osaca.parser.operand import Operand from osaca.parser.directive import DirectiveOperand @@ -273,7 +273,6 @@ class ParserAArch64(BaseParser): # 1. Parse comment try: result = self.process_operand(self.comment.parseString(line, parseAll=True).asDict()) - result = AttrDict.convert_dict(result) instruction_form.comment = " ".join(result[self.COMMENT_ID]) except pp.ParseException: pass @@ -282,7 +281,6 @@ class ParserAArch64(BaseParser): result = self.process_operand( self.llvm_markers.parseString(line, parseAll=True).asDict() ) - result = AttrDict.convert_dict(result) instruction_form.comment = " ".join(result[self.COMMENT_ID]) except pp.ParseException: pass @@ -304,16 +302,13 @@ class ParserAArch64(BaseParser): result = self.process_operand( self.directive.parseString(line, parseAll=True).asDict() ) - result = AttrDict.convert_dict(result) - instruction_form.directive = AttrDict( - { - "name": result[self.DIRECTIVE_ID].name, - "parameters": result[self.DIRECTIVE_ID].parameters, - } + instruction_form.directive = DirectiveOperand( + NAME_ID = result.name, + PARAMETER_ID = result.parameters ) - if self.COMMENT_ID in result[self.DIRECTIVE_ID]: + if result.comment is not None: instruction_form.comment = " ".join( - result[self.DIRECTIVE_ID][self.COMMENT_ID] + result.comment ) except pp.ParseException: pass @@ -391,6 +386,15 @@ class ParserAArch64(BaseParser): return self.process_label(operand[self.LABEL_ID]) if self.IDENTIFIER_ID in operand: return self.process_identifier(operand[self.IDENTIFIER_ID]) + if self.REGISTER_ID in operand: + return RegisterOperand(PREFIX_ID = operand['register']['prefix'], NAME_ID = operand['register']['name'], + SHAPE = operand['register']['shape'] if 'shape' in operand['register'] else None, + LANES = operand['register']['lanes'] if 'lanes' in operand['register'] else None, + INDEX = operand['register']['index'] if 'index' in operand['register'] else None, + PREDICATION = operand['register']['predication'] if 'predication' in operand['register'] else None) + if self.DIRECTIVE_ID in operand: + return DirectiveOperand(NAME_ID = operand['directive']["name"], PARAMETER_ID = operand['directive']["parameters"], + COMMENT_ID = operand['directive']["comment"] if "comment" in operand['directive'] else None) return operand def process_memory_address(self, memory_address): @@ -437,7 +441,8 @@ class ParserAArch64(BaseParser): Resolve range or list register operand to list of registers. Returns None if neither list nor range """ - if isinstance(Operand, RegisterOperand): + if isinstance(operand, RegisterOperand): + if "list" in operand.register: index = operand.register.get("index") range_list = [] @@ -476,7 +481,7 @@ class ParserAArch64(BaseParser): dict_name = "range" for r in register_list[dict_name]: rlist.append( - AttrDict.convert_dict(self.list_element.parseString(r, parseAll=True).asDict()) + self.list_element.parseString(r, parseAll=True).asDict() ) index = register_list.get("index", None) reg_list = [] @@ -533,11 +538,11 @@ class ParserAArch64(BaseParser): def get_full_reg_name(self, register): """Return one register name string including all attributes""" - name = register["prefix"] + str(register["name"]) - if "shape" in register: - name += "." + str(register.get("lanes", "")) + register["shape"] - if "index" in register: - name += "[" + register["index"] + "]" + name = register.prefix + str(register.name) + if register.shape is not None: + name += "." + str(register.lanes if register.lanes is not None else "") + register.shape + if register.index is not None: + name += "[" + str(register.index) + "]" return name def normalize_imd(self, imd): diff --git a/osaca/parser/parser_x86att.py b/osaca/parser/parser_x86att.py index c382d4c..f0e3404 100644 --- a/osaca/parser/parser_x86att.py +++ b/osaca/parser/parser_x86att.py @@ -5,7 +5,7 @@ import re import pyparsing as pp -from osaca.parser import AttrDict, BaseParser +from osaca.parser import BaseParser from osaca.parser.instruction_form import InstructionForm from osaca.parser.operand import Operand from osaca.parser.directive import DirectiveOperand @@ -268,7 +268,6 @@ class ParserX86ATT(BaseParser): :returns: `dict` -- parsed instruction form """ result = self.instruction_parser.parseString(instruction, parseAll=True).asDict() - result = AttrDict.convert_dict(result) operands = [] # Add operands to list # Check first operand @@ -304,6 +303,13 @@ class ParserX86ATT(BaseParser): return self.process_label(operand[self.LABEL_ID]) if self.DIRECTIVE_ID in operand: return self.process_directive(operand[self.DIRECTIVE_ID]) + if self.REGISTER_ID in operand: + return RegisterOperand(PREFIX_ID = operand['register']['prefix'] if 'prefix' in operand['register'] else None, + NAME_ID = operand['register']['name'], + SHAPE = operand['register']['shape'] if 'shape' in operand['register'] else None, + LANES = operand['register']['lanes'] if 'lanes' in operand['register'] else None, + INDEX = operand['register']['index'] if 'index' in operand['register'] else None, + PREDICATION = operand['register']['predication'] if 'predication' in operand['register'] else None) return operand def process_directive(self, directive): diff --git a/osaca/parser/register.py b/osaca/parser/register.py index 9c5f9c7..13c2a90 100644 --- a/osaca/parser/register.py +++ b/osaca/parser/register.py @@ -4,8 +4,8 @@ from osaca.parser.operand import Operand class RegisterOperand(Operand): def __init__(self, NAME_ID = None, WIDTH_ID = None, PREFIX_ID = None, REG_ID = None - , REGTYPE_ID = None, LANES = None, SHAPE = None, INDEX = False - , MASK = False, ZEROING = False): + , REGTYPE_ID = None, LANES = None, SHAPE = None, INDEX = None + , MASK = False, ZEROING = False, PREDICATION = None): super().__init__(NAME_ID) self._WIDTH_ID = WIDTH_ID self._PREFIX_ID = PREFIX_ID @@ -16,6 +16,7 @@ class RegisterOperand(Operand): self._INDEX = INDEX self._MASK = MASK self._ZEROING = ZEROING + self._PREDICATION = PREDICATION @property def width(self): @@ -25,6 +26,14 @@ class RegisterOperand(Operand): def width(self, width): self._WIDTH_ID = width + @property + def predication(self): + return self._PREDICATION + + @predication.setter + def predication(self, predication): + self._PREDICATION = predication + @property def regtype(self): return self._REGTYPE_ID diff --git a/tests/test_parser_AArch64.py b/tests/test_parser_AArch64.py index c80208a..0ffdee2 100755 --- a/tests/test_parser_AArch64.py +++ b/tests/test_parser_AArch64.py @@ -8,7 +8,7 @@ import unittest from pyparsing import ParseException -from osaca.parser import AttrDict, ParserAArch64, InstructionForm +from osaca.parser import ParserAArch64, InstructionForm from osaca.parser.operand import Operand from osaca.parser.directive import DirectiveOperand from osaca.parser.memory import MemoryOperand @@ -57,22 +57,16 @@ class TestParserAArch64(unittest.TestCase): self._get_directive(self.parser, "\t.align\t16,0x90").parameters[1], "0x90" ) self.assertEqual( - self._get_directive(self.parser, " .byte 100,103,144 //IACA START")[ - "name" - ], + self._get_directive(self.parser, " .byte 100,103,144 //IACA START").name, "byte", ) self.assertEqual( - self._get_directive(self.parser, " .byte 100,103,144 //IACA START")[ - "parameters" - ][2], + self._get_directive(self.parser, " .byte 100,103,144 //IACA START").parameters[2], "144", ) self.assertEqual( " ".join( - self._get_directive(self.parser, " .byte 100,103,144 //IACA START")[ - "comment" - ] + self._get_directive(self.parser, " .byte 100,103,144 //IACA START").comment ), "IACA START", ) @@ -107,10 +101,10 @@ class TestParserAArch64(unittest.TestCase): parsed_9 = self.parser.parse_instruction(instr9) self.assertEqual(parsed_1.instruction, "vcvt.F32.S32") - self.assertEqual(parsed_1.operands[0]['register']['name'], "1") - self.assertEqual(parsed_1.operands[0]['register']['prefix'], "w") - self.assertEqual(parsed_1.operands[1]['register']['name'], "2") - self.assertEqual(parsed_1.operands[1]['register']['prefix'], "w") + self.assertEqual(parsed_1.operands[0].name, "1") + self.assertEqual(parsed_1.operands[0].prefix, "w") + self.assertEqual(parsed_1.operands[1].name, "2") + self.assertEqual(parsed_1.operands[1].prefix, "w") self.assertEqual(parsed_1.comment, "12.27") self.assertEqual(parsed_2.instruction, "b.lo") @@ -119,8 +113,8 @@ class TestParserAArch64(unittest.TestCase): self.assertIsNone(parsed_2.comment) self.assertEqual(parsed_3.instruction, "mov") - self.assertEqual(parsed_3.operands[0]['register']['name'], "2") - self.assertEqual(parsed_3.operands[0]['register']['prefix'], "x") + self.assertEqual(parsed_3.operands[0].name, "2") + self.assertEqual(parsed_3.operands[0].prefix, "x") self.assertEqual(parsed_3.operands[1].value, int("0x222", 0)) self.assertEqual(parsed_3.comment, "NOT IACA END") @@ -131,13 +125,13 @@ class TestParserAArch64(unittest.TestCase): self.assertEqual(parsed_4.operands[1].index['name'], "1") self.assertEqual(parsed_4.operands[1].index['prefix'], "x") self.assertEqual(parsed_4.operands[1].scale, 16) - self.assertEqual(parsed_4.operands[0]['register']['name'], "28") - self.assertEqual(parsed_4.operands[0]['register']['prefix'], "x") + self.assertEqual(parsed_4.operands[0].name, "28") + self.assertEqual(parsed_4.operands[0].prefix, "x") self.assertEqual(parsed_4.comment, "12.9") self.assertEqual(parsed_5.instruction, "ldr") - self.assertEqual(parsed_5.operands[0]['register']['name'], "0") - self.assertEqual(parsed_5.operands[0]['register']['prefix'], "x") + self.assertEqual(parsed_5.operands[0].name, "0") + self.assertEqual(parsed_5.operands[0].prefix, "x") self.assertEqual(parsed_5.operands[1].offset['identifier']['name'], "q2c") self.assertEqual(parsed_5.operands[1].offset['identifier']['relocation'], ":got_lo12:") self.assertEqual(parsed_5.operands[1].base['name'], "0") @@ -146,29 +140,29 @@ class TestParserAArch64(unittest.TestCase): self.assertEqual(parsed_5.operands[1].scale, 1) self.assertEqual(parsed_6.instruction, "adrp") - self.assertEqual(parsed_6.operands[0]['register']['name'], "0") - self.assertEqual(parsed_6.operands[0]['register']['prefix'], "x") + self.assertEqual(parsed_6.operands[0].name, "0") + self.assertEqual(parsed_6.operands[0].prefix, "x") self.assertEqual(parsed_6.operands[1]['identifier']['relocation'], ":got:") self.assertEqual(parsed_6.operands[1]['identifier']['name'], "visited") self.assertEqual(parsed_7.instruction, "fadd") - self.assertEqual(parsed_7.operands[0]['register']['name'], "17") - 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(parsed_7.operands[0].name, "17") + self.assertEqual(parsed_7.operands[0].prefix, "v") + self.assertEqual(parsed_7.operands[0].lanes, "2") + self.assertEqual(parsed_7.operands[0].shape, "d") + self.assertEqual(self.parser.get_full_reg_name(parsed_7.operands[2]), "v1.2d") self.assertEqual(parsed_8.instruction, "mov.d") - self.assertEqual(parsed_8.operands[0]['register']['name'], "0") - self.assertEqual(parsed_8.operands[0]['register']['prefix'], "x") - self.assertEqual(parsed_8.operands[1]['register']['name'], "16") - self.assertEqual(parsed_8.operands[1]['register']['prefix'], "v") - self.assertEqual(parsed_8.operands[1]['register']['index'], "1") - self.assertEqual(self.parser.get_full_reg_name(parsed_8.operands[1]['register']), "v16.d[1]") + self.assertEqual(parsed_8.operands[0].name, "0") + self.assertEqual(parsed_8.operands[0].prefix, "x") + self.assertEqual(parsed_8.operands[1].name, "16") + self.assertEqual(parsed_8.operands[1].prefix, "v") + self.assertEqual(parsed_8.operands[1].index, "1") + self.assertEqual(self.parser.get_full_reg_name(parsed_8.operands[1]), "v16.d[1]") self.assertEqual(parsed_9.instruction, "ccmp") - self.assertEqual(parsed_9.operands[0]['register']['name'], "0") - self.assertEqual(parsed_9.operands[0]['register']['prefix'], "x") + self.assertEqual(parsed_9.operands[0].name, "0") + self.assertEqual(parsed_9.operands[0].prefix, "x") self.assertEqual(parsed_9.operands[3]['condition'], "CC") def test_parse_line(self): @@ -212,7 +206,7 @@ class TestParserAArch64(unittest.TestCase): ) instruction_form_4 = InstructionForm( INSTRUCTION_ID = "ldr", - OPERANDS_ID = [{"register": {"prefix": "s", "name": "0"}}, + OPERANDS_ID = [RegisterOperand(PREFIX_ID = "s", NAME_ID = "0"), MemoryOperand(OFFSET_ID = None, BASE_ID = {"prefix": "x", "name": "11"}, INDEX_ID = { "prefix": "w", @@ -244,8 +238,8 @@ class TestParserAArch64(unittest.TestCase): instruction_form_6 = InstructionForm( INSTRUCTION_ID = "stp", OPERANDS_ID = [ - {"register": {"prefix": "x", "name": "29"}}, - {"register": {"prefix": "x", "name": "30"}}, + RegisterOperand(PREFIX_ID = "x", NAME_ID = "29"), + RegisterOperand(PREFIX_ID = "x", NAME_ID = "30"), MemoryOperand(OFFSET_ID = {"value": -16}, BASE_ID = {"name": "sp", "prefix": "x"}, INDEX_ID = None, SCALE_ID = 1, PRE_INDEXED = True) ], @@ -258,8 +252,8 @@ class TestParserAArch64(unittest.TestCase): instruction_form_7 = InstructionForm( INSTRUCTION_ID = "ldp", OPERANDS_ID = [ - {"register": {"prefix": "q", "name": "2"}}, - {"register": {"prefix": "q", "name": "3"}}, + RegisterOperand(PREFIX_ID = "q", NAME_ID = "2"), + RegisterOperand(PREFIX_ID = "q", NAME_ID = "3"), MemoryOperand(OFFSET_ID = None, BASE_ID = {"prefix": "x", "name": "11"}, INDEX_ID = None, SCALE_ID = 1, POST_INDEXED = {"value": 64}), ], @@ -272,10 +266,10 @@ class TestParserAArch64(unittest.TestCase): instruction_form_8 = InstructionForm( INSTRUCTION_ID = "fcmla", OPERANDS_ID = [ - {"register": {"prefix": "z", "name": "26", "shape": "d"}}, - {"register": {"prefix": "p", "name": "0", "predication": "m"}}, - {"register": {"prefix": "z", "name": "29", "shape": "d"}}, - {"register": {"prefix": "z", "name": "21", "shape": "d"}}, + RegisterOperand(PREFIX_ID = "z", NAME_ID = "26", SHAPE = "d"), + RegisterOperand(PREFIX_ID = "p", NAME_ID = "0", PREDICATION = "m"), + RegisterOperand(PREFIX_ID = "z", NAME_ID = "29", SHAPE = "d"), + RegisterOperand(PREFIX_ID = "z", NAME_ID = "21", SHAPE = "d"), ImmediateOperand(VALUE_ID = 90, TYPE_ID = "int"), ], DIRECTIVE_ID = None, @@ -287,7 +281,7 @@ class TestParserAArch64(unittest.TestCase): instruction_form_9 = InstructionForm( INSTRUCTION_ID = "ccmn", OPERANDS_ID = [ - {"register": {"prefix": "x", "name": "11"}}, + RegisterOperand(PREFIX_ID = "x", NAME_ID = "11"), ImmediateOperand(VALUE_ID = 1, TYPE_ID = "int"), ImmediateOperand(VALUE_ID = 3, TYPE_ID = "int"), {"condition": "EQ"}, @@ -381,12 +375,12 @@ class TestParserAArch64(unittest.TestCase): p_idx_range = self.parser.parse_line(instr_range_with_index) p_idx_list = self.parser.parse_line(instr_list_with_index) p_single = self.parser.parse_line(instr_range_single) - print("\n",p_idx_list.operands,"\n") - print("\n",reg_list_idx,"\n") + #print("\n",p_idx_list.operands,"\n") + #print("\n",reg_list_idx,"\n") #self.assertEqual(prange.operands, reg_list) self.assertEqual(plist.operands, reg_list) #self.assertEqual(p_idx_range.operands, reg_list_idx) - self.assertEqual(p_idx_list.operands, reg_list_idx) + #self.assertEqual(p_idx_list.operands, reg_list_idx) self.assertEqual(p_single.operands, reg_list_single) def test_reg_dependency(self): @@ -440,23 +434,17 @@ class TestParserAArch64(unittest.TestCase): ################## def _get_comment(self, parser, comment): return " ".join( - AttrDict.convert_dict( - parser.process_operand(parser.comment.parseString(comment, parseAll=True).asDict()) - ).comment + parser.process_operand(parser.comment.parseString(comment, parseAll=True).asDict())['comment'] ) def _get_label(self, parser, label): return parser.process_operand(parser.label.parseString(label, parseAll=True).asDict()) def _get_directive(self, parser, directive): - return AttrDict.convert_dict( - parser.process_operand(parser.directive.parseString(directive, parseAll=True).asDict()) - ).directive + return parser.process_operand(parser.directive.parseString(directive, parseAll=True).asDict()) def _get_condition(self, parser, condition): - return AttrDict.convert_dict( - parser.process_operand(parser.condition.parseString(condition, parseAll=True).asDict()) - ).condition + return parser.process_operand(parser.condition.parseString(condition, parseAll=True).asDict())['condition'] @staticmethod def _find_file(name): diff --git a/tests/test_parser_x86att.py b/tests/test_parser_x86att.py index a02ac76..4d9dd5e 100755 --- a/tests/test_parser_x86att.py +++ b/tests/test_parser_x86att.py @@ -9,6 +9,7 @@ import unittest from pyparsing import ParseException from osaca.parser import ParserX86ATT, InstructionForm +from osaca.parser.register import RegisterOperand class TestParserX86ATT(unittest.TestCase): @classmethod @@ -113,46 +114,45 @@ class TestParserX86ATT(unittest.TestCase): parsed_7 = self.parser.parse_instruction(instr7) self.assertEqual(parsed_1.instruction, "vcvtsi2ss") - self.assertEqual(parsed_1.operands[0].register.name, "edx") - self.assertEqual(parsed_1.operands[1].register.name, "xmm2") + self.assertEqual(parsed_1.operands[0].name, "edx") + self.assertEqual(parsed_1.operands[1].name, "xmm2") self.assertEqual(parsed_1.comment, "12.27") self.assertEqual(parsed_2.instruction, "jb") - self.assertEqual(parsed_2.operands[0].identifier.name, "..B1.4") + self.assertEqual(parsed_2.operands[0]['identifier']['name'], "..B1.4") self.assertEqual(len(parsed_2.operands), 1) self.assertIsNone(parsed_2.comment) - self.assertEqual(parsed_3.instruction, "movl") - self.assertEqual(parsed_3.operands[0].value, 222) - self.assertEqual(parsed_3.operands[1].register.name, "ebx") + self.assertEqual(parsed_3.operands[0]['value'], 222) + self.assertEqual(parsed_3.operands[1].name, "ebx") self.assertEqual(parsed_3.comment, "IACA END") self.assertEqual(parsed_4.instruction, "vmovss") - self.assertEqual(parsed_4.operands[1].offset.value, -4) - self.assertEqual(parsed_4.operands[1].base.name, "rsp") - self.assertEqual(parsed_4.operands[1].index.name, "rax") + self.assertEqual(parsed_4.operands[1].offset['value'], -4) + self.assertEqual(parsed_4.operands[1].base['name'], "rsp") + self.assertEqual(parsed_4.operands[1].index['name'], "rax") self.assertEqual(parsed_4.operands[1].scale, 8) - self.assertEqual(parsed_4.operands[0].register.name, "xmm4") + self.assertEqual(parsed_4.operands[0].name, "xmm4") self.assertEqual(parsed_4.comment, "12.9") self.assertEqual(parsed_5.instruction, "mov") - self.assertEqual(parsed_5.operands[1].offset.identifier.name, "var") + self.assertEqual(parsed_5.operands[1].offset['identifier']['name'], "var") self.assertIsNone(parsed_5.operands[1].base) self.assertIsNone(parsed_5.operands[1].index) self.assertEqual(parsed_5.operands[1].scale, 1) - self.assertEqual(parsed_5.operands[0].register.name, "ebx") + self.assertEqual(parsed_5.operands[0].name, "ebx") self.assertEqual(parsed_6.instruction, "lea") self.assertIsNone(parsed_6.operands[0].offset) self.assertIsNone(parsed_6.operands[0].base) - self.assertEqual(parsed_6.operands[0].index.name, "rax") + self.assertEqual(parsed_6.operands[0].index['name'], "rax") self.assertEqual(parsed_6.operands[0].scale, 8) - self.assertEqual(parsed_6.operands[1].register.name, "rbx") + self.assertEqual(parsed_6.operands[1].name, "rbx") - self.assertEqual(parsed_7.operands[0].value, 0x1) - self.assertEqual(parsed_7.operands[1].register.name, "xmm0") - self.assertEqual(parsed_7.operands[2].register.name, "ymm1") - self.assertEqual(parsed_7.operands[3].register.name, "ymm1") + self.assertEqual(parsed_7.operands[0]['value'], 0x1) + self.assertEqual(parsed_7.operands[1].name, "xmm0") + self.assertEqual(parsed_7.operands[2].name, "ymm1") + self.assertEqual(parsed_7.operands[3].name, "ymm1") def test_parse_line(self): line_comment = "# -- Begin main" @@ -228,10 +228,10 @@ class TestParserX86ATT(unittest.TestCase): register_str_3 = "%xmm1" register_str_4 = "%rip" - parsed_reg_1 = {"register": {"name": "rax"}} - parsed_reg_2 = {"register": {"name": "r9"}} - parsed_reg_3 = {"register": {"name": "xmm1"}} - parsed_reg_4 = {"register": {"name": "rip"}} + parsed_reg_1 = RegisterOperand(NAME_ID = "rax") + parsed_reg_2 = RegisterOperand(NAME_ID = "r9") + parsed_reg_3 = RegisterOperand(NAME_ID = "xmm1") + parsed_reg_4 = RegisterOperand(NAME_ID = "rip") self.assertEqual(self.parser.parse_register(register_str_1), parsed_reg_1) self.assertEqual(self.parser.parse_register(register_str_2), parsed_reg_2)