/// <summary> /// Handles NullCoalescingInstruction case 1: reference types. /// /// stloc s(valueInst) /// if (comp(ldloc s == ldnull)) { /// stloc s(fallbackInst) /// } /// => /// stloc s(if.notnull(valueInst, fallbackInst)) /// </summary> bool TransformRefTypes(Block block, int pos, StatementTransformContext context) { if (!(block.Instructions[pos] is StLoc stloc)) { return(false); } if (stloc.Variable.Kind != VariableKind.StackSlot) { return(false); } if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } trueInst = Block.Unwrap(trueInst); if (condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull() && trueInst.MatchStLoc(stloc.Variable, out var fallbackValue) ) { context.Step("NullCoalescingTransform (reference types)", stloc); stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); block.Instructions.RemoveAt(pos + 1); // remove if instruction ILInlining.InlineOneIfPossible(block, pos, false, context); return(true); } return(false); }
public void Run(Block block, BlockTransformContext context) { this.context = context; if (!context.Settings.AnonymousMethods) { return; } for (int i = block.Instructions.Count - 1; i >= 0; i--) { if (block.Instructions[i] is IfInstruction inst) { if (CachedDelegateInitializationWithField(inst)) { block.Instructions.RemoveAt(i); continue; } if (CachedDelegateInitializationWithLocal(inst)) { ILInlining.InlineOneIfPossible(block, i, InliningOptions.Aggressive, context); continue; } if (CachedDelegateInitializationRoslynInStaticWithLocal(inst) || CachedDelegateInitializationRoslynWithLocal(inst)) { block.Instructions.RemoveAt(i); continue; } } } }
public void Run(Block block, int pos, StatementTransformContext context) { if (!context.Settings.NamedArguments) { return; } var options = ILInlining.OptionsForBlock(block, pos, context); options |= InliningOptions.IntroduceNamedArguments; ILInlining.InlineOneIfPossible(block, pos, options, context: context); }
/// <summary> /// Handles NullCoalescingInstruction case 1: reference types. /// /// stloc s(valueInst) /// if (comp(ldloc s == ldnull)) { /// stloc s(fallbackInst) /// } /// => /// stloc s(if.notnull(valueInst, fallbackInst)) /// </summary> bool TransformRefTypes(Block block, int pos, StatementTransformContext context) { if (!(block.Instructions[pos] is StLoc stloc)) { return(false); } if (stloc.Variable.Kind != VariableKind.StackSlot) { return(false); } if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } if (!(condition.MatchCompEquals(out var left, out var right) && left.MatchLdLoc(stloc.Variable) && right.MatchLdNull())) { return(false); } trueInst = Block.Unwrap(trueInst); if (trueInst.MatchStLoc(stloc.Variable, out var fallbackValue)) { context.Step("NullCoalescingTransform: simple (reference types)", stloc); stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); block.Instructions.RemoveAt(pos + 1); // remove if instruction ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context); return(true); } // sometimes the compiler generates: // stloc s(valueInst) // if (comp(ldloc s == ldnull)) { // stloc v(fallbackInst) // stloc s(ldloc v) // } // v must be single-assign and single-use. if (trueInst is Block trueBlock && trueBlock.Instructions.Count == 2 && trueBlock.Instructions[0].MatchStLoc(out var temporary, out fallbackValue) && temporary.IsSingleDefinition && temporary.LoadCount == 1 && trueBlock.Instructions[1].MatchStLoc(stloc.Variable, out var useOfTemporary) && useOfTemporary.MatchLdLoc(temporary)) { context.Step("NullCoalescingTransform: with temporary variable (reference types)", stloc); stloc.Value = new NullCoalescingInstruction(NullCoalescingKind.Ref, stloc.Value, fallbackValue); block.Instructions.RemoveAt(pos + 1); // remove if instruction ILInlining.InlineOneIfPossible(block, pos, InliningOptions.None, context); return(true); } return(false); }