Beispiel #1
0
 def resolve_range_list(self, operand):
     """
     Resolve range or list register operand to list of registers.
     Returns None if neither list nor range
     """
     if 'register' in operand:
         if 'list' in operand.register:
             index = operand.register.get('index')
             range_list = []
             for reg in operand.register.list:
                 reg = deepcopy(reg)
                 if index is not None:
                     reg['index'] = int(index, 0)
                 range_list.append(AttrDict({self.REGISTER_ID: reg}))
             return range_list
         elif 'range' in operand.register:
             base_register = operand.register.range[0]
             index = operand.register.get('index')
             range_list = []
             start_name = base_register.name
             end_name = operand.register.range[1].name
             for name in range(int(start_name), int(end_name) + 1):
                 reg = deepcopy(base_register)
                 if index is not None:
                     reg['index'] = int(index, 0)
                 reg['name'] = str(name)
                 range_list.append(AttrDict({self.REGISTER_ID: reg}))
             return range_list
     # neither register list nor range, return unmodified
     return operand
Beispiel #2
0
 def process_immediate(self, immediate):
     """Post-process immediate operand"""
     dict_name = ""
     if "identifier" in immediate:
         # actually an identifier, change declaration
         return immediate
     if "value" in immediate:
         # normal integer value
         immediate["type"] = "int"
         # convert hex/bin immediates to dec
         immediate["value"] = self.normalize_imd(immediate)
         return AttrDict({self.IMMEDIATE_ID: immediate})
     if "base_immediate" in immediate:
         # arithmetic immediate, add calculated value as value
         immediate["shift"] = immediate["shift"][0]
         immediate["value"] = self.normalize_imd(immediate["base_immediate"]) << int(
             immediate["shift"]["value"]
         )
         immediate["type"] = "int"
         return AttrDict({self.IMMEDIATE_ID: immediate})
     if "float" in immediate:
         dict_name = "float"
     if "double" in immediate:
         dict_name = "double"
     if "exponent" in immediate[dict_name]:
         immediate["type"] = dict_name
         return AttrDict({self.IMMEDIATE_ID: immediate})
     else:
         # change 'mantissa' key to 'value'
         return AttrDict({
             self.IMMEDIATE_ID: AttrDict({
                 "value": immediate[dict_name]["mantissa"],
                 "type": dict_name})}
         )
Beispiel #3
0
 def process_memory_address(self, memory_address):
     """Post-process memory address operand"""
     # Remove unecessarily created dictionary entries during memory address parsing
     offset = memory_address.get("offset", None)
     base = memory_address.get("base", None)
     index = memory_address.get("index", None)
     scale = 1 if "scale" not in memory_address else int(
         memory_address["scale"], 0)
     if isinstance(offset, str) and base is None and index is None:
         try:
             offset = {"value": int(offset, 0)}
         except ValueError:
             offset = {"value": offset}
     elif offset is not None and "value" in offset:
         offset["value"] = int(offset["value"], 0)
     new_dict = AttrDict({
         "offset": offset,
         "base": base,
         "index": index,
         "scale": scale
     })
     # Add segmentation extension if existing
     if self.SEGMENT_EXT_ID in memory_address:
         new_dict[self.SEGMENT_EXT_ID] = memory_address[self.SEGMENT_EXT_ID]
     return AttrDict({self.MEMORY_ID: new_dict})
Beispiel #4
0
 def process_memory_address(self, memory_address):
     """Post-process memory address operand"""
     # Remove unnecessarily created dictionary entries during parsing
     offset = memory_address.get("offset", None)
     if isinstance(offset, list) and len(offset) == 1:
         offset = offset[0]
     if offset is not None and "value" in offset:
         offset["value"] = int(offset["value"], 0)
     base = memory_address.get("base", None)
     index = memory_address.get("index", None)
     scale = 1
     if base is not None and "name" in base and base["name"] == "sp":
         base["prefix"] = "x"
     if index is not None and "name" in index and index["name"] == "sp":
         index["prefix"] = "x"
     valid_shift_ops = ["lsl", "uxtw", "sxtw"]
     if "index" in memory_address:
         if "shift" in memory_address["index"]:
             if memory_address["index"]["shift_op"].lower() in valid_shift_ops:
                 scale = 2 ** int(memory_address["index"]["shift"][0]["value"])
     new_dict = AttrDict({"offset": offset, "base": base, "index": index, "scale": scale})
     if "pre_indexed" in memory_address:
         new_dict["pre_indexed"] = True
     if "post_indexed" in memory_address:
         if "value" in memory_address["post_indexed"]:
             new_dict["post_indexed"] = {"value": int(
                 memory_address["post_indexed"]["value"], 0
             )}
         else:
             new_dict["post_indexed"] = memory_address["post_indexed"]
     return AttrDict({self.MEMORY_ID: new_dict})
Beispiel #5
0
 def process_memory_address(self, memory_address):
     """Post-process memory address operand"""
     # Remove unnecessarily created dictionary entries during parsing
     offset = memory_address.get('offset', None)
     if isinstance(offset, list) and len(offset) == 1:
         offset = offset[0]
     base = memory_address.get('base', None)
     index = memory_address.get('index', None)
     scale = 1
     if base is not None and 'name' in base and base['name'] == 'sp':
         base['prefix'] = 'x'
     if index is not None and 'name' in index and index['name'] == 'sp':
         index['prefix'] = 'x'
     valid_shift_ops = ['lsl', 'uxtw', 'sxtw']
     if 'index' in memory_address:
         if 'shift' in memory_address['index']:
             if memory_address['index']['shift_op'].lower(
             ) in valid_shift_ops:
                 scale = 2**int(memory_address['index']['shift']['value'])
     new_dict = AttrDict({
         'offset': offset,
         'base': base,
         'index': index,
         'scale': scale
     })
     if 'pre_indexed' in memory_address:
         new_dict['pre_indexed'] = True
     if 'post_indexed' in memory_address:
         new_dict['post_indexed'] = memory_address['post_indexed']
     return AttrDict({self.MEMORY_ID: new_dict})
