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
# The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ############################################################################### import sys from metalibm_core.utility.log_report import Log """ custom warning log level for pass management """ LOG_PASS_INFO = Log.LogLevel("Info", "passes") ## Parent class for all pass dependency class PassDependency: ## test if the @p self dependency is resolved # @p param pass_scheduler scheduler which requires dependency checking # @return boolean True if dependency is resolved, False otherwise def is_dep_resolved(self, pass_scheduler): return True class AfterPassByClass(PassDependency): def __init__(self, pass_class): self.pass_class = pass_class
from metalibm_core.core.legalizer import extract_placeholder from metalibm_core.core.passes import FunctionPass, Pass, LOG_PASS_INFO from metalibm_core.core.bb_operations import ( BasicBlockList, ConditionalBranch, UnconditionalBranch, BasicBlock, SequentialBlock, PhiNode ) from metalibm_core.utility.log_report import Log # specific debug log levels for this file: (very) verbose and # info(rmative) LOG_LEVEL_GEN_BB_VERBOSE = Log.LogLevel("GenBBVerbose") LOG_LEVEL_GEN_BB_INFO = Log.LogLevel("GenBBInfo") def transform_cb_to_bb(bb_translator, optree, fct=None, fct_group=None, memoization_map=None): """ Transform a ConditionBlock node to a list of BasicBlock returning the entry block as result. @param bb_translator generic basic-block translator object which can be called recursively on CB sub basic blocks @param optree input operation tree @return entry BasicBlock to the ConditionBlock translation """ # get current unfinished basic block (CB:) from top of stack # # When encoutering
result_type = (None if node_format is None else node_format.get_match_format() ,) if not is_leaf_node(node): arg_type = tuple((arg.get_precision().get_match_format() if not arg.get_precision() is None else None) for arg in node.get_inputs()) interface = result_type + arg_type else: interface = (result_type,) codegen_key = node.get_codegen_key() return op_class, interface, codegen_key @property def action_selection_table(self): """ semantic indirection between action_selection_table and code_generation_table """ return self.lowering_table LOG_LOWERING_INFO = Log.LogLevel("LoweringInfo") @METALIBM_PASS_REGISTER class Pass_GenericLowering(FunctionPass): """ implement generic lowering """ pass_tag = "generic_lowering" def __init__(self, target, description="lower operation for target"): FunctionPass.__init__(self, description, target) def execute_on_optree(self, optree, fct=None, fct_group=None, memoization_map=None): raise NotImplementedError def execute_on_graph(self, op_graph): lowering_engine = LoweringEngine(self.target) lowered_graph = lowering_engine.lower_node(op_graph) return lowered_graph
############################################################################### from metalibm_core.core.ml_formats import (ML_Custom_FixedPoint_Format) from metalibm_core.core.ml_hdl_format import (RTL_FixedPointFormat, ML_StdLogicVectorFormat) import metalibm_core.core.ml_hdl_format as ml_hdl_format from metalibm_core.core.ml_table import ML_TableFormat from metalibm_core.core.ml_operations import (is_leaf_node) from metalibm_core.core.passes import FunctionPass, METALIBM_PASS_REGISTER from metalibm_core.utility.log_report import Log # high verbosity log-level for expand_multi_precision pass module LOG_LEVEL_LEGALIZE_RTL2SW = Log.LogLevel("LegalizeRTL2SWFormat") class Pass_ExhaustiveSearch(FunctionPass): """ Check precision of every node appearing in the graph """ pass_tag = "exhaustive_search" def __init__(self, tag, target): FunctionPass.__init__(self, tag, target) def execute_on_node(self, node): """ execute pass action on node without input traversal """ raise NotImplementedError def execute_on_optree(self, optree, fct, fct_group, memoization_map): if optree in memoization_map:
MP_FMA2211, MP_FMA2222, MP_Add323, MP_Add332, MP_Add333, MP_Mul322, MP_Mul332, MP_Mul323, subnormalize_multi, Normalize_33, ) from metalibm_core.utility.log_report import Log # high verbosity log-level for expand_multi_precision pass module LOG_LEVEL_EXPAND_VERBOSE = Log.LogLevel("ExpandVerbose") def is_subnormalize_op(node): """ test if @p node is a Subnormalize operation """ return isinstance( node, SpecificOperation) and node.specifier is SpecificOperation.Subnormalize def get_elementary_precision(multi_precision): """ return the elementary precision corresponding to multi_precision """ multi_precision = multi_precision.get_match_format() if isinstance(multi_precision, ML_FP_MultiElementFormat): return multi_precision.field_format_list[0]
FormatSolver) from metalibm_core.core.legalizer import (subsignalsection_legalizer, fixed_point_position_legalizer, minmax_legalizer_wrapper) from metalibm_core.opt.opt_utils import forward_attributes ############################################################################### # PASS DESCRIPTION: # The pass implemented in this file processes an optree and legalize every # supported node # the output format ############################################################################### LOG_LEVEL_LEGALIZE = Log.LogLevel("LegalizeVerbose") def legalize_Select(optree): """ legalize Select operation node by converting if and else inputs to Select output format if the bit sizes do not match """ cond = optree.get_input(0) op0 = optree.get_input(1) op1 = optree.get_input(2) precision = optree.get_precision() if precision is None: Log.report(Log.Error, "None precision for Select:\n{}", optree) if op0.get_precision().get_bit_size() != precision.get_bit_size(): optree.set_input(1, Conversion(op0, precision=precision)) if op1.get_precision().get_bit_size() != precision.get_bit_size(): optree.set_input(2, Conversion(op1, precision=optree.get_precision()))
) from metalibm_core.core.ml_operations import ( VectorAssembling, Comparison, BooleanOperation, LogicalNot, LogicalOr, LogicalAnd, Test, ) from metalibm_core.utility.log_report import Log from metalibm_core.utility.debug_utils import debug_multi LOG_VERBOSE_VBOOL_LEGALIZATION = Log.LogLevel("VirtualBoolLegalizeVerbose") # List of tests which can be expanded by VirtualBoolVectorLegalizer EXPANDABLE_TEST_LIST = [ Test.IsInfOrNaN, Test.IsInfty, Test.IsNaN, Test.IsZero, Test.IsSubnormal, Test.IsQuietNaN, Test.IsSignalingNaN ] def is_virtual_bool_node(node): return (isinstance(node, BooleanOperation) or isinstance(node, VectorAssembling)) and \ node.get_precision().is_vector_format() and \ node.get_precision().get_scalar_format() is ML_Bool class VirtualBoolVectorLegalizer(object):
from metalibm_core.core.ml_formats import (ml_infty, is_fixed_format) from metalibm_core.core.ml_operations import ( is_leaf_node, Min, Max, Constant, Test, Comparison, ConditionBlock, LogicOperation, LogicalAnd, LogicalOr, LogicalNot, Statement, Multiplication, Addition, ) from metalibm_core.core.legalizer import is_constant from metalibm_core.core.meta_interval import MetaInterval, MetaIntervalList, inf, sup from metalibm_core.utility.log_report import Log from metalibm_core.utility.debug_utils import debug_multi LOG_VERBOSE_NUMERICAL_SIMPLIFICATION = Log.LogLevel("NumericalSimplificationVerbose") from metalibm_core.opt.opt_utils import is_false, is_true def is_simplifiable_to_cst(node): """ node can be simplified to a constant """ node_interval = node.get_interval() if node_interval is None or isinstance(node, Constant): return False elif isinstance(node_interval, SollyaObject) and node_interval.is_range(): return sollya.inf(node_interval) == sollya.sup(node_interval) elif isinstance(node_interval, (MetaInterval, MetaIntervalList)): return not node_interval.is_empty and (node_interval.inf == node_interval.sup) else: return False
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ############################################################################### # Description: evaluating node range accross the graph ############################################################################### from metalibm_core.core.ml_operations import is_leaf_node from metalibm_core.utility.log_report import Log from metalibm_core.core.passes import FunctionPass, LOG_PASS_INFO, Pass from metalibm_core.opt.opt_utils import evaluate_range LOG_VERBOSE_EVALUATE_RANGE = Log.LogLevel("EvaluateRangeVerbose") class Pass_EvaluateRange(FunctionPass): """ Verify that each node has a precision assigned to it """ pass_tag = "evaluate_range" def __init__(self, target): super().__init__("evaluate_range", target) def evaluate_set_range(self, optree, memoization_map=None): """ check if all precision-instantiated operation are supported by the processor """ # memoization map is used to store node's range/interval memoization_map = {} if memoization_map is None else memoization_map if optree in memoization_map: return optree else:
############################################################################### from metalibm_core.core.ml_operations import ( is_leaf_node, FunctionObject, Conversion, is_conversion, TypeCast, is_typecast, Constant, Abs, Subtraction) from metalibm_core.core.legalizer import is_constant from metalibm_core.core.ml_formats import ML_Void from metalibm_core.code_generation.code_constant import C_Code from metalibm_core.code_generation.generator_utility import TemplateOperatorFormat from metalibm_core.utility.log_report import Log LOG_RUNTIME_EVAL_ERROR = Log.LogLevel("LogRuntimeEvalError") 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 def evaluate_conversion_value(optree, value): return optree.get_precision().round_sollya_object(value)
# Description: optimization pass to expand multi-precision node to simple # precision implementation ############################################################################### from metalibm_core.core.passes import OptreeOptimization, Pass, LOG_PASS_INFO from metalibm_core.core.ml_operations import (VectorElementSelection) from metalibm_core.core.ml_hdl_operations import (BitSelection, SubSignalSelection) from metalibm_core.core.legalizer import evaluate_cst_graph from metalibm_core.opt.node_transformation import Pass_NodeTransformation from metalibm_core.opt.opt_utils import forward_attributes from metalibm_core.utility.log_report import Log LOG_VERBOSE_SIMPLIFY_RTL = Log.LogLevel("SimplifyRTLVerbose") def is_simplifiable(node): return (isinstance(node, VectorElementSelection) and isinstance(node.get_input(0), (Constant, SubSignalSelection))) or \ (isinstance(node, SubSignalSelection) and isinstance(node.get_input(0), SubSignalSelection)) class BasicSimplifier(object): """ Basic expansion engine """ def __init__(self, target): self.target = target self.memoization_map = {} def simplify_node(self, node): """ return the simplified version of @p node when possible
from metalibm_core.opt.opt_utils import ( forward_attributes, logical_reduce, ) from metalibm_core.core.ml_operations import ( is_leaf_node, LogicalAnd, LogicalOr, LogicalNot, ) from metalibm_core.core.legalizer import is_constant from metalibm_core.utility.log_report import Log LOG_LOGICAL_SIMPLIFICATION = Log.LogLevel("LogicalSimplification") from metalibm_core.opt.opt_utils import is_false, is_true def is_logical_and_not(node): """ test if node is a tree of And(Not(), And(..)) """ if not isinstance(node, LogicalAnd): return False lhs = node.get_input(0) rhs = node.get_input(0) def input_predicate(op): return isinstance(op, LogicalNot) or is_logical_and_not(op) return input_predicate(lhs) and input_predicate(rhs)
Equal, NotEqual, Constant, VectorElementSelection, Comparison, BooleanOperation, LogicalNot, LogicalOr, LogicalAnd, Test, ) from metalibm_core.utility.log_report import Log from metalibm_core.utility.debug_utils import debug_multi LOG_VERBOSE_VECTOR_MASK_TEST = Log.LogLevel("VectorMaskTestVerbose") # List of tests which can be expanded by VectorMaskTestExpander EXPANDABLE_TEST_LIST = [ Test.IsMaskAllZero, Test.IsMaskNotAllZero, Test.IsMaskNotAnyZero, Test.IsMaskAnyZero ] def is_vector_mask_test(node): return isinstance(node, Test) and node.specifier in EXPANDABLE_TEST_LIST class VectorMaskTestExpander(object): """ Basic expansion engine """ def __init__(self, target):
Division, is_leaf_node) from metalibm_core.core.ml_formats import ML_Binary32, ML_Float from metalibm_core.core.legalizer import evaluate_graph from metalibm_core.core.precisions import ML_Faithful from metalibm_core.opt.p_function_inlining import generate_inline_fct_scheme from metalibm_core.opt.opt_utils import evaluate_range from metalibm_core.code_generation.generic_processor import GenericProcessor from metalibm_core.utility.ml_template import DefaultArgTemplate, ML_NewArgTemplate from metalibm_core.utility.log_report import Log from metalibm_functions.function_map import FUNCTION_MAP LOG_VERBOSE_FUNCTION_EXPR = Log.LogLevel("FunctionExprVerbose") FUNCTION_OBJECT_MAPPING = { name: FunctionObject(name, [ML_Float] * FUNCTION_MAP[name][0].arity, ML_Float, None, range_function=FUNCTION_MAP[name][2]) for name in FUNCTION_MAP } FCT_DESC_PATTERN = r"([-+/* ().,]|\d+|{}|[xyzt])*".format("|".join( FUNCTION_OBJECT_MAPPING.keys())) def check_fct_expr(str_desc): """ check if function expression string is potentially valid """