示例#1
0
    def generate_approx_poly_near_zero(self, function, high_bound, error_bound,
                                       variable):
        """ Generate polynomial approximation scheme """
        error_function = lambda p, f, ai, mod, t: sollya.dirtyinfnorm(
            p - f, ai)
        # Some issues encountered when 0 is one of the interval bound
        # so we use a symetric interval around it
        approx_interval = Interval(-high_bound, high_bound)
        local_function = function / sollya.x

        degree = sollya.sup(
            sollya.guessdegree(local_function, approx_interval, error_bound))
        degree_list = range(0, int(degree) + 1, 1)

        poly_object, approx_error = Polynomial.build_from_approximation_with_error(
            function / sollya.x,
            degree_list, [1] + [self.precision] * (len(degree_list) - 1),
            approx_interval,
            sollya.absolute,
            error_function=error_function)
        Log.report(
            Log.Info, "approximation poly: {}\n  with error {}".format(
                poly_object, approx_error))

        poly_scheme = Multiplication(
            variable,
            PolynomialSchemeEvaluator.generate_horner_scheme(
                poly_object, variable, self.precision))
        return poly_scheme, approx_error
示例#2
0
def phi_node_insertion(bbg):
    """ Perform first phase of SSA translation: insert phi-node
        where required """

    for v in bbg.variable_list:
        F = set()  # set of bb where phi-node were added
        W = set()  # set of bb which contains definition of v
        try:
            def_list = bbg.variable_defs[v]
        except KeyError as e:
            Log.report(Log.Error, "variable {} has no defs", v, error=e)
        for bb in def_list:
            #bb = bb_map[op]
            W.add(bb)
        while W:  # non-empty set are evaluated to True
            x = W.pop()
            try:
                df = bbg.dominance_frontier_map[x]
            except KeyError:
                Log.report(LOG_LEVEL_GEN_BB_VERBOSE,
                           "could not find dominance frontier for {}",
                           x.get_tag())
                df = []
            for y in df:
                # Log.report(LOG_LEVEL_GEN_BB_VERBOSE, "y: {}", y)
                if not y in F:
                    # add phi-node x <- at entry of y
                    # TODO: manage more than 2 predecessor for v
                    phi_fct = PhiNode(v, v, None, v, None)
                    y.push(phi_fct)
                    # adding  phi funciton to bb map
                    bbg.bb_map[phi_fct] = y
                    F.add(y)
                    if not y in def_list:
                        W.add(y)
示例#3
0
    def generate_scheme(self):
        """ main scheme generation """
        Log.report(Log.Info, "width parameter is {}".format(self.width))
        int_size = 3
        frac_size = self.width - int_size

        input_precision = fixed_point(int_size, frac_size)
        output_precision = fixed_point(int_size, frac_size)

        # declaring main input variable
        var_x = self.implementation.add_input_signal("x", input_precision)
        var_y = self.implementation.add_input_signal("y", input_precision)
        var_x.set_attributes(debug = debug_fixed)
        var_y.set_attributes(debug = debug_fixed)

        sub = var_x - var_y
        c = Constant(0)

        self.implementation.start_new_stage()

        #pre_result = Select(
        #    c > sub,
        #    c,
        #    sub
        #)
        pre_result = Max(0, sub)

        self.implementation.start_new_stage()

        result = Conversion(pre_result + var_x, precision=output_precision)

        self.implementation.add_output_signal("vr_out", result)

        return [self.implementation]
示例#4
0
def build_dominator_map(bbg):
    """ Build a dict which associates to each node N
        a list of nodes which dominate N.
        (by definition this list contains at least N, since each node
        dominates itself) """
    predominance_map_list = build_predominance_map_list(bbg.cfg_edges)
    # building dominator map for each node
    dominator_map = {}
    for bb in bbg.bb_list.inputs:
        dominator_map[bb] = set(bbg.bb_list.get_inputs())
    dominator_map[bbg.root] = set([bbg.root])
    while True:
        change = False
        # dom(n) = fix point of intersect(dom(x), x in predecessor(n)) U {n}
        for bb in predominance_map_list:
            dom = set.union(
                set([bb]),
                set.intersection(*tuple(
                    dominator_map[pred]
                    for pred in predominance_map_list[bb])))
            if not bb in dominator_map:
                Log.report(Log.Error,
                           "following bb was not in dominator_map: {}", bb)
            if dom != dominator_map[bb]:
                change = True
            dominator_map[bb] = dom
            Log.report(LOG_LEVEL_GEN_BB_VERBOSE,
                       "bb {}'s dominator list is {}", bb.get_tag(),
                       [dom.get_tag() for dom in dominator_map[bb]])
        if not change:
            break
    return dominator_map