Beispiel #6
0
 def process_immediate(self, immediate):
     """Post-process immediate operand"""
     dict_name = ''
     if 'identifier' in immediate:
         # actually an identifier, change declaration
         return immediate
     if 'value' in immediate:
         # normal integer value, nothing to do
         return AttrDict({self.IMMEDIATE_ID: immediate})
     if 'base_immediate' in immediate:
         # arithmetic immediate, add calculated value as value
         immediate['shift'] = immediate['shift'][0]
         immediate['value'] = int(
             immediate['base_immediate']['value']) << int(
                 immediate['shift']['value'])
         return AttrDict({self.IMMEDIATE_ID: immediate})
     if 'float' in immediate:
         dict_name = 'float'
     if 'double' in immediate:
         dict_name = 'double'
     if 'exponent' in immediate[dict_name]:
         # nothing to do
         return AttrDict({self.IMMEDIATE_ID: immediate})
     else:
         # change 'mantissa' key to 'value'
         return AttrDict({
             self.IMMEDIATE_ID:
             AttrDict({'value': immediate[dict_name]['mantissa']})
         })
Beispiel #7
0
 def process_memory_address(self, memory_address):
     """Post-process memory address operand"""
     # Remove unecessarily created dictionary entries during memory address parsing
     offset = memory_address.get('offset', None)
     base = memory_address.get('base', None)
     index = memory_address.get('index', None)
     scale = 1 if 'scale' not in memory_address else int(memory_address['scale'])
     if isinstance(offset, str) and base is None and index is None:
         offset = {'value': offset}
     new_dict = AttrDict({'offset': offset, 'base': base, 'index': index, 'scale': scale})
     # Add segmentation extension if existing
     if self.SEGMENT_EXT_ID in memory_address:
         new_dict[self.SEGMENT_EXT_ID] = memory_address[self.SEGMENT_EXT_ID]
     return AttrDict({self.MEMORY_ID: new_dict})
Beispiel #8
0
    def test_multiple_regs(self):
        instr_range = "PUSH {x5-x7}"
        instr_list = "POP {x5, x6, x7}"
        instr_range_with_index = "ld4 {v0.S - v3.S}[2]"
        instr_list_with_index = "ld4 {v0.S, v1.S, v2.S, v3.S}[2]"
        instr_range_single = "dummy  { z1.d }"
        reg_list = [
            AttrDict({"register": {"prefix": "x", "name": "5"}}),
            AttrDict({"register": {"prefix": "x", "name": "6"}}),
            AttrDict({"register": {"prefix": "x", "name": "7"}}),
        ]
        reg_list_idx = [
            AttrDict({"register": {"prefix": "v", "name": "0", "shape": "S", "index": 2}}),
            AttrDict({"register": {"prefix": "v", "name": "1", "shape": "S", "index": 2}}),
            AttrDict({"register": {"prefix": "v", "name": "2", "shape": "S", "index": 2}}),
            AttrDict({"register": {"prefix": "v", "name": "3", "shape": "S", "index": 2}}),
        ]
        reg_list_single = [AttrDict({"register": {"prefix": "z", "name": "1", "shape": "d"}})]

        prange = self.parser.parse_line(instr_range)
        plist = self.parser.parse_line(instr_list)
        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)

        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_single.operands, reg_list_single)
Beispiel #9
0
 def test_register_funcs(self):
     reg_a1 = AttrDict({"name": "rax"})
     reg_a2 = AttrDict({"name": "eax"})
     register_string = "v1.2d"
     with self.assertRaises(NotImplementedError):
         self.parser.is_reg_dependend_of(reg_a1, reg_a2)
     with self.assertRaises(NotImplementedError):
         self.parser.parse_register(register_string)
     with self.assertRaises(NotImplementedError):
         self.parser.is_gpr(reg_a1)
     with self.assertRaises(NotImplementedError):
         self.parser.is_vector_register(reg_a1)
     with self.assertRaises(NotImplementedError):
         self.parser.process_operand(reg_a1)
     with self.assertRaises(NotImplementedError):
         self.parser.get_full_reg_name(reg_a1)
Beispiel #10
0
 def process_immediate(self, immediate):
     """Post-process immediate operand"""
     if 'identifier' in immediate:
         # actually an identifier, change declaration
         return immediate
     # otherwise nothing to do
     return AttrDict({self.IMMEDIATE_ID: immediate})
Beispiel #11
0
 def process_directive(self, directive):
     directive_new = {'name': directive['name'], 'parameters': []}
     if 'parameters' in directive:
         directive_new['parameters'] = directive['parameters']
     if 'comment' in directive:
         directive_new['comment'] = directive['comment']
     return AttrDict({self.DIRECTIVE_ID: directive_new})
