diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index dbdb7c7485108d..0178826d918017 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -19878,6 +19878,11 @@ bool GenTree::IsArrayAddr(GenTreeArrAddr** pArrAddr) // bool GenTree::SupportsSettingZeroFlag() { + if (SupportsSettingResultFlags()) + { + return true; + } + #if defined(TARGET_XARCH) if (OperIs(GT_LSH, GT_RSH, GT_RSZ, GT_ROL, GT_ROR)) { @@ -19896,18 +19901,42 @@ bool GenTree::SupportsSettingZeroFlag() return true; } #endif -#elif defined(TARGET_ARM64) +#endif + + return false; +} + +//------------------------------------------------------------------------ +// SupportsSettingResultFlags: Returns true if this is an arithmetic operation +// whose codegen supports setting the carry, overflow, zero and sign flags based +// on the result of the operation. +// +// Return Value: +// True if so. A false return does not imply that codegen for the node will +// not trash the result flags. +// +// Remarks: +// For example, for GT (AND x y) 0, arm64 can emit instructions that +// directly set the flags after the 'AND' and thus no comparison is needed. +// +// The backend expects any node for which the flags will be consumed to be +// marked with GTF_SET_FLAGS. +// +bool GenTree::SupportsSettingResultFlags() +{ +#if defined(TARGET_ARM64) if (OperIs(GT_AND, GT_AND_NOT)) { return true; } - // We do not support setting zero flag for madd/msub. + // We do not support setting result flags if neg has a contained mul if (OperIs(GT_NEG) && (!gtGetOp1()->OperIs(GT_MUL) || !gtGetOp1()->isContained())) { return true; } + // We do not support setting result flags for madd/msub. if (OperIs(GT_ADD, GT_SUB) && (!gtGetOp2()->OperIs(GT_MUL) || !gtGetOp2()->isContained())) { return true; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index b76a27879a4a7e..100f17301ea267 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2070,6 +2070,8 @@ struct GenTree bool SupportsSettingZeroFlag(); + bool SupportsSettingResultFlags(); + // These are only used for dumping. // The GetRegNum() is only valid in LIR, but the dumping methods are not easily // modified to check this. diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 73597ea88edffa..bd4886ae069c2f 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -4443,9 +4443,12 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) } } - // Optimize EQ/NE(op_that_sets_zf, 0) into op_that_sets_zf with GTF_SET_FLAGS + SETCC. + // Optimize EQ/NE/GT/GE/LT/LE(op_that_sets_zf, 0) into op_that_sets_zf with GTF_SET_FLAGS + SETCC. + // For GT/GE/LT/LE don't allow ADD/SUB, runtime has to check for overflow. LIR::Use use; - if (cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag() && + if (((cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag()) || + (cmp->OperIs(GT_GT, GT_GE, GT_LT, GT_LE) && op2->IsIntegralConst(0) && !op1->OperIs(GT_ADD, GT_SUB) && + op1->SupportsSettingResultFlags())) && BlockRange().TryGetUse(cmp, &use) && IsProfitableToSetZeroFlag(op1)) { op1->gtFlags |= GTF_SET_FLAGS; diff --git a/src/tests/JIT/opt/InstructionCombining/Add.cs b/src/tests/JIT/opt/InstructionCombining/Add.cs index 8838bd2fe187ae..e7932d731b99d9 100644 --- a/src/tests/JIT/opt/InstructionCombining/Add.cs +++ b/src/tests/JIT/opt/InstructionCombining/Add.cs @@ -135,6 +135,106 @@ public static int CheckAdd() fail = true; } + if (AddGtZero(-3, 4) != 1) + { + fail = true; + } + + if (AddGtZero(3, -3) != 0) + { + fail = true; + } + + if (AddGtZero(-5, -10) != 0) + { + fail = true; + } + + if (AddGtZero(int.MaxValue, 1) != 0) + { + fail = true; + } + + if (AddGtZero(int.MinValue, -1) != 1) + { + fail = true; + } + + if (AddGeZero(1, 1) != 1) + { + fail = true; + } + + if (AddGeZero(0, 0) != 1) + { + fail = true; + } + + if (AddGeZero(-1, -1) != 0) + { + fail = true; + } + + if (AddGeZero(int.MaxValue, 1) != 0) + { + fail = true; + } + + if (AddGeZero(int.MinValue, -1) != 1) + { + fail = true; + } + + if (AddLtZero(1, 1) != 0) + { + fail = true; + } + + if (AddLtZero(0, 0) != 0) + { + fail = true; + } + + if (AddLtZero(-1, -1) != 1) + { + fail = true; + } + + if (AddLtZero(int.MaxValue, 1) != 1) + { + fail = true; + } + + if (AddLtZero(int.MinValue, -1) != 0) + { + fail = true; + } + + if (AddLeZero(1, 1) != 0) + { + fail = true; + } + + if (AddLeZero(0, 0) != 1) + { + fail = true; + } + + if (AddLeZero(-1, -1) != 1) + { + fail = true; + } + + if (AddLeZero(int.MaxValue, 1) != 1) + { + fail = true; + } + + if (AddLeZero(int.MinValue, -1) != 0) + { + fail = true; + } + if (fail) { return 101; @@ -336,5 +436,48 @@ static bool AddsBinOpSingleLine(int a, int b, int c, int d) //ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} return (a + b == 0) | (c + d == 0); } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddGtZero(int a, int b) { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + if (a + b > 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddGeZero(int a, int b) { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + if (a + b >= 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddLtZero(int a, int b) { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + if (a + b < 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddLeZero(int a, int b) { + //ARM64-FULL-LINE: add {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + if (a + b <= 0) { + return 1; + } + return 0; + } } } diff --git a/src/tests/JIT/opt/InstructionCombining/And.cs b/src/tests/JIT/opt/InstructionCombining/And.cs index 483b008e3cf11f..f794bc20624a92 100644 --- a/src/tests/JIT/opt/InstructionCombining/And.cs +++ b/src/tests/JIT/opt/InstructionCombining/And.cs @@ -105,6 +105,26 @@ public static int CheckAnd() fail = true; } + if (!AndsGreaterThan(3, 2)) + { + fail = true; + } + + if (!AndsGreaterThanEq(5, 8)) + { + fail = true; + } + + if (!AndsLessThan(-8, -4)) + { + fail = true; + } + + if (!AndsLessThanEq(5, 2)) + { + fail = true; + } + if (fail) { return 101; @@ -264,5 +284,33 @@ static bool AndsBinOpSingleLine(uint a, uint b, uint c, uint d) //ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}} return ((a & b) == 0) | ((c & d) == 0); } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool AndsGreaterThan(int a, int b) + { + //ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}} + return (a & b) > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool AndsGreaterThanEq(int a, int b) + { + //ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}} + return (a & b) >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool AndsLessThan(int a, int b) + { + //ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}} + return (a & b) < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool AndsLessThanEq(int a, int b) + { + //ARM64-FULL-LINE: ands w0, {{w[0-9]+}}, {{w[0-9]+}} + return (a & b) <= 0; + } } } diff --git a/src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.cs b/src/tests/JIT/opt/InstructionCombining/Bic.cs similarity index 78% rename from src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.cs rename to src/tests/JIT/opt/InstructionCombining/Bic.cs index 15dca88683a76a..419981104094aa 100644 --- a/src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.cs +++ b/src/tests/JIT/opt/InstructionCombining/Bic.cs @@ -5,13 +5,13 @@ using System.Runtime.CompilerServices; using Xunit; -namespace TestBitwiseClearShift +namespace TestBic { public class Program { [MethodImpl(MethodImplOptions.NoInlining)] [Fact] - public static int CheckBitwiseClearShift() + public static int CheckBic() { bool fail = false; @@ -95,6 +95,26 @@ public static int CheckBitwiseClearShift() fail = true; } + if (!BicsGreaterThan(1, 2)) + { + fail = true; + } + + if (!BicsGreaterThanEq(-2, -2)) + { + fail = true; + } + + if (!BicsLessThan(-2, 15)) + { + fail = true; + } + + if (!BicsLessThanEq(-6, 6)) + { + fail = true; + } + if (fail) { return 101; @@ -117,7 +137,7 @@ static bool Bic(uint a, uint b, uint c) static bool BicLSL(uint a, uint b, uint c) { //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #4 - if ((a & ~(b<<4)) == c) + if ((a & ~(b << 4)) == c) { return true; } @@ -128,7 +148,7 @@ static bool BicLSL(uint a, uint b, uint c) static bool BicLSR(uint a, uint b, uint c) { //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #12 - if ((a & ~(b>>12)) == c) + if ((a & ~(b >> 12)) == c) { return true; } @@ -139,7 +159,7 @@ static bool BicLSR(uint a, uint b, uint c) static bool BicASR(int a, int b, int c) { //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ASR #7 - if ((a & ~(b>>7)) == c) + if ((a & ~(b >> 7)) == c) { return true; } @@ -150,7 +170,7 @@ static bool BicASR(int a, int b, int c) static bool BicLargeShift(uint a, uint b, uint c) { //ARM64-FULL-LINE: bic {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #17 - if ((a & ~(b<<145)) == c) + if ((a & ~(b << 145)) == c) { return true; } @@ -161,7 +181,7 @@ static bool BicLargeShift(uint a, uint b, uint c) static bool BicLargeShift64Bit(long a, long b, long c) { //ARM64-FULL-LINE: bic {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, ASR #36 - if ((a & ~(b>>292)) == c) + if ((a & ~(b >> 292)) == c) { return true; } @@ -183,7 +203,7 @@ static int Bics(uint a, uint b) static int BicsLSL(uint a, uint b) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #31 - if ((a & ~(b<<31)) == 0) + if ((a & ~(b << 31)) == 0) { return -1; } @@ -194,7 +214,7 @@ static int BicsLSL(uint a, uint b) static int BicsLSR(uint a, uint b) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #20 - if ((a & ~(b>>20)) == 0) + if ((a & ~(b >> 20)) == 0) { return -1; } @@ -205,7 +225,7 @@ static int BicsLSR(uint a, uint b) static int BicsASR(int a, int b) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ASR #9 - if ((a & ~(b>>9)) == 0) + if ((a & ~(b >> 9)) == 0) { return -1; } @@ -216,7 +236,7 @@ static int BicsASR(int a, int b) static int BicsLargeShift(uint a, uint b) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #3 - if ((a & ~(b>>99)) == 0) + if ((a & ~(b >> 99)) == 0) { return -1; } @@ -227,7 +247,7 @@ static int BicsLargeShift(uint a, uint b) static int BicsLargeShift64Bit(ulong a, ulong b) { //ARM64-FULL-LINE: bics {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, LSL #51 - if ((a & ~(b<<179)) == 0) + if ((a & ~(b << 179)) == 0) { return -1; } @@ -245,7 +265,7 @@ static bool BicsSingleLine(uint a, uint b) static bool BicsSingleLineLSL(uint a, uint b) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #5 - return (~(a<<5) & b) != 0; + return (~(a << 5) & b) != 0; } [MethodImpl(MethodImplOptions.NoInlining)] @@ -253,7 +273,8 @@ static int BicsBinOp(uint a, uint b, uint c, uint d) { //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #8 //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #12 - if (((a & ~(b<<12)) == 0) == ((~(c>>8) & d) == 0)) { + if ((a & ~(b << 12)) == 0 == ((~(c >> 8) & d) == 0)) + { return 1; } return -1; @@ -266,5 +287,34 @@ static bool BicsBinOpSingleLine(uint a, uint b, uint c, uint d) //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} return ((~a & b) != 0) & ((c & ~d) != 0); } + + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool BicsGreaterThan(int a, int b) + { + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + return (a & ~b) > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool BicsGreaterThanEq(int a, int b) + { + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + return (a & ~b) >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool BicsLessThan(int a, int b) + { + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + return (a & ~b) < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool BicsLessThanEq(int a, int b) + { + //ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + return (a & ~b) <= 0; + } } } diff --git a/src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.csproj b/src/tests/JIT/opt/InstructionCombining/Bic.csproj similarity index 92% rename from src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.csproj rename to src/tests/JIT/opt/InstructionCombining/Bic.csproj index fa7abf5d8a8d0b..6427e11abbe7dd 100644 --- a/src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.csproj +++ b/src/tests/JIT/opt/InstructionCombining/Bic.csproj @@ -8,7 +8,7 @@ True - + true diff --git a/src/tests/JIT/opt/InstructionCombining/Neg.cs b/src/tests/JIT/opt/InstructionCombining/Neg.cs index 2db9a7b70404fd..b6a3e8ab8a9f07 100644 --- a/src/tests/JIT/opt/InstructionCombining/Neg.cs +++ b/src/tests/JIT/opt/InstructionCombining/Neg.cs @@ -39,7 +39,7 @@ public static int CheckNeg() { fail = true; } - + if (NegLargeShift64Bit(0xD) != 0x6000000000000000) { fail = true; @@ -95,6 +95,26 @@ public static int CheckNeg() fail = true; } + if (!NegsGreaterThan(-1)) + { + fail = true; + } + + if (!NegsGreaterThanEq(0)) + { + fail = true; + } + + if (!NegsLessThan(5)) + { + fail = true; + } + + if (!NegsLessThanEq(20)) + { + fail = true; + } + if (fail) { return 101; @@ -113,7 +133,7 @@ static int Neg(int a) static int NegLSL(int a) { //ARM64-FULL-LINE: neg {{w[0-9]+}}, {{w[0-9]+}}, LSL #2 - return -(a<<2); + return -(a << 2); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -121,35 +141,36 @@ 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); + 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); + 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); + 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); + return -(a << 189); } [MethodImpl(MethodImplOptions.NoInlining)] static int Negs(int a) { //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} - if (-a != 0) { + if (-a != 0) + { return 1; } return -1; @@ -159,7 +180,8 @@ static int Negs(int a) static int NegsLSL(int a) { //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #14 - if (-(a<<14) != 0) { + if (-(a << 14) != 0) + { return 1; } return -1; @@ -170,7 +192,8 @@ static int NegsLSR(uint a) { //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) { + if (-(a >> 3) != 0) + { return 1; } return -1; @@ -180,7 +203,8 @@ static int NegsLSR(uint a) static int NegsASR(int a) { //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, ASR #2 - if (-(a>>2) != 0) { + if (-(a >> 2) != 0) + { return 1; } return -1; @@ -191,7 +215,8 @@ static int NegsLargeShift(uint a) { //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) { + if (-(a << 100) != 0) + { return 1; } return -1; @@ -201,7 +226,8 @@ static int NegsLargeShift(uint a) static int NegsLargeShift64Bits(long a) { //ARM64-FULL-LINE: negs {{x[0-9]+}}, {{x[0-9]+}}, ASR #34 - if (-(a>>98) != 0) { + if (-(a >> 98) != 0) + { return 1; } return -1; @@ -218,7 +244,7 @@ static bool NegsSingleLine(int a) static bool NegsSingleLineLSL(int a) { //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #13 - return -(a<<13) != 0; + return -(a << 13) != 0; } [MethodImpl(MethodImplOptions.NoInlining)] @@ -226,7 +252,8 @@ static int NegsBinOp(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)) { + if ((-a != 0) == (-(b >> 5) != 0)) + { return 1; } return -1; @@ -237,7 +264,35 @@ static bool NegsBinOpSingleLine(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); + return (-(a >> 1) != 0) | (-(b << 1) != 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegsGreaterThan(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} + return -a > 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegsGreaterThanEq(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} + return -a >= 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegsLessThan(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} + return -a < 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool NegsLessThanEq(int a) + { + //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}} + return -a <= 0; } } } diff --git a/src/tests/JIT/opt/InstructionCombining/Sub.cs b/src/tests/JIT/opt/InstructionCombining/Sub.cs index e01e15a1655d0d..9297abb5c750c9 100644 --- a/src/tests/JIT/opt/InstructionCombining/Sub.cs +++ b/src/tests/JIT/opt/InstructionCombining/Sub.cs @@ -54,7 +54,7 @@ public static int CheckSub() { fail = true; } - + if (SubsLSR(1, 0x80000000) != 1) { fail = true; @@ -121,6 +121,106 @@ public static int CheckSub() fail = true; } + if (SubGtZero(5, 3) != 1) + { + fail = true; + } + + if (SubGtZero(3, 3) != 0) + { + fail = true; + } + + if (SubGtZero(2, 4) != 0) + { + fail = true; + } + + if (SubGtZero(int.MinValue, 1) != 1) + { + fail = true; + } + + if (SubGtZero(int.MaxValue, -1) != 0) + { + fail = true; + } + + if (SubGeZero(5, 3) != 1) + { + fail = true; + } + + if (SubGeZero(3, 3) != 1) + { + fail = true; + } + + if (SubGeZero(2, 4) != 0) + { + fail = true; + } + + if (SubGeZero(int.MinValue, 1) != 1) + { + fail = true; + } + + if (SubGeZero(int.MaxValue, -1) != 0) + { + fail = true; + } + + if (SubLtZero(5, 3) != 0) + { + fail = true; + } + + if (SubLtZero(3, 3) != 0) + { + fail = true; + } + + if (SubLtZero(2, 4) != 1) + { + fail = true; + } + + if (SubLtZero(int.MinValue, 1) != 0) + { + fail = true; + } + + if (SubLtZero(int.MaxValue, -1) != 1) + { + fail = true; + } + + if (SubLeZero(5, 3) != 0) + { + fail = true; + } + + if (SubLeZero(3, 3) != 1) + { + fail = true; + } + + if (SubLeZero(2, 4) != 1) + { + fail = true; + } + + if (SubLeZero(int.MinValue, 1) != 0) + { + fail = true; + } + + if (SubLeZero(int.MaxValue, -1) != 1) + { + fail = true; + } + if (fail) { return 101; @@ -139,35 +239,35 @@ static int Sub(int a, int b) static int SubLSL(int a, int b) { //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #3 - return a - (b<<3); + return a - (b << 3); } [MethodImpl(MethodImplOptions.NoInlining)] static uint SubLSR(uint a, uint b) { //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #4 - return a - (b>>4); + return a - (b >> 4); } [MethodImpl(MethodImplOptions.NoInlining)] static int SubASR(int a, int b) { //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ASR #6 - return a - (b>>6); + return a - (b >> 6); } [MethodImpl(MethodImplOptions.NoInlining)] static int SubLargeShift(int a, int b) { //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #22 - return a - (b<<118); + return a - (b << 118); } [MethodImpl(MethodImplOptions.NoInlining)] static long SubLargeShift64Bit(long a, long b) { //ARM64-FULL-LINE: sub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, LSL #54 - return a - (b<<118); + return a - (b << 118); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -216,7 +316,8 @@ static long SubExtendedUW(long a, long b) static int Subs(int a, int b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} - if (a - b == 0) { + if (a - b == 0) + { return 1; } return -1; @@ -226,17 +327,19 @@ static int Subs(int a, int b) static int SubsLSL(int a, int b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #1 - if (a - (b<<1) == 0) { + if (a - (b << 1) == 0) + { return 1; } return -1; } - + [MethodImpl(MethodImplOptions.NoInlining)] static int SubsLSR(uint a, uint b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSR #31 - if (a - (b>>31) == 0) { + if (a - (b >> 31) == 0) + { return 1; } return -1; @@ -246,7 +349,8 @@ static int SubsLSR(uint a, uint b) static int SubsASR(int a, int b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ASR #20 - if (a - (b>>20) == 0) { + if (a - (b >> 20) == 0) + { return 1; } return -1; @@ -256,7 +360,8 @@ static int SubsASR(int a, int b) static int SubsLargeShift(int a, int b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #1 - if (a - (b<<33) == 0) { + if (a - (b << 33) == 0) + { return 1; } return -1; @@ -266,7 +371,8 @@ static int SubsLargeShift(int a, int b) static int SubsLargeShift64Bit(long a, long b) { //ARM64-FULL-LINE: subs {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, LSL #32 - if (a - (b<<96) == 0) { + if (a - (b << 96) == 0) + { return 1; } return -1; @@ -283,7 +389,7 @@ static bool SubsSingleLine(int a, int b) static bool SubsSingleLineLSL(int a, int b) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #2 - return a - (b<<2) == 0; + return a - (b << 2) == 0; } [MethodImpl(MethodImplOptions.NoInlining)] @@ -291,7 +397,8 @@ static int SubsBinOp(int a, int b, int c, int d) { //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #3 //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, ASR #1 - if ((a - (b<<3) == 0) == (c - (d>>1) == 0)) { + if ((a - (b << 3) == 0) == (c - (d >> 1) == 0)) + { return 1; } return -1; @@ -304,5 +411,48 @@ static bool SubsBinOpSingleLine(int a, int b, int c, int d) //ARM64-FULL-LINE: subs {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} return (a - b == 0) | (c - d == 0); } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubGtZero(int a, int b) { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, gt + if (a - b > 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubGeZero(int a, int b) { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, ge + if (a - b >= 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubLtZero(int a, int b) { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: lsr {{w[0-9]+}}, {{w[0-9]+}}, #31 + if (a - b < 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubLeZero(int a, int b) { + //ARM64-FULL-LINE: sub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}} + //ARM64-FULL-LINE: cmp {{w[0-9]+}}, #0 + //ARM64-FULL-LINE: cset {{x[0-9]+}}, le + if (a - b <= 0) { + return 1; + } + return 0; + } } }