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