Ejemplo n.º 1
0
 internal static bool IsProtectedIfInst(IfInstruction ifInst)
 {
     // We exclude logic.and to avoid turning
     // "logic.and(comp(interfaces != ldnull), call get_Count(interfaces))"
     // into "if ((interfaces?.Count ?? 0) != 0)".
     return((ifInst.MatchLogicAnd(out _, out _) || ifInst.MatchLogicOr(out _, out _)) &&
            IfInstruction.IsInConditionSlot(ifInst));
 }
Ejemplo n.º 2
0
        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;
            }
            if (inst.Right.MatchLdNull())
            {
                if (inst.Kind == ComparisonKind.GreaterThan)
                {
                    context.Step("comp(left > ldnull)  => comp(left != ldnull)", inst);
                    inst.Kind = ComparisonKind.Inequality;
                }
                else if (inst.Kind == ComparisonKind.LessThanOrEqual)
                {
                    context.Step("comp(left <= ldnull) => comp(left == ldnull)", inst);
                    inst.Kind = ComparisonKind.Equality;
                }
            }
            else if (inst.Left.MatchLdNull())
            {
                if (inst.Kind == ComparisonKind.LessThan)
                {
                    context.Step("comp(ldnull < right)  => comp(ldnull != right)", inst);
                    inst.Kind = ComparisonKind.Inequality;
                }
                else if (inst.Kind == ComparisonKind.GreaterThanOrEqual)
                {
                    context.Step("comp(ldnull >= right) => comp(ldnull == right)", inst);
                    inst.Kind = ComparisonKind.Equality;
                }
            }

            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);
                }
            }

            if (inst.Right.MatchLdNull() && inst.Left.MatchBox(out arg, out var type) && type.Kind == TypeKind.TypeParameter)
            {
                if (inst.Kind == ComparisonKind.Equality)
                {
                    context.Step("comp(box T(..) == ldnull) -> comp(.. == ldnull)", inst);
                    inst.Left = arg;
                }
                if (inst.Kind == ComparisonKind.Inequality)
                {
                    context.Step("comp(box T(..) != ldnull) -> comp(.. != ldnull)", inst);
                    inst.Left = arg;
                }
            }
        }