From 4e7329a751a38f00b594e753b9586fe2d1beced3 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Thu, 12 Feb 2026 09:47:43 +0000 Subject: [PATCH 1/2] arm64: Fold negative variable eq/ne to 0 i.e. Fold: (-(x)) == 0 -> x == 0 --- src/coreclr/jit/morph.cpp | 32 + src/tests/JIT/opt/InstructionCombining/Neg.cs | 1475 +++++++++++++++-- .../JIT/opt/InstructionCombining/Neg.csproj | 1 + 3 files changed, 1393 insertions(+), 115 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 5d8075ec7236d3..585258c9b66281 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8777,6 +8777,38 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) GenTree* op1 = cmp->gtGetOp1(); GenTreeIntConCommon* op2 = cmp->gtGetOp2()->AsIntConCommon(); + if (op1->OperIs(GT_NEG) && !op1->gtOverflowEx()) + { + GenTree* negOp = op1->AsUnOp()->gtGetOp1(); + + if (op2->IsIntegralConst(0)) + { + bool shouldFold = true; + +#ifdef TARGET_ARM64 + // On ARM64 negs with a shift can be more compact than shift; cmp #0. + // Avoid folding when the negated operand is a simple shift so we keep the single + // instruction form. + if (negOp->OperIs(GT_LSH, GT_RSH, GT_RSZ)) + { + GenTree* shiftAmount = negOp->AsOp()->gtGetOp2(); + if (shiftAmount->IsCnsIntOrI()) + { + shouldFold = false; + } + } +#endif + + if (shouldFold) + { + // Fold: (-(x)) == 0 -> x == 0 (avoid neg on compare-to-zero) + cmp->gtOp1 = negOp; + DEBUG_DESTROY_NODE(op1); + op1 = negOp; + } + } + } + // Check for "(expr +/- icon1) ==/!= (non-zero-icon2)". if (op2->IsCnsIntOrI() && (op2->IconValue() != 0)) { diff --git a/src/tests/JIT/opt/InstructionCombining/Neg.cs b/src/tests/JIT/opt/InstructionCombining/Neg.cs index 3086d3976739db..e270c013c2ccf8 100644 --- a/src/tests/JIT/opt/InstructionCombining/Neg.cs +++ b/src/tests/JIT/opt/InstructionCombining/Neg.cs @@ -45,296 +45,1541 @@ public static int CheckNeg() fail = true; } - if (Negs(12) != 1) + if (NegCmpZero(12) != 1) { fail = true; } - if (NegsLSL(2) != 1) + if (NegLslCmpZero(2) != 1) { fail = true; } - if (NegsLSR(8) != 1) + if (NegLsrCmpZero(8) != 1) { fail = true; } - if (NegsASR(-5) != 1) + if (NegAsrCmpZero(-5) != 1) { fail = true; } - if (NegsLargeShift(20) != 1) + if (NegLargeShiftCmpZero(20) != 1) { fail = true; } - if (NegsLargeShift64Bits(0x400000000) != 1) + if (NegLargeShift64BitsCmpZero(0x400000000) != 1) { fail = true; } - if (!NegsSingleLine(1)) + if (!NegNeZeroSingleLine(1)) { fail = true; } - if (!NegsSingleLineLSL(0xF)) + if (!NegNeZeroSingleLineLsl(0xF)) { fail = true; } - if (NegsBinOp(-4, 0x3F) != 1) + if (NegNeZeroBinOp(-4, 0x3F) != 1) { fail = true; } - if (!NegsBinOpSingleLine(1, -1)) + if (!NegNeZeroBinOpSingleLine(1, -1)) { fail = true; } - if (!NegsGreaterThan(-1)) + if (!NegGtZero(-1)) { fail = true; } - if (!NegsGreaterThanEq(0)) + if (!NegGeZero(0)) { fail = true; } - if (!NegsLessThan(5)) + if (!NegLtZero(5)) { fail = true; } - if (!NegsLessThanEq(20)) + if (!NegLeZero(20)) { fail = true; } - if (NegsGreaterThanIntMinValue()) + if (NegGtIntMinValue()) { fail = true; } - if (NegsGreaterThanLongMinValue()) + if (NegGtLongMinValue()) + { + fail = true; + } + + if (!NegGtZeroShort(-1)) + { + fail = true; + } + + if (!NegLtZeroShort(1)) + { + fail = true; + } + + if (!NegLtConstShort(5)) + { + fail = true; + } + + if (!NegLtConstInt(5)) + { + fail = true; + } + + if (!NegGeZeroShort(0)) + { + fail = true; + } + + if (!NegLeZeroShort(1)) + { + fail = true; + } + + if (!NegEqZeroShort(0)) + { + fail = true; + } + + if (!NegNeZeroShort(1)) + { + fail = true; + } + + if (!NegEqConstShort(-20)) + { + fail = true; + } + + if (!NegEqConstInt(-20)) + { + fail = true; + } + + if (!NegNeConstShort(20)) + { + fail = true; + } + + if (!NegNeConstInt(20)) + { + fail = true; + } + + if (NegAddNotEqualZero(5, -5)) + { + fail = true; + } + + if (!NegAddNotEqual1(5, -5)) + { + fail = true; + } + + if (!NegAddNotEqual4(5, -5)) + { + fail = true; + } + + if (!NegAddEquaLZero(5, -5)) + { + fail = true; + } + + if (!NegAddEquaL1(0, -1)) + { + fail = true; + } + + if (!NegAddEquaL4(0, -4)) + { + fail = true; + } + + + if (!NegAddGtZero(-5, 0)) + { + fail = true; + } + + if (!NegAddGt1(-5, 0)) + { + fail = true; + } + + if (!NegAddGt4(-5, 0)) + { + fail = true; + } + + if (!NegAddGeZero(-5, 0)) + { + fail = true; + } + + if (!NegAddGe1(-5, 0)) + { + fail = true; + } + + if (!NegAddGe4(-5, 0)) + { + fail = true; + } + + if (!NegAddLtZero(1, 0)) + { + fail = true; + } + + if (!NegAddLt1(1, 0)) + { + fail = true; + } + + if (!NegAddLt4(1, 0)) + { + fail = true; + } + + if (!NegAddLeZero(1, 0)) + { + fail = true; + } + + if (!NegAddLe1(1, 0)) + { + fail = true; + } + + if (!NegAddLe4(1, 0)) + { + fail = true; + } + + if (NegSubNotEqualZero(5, 5)) + { + fail = true; + } + + if (NegSubNotEqual1(0, 1)) + { + fail = true; + } + + if (NegSubNotEqual4(1, 5)) + { + fail = true; + } + + if (!NegSubEquaLZero(5, 5)) + { + fail = true; + } + + if (!NegSubEquaL1(0, 1)) + { + fail = true; + } + + if (!NegSubEquaL4(1, 5)) + { + fail = true; + } + + + if (!NegSubGtZero(-5, 0)) + { + fail = true; + } + + if (!NegSubGt1(-5, 0)) + { + fail = true; + } + + if (!NegSubGt4(-5, 0)) + { + fail = true; + } + + if (!NegSubGeZero(-5, 0)) + { + fail = true; + } + + if (!NegSubGe1(-5, 0)) + { + fail = true; + } + + if (!NegSubGe4(-5, 0)) + { + fail = true; + } + + if (!NegSubLtZero(1, 0)) + { + fail = true; + } + + if (!NegSubLt1(1, 0)) + { + fail = true; + } + + if (!NegSubLt4(1, 0)) + { + fail = true; + } + + if (!NegSubLeZero(1, 0)) + { + fail = true; + } + + if (!NegSubLe1(1, 0)) + { + fail = true; + } + + if (!NegSubLe4(1, 0)) + { + fail = true; + } + + if (NegAndNotEqualZero(5, 2)) + { + fail = true; + } + + if (NegAndNotEqual1(-1, -1)) + { + fail = true; + } + + if (NegAndNotEqual4(-4, -4)) + { + fail = true; + } + + if (!NegAndEquaLZero(5, 2)) + { + fail = true; + } + + if (!NegAndEquaL1(-1, -1)) + { + fail = true; + } + + if (!NegAndEquaL4(-4, -4)) + { + fail = true; + } + + + if (!NegBicEquaLZero(0, 0)) + { + fail = true; + } + + if (!NegBicEquaL1(-1, 0)) + { + fail = true; + } + + if (!NegBicEquaL4(-4, 0)) + { + fail = true; + } + + if (!NegBicNotEqualZero(1, 0)) + { + fail = true; + } + + if (!NegBicNotEqual1(0, 0)) + { + fail = true; + } + + if (!NegBicNotEqual4(0, 0)) + { + fail = true; + } + + if (!NegBicGtZero(-5, 0)) + { + fail = true; + } + + if (!NegBicGt1(-5, 0)) + { + fail = true; + } + + if (!NegBicGt4(-5, 0)) + { + fail = true; + } + + if (!NegBicGeZero(-5, 0)) + { + fail = true; + } + + if (!NegBicGe1(-5, 0)) + { + fail = true; + } + + if (!NegBicGe4(-5, 0)) + { + fail = true; + } + + if (!NegBicLtZero(1, 0)) + { + fail = true; + } + + if (!NegBicLt1(1, 0)) + { + fail = true; + } + + if (!NegBicLt4(1, 0)) + { + fail = true; + } + + if (!NegBicLeZero(1, 0)) + { + fail = true; + } + + if (!NegBicLe1(1, 0)) + { + fail = true; + } + + if (!NegBicLe4(1, 0)) + { + fail = true; + } + + + if (!NegAndGtZero(-5, -5)) + { + fail = true; + } + + if (!NegAndGt1(-5, -5)) + { + fail = true; + } + + if (!NegAndGt4(-5, -5)) + { + fail = true; + } + + if (!NegAndGeZero(-5, -5)) + { + fail = true; + } + + if (!NegAndGe1(-5, -5)) + { + fail = true; + } + + if (!NegAndGe4(-5, -5)) + { + fail = true; + } + + if (!NegAndLtZero(1, 1)) + { + fail = true; + } + + if (!NegAndLt1(1, 1)) + { + fail = true; + } + + if (!NegAndLt4(1, 1)) + { + fail = true; + } + + if (!NegAndLeZero(1, 1)) + { + fail = true; + } + + if (!NegAndLe1(1, 1)) + { + fail = true; + } + + if (!NegAndLe4(1, 1)) { fail = true; } if (fail) { - return 101; + return 101; + } + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int Neg(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + return -a; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLSL(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, LSL #2 + return -(a << 2); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static uint NegLSR(uint a) + { + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + return (uint)-(a >> 20); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegASR(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, ASR #13 + return -(a >> 13); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLargeShift(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, LSL #17 + return -(a << 81); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long NegLargeShift64Bit(long a) + { + //ARM64-FULL-LINE: neg {{x[0-9]+}}, {{x[0-9]+}}, LSL #61 + return -(a << 189); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegCmpZero(int a) + { + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + if (-a != 0) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLslCmpZero(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #14 + if (-(a << 14) != 0) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLsrCmpZero(uint a) + { + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #3 + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + if (-(a >> 3) != 0) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegAsrCmpZero(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #2 + if (-(a >> 2) != 0) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLargeShiftCmpZero(uint a) + { + //ARM64-FULL-LINE: lsl {{w[0-9]+}}, {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + if (-(a << 100) != 0) + { + return 1; } - return 100; + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegLargeShift64BitsCmpZero(long a) + { + //ARM64-FULL-LINE: negs {{x[0-9]+}}, {{x[0-9]+}}, ASR #34 + if (-(a >> 98) != 0) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeZeroSingleLine(int a) + { + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + return -a != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeZeroSingleLineLsl(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #13 + return -(a << 13) != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int NegNeZeroBinOp(int a, int b) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #5 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: csel {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ne + if ((-a != 0) == (-(b >> 5) != 0)) + { + return 1; + } + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeZeroBinOpSingleLine(int a, int b) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + //ARM64-FULL-LINE: orr {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + return (-(a >> 1) != 0) | (-(b << 1) != 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGtZero(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + return -a > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGeZero(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + return -a >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLtZero(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + return -a < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLeZero(int a) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + return -a <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGtIntMinValue() + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + return -IntMinValue() > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGtLongMinValue() + { + //ARM64-FULL-LINE: neg {{x[0-9]+}}, {{x[0-9]+}} + //ARM64-FULL-LINE: cmp {{x[0-9]+}}, #0 + return -LongMinValue() > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int IntMinValue() + { + return int.MinValue; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static long LongMinValue() + { + return long.MinValue; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGtZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return -x > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLtZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + return -x < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLtConstShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #5 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return -x < 5; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLtConstInt(int x) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #5 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return -x < 5; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegGeZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return -x >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegLeZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return -x <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegEqZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return -x == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeZeroShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return -x != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegEqConstShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return -x == 20; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegEqConstInt(int x) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return -x == 20; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeConstShort(short x) + { + //ARM64-FULL-LINE: sxth {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return -x != 20; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegNeConstInt(int x) + { + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return -x != 20; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddEquaLZero(int a, int b) + { + //ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a + b)) == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddEquaL1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a + b)) == 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddEquaL4(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a + b)) == 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddNotEqualZero(int a, int b) + { + //ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a + b)) != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddNotEqual1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a + b)) != 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddNotEqual4(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a + b)) != 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGtZero(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a + b)) > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGt1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a + b)) > 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGt4(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a + b)) > 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGeZero(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a + b)) >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGe1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a + b)) >= 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddGe4(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a + b)) >= 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddLtZero(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + return (-(a + b)) < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddLt1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a + b)) < 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddLt4(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return (-(a + b)) < 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddLeZero(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a + b)) <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAddLe1(int a, int b) + { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a + b)) <= 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static int Neg(int a) + static bool NegAddLe4(int a, int b) { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} - return -a; + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a + b)) <= 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegLSL(int a) + static bool NegSubEquaLZero(int a, int b) { - //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, LSL #2 - return -(a << 2); + //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a - b)) == 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static uint NegLSR(uint a) + static bool NegSubEquaL1(int a, int b) { - //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #20 + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} - return (uint)-(a >> 20); + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a - b)) == 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegASR(int a) + static bool NegSubEquaL4(int a, int b) { - //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, ASR #13 - return -(a >> 13); + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a - b)) == 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegLargeShift(int a) + static bool NegSubNotEqualZero(int a, int b) { - //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, LSL #17 - return -(a << 81); + //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a - b)) != 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static long NegLargeShift64Bit(long a) + static bool NegSubNotEqual1(int a, int b) { - //ARM64-FULL-LINE: neg {{x[0-9]+}}, {{x[0-9]+}}, LSL #61 - return -(a << 189); + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a - b)) != 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static int Negs(int a) + static bool NegSubNotEqual4(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} - if (-a != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a - b)) != 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsLSL(int a) + static bool NegSubGtZero(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #14 - if (-(a << 14) != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a - b)) > 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsLSR(uint a) + static bool NegSubGt1(int a, int b) { - //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #3 - //ARM64-FULL-LINE: negs {{x[0-9]+}}, {{x[0-9]+}} - if (-(a >> 3) != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a - b)) > 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsASR(int a) + static bool NegSubGt4(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #2 - if (-(a >> 2) != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a - b)) > 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsLargeShift(uint a) + static bool NegSubGeZero(int a, int b) { - //ARM64-FULL-LINE: lsl {{w[0-9]+}}, {{w[0-9]+}}, #4 - //ARM64-FULL-LINE: negs {{x[0-9]+}}, {{x[0-9]+}} - if (-(a << 100) != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a - b)) >= 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsLargeShift64Bits(long a) + static bool NegSubGe1(int a, int b) { - //ARM64-FULL-LINE: negs {{x[0-9]+}}, {{x[0-9]+}}, ASR #34 - if (-(a >> 98) != 0) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a - b)) >= 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsSingleLine(int a) + static bool NegSubGe4(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} - return -a != 0; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a - b)) >= 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsSingleLineLSL(int a) + static bool NegSubLtZero(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #13 - return -(a << 13) != 0; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + return (-(a - b)) < 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static int NegsBinOp(int a, int b) + static bool NegSubLt1(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #5 - if ((-a != 0) == (-(b >> 5) != 0)) - { - return 1; - } - return -1; + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a - b)) < 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsBinOpSingleLine(int a, int b) + static bool NegSubLt4(int a, int b) { - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #1 - //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #1 - return (-(a >> 1) != 0) | (-(b << 1) != 0); + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return (-(a - b)) < 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsGreaterThan(int a) + static bool NegSubLeZero(int a, int b) { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 - return -a > 0; + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a - b)) <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegSubLe1(int a, int b) + { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a - b)) <= 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegSubLe4(int a, int b) + { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a - b)) <= 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndEquaLZero(int a, int b) + { + //ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & b)) == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndEquaL1(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & b)) == 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndEquaL4(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & b)) == 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndNotEqualZero(int a, int b) + { + //ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & b)) != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndNotEqual1(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & b)) != 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndNotEqual4(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & b)) != 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsGreaterThanEq(int a) + static bool NegAndGtZero(int a, int b) { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 - return -a >= 0; + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & b)) > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndGt1(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & b)) > 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndGt4(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & b)) > 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndGeZero(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a & b)) >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndGe1(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & b)) >= 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsLessThan(int a) + static bool NegAndGe4(int a, int b) { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a & b)) >= 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndLtZero(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 - return -a < 0; + return (-(a & b)) < 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsLessThanEq(int a) + static bool NegAndLt1(int a, int b) { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 - return -a <= 0; + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & b)) < 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegAndLt4(int a, int b) + { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return (-(a & b)) < 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsGreaterThanIntMinValue() + static bool NegAndLeZero(int a, int b) { + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 - return -IntMinValue() > 0; + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & b)) <= 0; } [MethodImpl(MethodImplOptions.NoInlining)] - static bool NegsGreaterThanLongMinValue() + static bool NegAndLe1(int a, int b) { - //ARM64-FULL-LINE: neg {{x[0-9]+}}, {{x[0-9]+}} - //ARM64-FULL-LINE: cmp {{x[0-9]+}}, #0 - return -LongMinValue() > 0; + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & b)) <= 1; } [MethodImpl(MethodImplOptions.NoInlining)] - static int IntMinValue() + static bool NegAndLe4(int a, int b) { - return int.MinValue; + //ARM64-FULL-LINE: and {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & b)) <= 4; } [MethodImpl(MethodImplOptions.NoInlining)] - static long LongMinValue() + static bool NegBicEquaLZero(int a, int b) { - return long.MinValue; + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & ~b)) == 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicEquaL1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & ~b)) == 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicEquaL4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, eq + return (-(a & ~b)) == 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicNotEqualZero(int a, int b) + { + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & ~b)) != 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicNotEqual1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & ~b)) != 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicNotEqual4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ne + return (-(a & ~b)) != 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGtZero(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & ~b)) > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGt1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & ~b)) > 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGt4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & ~b)) > 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGeZero(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a & ~b)) >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGe1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + return (-(a & ~b)) >= 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicGe4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + return (-(a & ~b)) >= 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLtZero(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + return (-(a & ~b)) < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLt1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & ~b)) < 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLt4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, lt + return (-(a & ~b)) < 4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLeZero(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & ~b)) <= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLe1(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #1 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & ~b)) <= 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegBicLe4(int a, int b) + { + //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #4 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + return (-(a & ~b)) <= 4; } } } diff --git a/src/tests/JIT/opt/InstructionCombining/Neg.csproj b/src/tests/JIT/opt/InstructionCombining/Neg.csproj index 5593e2e3ec2db3..be851125410c35 100644 --- a/src/tests/JIT/opt/InstructionCombining/Neg.csproj +++ b/src/tests/JIT/opt/InstructionCombining/Neg.csproj @@ -13,5 +13,6 @@ + From 20648118f13e8da984767d638e74bb696a1254e5 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Wed, 11 Mar 2026 09:40:03 +0000 Subject: [PATCH 2/2] - Use OperIsShift() - Moved comment on what tree we are matching on - Removed setting DOTNET_JitStressProcedureSplitting=0 --- src/coreclr/jit/morph.cpp | 4 ++-- src/tests/JIT/opt/InstructionCombining/Neg.csproj | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index f1f229e6c8eeae..957a4fe6bab7b3 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8749,6 +8749,7 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) GenTree* op1 = cmp->gtGetOp1(); GenTreeIntConCommon* op2 = cmp->gtGetOp2()->AsIntConCommon(); + // Fold: (-(x)) == 0 -> x == 0 (avoid neg on compare-to-zero) if (op1->OperIs(GT_NEG) && !op1->gtOverflowEx()) { GenTree* negOp = op1->AsUnOp()->gtGetOp1(); @@ -8761,7 +8762,7 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) // On ARM64 negs with a shift can be more compact than shift; cmp #0. // Avoid folding when the negated operand is a simple shift so we keep the single // instruction form. - if (negOp->OperIs(GT_LSH, GT_RSH, GT_RSZ)) + if (negOp->OperIsShift()) { GenTree* shiftAmount = negOp->AsOp()->gtGetOp2(); if (shiftAmount->IsCnsIntOrI()) @@ -8773,7 +8774,6 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) if (shouldFold) { - // Fold: (-(x)) == 0 -> x == 0 (avoid neg on compare-to-zero) cmp->gtOp1 = negOp; DEBUG_DESTROY_NODE(op1); op1 = negOp; diff --git a/src/tests/JIT/opt/InstructionCombining/Neg.csproj b/src/tests/JIT/opt/InstructionCombining/Neg.csproj index be851125410c35..5593e2e3ec2db3 100644 --- a/src/tests/JIT/opt/InstructionCombining/Neg.csproj +++ b/src/tests/JIT/opt/InstructionCombining/Neg.csproj @@ -13,6 +13,5 @@ -