Example #1
0
    def __init__(self, name, descr, regs, address_base, address_index,
                 floating_point, vector):
        """

        :param name:
        :param descr:
        :param regs:
        :param address_base:
        :param address_index:
        :param floating_point:
        :param vector:

        """
        super(OperandReg, self).__init__(name, descr)

        if isinstance(regs, list):
            self._regs = OrderedDict()
            for reg in regs:
                self._regs[reg] = [reg]
        else:
            self._regs = regs

        self._ab = address_base
        self._ai = address_index
        self._fp = floating_point
        self._vector = vector

        if self._fp is None:
            self._fp = list(set([reg.type for reg in self._regs
                                 ]))[0].used_for_float_arithmetic

        if self._vector is None:
            self._vector = list(set([reg.type for reg in self._regs
                                     ]))[0].used_for_vector_arithmetic
Example #2
0
    def __init__(self):
        """ """

        super(Benchmark, self).__init__()
        self._cfg = microprobe.code.cfg.Cfg()
        self._global_vars = OrderedDict()
        self._init = []
        self._fini = []
        self._vardisplacement = 0
        self._context = None
Example #3
0
        def reset_dictionaries():
            """ Reset the local dependency tracking dictionaries """

            allregs = list(target.registers.values())
            allregs.sort(key=lambda x: int(re.findall(r'\d+', str(x))[0]))

            for reg in allregs:
                if reg.type not in lastreaded:
                    lastreaded[reg.type] = OrderedDict()

                if reg.type not in lastdefined:
                    lastdefined[reg.type] = OrderedDict()

                if reg.type not in lastdefread:
                    lastdefread[reg.type] = OrderedDict()

                lastreaded[reg.type][reg] = 0

                if reg not in building_block.context.reserved_registers:

                    lastdefined[reg.type][reg] = 0
                    lastdefread[reg.type][reg] = 0
Example #4
0
class OperandReg(Operand):
    """Class to represent a register operand.

    """
    def __init__(self, name, descr, regs, address_base, address_index,
                 floating_point, vector):
        """

        :param name:
        :param descr:
        :param regs:
        :param address_base:
        :param address_index:
        :param floating_point:
        :param vector:

        """
        super(OperandReg, self).__init__(name, descr)

        if isinstance(regs, list):
            self._regs = OrderedDict()
            for reg in regs:
                self._regs[reg] = [reg]
        else:
            self._regs = regs

        self._ab = address_base
        self._ai = address_index
        self._fp = floating_point
        self._vector = vector

        if self._fp is None:
            self._fp = list(set([reg.type for reg in self._regs
                                 ]))[0].used_for_float_arithmetic

        if self._vector is None:
            self._vector = list(set([reg.type for reg in self._regs
                                     ]))[0].used_for_vector_arithmetic

    def values(self):
        """Return the possible value of the operand.

        :rtype: :class:`list` of :class:`~.Register`
        """
        return list(self._regs.keys())

    def representation(self, value):
        """

        :param value:

        """
        return value.representation

    def codification(self, value):
        """

        :param value:

        """
        return value.codification

    def random_value(self):
        """Return a random possible value for the operand.

        :rtype: :class:`~.Register`
        """
        return list(self._regs.keys())[random.randrange(0, len(self._regs))]

    def access(self, value):
        """

        :param value:

        """
        return self._regs[value]

    def __contains__(self, value):
        """

        :param value:

        """

        if not isinstance(value, Register):
            return False

        return value.name in [reg.name for reg in self.values()]

    def copy(self):
        """ """

        return OperandReg(self.name, self.description, self._regs.copy(),
                          self._ab, self._ai, self._fp, self._vector)

    def set_valid_values(self, values):
        """

        :param values:

        """

        assert len(values) > 0

        for value in self.values():

            if value not in values:
                del self._regs[value]

        assert sorted(self.values()) == sorted(values), \
            "\nValues: %s \nValues(): %s" % (sorted(values),
                                             sorted(self.values()))

        self._const = len(values) == 1