示例#5
0
def test_cp_eval_optree(optree, combinatorial):
    """ Evaluate critical path for Test operation class """
    if optree.specifier is Test.IsZero:
        # floating-point is zero comparison is assumed to be equivalent
        # to a AND reduction on exponent + mantissa size
        operand = optree.get_input(0)
        base_precision = operand.get_precision().get_base_format()
        return CriticalPath(optree,
                            tree_cp_eval_value(
                                base_precision.get_exponent_size() +
                                base_precision.get_mantissa_size(),
                                TimingModel.AND_LEVEL),
                            combinatorial=combinatorial)
    elif optree.specifier in [
            Test.IsNaN, Test.IsInfty, Test.IsPositiveInfty,
            Test.IsNegativeInfty
    ]:
        # floating-point is nan/(+/-)infty test is assumed to be equivalent
        # to a AND reduction on exponent and an OR reduction on mantissa
        # plus neglected terms
        operand = optree.get_input(0)
        base_precision = operand.get_precision().get_base_format()
        return CriticalPath(
            optree,
            TimingModel.AND_LEVEL + max(
                tree_cp_eval_value(base_precision.get_exponent_size(),
                                   TimingModel.AND_LEVEL),
                tree_cp_eval_value(base_precision.get_mantissa_size(),
                                   TimingModel.OR_LEVEL)),
            combinatorial=combinatorial)

    else:
        Log.report(Log.Error,
                   "unknown Test specifier in test_cp_eval_optree: {}", optree)
示例#6
0
    def __init__(self, arg_template=None):
        """ Initialize """
        # building default arg_template if necessary
        arg_template = SubComponentInstance.get_default_args() if \
            arg_template is None else arg_template
        # initializing I/O precision
        self.width = arg_template.width
        precision = arg_template.precision
        io_precisions = [precision] * 2
        Log.report(
            Log.Info,
            "generating Adaptative Entity with width={}".format(self.width))

        # initializing base class
        ML_EntityBasis.__init__(self,
                                base_name="adaptative_design",
                                arg_template=arg_template)

        self.accuracy = arg_template.accuracy
        self.precision = arg_template.precision

        int_size = 3
        frac_size = 7

        self.input_precision = fixed_point(int_size, frac_size)
        self.output_precision = fixed_point(int_size, frac_size)
示例#7
0
    def generate_scheme(self):
        self.var_mapping = {}
        for var_index in range(self.arity):
            # FIXME: maximal arity is 4
            var_tag = ["x", "y", "z", "t"][var_index]
            self.var_mapping[var_tag] = self.implementation.add_input_variable(
                var_tag,
                self.get_input_precision(var_index),
                interval=self.input_intervals[var_index])

        self.function_expr = function_parser(self.function_expr_str,
                                             self.var_mapping)

        Log.report(Log.Info, "evaluating function range")
        evaluate_range(self.function_expr, update_interval=True)
        Log.report(
            LOG_VERBOSE_FUNCTION_EXPR, "scheme is: \n{}",
            self.function_expr.get_str(depth=None, display_interval=True))

        # defined copy map to avoid copying input Variables
        copy_map = dict((var, var) for var in self.var_mapping.items())

        function_expr_copy = self.function_expr.copy(copy_map)

        result, scheme = self.instanciate_graph(function_expr_copy,
                                                expand_div=self.expand_div)
        scheme.add(Return(result, precision=self.precision))

        return scheme
