def legalize_fixed_point_subselection(optree, input_prec_solver=default_prec_solver): """ Legalize a SubSignalSelection on a fixed-point node """ sub_input = optree.get_input(0) inf_index = evaluate_cst_graph(optree.get_inf_index(), input_prec_solver=input_prec_solver) sup_index = evaluate_cst_graph(optree.get_sup_index(), input_prec_solver=input_prec_solver) assert not inf_index is None and not sup_index is None input_format = ML_StdLogicVectorFormat( sub_input.get_precision().get_bit_size()) output_format = ML_StdLogicVectorFormat(sup_index - inf_index + 1) subselect = SubSignalSelection(TypeCast(sub_input, precision=input_format), inf_index, sup_index, precision=output_format) result = TypeCast( subselect, precision=optree.get_precision(), ) # TypeCast may be simplified during code generation so attributes # may also be forwarded to previous node forward_attributes(optree, subselect) forward_attributes(optree, result) return result
def legalize_multi_precision_vector_element_selection(optree): """ legalize a VectorElementSelection @p optree on a vector of multi-precision elements to a single element """ assert isinstance(optree, VectorElementSelection) multi_precision_vector = optree.get_input(0) elt_index = optree.get_input(1) hi_vector = multi_precision_vector.hi lo_vector = multi_precision_vector.lo limb_num = multi_precision_vector.get_precision().get_scalar_format().limb_num if limb_num == 2: component_vectors = [hi_vector, lo_vector] elif limb_num == 3: me_vector = multi_precision_vector.me component_vectors = [hi_vector, me_vector, lo_vector] else: Log.report(Log.Error, "unsupported number of limbs in legalize_multi_precision_vector_element_selection for {}", optree) result = BuildFromComponent( *tuple(VectorElementSelection(vector, elt_index) for vector in component_vectors) ) forward_attributes(optree, result) result.set_precision(optree.precision) return result
def fixed_point_position_legalizer(optree, input_prec_solver=default_prec_solver): """ Legalize a FixedPointPosition node to a constant """ assert isinstance(optree, FixedPointPosition) fixed_input = optree.get_input(0) fixed_precision = input_prec_solver(fixed_input) if not is_fixed_point(fixed_precision): Log.report( Log.Error, "in fixed_point_position_legalizer: precision of {} should be fixed-point but is {}" .format(fixed_input, fixed_precision)) position = optree.get_input(1).get_value() align = optree.get_align() value_computation_map = { FixedPointPosition.FromLSBToLSB: position, FixedPointPosition.FromMSBToLSB: fixed_precision.get_bit_size() - 1 - position, FixedPointPosition.FromPointToLSB: fixed_precision.get_frac_size() + position, FixedPointPosition.FromPointToMSB: fixed_precision.get_integer_size() - position } cst_value = value_computation_map[align] # display value Log.report( Log.LogLevel("FixedPoint"), "fixed-point position {tag} has been resolved to {value}".format( tag=optree.get_tag(), value=cst_value)) result = Constant(cst_value, precision=ML_Integer) forward_attributes(optree, result) return result
def legalize_operation_rec(self, optree): """ """ # looking into memoization map if optree in self.memoization_map: return self.memoization_map[optree] # has the npde been modified ? arg_changed = False if isinstance(optree, ML_LeafNode): pass else: for index, op_input in enumerate(optree.get_inputs()): is_modified, new_node = self.legalize_operation_rec(op_input) if is_modified: optree.set_input(index, new_node) arg_changed = True local_changed, new_optree = self.legalize_single_operation( optree, self.format_solver) if local_changed: forward_attributes(optree, new_optree) Log.report(LOG_LEVEL_LEGALIZE, "legalized {} to {}", optree, new_optree) self.memoization_map[optree] = local_changed, new_optree return (local_changed or arg_changed), new_optree
def simplify_logical_tree(node, op_predicate=lambda n: isinstance(n, LogicalAnd), leaf_predicate=lambda n: isinstance(n, LogicalNot), result_ctor=lambda node, input_list: None): """ simplify a tree of operation matching the following conditions: - each internal node verifies op_predicate(node) - each leaf verifies leaf_predicate(node) a list is built with the leaf node and the result is built by calling result_ctor(<input node>, <list>) """ def get_input_list(op): if leaf_predicate(op): # extract input of input (decapsulating LogicalNot) return [op] elif op_predicate(op): return get_input_list(op.get_input(0)) + get_input_list( op.get_input(1)) else: raise NotImplementedError input_list = get_input_list(node) result = result_ctor(node, input_list) #result = LogicalNot(logical_or_reduce(list(map(leaf_transform, input_list)))) forward_attributes(node, result) return result
def expand_sub(self, node): lhs = node.get_input(0) rhs = node.get_input(1) tag = node.get_tag() precision = node.get_precision() new_node = Addition(lhs, Negation(rhs, precision=rhs.precision), precision=precision) forward_attributes(node, new_node) return self.expand_node(new_node)
def reconstruct_from_transformed(self, node, transformed_node): """return a node at the root of a transformation chain, compatible with untransformed nodes """ if isinstance(node, Constant): return node else: result = BuildFromComponent(*tuple(transformed_node), precision=node.precision) forward_attributes(node, result) result.set_tag(node.get_tag()) return result
def simplify(self, node): def get_node_input(index): # look for input into simpifield list # and return directly node input if simplified input is None return node.get_input(index) result = None if node in self.memoization_map: return self.memoization_map[node] else: if not is_leaf_node(node): for index, op in enumerate(node.inputs): new_op = self.simplify(op) # replacing modified inputs if not new_op is None: node.set_input(index, new_op) if is_simplifiable_to_cst(node): new_node = Constant( sollya.inf(node.get_interval()), precision=node.get_precision() ) forward_attributes(node, new_node) result = new_node elif isinstance(node, Multiplication) and is_simplifiable_multiplication(node, get_node_input(0), get_node_input(1)): result = simplify_multiplication(node) elif isinstance(node, Min): simplified_min = is_simplifiable_min(node, get_node_input(0), get_node_input(1)) if simplified_min: result = simplified_min elif isinstance(node, Max): simplified_max = is_simplifiable_max(node, get_node_input(0), get_node_input(1)) if simplified_max: result = simplified_max elif isinstance(node, Comparison): cmp_value = is_simplifiable_cmp(node, get_node_input(0), get_node_input(1)) if cmp_value is BooleanValue.AlwaysTrue: result = generate_uniform_cst(True, node.get_precision()) elif cmp_value is BooleanValue.AlwaysFalse: result = generate_uniform_cst(False, node.get_precision()) elif isinstance(node, Test): test_value = is_simplifiable_test(node, node.inputs) if test_value is BooleanValue.AlwaysTrue: result = generate_uniform_cst(True, node.get_precision()) elif test_value is BooleanValue.AlwaysFalse: result = generate_uniform_cst(False, node.get_precision()) elif isinstance(node, ConditionBlock): result = simplify_condition_block(node) elif isinstance(node, LogicOperation): result = simplify_logical_op(node) if not result is None: Log.report(LOG_VERBOSE_NUMERICAL_SIMPLIFICATION, "{} has been simplified to {}", node, result) self.memoization_map[node] = result return result
def minmax_legalizer(optree): op0 = optree.get_input(0) op1 = optree.get_input(1) bool_prec = get_compatible_bool_format(optree) comp = Comparison(op0, op1, specifier=predicate, precision=bool_prec, tag="minmax_pred") # forward_stage_attributes(optree, comp) result = Select(comp, op0, op1, precision=optree.get_precision()) forward_attributes(optree, result) return result
def reconstruct_from_transformed(self, node, transformed_node): Log.report(LOG_LEVEL_EXPAND_VERBOSE, "reconstructed : {}", node) Log.report(LOG_LEVEL_EXPAND_VERBOSE, "from transformed: {}", "\n".join([str(n) for n in transformed_node])) if isinstance(node, Constant): result = node else: if len(transformed_node) == 1: result = transformed_node[0] else: result = BuildFromComponent(*tuple(transformed_node), precision=node.precision) forward_attributes(node, result) result.set_tag(node.get_tag()) Log.report(LOG_LEVEL_EXPAND_VERBOSE, " result is : {}", result) return result
def expand_sub(self, node): lhs = node.get_input(0) rhs = node.get_input(1) tag = node.get_tag() precision = node.get_precision() # Subtraction x - y is transformed into x + (-y) # WARNING: if y is not expandable (e.g. scalar precision) # this could stop expansion new_node = Addition(lhs, Negation(rhs, precision=rhs.precision), precision=precision) forward_attributes(node, new_node) expanded_node = self.expand_node(new_node) Log.report( LOG_LEVEL_EXPAND_VERBOSE, "expanding Subtraction {} into {} with expanded form {}", node, new_node, ", ".join( (op.get_str(display_precision=True, depth=None)) for op in expanded_node)) return expanded_node
def simplify_logical_or_not(node, leaf_transform): """ Simplify a tree of LogicalOr nodes, whose leaf are LogicalNot nodes """ # the leaf_function transforms a leaf by extracting # its single input (decapsulating LogicalNot) and # calling leaf_transform on this input def leaf_function(op): return leaf_transform(op.get_input(0)) result = simplify_logical_tree( node, op_predicate=(lambda op: isinstance(op, LogicalOr)), leaf_predicate=(lambda op: isinstance(op, LogicalNot)), result_ctor=lambda op, op_list: LogicalNot( logical_reduce(list(map(leaf_transform, op_list)), LogicalAnd, precision=node.get_precision()), precision=node.get_precision())) forward_attributes(node, result) return result
def expand_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 if node in self.memoization_map: return self.memoization_map[node] elif isinstance(node, ExponentExtraction): op = wrap_expansion(node.get_input(0), self.expand_node(node.get_input(0))) result = generate_exp_extraction(op) forward_attributes(node, result) elif isinstance(node, ExponentInsertion): op = wrap_expansion(node.get_input(0), self.expand_node(node.get_input(0))) result = generate_exp_insertion(op, node.precision) forward_attributes(node, result) elif is_expandable_test(node): op = wrap_expansion(node.get_input(0), self.expand_node(node.get_input(0))) result = generate_test_expansion(node.specifier, op) forward_attributes(node, result) else: result = None self.memoization_map[node] = result return result
def mantissa_extraction_modifier(optree): """ Legalizing a MantissaExtraction node into a sub-graph of basic operation """ init_stage = optree.attributes.get_dyn_attribute("init_stage") op = optree.get_input(0) tag = optree.get_tag() or "mant_extr" op_precision = op.get_precision().get_base_format() exp_prec = ML_StdLogicVectorFormat(op_precision.get_exponent_size()) field_prec = ML_StdLogicVectorFormat(op_precision.get_field_size()) exp_op = RawExponentExtraction(op, precision=exp_prec, init_stage=init_stage, tag=tag + "_exp_extr") field_op = SubSignalSelection(TypeCast( op, precision=op.get_precision().get_support_format(), init_stage=init_stage, tag=tag + "_field_cast"), 0, op_precision.get_field_size() - 1, precision=field_prec, init_stage=init_stage, tag=tag + "_field") exp_is_zero = Comparison(exp_op, Constant(op_precision.get_zero_exponent_value(), precision=exp_prec, init_stage=init_stage), precision=ML_Bool, specifier=Comparison.Equal, init_stage=init_stage) result = mantissa_extraction_modifier_from_fields(op, field_op, exp_is_zero) forward_attributes(optree, result) return result
def simplify_node(self, node): """ return the simplified version of @p node when possible else the node itself """ result = node if node in self.memoization_map: return self.memoization_map[node] elif isinstance(node, SubSignalSelection): op_input = self.simplify_node(node.get_input(0)) lo_index = evaluate_cst_graph(node.get_input(1)) hi_index = evaluate_cst_graph(node.get_input(2)) if isinstance(op_input, SubSignalSelection): parent_input = self.simplify_node(op_input.get_input(0)) parent_lo_index = evaluate_cst_graph(op_input.get_input(1)) new_node = SubSignalSelection(parent_input, parent_lo_index + lo_index, parent_lo_index + hi_index) forward_attributes(node, new_node) result = new_node elif isinstance(node, VectorElementSelection): op_input = self.simplify_node(node.get_input(0)) op_index = evaluate_cst_graph(node.get_input(1)) if isinstance(op_input, SubSignalSelection): parent_input = op_input.get_input(0) base_index = evaluate_cst_graph(op_input.get_input(1)) new_node = BitSelection(parent_input, base_index + op_index) forward_attributes(node, new_node) result = new_node elif isinstance(op_input, Constant): offset = 0 if is_fixed_point(op_input.get_precision()): offset = -op_input.get_precision().get_frac_size() bit_value = (op_input.get_value() >> (op_index + offset)) & 1 new_node = Constant(bit_value, precision=node.get_precision()) forward_attributes(node, new_node) result = new_node else: result = node Log.report(LOG_VERBOSE_SIMPLIFY_RTL, "Simplifying {} to {}", node, result) self.memoization_map[node] = result return result