Beispiel #12
0
 def process_directive(self, directive):
     directive_new = {"name": directive["name"], "parameters": []}
     if "parameters" in directive:
         directive_new["parameters"] = directive["parameters"]
     if "comment" in directive:
         directive_new["comment"] = directive["comment"]
     return AttrDict({self.DIRECTIVE_ID: directive_new})
Beispiel #13
0
    def parse_instruction(self, instruction):
        """
        Parse instruction in asm line.

        :param str instruction: Assembly line string.
        :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
        if 'operand1' in result:
            operands.append(self.process_operand(result['operand1']))
        # Check second operand
        if 'operand2' in result:
            operands.append(self.process_operand(result['operand2']))
        # Check third operand
        if 'operand3' in result:
            operands.append(self.process_operand(result['operand3']))
        # Check fourth operand
        if 'operand4' in result:
            operands.append(self.process_operand(result['operand4']))
        return_dict = AttrDict({
            self.INSTRUCTION_ID:
            result['mnemonic'],
            self.OPERANDS_ID:
            operands,
            self.COMMENT_ID:
            ' '.join(result[self.COMMENT_ID])
            if self.COMMENT_ID in result else None,
        })
        return return_dict
Beispiel #14
0
 def process_immediate(self, immediate):
     """Post-process immediate operand"""
     if "identifier" in immediate:
         # actually an identifier, change declaration
         return immediate
     # otherwise just make sure the immediate is a decimal
     immediate["value"] = int(immediate["value"], 0)
     return AttrDict({self.IMMEDIATE_ID: immediate})
Beispiel #15
0
 def process_register_list(self, register_list):
     """Post-process register lists (e.g., {r0,r3,r5}) and register ranges (e.g., {r0-r7})"""
     # Remove unnecessarily created dictionary entries during parsing
     rlist = []
     dict_name = ''
     if 'list' in register_list:
         dict_name = 'list'
     if 'range' in register_list:
         dict_name = 'range'
     for r in register_list[dict_name]:
         rlist.append(
             AttrDict.convert_dict(
                 self.list_element.parseString(r, parseAll=True).asDict()))
     index = register_list.get('index', None)
     new_dict = AttrDict({dict_name: rlist, 'index': index})
     if len(new_dict[dict_name]) == 1:
         return AttrDict({self.REGISTER_ID: new_dict[dict_name][0]})
     return AttrDict({self.REGISTER_ID: new_dict})
Beispiel #16
0
    def test_multiple_regs(self):
        instr_range = 'PUSH {x5-x7}'
        reg_range = AttrDict({
            'register': {
                'range': [{
                    'prefix': 'x',
                    'name': '5'
                }, {
                    'prefix': 'x',
                    'name': '7'
                }],
                'index':
                None
            }
        })
        instr_list = 'POP {x5, x7, x9}'
        reg_list = AttrDict({
            'register': {
                'list': [{
                    'prefix': 'x',
                    'name': '5'
                }, {
                    'prefix': 'x',
                    'name': '7'
                }, {
                    'prefix': 'x',
                    'name': '9'
                }],
                'index':
                None
            }
        })
        prange = self.parser.parse_line(instr_range)
        plist = self.parser.parse_line(instr_list)

        self.assertEqual(prange.operands[0], reg_range)
        self.assertEqual(plist.operands[0], reg_list)
Beispiel #17
0
    def test_is_read_is_written_x86(self):
        # independent form HW model
        dag = KernelDG(self.kernel_x86, self.parser_x86, None)
        reg_rcx = AttrDict({'name': 'rcx'})
        reg_ymm1 = AttrDict({'name': 'ymm1'})

        instr_form_r_c = self.parser_x86.parse_line(
            'vmovsd  %xmm0, (%r15,%rcx,8)')
        self.semantics_csx.assign_src_dst(instr_form_r_c)
        instr_form_non_r_c = self.parser_x86.parse_line(
            'movl  %xmm0, (%r15,%rax,8)')
        self.semantics_csx.assign_src_dst(instr_form_non_r_c)
        instr_form_w_c = self.parser_x86.parse_line('movi $0x05ACA, %rcx')
        self.semantics_csx.assign_src_dst(instr_form_w_c)

        instr_form_rw_ymm_1 = self.parser_x86.parse_line(
            'vinsertf128 $0x1, %xmm1, %ymm0, %ymm1')
        self.semantics_csx.assign_src_dst(instr_form_rw_ymm_1)
        instr_form_rw_ymm_2 = self.parser_x86.parse_line(
            'vinsertf128 $0x1, %xmm0, %ymm1, %ymm1')
        self.semantics_csx.assign_src_dst(instr_form_rw_ymm_2)
        instr_form_r_ymm = self.parser_x86.parse_line('vmovapd %ymm1, %ymm0')
        self.semantics_csx.assign_src_dst(instr_form_r_ymm)

        self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
        self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
        self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c))
        self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c))
        self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c))

        self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1))
        self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2))
        self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm))
        self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1))
        self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2))
        self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm))
Beispiel #18
0
    def parse_instruction(self, instruction):
        """
        Parse instruction in asm line.

        :param str instruction: Assembly line string.
        :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
        if "operand1" in result:
            operand = self.process_operand(result["operand1"])
            operands.extend(operand) if isinstance(operand, list) else operands.append(operand)
        # Check second operand
        if "operand2" in result:
            operand = self.process_operand(result["operand2"])
            operands.extend(operand) if isinstance(operand, list) else operands.append(operand)
        # Check third operand
        if "operand3" in result:
            operand = self.process_operand(result["operand3"])
            operands.extend(operand) if isinstance(operand, list) else operands.append(operand)
        # Check fourth operand
        if "operand4" in result:
            operand = self.process_operand(result["operand4"])
            operands.extend(operand) if isinstance(operand, list) else operands.append(operand)
        # Check fifth operand
        if "operand5" in result:
            operand = self.process_operand(result["operand5"])
            operands.extend(operand) if isinstance(operand, list) else operands.append(operand)

        return_dict = AttrDict(
            {
                self.INSTRUCTION_ID: result.mnemonic,
                self.OPERANDS_ID: operands,
                self.COMMENT_ID: " ".join(result[self.COMMENT_ID])
                if self.COMMENT_ID in result
                else None,
            }
        )
        return return_dict