示例#8
0
    def generate_scheme(self):
        """ main scheme generation """
        Log.report(Log.Info,
                   "input_precision is {}".format(self.input_precision))
        Log.report(Log.Info,
                   "output_precision is {}".format(self.output_precision))

        # declaring main input variable
        var_x = self.implementation.add_input_signal("x", self.input_precision)
        var_y = self.implementation.add_input_signal("y", self.input_precision)
        var_x.set_attributes(debug=debug_fixed)
        var_y.set_attributes(debug=debug_fixed)

        self.implementation.start_new_stage()

        add = var_x + var_y

        self.implementation.start_new_stage()

        sub = add - var_y

        self.implementation.start_new_stage()

        pre_result = sub - var_x

        self.implementation.start_new_stage()

        post_result = pre_result + var_x

        result = Conversion(pre_result, precision=self.output_precision)

        self.implementation.add_output_signal("vr_out", result)

        return [self.implementation]
示例#9
0
 def flush_bb_stack(self):
     """ Pop all basic-blocks from the stack except the last (function
         enttry point) """
     # flush all but last bb (which is root/main)
     while len(self.current_bb_stack) > 1:
         assert self.pop_current_bb()
     Log.report(LOG_LEVEL_GEN_BB_VERBOSE, "bb_stack after flush: ",
                [bb.get_tag() for bb in self.current_bb_stack])
示例#10
0
 def elab(self, entity_name=None):
     # TODO/FIXME: a single file supported for now
     output_file = self.source_file_list[0]
     modelsim_elab_cmd = "vlib work && vcom -2008 {}".format(output_file)
     Log.report(Log.Info, "elaboration command:\n{}".format(modelsim_elab_cmd))
     elab_result = subprocess.call(modelsim_elab_cmd, shell=True)
     Log.report(Log.Info, "elaboration result:{}".format(elab_result))
     return elab_result
示例#11
0
 def execute(self, optree):
     Log.report(Log.Info, "executing PassDumpWithStages")
     print(
         optree.get_str(depth=None,
                        display_precision=True,
                        memoization_map={},
                        custom_callback=lambda op: " [S={}] ".format(
                            op.attributes.init_stage)))
示例#12
0
 def execute_on_function(self, fct, fct_group):
     """ execute generic lowering on function <fct> from group <fct_group>
     """
     Log.report(LOG_LOWERING_INFO, "executing pass {} on fct {}".format(
         self.pass_tag, fct.get_name()))
     fct_scheme = fct.get_scheme()
     lowered_scheme = self.execute_on_graph(fct_scheme)
     fct.set_scheme(lowered_scheme)
示例#13
0
def evaluate_typecast_value(optree, value):
    assert isinstance(optree, TypeCast)
    input_format = optree.get_input(0).get_precision()
    output_format = optree.get_precision() 
    input_value = input_format.get_integer_coding(value)
    output_value = output_format.get_value_from_integer_coding(input_value, base=None)
    Log.report(LOG_RUNTIME_EVAL_ERROR, "value={}, input_value= {}, output_value={}", value, input_value, output_value) 
    return output_value
示例#14
0
 def get_memoization_value(self, node, *args):
     node_key = self.get_memoization_key(node, *args)
     try:
         return self.memoization_map[node_key]
     except KeyError:
         Log.report(Log.Error,
                    "unable to found key {} in {} memoization map",
                    node_key, self)
示例#15
0
 def execute_on_function(self, fct, fct_group):
     """ execute basic-block generation pass on function @p fct from
         function-group @p fct_group """
     Log.report(LOG_LEVEL_GEN_BB_INFO, "executing pass {} on fct {}".format(
         self.pass_tag, fct.get_name()))
     op_graph = fct.get_scheme()
     top_bb_list = self.execute_on_graph(op_graph)
     fct.set_scheme(top_bb_list)
示例#16
0
 def register_pass(self,
                   pass_object,
                   pass_dep=PassDependency(),
                   pass_slot=None):
     Log.report(
         LOG_PASS_INFO, "PassScheduler: registering pass {} at {}".format(
             pass_object, pass_slot))
     self.pass_map[pass_slot].append(PassWrapper(pass_object, pass_dep))
