Example #1
0
    def parse_instruction(self) -> None:
        """Parses all operands of the instruction which are encoded."""

        self.llvm_filtered_operands = self.remove_invisible_in_out_regs(
            self.llvm_syntax, deepcopy(self.llvm_in_out_operands)
        )
        self.operand_indices = self.get_syntax_operand_indices(
            self.llvm_syntax, self.llvm_filtered_operands
        )

        # Update syntax indices
        if self.has_new_non_predicate:
            op_name = self.llvm_in_out_operands[self.new_operand_index][1]
            self.new_operand_index = self.operand_indices[op_name]
            # log("{}\nnew: {}".format(self.llvm_syntax, self.new_operand_index), LogLevel.DEBUG)
        if self.has_extendable_imm:
            op_name = self.llvm_in_out_operands[self.ext_operand_index][1]
            self.ext_operand_index = self.operand_indices[op_name]
            # log("{}\next: {}".format(self.llvm_syntax, self.ext_operand_index), LogLevel.DEBUG)

        if len(self.llvm_filtered_operands) > PluginInfo.MAX_OPERANDS:
            warning = "{} instruction struct can only hold {} operands. This instruction has {} operands.".format(
                PluginInfo.FRAMEWORK_NAME,
                PluginInfo.MAX_OPERANDS,
                len(self.llvm_filtered_operands),
            )
            raise ImplementationException(warning)

        # TODO Some instructions encode some register explicitly in the syntax. At the moment we do not,
        #  but maybe should add them here somehow as registers. Example: J4_cmpeq_fp0_jump_t
        #  But note that they don't seem to have an index attached to them.

        # TODO Parse high/low access of registers.

        for in_out_operand in self.llvm_filtered_operands:
            op_name = in_out_operand[1]
            op_type = in_out_operand[0]["def"]
            syntax_index = self.operand_indices[op_name]

            # Parse register operand
            if Operand.get_operand_type(op_type) is OperandType.REGISTER:
                # Indices of new values (stored in "opNewValue") are only for non predicates.
                is_new_value = (
                    self.new_operand_index == syntax_index
                    and self.has_new_non_predicate
                )
                operand = Register(op_name, op_type, is_new_value, syntax_index)
                # Whether the predicate registers holds a new value is denoted in "isPredicatedNew".
                if self.predicate_info.new_value and operand.is_predicate:
                    operand.is_new_value = True
            # Parse immediate operands
            elif Operand.get_operand_type(op_type) is OperandType.IMMEDIATE:
                extendable = (
                    self.has_extendable_imm and self.ext_operand_index == syntax_index
                )
                operand = Immediate(
                    op_name,
                    op_type,
                    extendable,
                    self.extendable_alignment,
                    syntax_index,
                )

            else:
                raise ImplementationException(
                    "Unknown operand type: {}, op_name: {}".format(op_type, op_name)
                )

            if op_name in self.constraints:
                operand.is_in_out_operand = True
                operand.is_out_operand = True
                operand.is_in_operand = True
            elif in_out_operand in self.llvm_in_operands:
                operand.is_in_operand = True
            elif in_out_operand in self.llvm_out_operands:
                operand.is_out_operand = True

            # Add opcode extraction code
            if (
                operand.type == OperandType.IMMEDIATE and operand.is_constant
            ):  # Constants have no parsing code.
                pass
            else:
                if (
                    operand.is_in_out_operand and op_name[-2:] == "in"
                ):  # In/Out Register
                    mask = self.encoding.operand_masks[op_name[:-2]]  # Ends with "in"
                else:
                    mask = self.encoding.operand_masks[op_name]
                operand.opcode_mask = mask
                operand.add_code_for_opcode_parsing(Operand.make_sparse_mask(mask))

            # On the fly check whether the new values have been assigned correctly.
            if op_name + ".new" in self.llvm_syntax:
                if not operand.is_new_value:
                    raise ImplementationException(
                        "Register has new value in syntax but not as object."
                        + "It has been parsed incorrectly! Are the indices correctly set?"
                        + "Affected instruction: {}".format(self.llvm_syntax)
                    )

            self.operands[op_name] = operand