Beispiel #19
0
    def parse_line(self, line, line_number=None):
        """
        Parse line and return instruction form.

        :param str line: line of assembly code
        :param line_number: default None, identifier of instruction form
        :type line_number: int, optional
        :return: ``dict`` -- parsed asm line (comment, label, directive or instruction form)
        """
        instruction_form = AttrDict({
            self.INSTRUCTION_ID: None,
            self.OPERANDS_ID: [],
            self.DIRECTIVE_ID: None,
            self.COMMENT_ID: None,
            self.LABEL_ID: None,
            'line': line,
            'line_number': line_number,
        })
        result = None

        # 1. Parse comment
        try:
            result = self.process_operand(
                self.comment.parseString(line, parseAll=True).asDict())
            result = AttrDict.convert_dict(result)
            instruction_form[self.COMMENT_ID] = ' '.join(
                result[self.COMMENT_ID])
        except pp.ParseException:
            pass

        # 2. Parse label
        if result is None:
            try:
                result = self.process_operand(
                    self.label.parseString(line, parseAll=True).asDict())
                result = AttrDict.convert_dict(result)
                instruction_form[self.LABEL_ID] = result[self.LABEL_ID]['name']
                if self.COMMENT_ID in result[self.LABEL_ID]:
                    instruction_form[self.COMMENT_ID] = ' '.join(
                        result[self.LABEL_ID][self.COMMENT_ID])
            except pp.ParseException:
                pass

        # 3. Parse directive
        if result is None:
            try:
                result = self.process_operand(
                    self.directive.parseString(line, parseAll=True).asDict())
                result = AttrDict.convert_dict(result)
                instruction_form[self.DIRECTIVE_ID] = AttrDict({
                    'name':
                    result[self.DIRECTIVE_ID]['name'],
                    'parameters':
                    result[self.DIRECTIVE_ID]['parameters'],
                })
                if self.COMMENT_ID in result[self.DIRECTIVE_ID]:
                    instruction_form[self.COMMENT_ID] = ' '.join(
                        result[self.DIRECTIVE_ID][self.COMMENT_ID])
            except pp.ParseException:
                pass

        # 4. Parse instruction
        if result is None:
            try:
                result = self.parse_instruction(line)
            except pp.ParseException:
                raise ValueError(
                    'Could not parse instruction on line {}: {!r}'.format(
                        line_number, line))
            instruction_form[self.INSTRUCTION_ID] = result[self.INSTRUCTION_ID]
            instruction_form[self.OPERANDS_ID] = result[self.OPERANDS_ID]
            instruction_form[self.COMMENT_ID] = result[self.COMMENT_ID]

        return instruction_form
Beispiel #20
0
 def process_identifier(self, identifier):
     """Post-process identifier operand"""
     # remove value if it consists of symbol+offset
     if 'value' in identifier:
         del identifier['value']
     return AttrDict({self.IDENTIFIER_ID: identifier})
Beispiel #21
0
 def assign_src_dst(self, instruction_form):
     """Update instruction form dictionary with source, destination and flag information."""
     # if the instruction form doesn't have operands or is None, there's nothing to do
     if instruction_form['operands'] is None or instruction_form['instruction'] 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)
     isa_data = self._isa_model.get_instruction(
         instruction_form['instruction'], instruction_form['operands']
     )
     if (
         isa_data is None
         and self._isa == 'x86'
         and instruction_form['instruction'][-1] in self.GAS_SUFFIXES
     ):
         # Check for instruction without GAS suffix
         isa_data = self._isa_model.get_instruction(
             instruction_form['instruction'][:-1], instruction_form['operands']
         )
     operands = instruction_form['operands']
     op_dict = {}
     assign_default = False
     if isa_data:
         # load src/dst structure from isa_data
         op_dict = self._apply_found_ISA_data(isa_data, operands)
     else:
         # Couldn't found instruction form in ISA DB
         assign_default = True
         # check for equivalent register-operands DB entry if LD/ST
         if any(['memory' in op for op in operands]):
             operands_reg = self.substitute_mem_address(instruction_form['operands'])
             isa_data_reg = self._isa_model.get_instruction(
                 instruction_form['instruction'], operands_reg
             )
             if (
                 isa_data_reg is None
                 and self._isa == 'x86'
                 and instruction_form['instruction'][-1] in self.GAS_SUFFIXES
             ):
                 # Check for instruction without GAS suffix
                 isa_data_reg = self._isa_model.get_instruction(
                     instruction_form['instruction'][:-1], operands_reg
                 )
             if isa_data_reg:
                 assign_default = False
                 op_dict = self._apply_found_ISA_data(isa_data_reg, operands)
     if assign_default:
         # no irregular operand structure, apply default
         op_dict['source'] = self._get_regular_source_operands(instruction_form)
         op_dict['destination'] = self._get_regular_destination_operands(instruction_form)
         op_dict['src_dst'] = []
     # post-process pre- and post-indexing for aarch64 memory operands
     if self._isa == 'aarch64':
         for operand in [op for op in op_dict['source'] if 'memory' in op]:
             if ('post_indexed' in operand['memory'] and operand['memory']['post_indexed']) or (
                 'pre_indexed' in operand['memory'] and operand['memory']['pre_indexed']
             ):
                 op_dict['src_dst'].append(AttrDict.convert_dict(
                     {'register': operand['memory']['base']}))
         for operand in [op for op in op_dict['destination'] if 'memory' in op]:
             if ('post_indexed' in operand['memory'] and operand['memory']['post_indexed']) or (
                 'pre_indexed' in operand['memory'] and operand['memory']['pre_indexed']
             ):
                 op_dict['src_dst'].append(AttrDict.convert_dict(
                     {'register': operand['memory']['base']}))
     # store operand list in dict and reassign operand key/value pair
     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 []
     )
     if self._has_load(instruction_form):
         instruction_form['flags'] += [INSTR_FLAGS.HAS_LD]
     if self._has_store(instruction_form):
         instruction_form['flags'] += [INSTR_FLAGS.HAS_ST]