示例#17
0
 def elab(self, entity_name):
     # TODO/FIXME: a single file supported for now
     output_file = self.source_file_list[0]
     ghdl_elab_cmd = "ghdl -c --ieee=synopsys --std=08 {} -e {} ".format(output_file, entity_name)
     Log.report(Log.Info, "elaboration command:\n{}".format(ghdl_elab_cmd))
     elab_result = subprocess.call(ghdl_elab_cmd, shell=True)
     Log.report(Log.Info, "elaboration result:{}".format(elab_result))
     return elab_result
示例#18
0
 def execute_on_function(self, fct, fct_group):
     Log.report(Log.Info, "executing pass {} on fct {}".format(
         self.pass_tag, fct.get_name()))
     optree = fct.get_scheme()
     memoization_map = {}
     new_scheme = self.execute_on_optree(optree, fct, fct_group, memoization_map)
     if not new_scheme is None:
         fct.set_scheme(new_scheme)
示例#19
0
def dadda_4to2_reduction(previous_bit_heap):
    """ BitHeap Wallace reduction using 4:2 compressors """
    next_bit_heap = BitHeap()
    carry_bit_heap = BitHeap()
    max_count = previous_bit_heap.max_count()
    new_count = int(math.ceil(max_count / 2.0))
    # each step reduce the height of the bit heap at at most
    # new_count. However it is not necessary to reduce over it
    while previous_bit_heap.max_count() > 0:
        bit_list, w = previous_bit_heap.pop_lower_bits(4)
        # if a carry from this weight exists, we must try to
        # accumulate it
        if carry_bit_heap.bit_count(w) > 0:
            cin = carry_bit_heap.pop_bit(w)
        else:
            cin = None
        if len(bit_list) == 0:
            if cin:
                next_bit_heap.insert(w, cin)
        elif len(bit_list) == 1:
            next_bit_heap.insert_bit(w, bit_list[0])
            if cin:
                next_bit_heap.insert_bit(w, cin)
        elif (0 if cin is None else 1) + previous_bit_heap.bit_count(w) + len(
                bit_list) + next_bit_heap.bit_count(w) <= new_count:
            Log.report(Log.Verbose, "dropping bits without compression")
            # drop every bit in next stage
            if not cin is None:
                next_bit_heap.insert_bit(w, cin)
            for b in bit_list:
                next_bit_heap.insert_bit(w, b)
        elif len(bit_list) == 2:
            if cin is None:
                for b in bit_list:
                    next_bit_heap.insert_bit(w, b)
            else:
                b_wp1, b_w = comp_3to2(bit_list[0], bit_list[1], cin)
                next_bit_heap.insert_bit(w + 1, b_wp1)
                next_bit_heap.insert_bit(w, b_w)
                cin = None
        elif len(bit_list) == 3:
            if cin:
                next_bit_heap.insert_bit(w, cin)
            b_wp1, b_w = comp_3to2(bit_list[0], bit_list[1], bit_list[2])
            next_bit_heap.insert_bit(w + 1, b_wp1)
            next_bit_heap.insert_bit(w, b_w)
        else:
            assert len(bit_list) == 4
            cout, b_wp1, b_w = comp_4to2(cin, bit_list[0], bit_list[1],
                                         bit_list[2], bit_list[3])
            next_bit_heap.insert_bit(w + 1, b_wp1)
            next_bit_heap.insert_bit(w, b_w)
            carry_bit_heap.insert_bit(w + 1, cout)
    # flush carry-bit heap
    while carry_bit_heap.max_count() > 0:
        bit_list, w = carry_bit_heap.pop_lower_bits(1)
        next_bit_heap.insert_bit(w, bit_list[0])
    return next_bit_heap
    def expand_node(self, node):
        """ If node @p node is a multi-precision node, expands to a list
            of scalar element, ordered from most to least significant """

        if node in self.memoization_map:
            return self.memoization_map[node]
        else:
            if not (multi_element_output(node) or multi_element_inputs(node)):
                if not is_leaf_node(node):
                    # recursive processing of node's input
                    for index, op in enumerate(node.get_inputs()):
                        op_input = self.expand_node(op)
                        if not op_input is None:
                            reconstructed_input = self.reconstruct_from_transformed(
                                op, op_input)
                            node.set_input(index, reconstructed_input)
                result = (node, )
            elif isinstance(node, Variable):
                result = self.expand_var(node)
            elif isinstance(node, Constant):
                result = self.expand_cst(node)
            elif isinstance(node, Addition):
                result = self.expand_add(node)
            elif isinstance(node, Multiplication):
                result = self.expand_mul(node)
            elif isinstance(node, Subtraction):
                result = self.expand_sub(node)
            elif isinstance(node, FusedMultiplyAdd):
                result = self.expand_fma(node)
            elif isinstance(node, Conversion):
                result = self.expand_conversion(node)
            elif isinstance(node, Negation):
                result = self.expand_negation(node)
            elif isinstance(node, BuildFromComponent):
                result = self.expand_build_from_component(node)
            elif isinstance(node, ComponentSelection):
                result = self.expand_component_selection(node)
            elif is_subnormalize_op(node):
                result = self.expand_subnormalize(node)
            else:
                if is_leaf_node(node):
                    pass
                else:
                    # recursive processing of node's input
                    for index, op in enumerate(node.get_inputs()):
                        op_input = self.expand_node(op)
                        if not op_input is None:
                            reconstructed_input = self.reconstruct_from_transformed(
                                op, op_input)
                            node.set_input(index, reconstructed_input)
                # no modification
                result = None

            if result is None:
                Log.report(LOG_LEVEL_EXPAND_VERBOSE,
                           "expansion is None for {}", node)
            self.memoization_map[node] = result
            return result
