private ValueDispatchNode GatherValueDispatchNodes( BoundDecisionDagNode node, HashSet <BoundDecisionDagNode> loweredNodes, BoundDagTemp input) { IValueSetFactory fac = ValueSetFactory.ForType(input.Type); return(GatherValueDispatchNodes(node, loweredNodes, input, fac)); }
/// <summary> /// Given a decision dag and a constant-valued input, produce a simplified decision dag that has removed all the /// tests that are unnecessary due to that constant value. This simplification affects flow analysis (reachability /// and definite assignment) and permits us to simplify the generated code. /// </summary> public BoundDecisionDag SimplifyDecisionDagIfConstantInput(BoundExpression input) { if (input.ConstantValue == null) { return(this); } else { ConstantValue inputConstant = input.ConstantValue; return(Rewrite(makeReplacement)); // Make a replacement for a given node, using the precomputed replacements for its successors. BoundDecisionDagNode makeReplacement(BoundDecisionDagNode dag, Func <BoundDecisionDagNode, BoundDecisionDagNode> replacement) { if (dag is BoundTestDecisionDagNode p) { // This is the key to the optimization. The result of a top-level test might be known if the input is constant. switch (knownResult(p.Test)) { case true: return(replacement(p.WhenTrue)); case false: return(replacement(p.WhenFalse)); } } return(TrivialReplacement(dag, replacement)); } // Is the decision's result known because the input is a constant? bool?knownResult(BoundDagTest choice) { if (!choice.Input.IsOriginalInput) { // This is a test of something other than the main input; result unknown return(null); } switch (choice) { case BoundDagExplicitNullTest d: return(inputConstant.IsNull); case BoundDagNonNullTest d: return(!inputConstant.IsNull); case BoundDagValueTest d: return(d.Value == inputConstant); case BoundDagTypeTest d: return(inputConstant.IsNull ? (bool?)false : null); case BoundDagRelationalTest d: var f = ValueSetFactory.ForType(input.Type); if (f is null) { return(null); } // TODO: When ValueSetFactory has a method for comparing two values, use it. var set = f.Related(d.Relation.Operator(), d.Value); return(set.Any(BinaryOperatorKind.Equal, inputConstant)); default: throw ExceptionUtilities.UnexpectedValue(choice); } } } }