Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e89057c
arm64: Set zero flag for more comparisons
jonathandavies-arm Feb 24, 2025
077d8cd
Rename SupportsSettingZeroFlag to SupportsSettingFlags
jonathandavies-arm Feb 25, 2025
ff70f1d
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm Feb 26, 2025
f573c26
Fix Bic csproj
jonathandavies-arm Feb 28, 2025
1f488a6
Only support other comparisons on ARM64
jonathandavies-arm Mar 4, 2025
d507f31
Add SupportsSettingResultFlags() and restore SupportsSettingZeroFlag()
jonathandavies-arm Mar 5, 2025
24aa340
* Call SupportsSettingResultFlags() from SupportsSettingZeroFlag()
jonathandavies-arm Mar 5, 2025
d42e598
Fix formatting
jonathandavies-arm Mar 5, 2025
dc2e09f
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm Mar 6, 2025
61c1144
Remove duplicated SupportsSettingResultFlags() definition
jonathandavies-arm Mar 6, 2025
753e19f
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm Mar 7, 2025
fd77f15
Merge remote-tracking branch 'upstream-fork/main' into upstream/ce/cm…
jonathandavies-arm Mar 26, 2025
0134f3a
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm Apr 9, 2025
908b045
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm Apr 24, 2025
a17dece
Only build stack frame if skipFrames is greater than zero
jonathandavies-arm Apr 24, 2025
60c2cbb
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm May 6, 2025
00f0b60
Don't allow ADD/SUB because they don't work with the overflow
jonathandavies-arm May 6, 2025
82b8f63
Merge branch 'main' into upstream/ce/cmp-gt
jonathandavies-arm May 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
67 changes: 65 additions & 2 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
9 changes: 6 additions & 3 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
143 changes: 143 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/Add.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
}
48 changes: 48 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/And.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
}
Loading
Loading