Example #5
0
def import_definition(filenames, registers):
    """

    :param filenames:
    :param registers:

    """

    LOG.debug("Start")
    operands = {}
    operands_duplicated = {}
    register_types = tuple([reg.type.name for reg in registers.values()])

    for filename in filenames:
        ope_data = read_yaml(filename, SCHEMA)

        if ope_data is None:
            continue

        for elem in ope_data:

            name = elem["Name"]
            descr = elem.get("Description", "No description")
            override = elem.get("Override", False)
            key = []

            try:

                if "Registers" in elem:

                    regnames = elem["Registers"]

                    if isinstance(regnames, list):

                        if len(regnames) == 1 and \
                                regnames[0] in register_types:
                            regs = [
                                reg for reg in registers.values()
                                if reg.type.name == regnames[0]
                            ]
                        else:
                            regs = [
                                registers[regname]
                                for regname in natural_sort(regnames)
                            ]

                        key.append(tuple(regnames))

                    else:
                        regs = OrderedDict()
                        for regname in natural_sort(regnames):
                            regs[registers[regname]] = []
                            for regname2 in regnames[regname]:
                                regs[registers[regname]].append(
                                    registers[regname2])

                        key.append(
                            tuple([(k, tuple(v))
                                   for k, v in regnames.items()]))

                    address_base = elem.get("AddressBase", False)
                    address_index = elem.get("AddressIndex", False)
                    floating_point = elem.get("FloatingPoint", None)
                    vector = elem.get("Vector", None)

                    key.append(address_base)
                    key.append(address_index)
                    key.append(floating_point)
                    key.append(vector)

                    # Filter out Register without
                    # representation (N/A)
                    #
                    # These are pseudo registers used in
                    # simulation/emulation environment.
                    # They are not architected registers.

                    regs = [reg for reg in regs if reg.representation != 'N/A']

                    operand = OperandReg(name, descr, regs, address_base,
                                         address_index, floating_point, vector)

                elif "Min" in elem and "Max" in elem:

                    minval = elem["Min"]
                    maxval = elem["Max"]
                    step = elem.get("Step", 1)
                    novalues = elem.get("Except", [])
                    address_index = elem.get("AddressIndex", False)
                    shift = elem.get("Shift", 0)
                    add = elem.get("Add", 0)

                    key.append(minval)
                    key.append(maxval)
                    key.append(step)
                    key.append(tuple(novalues))
                    key.append(address_index)
                    key.append(shift)
                    key.append(add)

                    operand = OperandImmRange(name, descr, minval, maxval,
                                              step, address_index, shift,
                                              novalues, add)

                elif "Values" in elem:

                    values = tuple(elem["Values"])
                    key.append(tuple(values))

                    operand = OperandValueSet(name, descr, values)

                elif "Value" in elem:

                    value = elem["Value"]
                    key.append(value)

                    operand = OperandConst(name, descr, value)

                elif "Register" in elem:

                    reg = registers[elem["Register"]]
                    address_base = elem.get("AddressBase", False)
                    address_index = elem.get("AddressIndex", False)
                    floating_point = elem.get("FloatingPoint", False)
                    vector = elem.get("Vector", False)

                    key.append(elem["Register"])
                    key.append(address_base)
                    key.append(address_index)
                    key.append(floating_point)
                    key.append(vector)

                    operand = OperandConstReg(name, descr, reg, address_base,
                                              address_index, floating_point,
                                              vector)

                elif "Relative" in elem:

                    mindispl = elem["MinDisplacement"]
                    maxdispl = elem["MaxDisplacement"]
                    relative = elem["Relative"]
                    shift = elem.get("Shift", 0)
                    except_ranges = elem.get("ExceptRange", [])

                    key.append(mindispl)
                    key.append(maxdispl)
                    key.append(shift)
                    key.append(tuple([tuple(elem) for elem in except_ranges]))

                    operand = InstructionAddressRelativeOperand(
                        name, descr, maxdispl, mindispl, shift, except_ranges,
                        relative)

                else:
                    raise MicroprobeArchitectureDefinitionError(
                        "Operand definition '%s' in '%s' not supported" %
                        (name, filename))

                tkey = tuple(key)
                if tkey in operands_duplicated:
                    LOG.warning(
                        "Similar definition of operands: '%s' and"
                        " '%s'. Check if definition needed.", name,
                        operands_duplicated[tkey])
                else:
                    operands_duplicated[tkey] = name

            except KeyError as exception:

                raise MicroprobeArchitectureDefinitionError(
                    "Definition"
                    " of operand '%s' "
                    "uses an unknown "
                    "register in '%s'"
                    "\nMissing defini"
                    "tion of: %s" % (name, filename, exception))

            if name in operands and not override:
                raise MicroprobeArchitectureDefinitionError(
                    "Duplicated definition of operand '%s' found in '%s'" %
                    (name, filename))

            LOG.debug(operand)
            operands[name] = operand

    LOG.debug("End")
    return operands
