Ejemplo n.º 1
0
    def _apply_found_ISA_data(self, isa_data, operands):
        """
        Create operand dictionary containing src/dst operands out of the ISA data entry and
        the oeprands of an instruction form

        If breaks_pedendency_on_equal_operands is True (configuted per instruction in ISA db)
        and all operands are equal, place operand into destination only.

        :param dict isa_data: ISA DB entry
        :param list operands: operands of the instruction form
        :returns: `dict` -- operands dictionary with src/dst assignment
        """
        op_dict = {}
        op_dict["source"] = []
        op_dict["destination"] = []
        op_dict["src_dst"] = []

        # handle dependency breaking instructions
        if "breaks_pedendency_on_equal_operands" in isa_data and operands[
                1:] == operands[:-1]:
            op_dict["destination"] += operands
            if "hidden_operands" in isa_data:
                op_dict["destination"] += [
                    AttrDict.convert_dict({
                        hop["class"]: {
                            k: hop[k]
                            for k in ["class", "source", "destination"]
                        }
                    }) for hop in isa_data["hidden_operands"]
                ]
            return op_dict

        for i, op in enumerate(isa_data["operands"]):
            if op["source"] and op["destination"]:
                op_dict["src_dst"].append(operands[i])
                continue
            if op["source"]:
                op_dict["source"].append(operands[i])
                continue
            if op["destination"]:
                op_dict["destination"].append(operands[i])
                continue
        # check for hidden operands like flags or registers
        if "hidden_operands" in isa_data:
            # add operand(s) to semantic_operands of instruction form
            for op in isa_data["hidden_operands"]:
                dict_key = ("src_dst" if op["source"] and op["destination"]
                            else "source" if op["source"] else "destination")
                hidden_op = {op["class"]: {}}
                key_filter = ["class", "source", "destination"]
                for key in [k for k in op.keys() if k not in key_filter]:
                    hidden_op[op["class"]][key] = op[key]
                hidden_op = AttrDict.convert_dict(hidden_op)
                op_dict[dict_key].append(hidden_op)
        return op_dict
Ejemplo n.º 2
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
Ejemplo n.º 3
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})
Ejemplo n.º 4
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
Ejemplo n.º 5
0
    def _apply_found_ISA_data(self, isa_data, operands):
        """
        Create operand dictionary containing src/dst operands out of the ISA data entry and
        the oeprands of an instruction form

        :param dict isa_data: ISA DB entry
        :param list operands: operands of the instruction form
        :returns: `dict` -- operands dictionary with src/dst assignment
        """
        op_dict = {}
        op_dict['source'] = []
        op_dict['destination'] = []
        op_dict['src_dst'] = []
        for i, op in enumerate(isa_data['operands']):
            if op['source'] and op['destination']:
                op_dict['src_dst'].append(operands[i])
                continue
            if op['source']:
                op_dict['source'].append(operands[i])
                continue
            if op['destination']:
                op_dict['destination'].append(operands[i])
                continue
        # check for hidden operands like flags or registers
        if 'hidden_operands' in isa_data:
            # add operand(s) to semantic_operands of instruction form
            for op in isa_data['hidden_operands']:
                dict_key = (
                    'src_dst'
                    if op['source'] and op['destination']
                    else 'source'
                    if op['source']
                    else 'destination'
                )
                hidden_op = {op['class']: {}}
                key_filter = ['class', 'source', 'destination']
                for key in [k for k in op.keys() if k not in key_filter]:
                    hidden_op[op['class']][key] = op[key]
                hidden_op = AttrDict.convert_dict(hidden_op)
                op_dict[dict_key].append(hidden_op)
        return op_dict
Ejemplo n.º 6
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
Ejemplo n.º 7
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
Ejemplo n.º 8
0
 def _get_directive(self, parser, directive):
     return AttrDict.convert_dict(
         parser.process_operand(
             parser.directive.parseString(
                 directive, parseAll=True).asDict())).directive
Ejemplo n.º 9
0
 def _get_label(self, parser, label):
     return AttrDict.convert_dict(
         parser.process_operand(
             parser.label.parseString(label, parseAll=True).asDict())).label
Ejemplo n.º 10
0
 def _get_comment(self, parser, comment):
     return ' '.join(
         AttrDict.convert_dict(
             parser.process_operand(
                 parser.comment.parseString(
                     comment, parseAll=True).asDict())).comment)
Ejemplo n.º 11
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]
Ejemplo n.º 12
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]
Ejemplo n.º 13
0
    def check_for_loopcarried_dep(self, kernel):
        """
        Try to find loop-carried dependencies in given kernel.

        :param kernel: Parsed asm kernel with assigned semantic information
        :type kernel: list
        :returns: `dict` -- dependency dictionary with all cyclic LCDs
        """
        multiplier = len(kernel) + 1
        # increase line number for second kernel loop
        kernel_length = len(kernel)
        first_line_no = kernel[0].line_number
        kernel_copy = [AttrDict.convert_dict(d) for d in copy.deepcopy(kernel)]
        tmp_kernel = kernel + kernel_copy
        for i, instruction_form in enumerate(tmp_kernel[kernel_length:]):
            tmp_kernel[
                i +
                kernel_length].line_number = instruction_form.line_number * multiplier
        # get dependency graph
        dg = self.create_DG(tmp_kernel)

        # build cyclic loop-carried dependencies
        loopcarried_deps = [
            (node,
             list(
                 nx.algorithms.simple_paths.all_simple_paths(
                     dg, node, node * multiplier))) for node in dg.nodes
            if node < first_line_no * multiplier and node == int(node)
        ]
        # filter others and create graph
        loopcarried_deps = list(
            chain.from_iterable([
                list(product([dep_chain[0]], dep_chain[1]))
                for dep_chain in loopcarried_deps
            ]))
        # adjust line numbers, filter duplicates
        # and add reference to kernel again
        loopcarried_deps_dict = {}
        tmp_list = []
        for i, dep in enumerate(loopcarried_deps):
            nodes = [
                int(n / multiplier) for n in dep[1]
                if n >= first_line_no * multiplier
            ]
            loopcarried_deps[i] = (dep[0], nodes)
        for dep in loopcarried_deps:
            is_subset = False
            for other_dep in [x for x in loopcarried_deps if x[0] != dep[0]]:
                if set(dep[1]).issubset(set(
                        other_dep[1])) and dep[0] in other_dep[1]:
                    is_subset = True
            if not is_subset:
                tmp_list.append(dep)
        loopcarried_deps = tmp_list
        for dep in loopcarried_deps:
            nodes = []
            for n in dep[1]:
                self._get_node_by_lineno(int(n))['latency_lcd'] = 0
            for n in dep[1]:
                node = self._get_node_by_lineno(int(n))
                if int(n) != n and int(n) in dep[1]:
                    node['latency_lcd'] += node['latency'] - node[
                        'latency_wo_load']
                else:
                    node['latency_lcd'] += node['latency_wo_load']
                nodes.append(node)
            loopcarried_deps_dict[dep[0]] = {
                'root': self._get_node_by_lineno(dep[0]),
                'dependencies': nodes,
            }

        return loopcarried_deps_dict