Beispiel #22
0
    def test_is_read_is_written_AArch64(self):
        # independent form HW model
        dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None, None)
        reg_x1 = AttrDict({"prefix": "x", "name": "1"})
        reg_w1 = AttrDict({"prefix": "w", "name": "1"})
        reg_d1 = AttrDict({"prefix": "d", "name": "1"})
        reg_q1 = AttrDict({"prefix": "q", "name": "1"})
        reg_v1 = AttrDict({
            "prefix": "v",
            "name": "1",
            "lanes": "2",
            "shape": "d"
        })
        regs = [reg_d1, reg_q1, reg_v1]
        regs_gp = [reg_w1, reg_x1]

        instr_form_r_1 = self.parser_AArch64.parse_line(
            "stp q1, q3, [x12, #192]")
        self.semantics_tx2.assign_src_dst(instr_form_r_1)
        instr_form_r_2 = self.parser_AArch64.parse_line(
            "fadd v2.2d, v1.2d, v0.2d")
        self.semantics_tx2.assign_src_dst(instr_form_r_2)
        instr_form_w_1 = self.parser_AArch64.parse_line(
            "ldr d1, [x1, #:got_lo12:q2c]")
        self.semantics_tx2.assign_src_dst(instr_form_w_1)
        instr_form_non_w_1 = self.parser_AArch64.parse_line(
            "ldr x1, [x1, #:got_lo12:q2c]")
        self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
        instr_form_rw_1 = self.parser_AArch64.parse_line(
            "fmul v1.2d, v1.2d, v0.2d")
        self.semantics_tx2.assign_src_dst(instr_form_rw_1)
        instr_form_rw_2 = self.parser_AArch64.parse_line(
            "ldp q2, q4, [x1, #64]!")
        self.semantics_tx2.assign_src_dst(instr_form_rw_2)
        instr_form_rw_3 = self.parser_AArch64.parse_line("str x4, [x1], #64")
        self.semantics_tx2.assign_src_dst(instr_form_rw_3)
        instr_form_non_rw_1 = self.parser_AArch64.parse_line("adds x1, x11")
        self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)

        for reg in regs:
            with self.subTest(reg=reg):
                self.assertTrue(dag.is_read(reg, instr_form_r_1))
                self.assertTrue(dag.is_read(reg, instr_form_r_2))
                self.assertTrue(dag.is_read(reg, instr_form_rw_1))
                self.assertFalse(dag.is_read(reg, instr_form_rw_2))
                self.assertFalse(dag.is_read(reg, instr_form_rw_3))
                self.assertFalse(dag.is_read(reg, instr_form_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_rw_1))
                self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_rw_2))
                self.assertFalse(dag.is_written(reg, instr_form_rw_3))
                self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
                self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
        for reg in regs_gp:
            with self.subTest(reg=reg):
                self.assertFalse(dag.is_read(reg, instr_form_r_1))
                self.assertFalse(dag.is_read(reg, instr_form_r_2))
                self.assertFalse(dag.is_read(reg, instr_form_rw_1))
                self.assertTrue(dag.is_read(reg, instr_form_rw_2))
                self.assertTrue(dag.is_read(reg, instr_form_rw_3))
                self.assertTrue(dag.is_read(reg, instr_form_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_rw_1))
                self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_rw_2))
                self.assertTrue(dag.is_written(reg, instr_form_rw_3))
                self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
                self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
