Removed all AttrDict() usage in parser. process_operand() now turns single registers into operands

This commit is contained in:
stefandesouza
2023-08-21 18:53:56 +02:00
parent b06e6424f7
commit 76f3baf74e
5 changed files with 109 additions and 101 deletions

View File

@@ -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):

View File

@@ -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):

View File

@@ -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

View File

@@ -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):

View File

@@ -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)