protected internal override void VisitStObj(StObj inst) { base.VisitStObj(inst); if (EarlyExpressionTransforms.StObjToStLoc(inst, context)) { context.RequestRerun(); return; } TransformAssignment.HandleCompoundAssign(inst, context); }
protected internal override void VisitCall(Call inst) { var expr = EarlyExpressionTransforms.HandleCall(inst, context); if (expr != null) { // The resulting expression may trigger further rules, so continue visiting the replacement: expr.AcceptVisitor(this); } else { base.VisitCall(inst); TransformAssignment.HandleCompoundAssign(inst, context); } }
protected internal override void VisitLdObj(LdObj inst) { base.VisitLdObj(inst); EarlyExpressionTransforms.AddressOfLdLocToLdLoca(inst, context); if (EarlyExpressionTransforms.LdObjToLdLoc(inst, context)) { return; } if (TransformDecimalFieldToConstant(inst, out LdcDecimal decimalConstant)) { context.Step("TransformDecimalFieldToConstant", inst); inst.ReplaceWith(decimalConstant); return; } }
protected internal override void VisitStObj(StObj inst) { if (IsDisplayClassFieldAccess(inst.Target, out var v, out var displayClass, out var field)) { VariableToDeclare vd = displayClass.VariablesToDeclare[(IField)field.MemberDefinition]; if (vd.CanPropagate && vd.Initializers.Contains(inst)) { if (inst.Parent is Block containingBlock) { context.Step($"Remove initializer of {v.Name}.{vd.Name} due to propagation", inst); containingBlock.Instructions.Remove(inst); return; } } } base.VisitStObj(inst); EarlyExpressionTransforms.StObjToStLoc(inst, context); }
protected internal override void VisitStObj(StObj inst) { base.VisitStObj(inst); if (EarlyExpressionTransforms.StObjToStLoc(inst, context)) { context.RequestRerun(); return; } if (inst.Value is BinaryNumericInstruction binary && binary.Left.MatchLdObj(out ILInstruction target, out IType t) && inst.Target.Match(target).Success && SemanticHelper.IsPure(target.Flags) && CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, t)) { context.Step("compound assignment", inst); // stobj(target, binary.op(ldobj(target), ...)) // => compound.op(target, ...) inst.ReplaceWith(new CompoundAssignmentInstruction( binary, binary.Left, binary.Right, t, CompoundAssignmentType.EvaluatesToNewValue)); } }
protected internal override void VisitStObj(StObj inst) { inst.Value.AcceptVisitor(this); if (inst.Parent is Block) { if (IsParameterAssignment(inst, out var displayClass, out var field, out var parameter)) { context.Step($"Detected parameter assignment {parameter.Name}", inst); displayClass.Variables.Add((IField)field.MemberDefinition, parameter); instructionsToRemove.Add(inst); return; } if (IsDisplayClassAssignment(inst, out displayClass, out field, out var variable)) { context.Step($"Detected display-class assignment {variable.Name}", inst); displayClass.Variables.Add((IField)field.MemberDefinition, variable); instructionsToRemove.Add(inst); return; } } inst.Target.AcceptVisitor(this); EarlyExpressionTransforms.StObjToStLoc(inst, context); }
protected internal override void VisitLdObj(LdObj inst) { base.VisitLdObj(inst); EarlyExpressionTransforms.LdObjToLdLoc(inst, context); }
protected internal override void VisitComp(Comp inst) { // "logic.not(arg)" is sugar for "comp(arg != ldc.i4 0)" if (inst.MatchLogicNot(out var arg)) { VisitLogicNot(inst, arg); return; } else if (inst.Kind == ComparisonKind.Inequality && inst.LiftingKind == ComparisonLiftingKind.None && inst.Right.MatchLdcI4(0) && (IfInstruction.IsInConditionSlot(inst) || inst.Left is Comp) ) { // if (comp(x != 0)) ==> if (x) // comp(comp(...) != 0) => comp(...) context.Step("Remove redundant comp(... != 0)", inst); inst.Left.AddILRange(inst); inst.ReplaceWith(inst.Left); inst.Left.AcceptVisitor(this); return; } base.VisitComp(inst); if (inst.IsLifted) { return; } EarlyExpressionTransforms.FixComparisonKindLdNull(inst, context); var rightWithoutConv = inst.Right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend); if (rightWithoutConv.MatchLdcI4(0) && inst.Sign == Sign.Unsigned && (inst.Kind == ComparisonKind.GreaterThan || inst.Kind == ComparisonKind.LessThanOrEqual)) { if (inst.Kind == ComparisonKind.GreaterThan) { context.Step("comp.unsigned(left > ldc.i4 0) => comp(left != ldc.i4 0)", inst); inst.Kind = ComparisonKind.Inequality; VisitComp(inst); return; } else if (inst.Kind == ComparisonKind.LessThanOrEqual) { context.Step("comp.unsigned(left <= ldc.i4 0) => comp(left == ldc.i4 0)", inst); inst.Kind = ComparisonKind.Equality; VisitComp(inst); return; } } else if (rightWithoutConv.MatchLdcI4(0) && inst.Kind.IsEqualityOrInequality()) { if (inst.Left.MatchLdLen(StackType.I, out ILInstruction array)) { // comp.unsigned(ldlen array == conv i4->i(ldc.i4 0)) // => comp(ldlen.i4 array == ldc.i4 0) // This is a special case where the C# compiler doesn't generate conv.i4 after ldlen. context.Step("comp(ldlen.i4 array == ldc.i4 0)", inst); inst.InputType = StackType.I4; inst.Left.ReplaceWith(new LdLen(StackType.I4, array).WithILRange(inst.Left)); inst.Right = rightWithoutConv; } else if (inst.Left is Conv conv && conv.TargetType == PrimitiveType.I && conv.Argument.ResultType == StackType.O) { // C++/CLI sometimes uses this weird comparison with null: context.Step("comp(conv o->i (ldloc obj) == conv i4->i <sign extend>(ldc.i4 0))", inst); // -> comp(ldloc obj == ldnull) inst.InputType = StackType.O; inst.Left = conv.Argument; inst.Right = new LdNull().WithILRange(inst.Right); inst.Right.AddILRange(rightWithoutConv); } } }