Beispiel #23
0
    def parse_line(self, line, line_number=None):
        """
        Parse line and return instruction form.

        :param str line: line of assembly code
        :param line_number: identifier of instruction form, defautls to None
        :type line_number: int, optional
        :return: `dict` -- parsed asm line (comment, label, directive or instruction form)
        """
        instruction_form = AttrDict({
            self.INSTRUCTION_ID: None,
            self.OPERANDS_ID: [],
            self.DIRECTIVE_ID: None,
            self.COMMENT_ID: None,
            self.LABEL_ID: None,
            'line': line,
            'line_number': line_number,
        })
        result = None

        # 1. Parse comment
        try:
            result = self.process_operand(
                self.comment.parseString(line, parseAll=True).asDict())
            result = AttrDict.convert_dict(result)
            instruction_form[self.COMMENT_ID] = ' '.join(
                result[self.COMMENT_ID])
        except pp.ParseException:
            pass
        # 1.2 check for llvm-mca marker
        try:
            result = self.process_operand(
                self.llvm_markers.parseString(line, parseAll=True).asDict())
            result = AttrDict.convert_dict(result)
            instruction_form[self.COMMENT_ID] = ' '.join(
                result[self.COMMENT_ID])
        except pp.ParseException:
            pass
        # 2. Parse label
        if result is None:
            try:
                result = self.process_operand(
                    self.label.parseString(line, parseAll=True).asDict())
                result = AttrDict.convert_dict(result)
                instruction_form[self.LABEL_ID] = result[self.LABEL_ID].name
                if self.COMMENT_ID in result[self.LABEL_ID]:
                    instruction_form[self.COMMENT_ID] = ' '.join(
                        result[self.LABEL_ID][self.COMMENT_ID])
            except pp.ParseException:
                pass

        # 3. Parse directive
        if result is None:
            try:
                result = self.process_operand(
                    self.directive.parseString(line, parseAll=True).asDict())
                result = AttrDict.convert_dict(result)
                instruction_form[self.DIRECTIVE_ID] = AttrDict({
                    'name':
                    result[self.DIRECTIVE_ID].name,
                    'parameters':
                    result[self.DIRECTIVE_ID].parameters,
                })
                if self.COMMENT_ID in result[self.DIRECTIVE_ID]:
                    instruction_form[self.COMMENT_ID] = ' '.join(
                        result[self.DIRECTIVE_ID][self.COMMENT_ID])
            except pp.ParseException:
                pass

        # 4. Parse instruction
        if result is None:
            try:
                result = self.parse_instruction(line)
            except (pp.ParseException, KeyError):
                print(
                    '\n\n*-*-*-*-*-*-*-*-*-*-\n{}: {}\n*-*-*-*-*-*-*-*-*-*-\n\n'
                    .format(line_number, line))
            instruction_form[self.INSTRUCTION_ID] = result[self.INSTRUCTION_ID]
            instruction_form[self.OPERANDS_ID] = result[self.OPERANDS_ID]
            instruction_form[self.COMMENT_ID] = result[self.COMMENT_ID]

        return instruction_form
Beispiel #24
0
    def test_reg_dependency(self):
        reg_1_1 = AttrDict({'prefix': 'b', 'name': '1'})
        reg_1_2 = AttrDict({'prefix': 'h', 'name': '1'})
        reg_1_3 = AttrDict({'prefix': 's', 'name': '1'})
        reg_1_4 = AttrDict({'prefix': 'd', 'name': '1'})
        reg_1_4 = AttrDict({'prefix': 'q', 'name': '1'})
        reg_2_1 = AttrDict({'prefix': 'w', 'name': '2'})
        reg_2_2 = AttrDict({'prefix': 'x', 'name': '2'})
        reg_v1_1 = AttrDict({
            'prefix': 'v',
            'name': '11',
            'lanes': '16',
            'shape': 'b'
        })
        reg_v1_2 = AttrDict({
            'prefix': 'v',
            'name': '11',
            'lanes': '8',
            'shape': 'h'
        })
        reg_v1_3 = AttrDict({
            'prefix': 'v',
            'name': '11',
            'lanes': '4',
            'shape': 's'
        })
        reg_v1_4 = AttrDict({
            'prefix': 'v',
            'name': '11',
            'lanes': '2',
            'shape': 'd'
        })

        reg_b5 = AttrDict({'prefix': 'b', 'name': '5'})
        reg_q15 = AttrDict({'prefix': 'q', 'name': '15'})
        reg_v10 = AttrDict({
            'prefix': 'v',
            'name': '10',
            'lanes': '2',
            'shape': 's'
        })
        reg_v20 = AttrDict({
            'prefix': 'v',
            'name': '20',
            'lanes': '2',
            'shape': 'd'
        })

        reg_1 = [reg_1_1, reg_1_2, reg_1_3, reg_1_4]
        reg_2 = [reg_2_1, reg_2_2]
        reg_v = [reg_v1_1, reg_v1_2, reg_v1_3, reg_v1_4]
        reg_others = [reg_b5, reg_q15, reg_v10, reg_v20]
        regs = reg_1 + reg_2 + reg_v + reg_others

        # test each register against each other
        for ri in reg_1:
            for rj in regs:
                assert_value = True if rj in reg_1 else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_2:
            for rj in regs:
                assert_value = True if rj in reg_2 else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_v:
            for rj in regs:
                assert_value = True if rj in reg_v else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_others:
            for rj in regs:
                assert_value = True if rj == ri else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
