/// <summary> /// If the condition has a constant value, then just use the selected branch. /// e.g. "true ? x : y" becomes "x". /// </summary> public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { // just a fact, not a requirement (VisitExpression would have rewritten otherwise) Debug.Assert(node.ConstantValue == null); var rewrittenCondition = VisitExpression(node.Condition); var rewrittenConsequence = VisitExpression(node.Consequence); var rewrittenAlternative = VisitExpression(node.Alternative); if (rewrittenCondition.ConstantValue == null) { return(node.Update( node.IsRef, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.NaturalTypeOpt, node.WasTargetTyped, node.Type )); } return(RewriteConditionalOperator( node.Syntax, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type, node.IsRef )); }
private BoundExpression VisitConditionalOperator(BoundConditionalOperator node) { var condition = Visit(node.Condition); var consequence = VisitExactType(node.Consequence); var alternative = VisitExactType(node.Alternative); return(ExprFactory("Condition", condition, consequence, alternative)); }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequenceBuilder conditionBuilder = null; var condition = VisitExpression(ref conditionBuilder, node.Condition); BoundSpillSequenceBuilder consequenceBuilder = null; var consequence = VisitExpression(ref consequenceBuilder, node.Consequence); BoundSpillSequenceBuilder alternativeBuilder = null; var alternative = VisitExpression(ref alternativeBuilder, node.Alternative); if (consequenceBuilder == null && alternativeBuilder == null) { return(UpdateExpression(conditionBuilder, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type))); } if (conditionBuilder == null) { conditionBuilder = new BoundSpillSequenceBuilder(); } if (consequenceBuilder == null) { consequenceBuilder = new BoundSpillSequenceBuilder(); } if (alternativeBuilder == null) { alternativeBuilder = new BoundSpillSequenceBuilder(); } if (node.Type.SpecialType == SpecialType.System_Void) { conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence), substituteTemps: false), UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative), substituteTemps: false))); return(conditionBuilder.Update(_F.Default(node.Type))); } else { Debug.Assert(_F.Syntax.IsKind(SyntaxKind.AwaitExpression)); var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.AwaitSpill, syntax: _F.Syntax); conditionBuilder.AddLocal(tmp, _F.Diagnostics); conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence), substituteTemps: false), UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative), substituteTemps: false))); return(conditionBuilder.Update(_F.Local(tmp))); } }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequenceBuilder conditionBuilder = null; var condition = VisitExpression(ref conditionBuilder, node.Condition); BoundSpillSequenceBuilder consequenceBuilder = null; var consequence = VisitExpression(ref consequenceBuilder, node.Consequence); BoundSpillSequenceBuilder alternativeBuilder = null; var alternative = VisitExpression(ref alternativeBuilder, node.Alternative); if (consequenceBuilder == null && alternativeBuilder == null) { return(UpdateExpression(conditionBuilder, node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type))); } if (conditionBuilder == null) { conditionBuilder = new BoundSpillSequenceBuilder(); } if (consequenceBuilder == null) { consequenceBuilder = new BoundSpillSequenceBuilder(); } if (alternativeBuilder == null) { alternativeBuilder = new BoundSpillSequenceBuilder(); } if (node.Type.IsVoidType()) { conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence)), UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative)))); return(conditionBuilder.Update(_F.Default(node.Type))); } else { var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax); conditionBuilder.AddLocal(tmp); conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence)), UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative)))); return(conditionBuilder.Update(_F.Local(tmp))); } }
/// <summary> /// If the condition has a constant value, then just use the selected branch. /// e.g. "true ? x : y" becomes "x". /// </summary> public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { // just a fact, not a requirement (VisitExpression would have rewritten otherwise) Debug.Assert(node.ConstantValue == null); var rewrittenCondition = VisitExpression(node.Condition); var rewrittenConsequence = VisitExpression(node.Consequence); var rewrittenAlternative = VisitExpression(node.Alternative); if (rewrittenCondition.ConstantValue == null) { return node.Update(rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type); } return RewriteConditionalOperator( node.Syntax, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type); }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundExpression condition = (BoundExpression)this.Visit(node.Condition); BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence); BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative); TypeSymbol type = this.VisitType(node.Type); if (!RequiresSpill(condition, consequence, alternative)) { return(node.Update(condition, consequence, alternative, node.ConstantValueOpt, type)); } var spillBuilder = new SpillBuilder(); LocalSymbol resultLocal = F.SynthesizedLocal(type, null); spillBuilder.Locals.Add(resultLocal); BoundExpression newCondition; if (condition.Kind == BoundKind.SpillSequence) { var spill = (BoundSpillSequence)condition; spillBuilder.AddSpill(spill); newCondition = spill.Value; } else { newCondition = condition; } spillBuilder.Statements.Add( F.If( condition: newCondition, thenClause: CrushExpression(consequence, resultLocal), elseClause: CrushExpression(alternative, resultLocal))); return(spillBuilder.BuildSequenceAndFree(F, F.Local(resultLocal))); }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequence2 ss1 = null; var condition = VisitExpression(ref ss1, node.Condition); BoundSpillSequence2 ss2 = null; var consequence = VisitExpression(ref ss2, node.Consequence); BoundSpillSequence2 ss3 = null; var alternative = VisitExpression(ref ss3, node.Alternative); if (ss2 == null && ss3 == null) { return(UpdateExpression(ss1, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type))); } var tmp = F.SynthesizedLocal(node.Type); if (ss1 == null) { ss1 = new BoundSpillSequence2(); } if (ss2 == null) { ss2 = new BoundSpillSequence2(); } if (ss3 == null) { ss3 = new BoundSpillSequence2(); } ss1.Add(tmp); ss1.Add( F.If(condition, UpdateStatement(ss2, F.Assignment(F.Local(tmp), consequence)), UpdateStatement(ss3, F.Assignment(F.Local(tmp), alternative)))); return(ss1.Update(F.Local(tmp))); }
private BoundExpression OptimizeLiftedUnaryOperator( UnaryOperatorKind operatorKind, SyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (NullableNeverHasValue(loweredOperand)) { return(new BoundDefaultOperator(syntax, null, type)); } // Second, another simple optimization. If we know that the operand is never null // then we can obtain the non-null value and skip generating the temporary. That is, // "~(new int?(M()))" is the same as "new int?(~M())". BoundExpression neverNull = NullableAlwaysHasValue(loweredOperand); if (neverNull != null) { return(GetLiftedUnaryOperatorConsequence(operatorKind, syntax, method, type, neverNull)); } var conditionalLeft = loweredOperand as BoundLoweredConditionalAccess; // NOTE: we could in theory handle side-effecting loweredRight here too // by including it as a part of whenNull, but there is a concern // that it can lead to code duplication var optimize = conditionalLeft != null && (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue()); if (optimize) { var result = LowerLiftedUnaryOperator(operatorKind, syntax, method, conditionalLeft.WhenNotNull, type); return(conditionalLeft.Update( conditionalLeft.Receiver, conditionalLeft.HasValueMethodOpt, whenNotNull: result, whenNullOpt: null, id: conditionalLeft.Id, type: result.Type )); } // This optimization is analogous to DistributeLiftedConversionIntoLiftedOperand. // Suppose we have a lifted unary conversion whose operand is itself a lifted operation. // That is, we have something like: // // int? r = - (M() + N()); // // where M() and N() return nullable ints. We would simply codegen this as first // creating the nullable int result of M() + N(), then checking it for nullity, // and then doing the unary minus. That is: // // int? m = M(); // int? n = N(); // int? t = m.HasValue && n.HasValue ? new int?(m.Value + n.Value) : new int?(); // int? r = t.HasValue ? new int?(-t.Value) : new int?(); // // However, we also observe that we can distribute the unary minus into both branches of // the conditional: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? - (new int?(m.Value + n.Value))) : - new int?(); // // And we already optimize those! So we could reduce this to: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? new int?(- (m.Value + n.Value)) : new int?()); // // which avoids entirely the creation of the unnecessary nullable int and the unnecessary // extra null check. if (loweredOperand.Kind == BoundKind.Sequence) { BoundSequence seq = (BoundSequence)loweredOperand; if (seq.Value.Kind == BoundKind.ConditionalOperator) { BoundConditionalOperator conditional = (BoundConditionalOperator)seq.Value; Debug.Assert(seq.Type == conditional.Type); Debug.Assert(conditional.Type == conditional.Consequence.Type); Debug.Assert(conditional.Type == conditional.Alternative.Type); if (NullableAlwaysHasValue(conditional.Consequence) != null && NullableNeverHasValue(conditional.Alternative)) { return(new BoundSequence( syntax, seq.Locals, seq.SideEffects, RewriteConditionalOperator( syntax, conditional.Condition, MakeUnaryOperator(operatorKind, syntax, method, conditional.Consequence, type), MakeUnaryOperator(operatorKind, syntax, method, conditional.Alternative, type), ConstantValue.NotAvailable, type), type)); } } } return(null); }
private BoundExpression VisitConditionalOperator(BoundConditionalOperator node) { var condition = Visit(node.Condition); var consequence = VisitExactType(node.Consequence); var alternative = VisitExactType(node.Alternative); return ExprFactory("Condition", condition, consequence, alternative); }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequence2 ss1 = null; var condition = VisitExpression(ref ss1, node.Condition); BoundSpillSequence2 ss2 = null; var consequence = VisitExpression(ref ss2, node.Consequence); BoundSpillSequence2 ss3 = null; var alternative = VisitExpression(ref ss3, node.Alternative); if (ss2 == null && ss3 == null) { return UpdateExpression(ss1, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type)); } var tmp = F.SynthesizedLocal(node.Type); if (ss1 == null) ss1 = new BoundSpillSequence2(); if (ss2 == null) ss2 = new BoundSpillSequence2(); if (ss3 == null) ss3 = new BoundSpillSequence2(); ss1.Add(tmp); ss1.Add( F.If(condition, UpdateStatement(ss2, F.Assignment(F.Local(tmp), consequence)), UpdateStatement(ss3, F.Assignment(F.Local(tmp), alternative)))); return ss1.Update(F.Local(tmp)); }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundExpression condition = (BoundExpression)this.Visit(node.Condition); BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence); BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative); TypeSymbol type = this.VisitType(node.Type); if (!RequiresSpill(condition, consequence, alternative)) { return node.Update(condition, consequence, alternative, node.ConstantValueOpt, type); } var spillBuilder = new SpillBuilder(); LocalSymbol resultLocal = F.SynthesizedLocal(type, null); spillBuilder.Locals.Add(resultLocal); BoundExpression newCondition; if (condition.Kind == BoundKind.SpillSequence) { var spill = (BoundSpillSequence)condition; spillBuilder.AddSpill(spill); newCondition = spill.Value; } else { newCondition = condition; } spillBuilder.Statements.Add( F.If( condition: newCondition, thenClause: CrushExpression(consequence, resultLocal), elseClause: CrushExpression(alternative, resultLocal))); return spillBuilder.BuildSequenceAndFree(F, F.Local(resultLocal)); }