Skip to content

arm64: Change EQ/NE node to SETCC if the operand supports the zero flag #112235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 19, 2025
2 changes: 1 addition & 1 deletion src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20082,7 +20082,7 @@ bool GenTree::SupportsSettingZeroFlag()
}
#endif
#elif defined(TARGET_ARM64)
if (OperIs(GT_AND, GT_AND_NOT))
if (OperIs(GT_AND, GT_AND_NOT, GT_NEG))
{
return true;
}
Expand Down
77 changes: 41 additions & 36 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4358,6 +4358,26 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp)
}
}

// Optimize EQ/NE(op_that_sets_zf, 0) into op_that_sets_zf with GTF_SET_FLAGS + SETCC.
LIR::Use use;
if (cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag() &&
BlockRange().TryGetUse(cmp, &use))
{
op1->gtFlags |= GTF_SET_FLAGS;
op1->SetUnusedValue();

GenTree* next = cmp->gtNext;
BlockRange().Remove(cmp);
BlockRange().Remove(op2);

GenCondition cmpCondition = GenCondition::FromRelop(cmp);
GenTreeCC* setcc = comp->gtNewCC(GT_SETCC, cmp->TypeGet(), cmpCondition);
BlockRange().InsertAfter(op1, setcc);

use.ReplaceWith(setcc);
return next;
}

return cmp;
}

Expand Down Expand Up @@ -4622,50 +4642,35 @@ bool Lowering::TryLowerConditionToFlagsNode(GenTree* parent, GenTree* condition,
}
#endif

// Optimize EQ/NE(op_that_sets_zf, 0) into op_that_sets_zf with GTF_SET_FLAGS.
if (optimizing && relop->OperIs(GT_EQ, GT_NE) && relopOp2->IsIntegralConst(0) &&
relopOp1->SupportsSettingZeroFlag() && IsInvariantInRange(relopOp1, parent))
{
relopOp1->gtFlags |= GTF_SET_FLAGS;
relopOp1->SetUnusedValue();
relop->gtType = TYP_VOID;
relop->gtFlags |= GTF_SET_FLAGS;

BlockRange().Remove(relopOp1);
BlockRange().InsertBefore(parent, relopOp1);
BlockRange().Remove(relop);
BlockRange().Remove(relopOp2);
}
else
if (relop->OperIs(GT_EQ, GT_NE, GT_LT, GT_LE, GT_GE, GT_GT))
{
relop->gtType = TYP_VOID;
relop->gtFlags |= GTF_SET_FLAGS;
relop->SetOper(GT_CMP);

if (relop->OperIs(GT_EQ, GT_NE, GT_LT, GT_LE, GT_GE, GT_GT))
if (cond->PreferSwap())
{
relop->SetOper(GT_CMP);

if (cond->PreferSwap())
{
std::swap(relop->gtOp1, relop->gtOp2);
*cond = GenCondition::Swap(*cond);
}
std::swap(relop->gtOp1, relop->gtOp2);
*cond = GenCondition::Swap(*cond);
}
}
#ifdef TARGET_XARCH
else if (relop->OperIs(GT_BITTEST_EQ, GT_BITTEST_NE))
{
relop->SetOper(GT_BT);
}
else if (relop->OperIs(GT_BITTEST_EQ, GT_BITTEST_NE))
{
relop->SetOper(GT_BT);
}
#endif
else
{
assert(relop->OperIs(GT_TEST_EQ, GT_TEST_NE));
relop->SetOper(GT_TEST);
}
else
{
assert(relop->OperIs(GT_TEST_EQ, GT_TEST_NE));
relop->SetOper(GT_TEST);
}

if (relop->gtNext != parent)
{
BlockRange().Remove(relop);
BlockRange().InsertBefore(parent, relop);
}
if (relop->gtNext != parent)
{
BlockRange().Remove(relop);
BlockRange().InsertBefore(parent, relop);
}