Beispiel #25
0
    def test_reg_dependency(self):
        reg_a1 = AttrDict({'name': 'rax'})
        reg_a2 = AttrDict({'name': 'eax'})
        reg_a3 = AttrDict({'name': 'ax'})
        reg_a4 = AttrDict({'name': 'al'})
        reg_r11 = AttrDict({'name': 'r11'})
        reg_r11b = AttrDict({'name': 'r11b'})
        reg_r11d = AttrDict({'name': 'r11d'})
        reg_r11w = AttrDict({'name': 'r11w'})
        reg_xmm1 = AttrDict({'name': 'xmm1'})
        reg_ymm1 = AttrDict({'name': 'ymm1'})
        reg_zmm1 = AttrDict({'name': 'zmm1'})

        reg_b1 = AttrDict({'name': 'rbx'})
        reg_r15 = AttrDict({'name': 'r15'})
        reg_xmm2 = AttrDict({'name': 'xmm2'})
        reg_ymm3 = AttrDict({'name': 'ymm3'})

        reg_a = [reg_a1, reg_a2, reg_a3, reg_a4]
        reg_r = [reg_r11, reg_r11b, reg_r11d, reg_r11w]
        reg_vec_1 = [reg_xmm1, reg_ymm1, reg_zmm1]
        reg_others = [reg_b1, reg_r15, reg_xmm2, reg_ymm3]
        regs = reg_a + reg_r + reg_vec_1 + reg_others

        # test each register against each other
        for ri in reg_a:
            for rj in regs:
                assert_value = True if rj in reg_a else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_r:
            for rj in regs:
                assert_value = True if rj in reg_r else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_vec_1:
            for rj in regs:
                assert_value = True if rj in reg_vec_1 else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
        for ri in reg_others:
            for rj in regs:
                assert_value = True if rj == ri else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj),
                                     assert_value)
Beispiel #26
0
 def process_label(self, label):
     """Post-process label asm line"""
     # remove duplicated 'name' level due to identifier
     label['name'] = label['name'][0]['name']
     return AttrDict({self.LABEL_ID: label})
Beispiel #27
0
 def process_sp_register(self, register):
     """Post-process stack pointer register"""
     reg = register
     reg['prefix'] = 'x'
     return AttrDict({self.REGISTER_ID: reg})
Beispiel #28
0
    def test_reg_dependency(self):
        reg_1_1 = AttrDict({"prefix": "b", "name": "1"})
        reg_1_2 = AttrDict({"prefix": "h", "name": "1"})
        reg_1_3 = AttrDict({"prefix": "s", "name": "1"})
        reg_1_4 = AttrDict({"prefix": "d", "name": "1"})
        reg_1_4 = AttrDict({"prefix": "q", "name": "1"})
        reg_2_1 = AttrDict({"prefix": "w", "name": "2"})
        reg_2_2 = AttrDict({"prefix": "x", "name": "2"})
        reg_v1_1 = AttrDict({"prefix": "v", "name": "11", "lanes": "16", "shape": "b"})
        reg_v1_2 = AttrDict({"prefix": "v", "name": "11", "lanes": "8", "shape": "h"})
        reg_v1_3 = AttrDict({"prefix": "v", "name": "11", "lanes": "4", "shape": "s"})
        reg_v1_4 = AttrDict({"prefix": "v", "name": "11", "lanes": "2", "shape": "d"})

        reg_b5 = AttrDict({"prefix": "b", "name": "5"})
        reg_q15 = AttrDict({"prefix": "q", "name": "15"})
        reg_v10 = AttrDict({"prefix": "v", "name": "10", "lanes": "2", "shape": "s"})
        reg_v20 = AttrDict({"prefix": "v", "name": "20", "lanes": "2", "shape": "d"})

        reg_1 = [reg_1_1, reg_1_2, reg_1_3, reg_1_4]
        reg_2 = [reg_2_1, reg_2_2]
        reg_v = [reg_v1_1, reg_v1_2, reg_v1_3, reg_v1_4]
        reg_others = [reg_b5, reg_q15, reg_v10, reg_v20]
        regs = reg_1 + reg_2 + reg_v + reg_others

        # test each register against each other
        for ri in reg_1:
            for rj in regs:
                assert_value = True if rj in reg_1 else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj), assert_value)
        for ri in reg_2:
            for rj in regs:
                assert_value = True if rj in reg_2 else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj), assert_value)
        for ri in reg_v:
            for rj in regs:
                assert_value = True if rj in reg_v else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj), assert_value)
        for ri in reg_others:
            for rj in regs:
                assert_value = True if rj == ri else False
                with self.subTest(reg_a=ri, reg_b=rj, assert_val=assert_value):
                    self.assertEqual(self.parser.is_reg_dependend_of(ri, rj), assert_value)
