Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 31 additions & 2 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand All @@ -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;
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 @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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