return true;
Expand Down
53 changes: 53 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/Add.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@ public static int CheckAdd()
fail = true;
}

if (!AddsSingleLine(-5, 5))
{
fail = true;
}

if (!AddsSingleLineLSL(-0x70, 0x7))
{
fail = true;
}

if (AddsBinOp(-5, 5, 2, -2) != 1)
{
fail = true;
}

if (!AddsBinOpSingleLine(-5, 5, 4, -2))
{
fail = true;
}

if (AddExtendedB(0, 0x101) != 1)
{
fail = true;
Expand Down Expand Up @@ -283,5 +303,38 @@ static long AddsLargeShift64Bit(long a, long b)
}
return -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AddsSingleLine(int a, int b)
{
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return a + b == 0;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AddsSingleLineLSL(int a, int b)
{
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, LSL #4
return a + (b<<4) == 0;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int AddsBinOp(int a, int b, int c, int d)
{
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
if ((a + b == 0) == (c + d == 0)) {
return 1;
}
return -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AddsBinOpSingleLine(int a, int b, int c, int d)
{
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
//ARM64-FULL-LINE: adds {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return (a + b == 0) | (c + d == 0);
}
}
}
53 changes: 53 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/And.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@ public static int CheckAnd()
fail = true;
}

if (!AndsSingleLine(6, 10))
{
fail = true;
}

if (!AndsSingleLineLSR(0xB00, 8))
{
fail = true;
}

if (AndsBinOp(4, 1, 0x3000, 4) != 1)
{
fail = true;
}

if (!AndsBinOpSingleLine(1, 2, 4, 12))
{
fail = true;
}

if (fail)
{
return 101;
Expand Down Expand Up @@ -211,5 +231,38 @@ static int AndsLargeShift64Bit(ulong a, ulong b)
}
return -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AndsSingleLine(uint a, uint b)
{
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}
return (a & b) != 0;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AndsSingleLineLSR(uint a, uint b)
{
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}, LSR #8
return ((a>>8) & b) != 0;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int AndsBinOp(uint a, uint b, uint c, uint d)
{
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}, LSL #2
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}, LSR #10
if (((a & (b<<2)) == 0) == (((c>>10) & d) == 0)) {
return 1;
}
return -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AndsBinOpSingleLine(uint a, uint b, uint c, uint d)
{
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}
//ARM64-FULL-LINE: tst {{w[0-9]+}}, {{w[0-9]+}}
return ((a & b) == 0) | ((c & d) == 0);
}
}
}
53 changes: 53 additions & 0 deletions src/tests/JIT/opt/InstructionCombining/BitwiseClearShift.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ public static int CheckBitwiseClearShift()
fail = true;
}

if (!BicsSingleLine(0x22446688, 0x22446688))
{
fail = true;
}

if (!BicsSingleLineLSL(0xABC, 0xFFFEA87F))
{
fail = true;
}

if (BicsBinOp(0xFF012FFF, 0xFED, 0xFFDDBB99, 0xFF002244) != 1)
{
fail = true;
}

if (!BicsBinOpSingleLine(0x66665555, 0x9999AAAA, 0xFFFFFFFD, 0x2))
{
fail = true;
}

if (fail)
{
return 101;
Expand Down Expand Up @@ -213,5 +233,38 @@ static int BicsLargeShift64Bit(ulong a, ulong b)
}
return 1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool BicsSingleLine(uint a, uint b)
{
//ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return (a & ~b) == 0;
}

[MethodImpl(MethodImplOptions.NoInlining)]
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;
}

[MethodImpl(MethodImplOptions.NoInlining)]
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)) {
return 1;
}
return -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool BicsBinOpSingleLine(uint a, uint b, uint c, uint d)
{
//ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
//ARM64-FULL-LINE: bics {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return ((~a & b) != 0) & ((c & ~d) != 0);
}
}
}
Loading
Loading