示例#21
0
def update_def_var(node, var, new_var):
    """ Update @p var which should be the variable defined by @p
        and replace it by @p vp """
    # TODO: manage sub-assignation cases
    assert isinstance(node, (ReferenceAssign, PhiNode))
    assert node.get_input(0) is var
    assert not new_var is None
    Log.report(LOG_LEVEL_GEN_BB_VERBOSE, "updating var def in {} from {} to {}", node, var, new_var)
    node.set_input(0, new_var)
示例#22
0
 def dominator_map(self):
     """ dict associating to each node the least of nodes which dominate it """
     if self._dominator_map is None:
         self._dominator_map = build_dominator_map(self)
         for bb in self._dominator_map:
             Log.report(LOG_LEVEL_GEN_BB_VERBOSE, "bb {}'s dominator: {}",
                        bb.get_tag(),
                        [dom.get_tag() for dom in self._dominator_map[bb]])
     return self._dominator_map
示例#23
0
 def add_output_variable(self, name, output_node):
     output_var = Variable(name,
                           precision=output_node.get_precision(),
                           var_type=Variable.Output)
     output_assign = ReferenceAssign(output_var, output_node)
     if name in self.output_map:
         Log.report(Log.error,
                    "pre-existing name {} in output_map".format(name))
     self.output_map[name] = output_assign