Example #6
0
class Benchmark(BuildingBlock):
    """Class to represent a benchmark (highest level building block)."""
    def __init__(self):
        """ """

        super(Benchmark, self).__init__()
        self._cfg = microprobe.code.cfg.Cfg()
        self._global_vars = OrderedDict()
        self._init = []
        self._fini = []
        self._vardisplacement = 0
        self._context = None

    @property
    def init(self):
        """Initialization instructions

        Initialization instructions (:class:`~.list` of :class:`~.Instruction`)
        """
        return self._init

    def add_init(self, inits):
        """Appends the specified list of instructions to initialization list

        :param inits: List of instructions to be added
        :type inits: :class:`~.list` of :class:`~.Instruction`

        """
        LOG.debug("Add Init")
        for init in inits:
            LOG.debug("INIT: %s", init)
        self._init = self._init + inits

    def rm_init(self, inits):
        """Removes from the initialization list the specified instructions.

        :param inits: List of instructions to be removed
        :type inits: :class:`~.list` of :class:`~.Instruction`

        """
        self._init = self._init[0:-len(inits)]

    def add_fini(self, finis):
        """Appends the specified list of instructions to the finalization list

        :param finis: List of instructions to be added
        :type finis: :class:`~.list` of :class:`~.Instruction`

        """
        self._fini = self._fini + finis

    @property
    def fini(self):
        """Finalization instructions
        (:class:`~.list` of :class:`~.Instruction`)"""
        return self._fini

    @property
    def cfg(self):
        """Returns the benchmark control flow graph."""
        return self._cfg

    def set_cfg(self, cfg):
        """Sets the benchmarks control flow graph.

        :param cfg: Control flow graph
        :type cfg: :class:`~.Cfg`

        """
        self._cfg = cfg

    def registered_global_vars(self):
        """Returns the list of registered global variables."""
        return list(self._global_vars.values())

    def register_var(self, var, context):
        """Registers the given variable as a global variable.

        :param var: Variable to register
        :type var: :class:`~.Variable`

        """

        LOG.debug("Registering global var: '%s'", var.name)

        if var.name in self._global_vars:

            var2 = self._global_vars[var.name]
            if (var.value == var2.value and var.address == var2.address
                    and var.address is not None and MICROPROBE_RC['safe_bin']):
                LOG.warning("Variable: '%s' registered multiple times!",
                            var.name)
                return

            LOG.critical("Registered variables: %s",
                         list(self._global_vars.keys()))
            raise MicroprobeCodeGenerationError(
                "Variable already registered: %s" % (var.name))

        self._global_vars[var.name] = var

        if context.symbolic:

            LOG.debug("Context symbolic. No need to track base addresses")
            var_address = Address(base_address=var.name, displacement=0)
            var.set_address(var_address)

        elif var.address is None:
            LOG.debug("Context not symbolic and variable address not set")

            # if (self._vardisplacement == 0 and
            #        context.data_segment is not None):
            #     self._vardisplacement = context.data_segment

            address_ok = False

            while not address_ok:
                var_address = Address(base_address="data",
                                      displacement=self._vardisplacement)

                LOG.debug("Address before alignment: %s", var_address)

                align = var.align
                if align is None:
                    align = 1

                LOG.debug("Variable alignment: %s", align)
                LOG.debug("Current address: %s", var_address)

                if var_address.displacement % align != 0:
                    # alignment needed
                    var_address += align - (var_address.displacement % align)

                LOG.debug("Address after alignment: %s", var_address)
                LOG.debug("Current var displacement: %x",
                          self._vardisplacement)

                var.set_address(var_address)
                over = self._check_variable_overlap(var)

                if over is not None:
                    self._vardisplacement = max(
                        self._vardisplacement,
                        over.address.displacement + over.size)
                    continue

                address_ok = True
                LOG.debug("Variable registered at address: '%s'", var_address)

            self._vardisplacement = var_address.displacement + var.size

        else:
            LOG.debug("Using pre-defined address: '%s'", var.address)

        over = self._check_variable_overlap(var)
        if over is not None:
            raise MicroprobeCodeGenerationError(
                "Variable '%s' overlaps with variable '%s'" %
                (var.name, over.name))

    def _check_variable_overlap(self, var):

        vara = var.address
        vara2 = vara + var.size

        for rvar in self._global_vars.values():

            if var.name == rvar.name:
                continue

            rvara = rvar.address
            rvara2 = rvara + rvar.size

            if rvara < vara2 and rvara2 >= vara2:
                print(1)
                return rvar

            if rvara <= vara and rvara2 > vara:
                print(2)
                return rvar

            if rvara >= vara and rvara2 <= vara2:
                print(3)
                return rvar

            if rvara <= vara and rvara2 >= vara2:
                print(4)
                return rvar

        return None

    def set_context(self, context):
        """Set the execution context of the building block.

        :param context: Execution context
        :type context: :class:`~.Context`

        """
        self._context = context

    @property
    def context(self):
        """Return benchmark's context"""
        return self._context

    def add_instructions(self, instrs, after=None, before=None):
        """Adds the given instruction to the building block.

        Adds the given instructions right after the specified instruction and
        before the specified one. If the condition can not be fulfilled an
        specification exception is raised.

        :param instrs: Instruction to add
        :type instrs: :class:`~.list` of :class:`~.Instruction`
        :param after: Instruction after which to add the new instruction
                      (Default value = None)
        :type after: :class:`~.Instruction`
        :param before: Instruction before which to add the new instruction
                       (Default value = None)
        :type before: :class:`~.Instruction`

        """

        if after is None and before is None:
            bbl = self.cfg.last_bbl()
            bbl.insert_instr(instrs)

        elif after is not None and before is None:
            idx_after = self.cfg.index(after)
            bbl = self.cfg.get_bbl(idx_after)
            bbl.insert_instr(instrs, after=after)

        elif after is None and before is not None:
            idx_before = self.cfg.index(before)
            bbl = self.cfg.get_bbl(idx_before)
            bbl.insert_instr(instrs, before=before)

        elif after is not None and before is not None:
            idx_before = self.cfg.index(before)
            idx_after = self.cfg.index(after)

            if idx_before < idx_after:
                bbl = self.cfg.get_bbl(idx_before)
                bbl.insert_instr(instrs)
            elif idx_before == idx_after:
                bbl = self.cfg.get_bbl(idx_before)
                bbl.insert_instr(instrs, after=after, before=before)
            else:
                raise MicroprobeCodeGenerationError(
                    "Attempt to inserst instruction in a position that it is"
                    " not possible")

    @property
    def code_size(self):
        """Return benchmark's size"""

        size = 0
        for bbl in self.cfg.bbls:
            for instr in bbl.instrs:
                size += instr.architecture_type.format.length

        return size

    @property
    def labels(self):
        """Return the a list of the current defined labels and symbols"""
        labels = [key.upper() for key in self._global_vars.keys()]
        for bbl in self.cfg.bbls:
            for instr in bbl.instrs:
                if instr.label is not None:
                    labels.append(instr.label.upper())

        labels += [
            instr.label.upper() for instr in self._fini
            if instr.label is not None
        ]

        labels += [
            instr.label.upper() for instr in self._init
            if instr.label is not None
        ]

        return labels
