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