示例#24
0
    def legalize_node(self, node):
        """ return the expansion of @p node when possible
            else None """
        def wrap_expansion(node, transformed_node):
            return node if transformed_node is None else transformed_node

        def general_get_scalar_format(node_format):
            """ Overload of get_scalar_format which works
                for both vector and scalar formats """
            if node_format.is_vector_format():
                return node_format.get_scalar_format()
            return node_format

        if node in self.memoization_map:
            return self.memoization_map[node]
        elif not is_virtual_bool_node(node):
            result = None
        elif isinstance(node, Comparison) or isinstance(
                node, LogicalAnd) or isinstance(node, LogicalOr):
            scalar_bit_size = max(
                general_get_scalar_format(
                    node.get_input(0).get_precision()).get_bit_size(),
                general_get_scalar_format(
                    node.get_input(1).get_precision()).get_bit_size())
            legalized_format = VECTOR_TYPE_MAP[ML_Bool][scalar_bit_size][
                node.get_precision().get_vector_size()]
            Log.report(LOG_VERBOSE_VBOOL_LEGALIZATION,
                       "legalizing format of {} from {} to {}", node,
                       node.get_precision(), legalized_format)
            node.set_attributes(precision=legalized_format)
            result = node
        elif isinstance(node, LogicalNot) or (isinstance(
                node, Test) and node.specifier in EXPANDABLE_TEST_LIST):
            scalar_bit_size = general_get_scalar_format(
                node.get_input(0).get_precision()).get_bit_size()
            legalized_format = VECTOR_TYPE_MAP[ML_Bool][scalar_bit_size][
                node.get_precision().get_vector_size()]
            Log.report(LOG_VERBOSE_VBOOL_LEGALIZATION,
                       "legalizing format of {} from {} to {}", node,
                       node.get_precision(), legalized_format)
            node.set_attributes(precision=legalized_format)
            result = node
        elif isinstance(node, VectorAssembling):
            scalar_bit_size = max(
                general_get_scalar_format(
                    node.get_input(0).get_precision()).get_bit_size(),
                general_get_scalar_format(
                    node.get_input(1).get_precision()).get_bit_size())
            legalized_format = VECTOR_TYPE_MAP[ML_Bool][scalar_bit_size][
                node.get_precision().get_vector_size()]
            node.set_attributes(precision=legalized_format)
            result = node
        else:
            result = None

        self.memoization_map[node] = result
        return result
示例#25
0
 def add_stage_forward(self, op_dst, op_src, stage):
     Log.report(
         Log.Verbose,
         " adding stage forward {op_src} to {op_dst} @ stage {stage}".
         format(op_src=op_src, op_dst=op_dst, stage=stage))
     if not stage in self.stage_forward:
         self.stage_forward[stage] = []
     self.stage_forward[stage].append(ReferenceAssign(op_dst, op_src))
     self.pre_statement.add(op_src)
示例#26
0
 def run(self, simulation_time, debug=False, exit_after_test=True):
     debug_cmd = "do {debug_file};".format(debug_file=self.debug_file) if debug else "" 
     debug_cmd += " exit;" if exit_after_test else ""
     # simulation
     modelsim_run_cmd = "vsim -c work.testbench -do \"run {test_delay} ns; {debug_cmd}\"".format(
         debug_cmd=debug_cmd, test_delay=simulation_time)
     Log.report(Log.Info, "simulation command:\n{}".format(modelsim_run_cmd))
     sim_result = subprocess.call(modelsim_run_cmd, shell=True)
     Log.report(Log.Info, "simulation result:{}".format(sim_result))
     return sim_result
示例#27
0
def llvm_ir_format(precision):
    """ Translate from Metalibm precision to string for LLVM-IR format """
    if is_pointer_format(precision):
        return "{}*".format(llvm_ir_format(precision.get_data_precision()))
    elif precision in LLVM_IR_DATA_FORMAT_MAP:
        return LLVM_IR_DATA_FORMAT_MAP[precision]
    else:
        Log.report(Log.Error,
                   "unknown precision {} in llvm_ir_format".format(precision),
                   error=KeyError)
示例#28
0
 def successors(self):
     last_op = self.get_input(-1)
     if not isinstance(last_op, ControlFlowOperation):
         Log.report(
             Log.Info,
             "last operation of BB is not a ControlFlowOperation: BB is {}",
             self)
         return []
     else:
         return last_op.destination_list
示例#29
0
    def execute_on_fct_group(self, fct_group):
        Log.report(
            Log.Info,
            "executing pass {} on fct group {}".format(self.pass_tag,
                                                       fct_group))

        def local_fct_apply(group, fct):
            return self.execute_on_function(fct, group)

        return fct_group.apply_to_all_functions(local_fct_apply)
示例#30
0
 def execute_on_function(self, fct, fct_group):
     """ Execute SSA translation pass on function @p fct from
         function-group @p fct_group """
     Log.report(LOG_LEVEL_GEN_BB_INFO, "executing pass {} on fct {}".format(
         self.pass_tag, fct.get_name()))
     optree = fct.get_scheme()
     assert isinstance(optree, BasicBlockList)
     bb_root = optree.get_input(0)
     bbg = BasicBlockGraph(bb_root, optree)
     phi_node_insertion(bbg)
     variable_renaming(bbg)