Example #7
0
    def __call__(self, building_block, target):
        """

        :param building_block:
        :param target:

        """

        allregs = target.registers
        lastdefined = {}
        lastused = {}
        rregs = set(building_block.context.reserved_registers)

        # TODO: All this pass has to be reimplemented

        for reg in allregs.values():

            if reg in rregs:
                # TODO:  rregs can be used but only as input, now we discard
                #       them for input and output
                continue

            if reg.type not in lastused:
                lastused[reg.type] = OrderedDict()
                lastdefined[reg.type] = OrderedDict()

            lastdefined[reg.type][reg] = 0
            lastused[reg.type][reg] = 1

        idx = 1
        for bbl in building_block.cfg.bbls:

            for instr in bbl.instrs:

                dependency_ok = False

                used = []
                defined = []

                distance = self._dd()

                for operand in instr.operands():

                    if operand.value is not None:
                        # operand already set
                        pass
                    elif operand.type.immediate:
                        if self._immediate != "random":
                            try:
                                svalue = self._immediate
                                while callable(svalue):
                                    svalue = svalue()
                                operand.set_value(svalue)
                            except MicroprobeValueError:

                                LOG.warning(
                                    "Operand '%s' in instruction '%s' "
                                    "not modeled properly. Tried to "
                                    "'%s' value ...", operand.type,
                                    instr.name, svalue
                                )

                                value = list(operand.type.values())[0]
                                operand.set_value(value)

                                LOG.warning("Operand set to: '%s'", value)

                        else:
                            operand.set_value(operand.type.random_value())

                    elif operand.type.address_relative:

                        LOG.warning(
                            "Operand '%s' in instruction '%s' "
                            "not modeled properly", operand.type, instr.name
                        )
                        operand.set_value(list(operand.type.values())[0])

                    else:

                        if operand.is_input and distance > 0 and \
                           not dependency_ok and idx > distance:

                            LOG.debug("Setting dependency distance")

                            regs = list(operand.type.values())
                            valid_values = []

                            for reg in regs:

                                if len(
                                    rregs.intersection(
                                        operand.type.access(reg)
                                    )
                                ) == 0:
                                    valid_values.append(reg)

                            if (len(valid_values) == 0 and
                                    operand.is_input and
                                    not operand.is_output):
                                # Try to use reserved values
                                # if the operand is reading only
                                valid_values = list(operand.type.values())

                            LOG.debug("Current idx: %d", idx)
                            LOG.debug("Requested idx: %d", idx - distance)

                            reg = microprobe.utils.distrib.sort_by_distance(
                                valid_values, lastdefined[regs[0].type],
                                lastused[regs[0].type], idx - distance, instr,
                                idx
                            )

                            LOG.debug("%s selected", reg)

                            if reg in lastdefined[regs[0].type]:
                                LOG.debug(
                                    "Last defined: %s", lastdefined[
                                        regs[0].type
                                    ][reg]
                                )

                            if reg in lastused[regs[0].type]:
                                LOG.debug(
                                    "Last used: %s", lastused[
                                        regs[0].type
                                    ][reg]
                                )

                            dependency_ok = True

                        else:

                            regs = list(operand.type.values())
                            valid_values = []

                            for reg in regs:
                                if len(
                                    rregs.intersection(
                                        operand.type.access(reg)
                                    )
                                ) == 0:
                                    valid_values.append(reg)

                            if (len(valid_values) == 0 and
                                    operand.is_input and
                                    not operand.is_output):
                                # Try to use reserved values
                                # if the operand is reading only
                                valid_values = list(operand.type.values())

                            if len(valid_values) == 0:
                                LOG.critical("Instruction: %s", instr)
                                LOG.critical("Operand: %s", operand)
                                LOG.critical("Possible all values: %s",
                                             sorted(operand.type.values()))
                                LOG.critical(
                                    "Possible values: %s",
                                    sorted(regs))
                                LOG.critical(
                                    "Reserved values: %s",
                                    sorted(rregs))
                                raise MicroprobeCodeGenerationError(
                                    "Unable to find proper operand"
                                    " values for register allocation."
                                )

                            reg = microprobe.utils.distrib.sort_by_usage(
                                valid_values, lastused[regs[0].type],
                                lastdefined[regs[0].type]
                            )

                        operand.set_value(reg)

                        if self._min is False:
                            for reg in operand.uses():
                                LOG.debug("Updating usage of %s", reg)
                                LOG.debug(list(lastused[reg.type].keys()))
                                if reg in lastused[reg.type]:
                                    del lastused[reg.type][reg]
                                lastused[reg.type][reg] = idx
                                used.append(reg)
                                LOG.debug(list(lastused[reg.type].keys()))

                        if operand.is_output:
                            for reg in operand.sets():
                                LOG.debug("Updating definition of %s", reg)
                                if reg in lastdefined[reg.type]:
                                    del lastdefined[reg.type][reg]
                                lastdefined[reg.type][reg] = idx
                                defined.append(reg)

                                LOG.debug("Updating usage of %s", reg)
                                LOG.debug(list(lastused[reg.type].keys()))
                                if reg in lastused[reg.type]:
                                    del lastused[reg.type][reg]
                                lastused[reg.type][reg] = idx
                                used.append(reg)
                                LOG.debug(list(lastused[reg.type].keys()))

                # if self._min is True:
                #    for reg in instr.uses():
                #        if reg in lastused[reg.type]:
                #            del lastused[reg.type][reg]
                #        lastused[reg.type][reg] = idx
                #        used.append(reg)
                #    for reg in instr.sets():
                #        if reg in lastused[reg.type]:
                #            del lastused[reg.type][reg]
                #        lastused[reg.type][reg] = idx
                #        used.append(reg)

                fail = rregs.intersection(set(instr.sets()))

                if len(fail) > 0 and not self._relax:
                    for reg in fail:
                        if not instr.allows(reg):
                            raise MicroprobeCodeGenerationError(
                                "Instruction '%s' sets a reserved"
                                " register but not allowed before:"
                                "Register: %s. Reserved: %s" % (
                                    instr.name, reg.name,
                                    sorted([reg.name for reg in rregs])
                                )
                            )

                for reg in instr.uses():
                    if reg not in used and reg not in rregs:
                        LOG.debug("Updating usage of %s", reg)
                        lastused[reg.type][reg] = idx

                for reg in instr.sets():
                    if reg not in defined and reg not in rregs:
                        LOG.debug("Updating definition of %s", reg)
                        del lastdefined[reg.type][reg]
                        lastdefined[reg.type][reg] = idx

                LOG.debug("Instruction: %s", instr)
                LOG.debug("Last used rank:")
                for rtype in lastused:
                    for reg in lastused[rtype]:
                        if lastused[rtype][
                            reg
                        ] > 0 and reg.name.startswith("GPR"):
                            LOG.debug("%s: %d", reg.name, lastused[rtype][reg])
                LOG.debug("Last defined rank:")
                for rtype in lastdefined:
                    for reg in lastdefined[rtype]:
                        if lastdefined[rtype][
                            reg
                        ] > 0 and reg.name.startswith("GPR"):
                            LOG.debug(
                                "%s: %d", reg.name, lastdefined[rtype][reg]
                            )

                idx = idx + 1