private ValueDispatchNode GatherValueDispatchNodes( BoundDecisionDagNode node, HashSet <BoundDecisionDagNode> loweredNodes, BoundDagTemp input, IValueSetFactory fac) { if (loweredNodes.Contains(node)) { bool foundLabel = this._dagNodeLabels.TryGetValue(node, out LabelSymbol label); Debug.Assert(foundLabel); return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label)); } if (!(node is BoundTestDecisionDagNode testNode && testNode.Test.Input.Equals(input))) { var label = GetDagNodeLabel(node); return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label)); } switch (testNode.Test) { case BoundDagRelationalTest relational: { loweredNodes.Add(testNode); var whenTrue = GatherValueDispatchNodes(testNode.WhenTrue, loweredNodes, input, fac); var whenFalse = GatherValueDispatchNodes(testNode.WhenFalse, loweredNodes, input, fac); return(ValueDispatchNode.RelationalDispatch.CreateBalanced(testNode.Syntax, relational.Value, relational.OperatorKind, whenTrue: whenTrue, whenFalse: whenFalse)); } case BoundDagValueTest value: { // Gather up the (value, label) pairs, starting with the first one loweredNodes.Add(testNode); var cases = ArrayBuilder <(ConstantValue value, LabelSymbol label)> .GetInstance(); cases.Add((value: value.Value, label: GetDagNodeLabel(testNode.WhenTrue))); BoundTestDecisionDagNode previous = testNode; while (previous.WhenFalse is BoundTestDecisionDagNode p && p.Test is BoundDagValueTest vd && vd.Input.Equals(input) && !this._dagNodeLabels.ContainsKey(p) && !loweredNodes.Contains(p)) { cases.Add((value: vd.Value, label: GetDagNodeLabel(p.WhenTrue))); loweredNodes.Add(p); previous = p; } var otherwise = GatherValueDispatchNodes(previous.WhenFalse, loweredNodes, input, fac); return(PushEqualityTestsIntoTree(value.Syntax, otherwise, cases.ToImmutableAndFree(), fac)); } default: { var label = GetDagNodeLabel(node); return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label)); } } }
private bool GenerateSwitchDispatch(BoundDecisionDagNode node, HashSet <BoundDecisionDagNode> loweredNodes) { Debug.Assert(!loweredNodes.Contains(node)); // We only generate a switch dispatch if we have two or more value tests in a row if (!(node is BoundTestDecisionDagNode firstTestNode && firstTestNode.Test is BoundDagValueTest firstTest && firstTestNode.WhenFalse is BoundTestDecisionDagNode whenFalse && whenFalse.Test is BoundDagValueTest secondTest && !loweredNodes.Contains(whenFalse) && !this._dagNodeLabels.ContainsKey(whenFalse) && firstTest.Input == secondTest.Input && firstTest.Input.Type.IsValidV6SwitchGoverningType())) { // https://github.com/dotnet/roslyn/issues/12509 Could optimize float, double, decimal value switches. For now use if-then-else return(false); } // Gather up the (value, label) pairs, starting with the first one var cases = ArrayBuilder <(ConstantValue value, LabelSymbol label)> .GetInstance(); cases.Add((value: firstTest.Value, label: GetDagNodeLabel(firstTestNode.WhenTrue))); BoundTestDecisionDagNode previous = firstTestNode; while (previous.WhenFalse is BoundTestDecisionDagNode p && p.Test is BoundDagValueTest vd && vd.Input == firstTest.Input && !this._dagNodeLabels.ContainsKey(p) && !loweredNodes.Contains(p)) { cases.Add((value: vd.Value, label: GetDagNodeLabel(p.WhenTrue))); loweredNodes.Add(p); previous = p; } // If we are emitting a hash table based string switch, // we need to generate a helper method for computing // string hash value in <PrivateImplementationDetails> class. MethodSymbol?stringEquality = null; if (firstTest.Input.Type.SpecialType == SpecialType.System_String) { EnsureStringHashFunction(cases.Count, node.Syntax); stringEquality = _localRewriter.UnsafeGetSpecialTypeMethod(node.Syntax, SpecialMember.System_String__op_Equality); } LabelSymbol defaultLabel = GetDagNodeLabel(previous.WhenFalse); var dispatch = new BoundSwitchDispatch( node.Syntax, _tempAllocator.GetTemp(firstTest.Input), cases.ToImmutableAndFree(), defaultLabel, stringEquality); _loweredDecisionDag.Add(dispatch); return(true); }