Beispiel #29
0
    def test_is_read_is_written_AArch64(self):
        # independent form HW model
        dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None)
        reg_x1 = AttrDict({'prefix': 'x', 'name': '1'})
        reg_w1 = AttrDict({'prefix': 'w', 'name': '1'})
        reg_d1 = AttrDict({'prefix': 'd', 'name': '1'})
        reg_q1 = AttrDict({'prefix': 'q', 'name': '1'})
        reg_v1 = AttrDict({
            'prefix': 'v',
            'name': '1',
            'lanes': '2',
            'shape': 'd'
        })
        regs = [reg_d1, reg_q1, reg_v1]
        regs_gp = [reg_w1, reg_x1]

        instr_form_r_1 = self.parser_AArch64.parse_line(
            'stp q1, q3, [x12, #192]')
        self.semantics_tx2.assign_src_dst(instr_form_r_1)
        instr_form_r_2 = self.parser_AArch64.parse_line(
            'fadd v2.2d, v1.2d, v0.2d')
        self.semantics_tx2.assign_src_dst(instr_form_r_2)
        instr_form_w_1 = self.parser_AArch64.parse_line(
            'ldr d1, [x1, #:got_lo12:q2c]')
        self.semantics_tx2.assign_src_dst(instr_form_w_1)
        instr_form_non_w_1 = self.parser_AArch64.parse_line(
            'ldr x1, [x1, #:got_lo12:q2c]')
        self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
        instr_form_rw_1 = self.parser_AArch64.parse_line(
            'fmul v1.2d, v1.2d, v0.2d')
        self.semantics_tx2.assign_src_dst(instr_form_rw_1)
        instr_form_rw_2 = self.parser_AArch64.parse_line(
            'ldp q2, q4, [x1, #64]!')
        self.semantics_tx2.assign_src_dst(instr_form_rw_2)
        instr_form_rw_3 = self.parser_AArch64.parse_line('str x4, [x1], #64')
        self.semantics_tx2.assign_src_dst(instr_form_rw_3)
        instr_form_non_rw_1 = self.parser_AArch64.parse_line('adds x1, x11')
        self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)

        for reg in regs:
            with self.subTest(reg=reg):
                self.assertTrue(dag.is_read(reg, instr_form_r_1))
                self.assertTrue(dag.is_read(reg, instr_form_r_2))
                self.assertTrue(dag.is_read(reg, instr_form_rw_1))
                self.assertFalse(dag.is_read(reg, instr_form_rw_2))
                self.assertFalse(dag.is_read(reg, instr_form_rw_3))
                self.assertFalse(dag.is_read(reg, instr_form_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_rw_1))
                self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_rw_2))
                self.assertFalse(dag.is_written(reg, instr_form_rw_3))
                self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
                self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
        for reg in regs_gp:
            with self.subTest(reg=reg):
                self.assertFalse(dag.is_read(reg, instr_form_r_1))
                self.assertFalse(dag.is_read(reg, instr_form_r_2))
                self.assertFalse(dag.is_read(reg, instr_form_rw_1))
                self.assertTrue(dag.is_read(reg, instr_form_rw_2))
                self.assertTrue(dag.is_read(reg, instr_form_rw_3))
                self.assertTrue(dag.is_read(reg, instr_form_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_w_1))
                self.assertFalse(dag.is_written(reg, instr_form_rw_1))
                self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
                self.assertTrue(dag.is_written(reg, instr_form_rw_2))
                self.assertTrue(dag.is_written(reg, instr_form_rw_3))
                self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
                self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
Beispiel #30
0
    def assign_src_dst(self, instruction_form):
        """Update instruction form dictionary with source, destination and flag information."""
        # if the instruction form doesn't have operands or is None, there's nothing to do
        if instruction_form["operands"] is None or instruction_form[
                "instruction"] 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)
        isa_data = self._isa_model.get_instruction(
            instruction_form["instruction"], instruction_form["operands"])
        if (isa_data is None and self._isa == "x86"
                and instruction_form["instruction"][-1] in self.GAS_SUFFIXES):
            # Check for instruction without GAS suffix
            isa_data = self._isa_model.get_instruction(
                instruction_form["instruction"][:-1],
                instruction_form["operands"])
        operands = instruction_form["operands"]
        op_dict = {}
        assign_default = False
        if isa_data:
            # load src/dst structure from isa_data
            op_dict = self._apply_found_ISA_data(isa_data, operands)
        else:
            # Couldn't found instruction form in ISA DB
            assign_default = True
            # check for equivalent register-operands DB entry if LD/ST
            if any(["memory" in op for op in operands]):
                operands_reg = self.substitute_mem_address(
                    instruction_form["operands"])
                isa_data_reg = self._isa_model.get_instruction(
                    instruction_form["instruction"], operands_reg)
                if (isa_data_reg is None and self._isa == "x86"
                        and instruction_form["instruction"][-1]
                        in self.GAS_SUFFIXES):
                    # Check for instruction without GAS suffix
                    isa_data_reg = self._isa_model.get_instruction(
                        instruction_form["instruction"][:-1], operands_reg)
                if isa_data_reg:
                    assign_default = False
                    op_dict = self._apply_found_ISA_data(
                        isa_data_reg, operands)
        if assign_default:
            # no irregular operand structure, apply default
            op_dict["source"] = self._get_regular_source_operands(
                instruction_form)
            op_dict["destination"] = self._get_regular_destination_operands(
                instruction_form)
            op_dict["src_dst"] = []
        # post-process pre- and post-indexing for aarch64 memory operands
        if self._isa == "aarch64":
            for operand in [op for op in op_dict["source"] if "memory" in op]:
                post_indexed = ("post_indexed" in operand["memory"]
                                and operand["memory"]["post_indexed"])
                pre_indexed = ("pre_indexed" in operand["memory"]
                               and operand["memory"]["pre_indexed"])
                if post_indexed or pre_indexed:
                    op_dict["src_dst"].append(
                        AttrDict.convert_dict({
                            "register":
                            operand["memory"]["base"],
                            "pre_indexed":
                            pre_indexed,
                            "post_indexed":
                            post_indexed
                        }))
            for operand in [
                    op for op in op_dict["destination"] if "memory" in op
            ]:
                post_indexed = ("post_indexed" in operand["memory"]
                                and operand["memory"]["post_indexed"])
                pre_indexed = ("pre_indexed" in operand["memory"]
                               and operand["memory"]["pre_indexed"])
                if post_indexed or pre_indexed:
                    op_dict["src_dst"].append(
                        AttrDict.convert_dict({
                            "register":
                            operand["memory"]["base"],
                            "pre_indexed":
                            pre_indexed,
                            "post_indexed":
                            post_indexed
                        }))

        # store operand list in dict and reassign operand key/value pair
        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 []
        if self._has_load(instruction_form):
            instruction_form["flags"] += [INSTR_FLAGS.HAS_LD]
        if self._has_store(instruction_form):
            instruction_form["flags"] += [INSTR_FLAGS.HAS_ST]