protected internal override void VisitStObj(StObj inst) { base.VisitStObj(inst); if (EarlyExpressionTransforms.StObjToStLoc(inst, context)) { context.RequestRerun(); return; } TransformAssignment.HandleCompoundAssign(inst, context); }
bool LegacyPattern(Block block, int pos, StatementTransformContext context) { // Legacy csc pattern: // stloc s(lhsInst) // if (logic.not(call op_False(ldloc s))) Block { // stloc s(call op_BitwiseAnd(ldloc s, rhsInst)) // } // -> // stloc s(user.logic op_BitwiseAnd(lhsInst, rhsInst)) if (!block.Instructions[pos].MatchStLoc(out var s, out var lhsInst)) { return(false); } if (!(s.Kind == VariableKind.StackSlot)) { return(false); } if (!(block.Instructions[pos + 1] is IfInstruction ifInst)) { return(false); } if (!ifInst.Condition.MatchLogicNot(out var condition)) { return(false); } if (!(MatchCondition(condition, out var s2, out string conditionMethodName) && s2 == s)) { return(false); } if (ifInst.FalseInst.OpCode != OpCode.Nop) { return(false); } var trueInst = Block.Unwrap(ifInst.TrueInst); if (!trueInst.MatchStLoc(s, out var storeValue)) { return(false); } if (storeValue is Call call) { if (!MatchBitwiseCall(call, s, conditionMethodName)) { return(false); } if (s.IsUsedWithin(call.Arguments[1])) { return(false); } context.Step("User-defined short-circuiting logic operator (legacy pattern)", condition); ((StLoc)block.Instructions[pos]).Value = new UserDefinedLogicOperator(call.Method, lhsInst, call.Arguments[1]) .WithILRange(call); block.Instructions.RemoveAt(pos + 1); context.RequestRerun(); // the 'stloc s' may now be eligible for inlining return(true); } return(false); }
public void Run(Block block, BlockTransformContext context) { var ctx = new StatementTransformContext(context); int pos = 0; ctx.rerunPosition = block.Instructions.Count - 1; while (pos >= 0) { if (ctx.rerunPosition != null) { Debug.Assert(ctx.rerunPosition >= pos); #if DEBUG for (; pos < ctx.rerunPosition; ++pos) { block.Instructions[pos].ResetDirty(); } #else pos = ctx.rerunPosition.Value; #endif Debug.Assert(pos == ctx.rerunPosition); ctx.rerunPosition = null; } foreach (var transform in children) { transform.Run(block, pos, ctx); #if DEBUG block.Instructions[pos].CheckInvariant(ILPhase.Normal); for (int i = Math.Max(0, pos - 100); i < pos; ++i) { if (block.Instructions[i].IsDirty) { Debug.Fail($"{transform.GetType().Name} modified an instruction before pos"); } } #endif if (ctx.rerunCurrentPosition) { ctx.rerunCurrentPosition = false; ctx.RequestRerun(pos); } if (ctx.rerunPosition != null) { break; } } if (ctx.rerunPosition == null) { pos--; } } }
void IStatementTransform.Run(Block block, int pos, StatementTransformContext context) { this.context = context; if (context.Settings.MakeAssignmentExpressions) { if (TransformInlineAssignmentStObjOrCall(block, pos) || TransformInlineAssignmentLocal(block, pos)) { // both inline assignments create a top-level stloc which might affect inlining context.RequestRerun(); return; } } if (context.Settings.IntroduceIncrementAndDecrement) { if (TransformPostIncDecOperatorWithInlineStore(block, pos) || TransformPostIncDecOperator(block, pos) || TransformPostIncDecOperatorLocal(block, pos)) { // again, new top-level stloc might need inlining: context.RequestRerun(); return; } } }