Example #2
0
    def parse_instruction(self) -> None:
        """Parses all operands of the instruction which are encoded."""

        # TODO A lot of duplicate code with Instruction::parse:instruction()
        # Operand names seen during parsing the encoding. Twin operands (Operands which appear in high and low instr.)
        # were renamed.

        all_ops = deepcopy(
            self.high_instr.llvm_in_out_operands + self.low_instr.llvm_in_out_operands
        )
        self.llvm_filtered_operands = self.remove_invisible_in_out_regs(
            self.llvm_syntax, all_ops
        )
        self.operand_indices = self.get_syntax_operand_indices(
            self.llvm_syntax, self.llvm_filtered_operands
        )

        # Update syntax indices
        if self.has_new_non_predicate:
            op_name = self.llvm_in_out_operands[self.new_operand_index][1]
            self.new_operand_index = self.operand_indices[op_name]
            # log("{}\n new: {}".format(self.llvm_syntax, self.new_operand_index), LogLevel.DEBUG)
        if self.has_extendable_imm:
            op_name = self.llvm_in_out_operands[self.ext_operand_index][1]
            self.ext_operand_index = self.operand_indices[op_name]
            # log("{}\n ext: {}".format(self.llvm_syntax, self.ext_operand_index), LogLevel.DEBUG)

        if len(self.llvm_filtered_operands) > PluginInfo.MAX_OPERANDS:
            warning = "{} instruction struct can only hold {} operands. This instruction has {} operands.".format(
                PluginInfo.FRAMEWORK_NAME,
                PluginInfo.MAX_OPERANDS,
                len(self.llvm_filtered_operands),
            )
            raise ImplementationException(warning)

        for in_out_operand in self.llvm_filtered_operands:
            op_name = in_out_operand[1]
            op_type = in_out_operand[0]["def"]
            index = self.operand_indices[op_name]

            # Parse register operand
            if Operand.get_operand_type(op_type) is OperandType.REGISTER:
                # Indices of new values (stored in "opNewValue") are only for non predicates.
                is_new_value = (
                    self.new_operand_index == index and self.has_new_non_predicate
                )
                operand = Register(op_name, op_type, is_new_value, index)
                # Whether the predicate registers holds a new value is denoted in "isPredicatedNew".
                if self.predicate_info.new_value and operand.is_predicate:
                    operand.is_new_value = True

            # Parse immediate operands
            elif Operand.get_operand_type(op_type) is OperandType.IMMEDIATE:
                extendable = self.has_extendable_imm and self.ext_operand_index == index
                if self.extendable_alignment > 0:
                    log(str(self.extendable_alignment), op_type)
                operand = Immediate(
                    op_name, op_type, extendable, self.extendable_alignment, index
                )

            else:
                raise ImplementationException(
                    "Unknown operand type: {}, op_name: {}".format(op_type, op_name)
                )

            # Use lower() because we can get RX16in and Rx16in but constraints are always Rx16in.
            if op_name.lower() in self.constraints.lower():
                operand.is_in_out_operand = True
                operand.is_out_operand = True
                operand.is_in_operand = True
            elif in_out_operand in self.llvm_in_operands:
                operand.is_in_operand = True
            elif in_out_operand in self.llvm_out_operands:
                operand.is_out_operand = True

            # Add opcode extraction code
            if (
                operand.type == OperandType.IMMEDIATE and operand.is_constant
            ):  # Constants have no parsing code.
                pass
            else:
                if (
                    operand.is_in_out_operand and op_name[-2:] == "in"
                ):  # In/Out Register
                    mask = self.encoding.operand_masks[op_name[:-2]]  # Ends with "in"
                else:
                    mask = self.encoding.operand_masks[op_name]
                operand.opcode_mask = mask
                operand.add_code_for_opcode_parsing(Operand.make_sparse_mask(mask))

            # On the fly check whether the new values have been assigned correctly.
            if op_name + ".new" in self.llvm_syntax:
                if not operand.is_new_value:
                    raise ImplementationException(
                        "Register has new value in syntax but not as object."
                        + "It has been parsed incorrectly! Are the indices correctly set?"
                        + "Affected instruction: {}".format(self.llvm_syntax)
                    )

            # log("Add operand: {}".format(op_name), LogLevel.DEBUG)
            # TODO This uses the llvm name as key. Maybe use normalized name? Rs16 -> Rs?
            self.operands[op_name] = operand