diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs index 8c1850d31e840b..28fe1e0f69b883 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs @@ -38,7 +38,7 @@ private void BuildStackFrame(int skipFrames, bool needFileInfo) skipFrames += StackTrace.CalculateFramesToSkip(StackF, iNumOfFrames); - if ((iNumOfFrames - skipFrames) > 0) + if (((iNumOfFrames - skipFrames) > 0) && (skipFrames >= 0)) { _method = StackF.GetMethodBase(skipFrames); _nativeOffset = StackF.GetOffset(skipFrames); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 54af242fa6cd28..cc7aaa718c8369 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20024,6 +20024,11 @@ bool GenTree::IsArrayAddr(GenTreeArrAddr** pArrAddr) // bool GenTree::SupportsSettingZeroFlag() { + if (SupportsSettingResultFlags()) + { + return true; + } + #if defined(TARGET_XARCH) if (OperIs(GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_NEG)) { @@ -20036,18 +20041,76 @@ 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; + } +#endif + + return false; +} + +//------------------------------------------------------------------------ +// SupportsSettingResultFlags: Returns true if this is an arithmetic operation +// whose codegen supports setting "result flags" as part of its operation +// other than the "zero flag" +// +// 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, both 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, GT_NEG)) + { + 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 e57d334a2805b5..6be0887bf29359 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2034,6 +2034,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 cc3cf97d919336..d754f7322d0f7a 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -4201,10 +4201,13 @@ 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, C# has to check for overflow. LIR::Use use; - if (cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag() && - BlockRange().TryGetUse(cmp, &use)) + if (((cmp->OperIs(GT_EQ, GT_NE) && op1->SupportsSettingZeroFlag()) || + (cmp->OperIs(GT_GT, GT_GE, GT_LT, GT_LE) && !op1->OperIs(GT_ADD, GT_SUB) && + op1->SupportsSettingResultFlags())) && + op2->IsIntegralConst(0) && BlockRange().TryGetUse(cmp, &use)) { op1->gtFlags |= GTF_SET_FLAGS; op1->SetUnusedValue(); 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 84% rename from src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.cs rename to src/tests/JIT/opt/InstructionCombining/Bic.cs index 15dca88683a76a..adb7eb7816ee4b 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; @@ -266,5 +286,33 @@ 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/CmpZero.cs b/src/tests/JIT/opt/InstructionCombining/CmpZero.cs new file mode 100644 index 00000000000000..f6e89bce9faa38 --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/CmpZero.cs @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +namespace TestCompareZero +{ + public class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + [Fact] + public static int CheckCompareZero() + { + bool fail = false; + + 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 (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; + } + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddGtZero(int a, int b) { + if (a + b > 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddGeZero(int a, int b) { + if (a + b >= 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddLtZero(int a, int b) { + if (a + b < 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int AddLeZero(int a, int b) { + if (a + b <= 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubGtZero(int a, int b) { + if (a - b > 0) { + return 1; + } + return 0; + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubGeZero(int a, int b) { + if (a - b >= 0) { + return 1; + } + return 0; + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubLtZero(int a, int b) { + if (a - b < 0) { + return 1; + } + return 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int SubLeZero(int a, int b) { + if (a - b <= 0) { + return 1; + } + return 0; + } + } +} diff --git a/src/tests/JIT/opt/InstructionCombining/CmpZero.csproj b/src/tests/JIT/opt/InstructionCombining/CmpZero.csproj new file mode 100644 index 00000000000000..5487a7ec88d8ff --- /dev/null +++ b/src/tests/JIT/opt/InstructionCombining/CmpZero.csproj @@ -0,0 +1,17 @@ + + + + true + + + None + True + + + + true + + + + + diff --git a/src/tests/JIT/opt/InstructionCombining/Neg.cs b/src/tests/JIT/opt/InstructionCombining/Neg.cs index 2db9a7b70404fd..d994936687894e 100644 --- a/src/tests/JIT/opt/InstructionCombining/Neg.cs +++ b/src/tests/JIT/opt/InstructionCombining/Neg.cs @@ -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; @@ -239,5 +259,33 @@ static bool NegsBinOpSingleLine(int a, int b) //ARM64-FULL-LINE: negs {{w[0-9]+}}, {{w[0-9]+}}, LSL #1 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..d635c537beeb51 100644 --- a/src/tests/JIT/opt/InstructionCombining/Sub.cs +++ b/src/tests/JIT/opt/InstructionCombining/Sub.cs @@ -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; @@ -304,5 +404,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; + } } }