Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit bbc477f

Browse files
committed
Reimplement compare flags reuse using SETCC/JCC
1 parent 3c32232 commit bbc477f

File tree

4 files changed

+41
-77
lines changed

4 files changed

+41
-77
lines changed

src/jit/codegenxarch.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6244,42 +6244,6 @@ void CodeGen::genCompareInt(GenTreePtr treeNode)
62446244
var_types op2Type = op2->TypeGet();
62456245
regNumber targetReg = tree->gtRegNum;
62466246

6247-
// Case of op1 == 0 or op1 != 0:
6248-
// Optimize generation of 'test' instruction if op1 sets flags.
6249-
//
6250-
// Note that if LSRA has inserted any GT_RELOAD/GT_COPY before
6251-
// op1, it will not modify the flags set by codegen of op1.
6252-
// Similarly op1 could also be reg-optional at its use and
6253-
// it was spilled after producing its result in a register.
6254-
// Spill code too will not modify the flags set by op1.
6255-
GenTree* realOp1 = op1->gtSkipReloadOrCopy();
6256-
if ((tree->gtFlags & GTF_USE_FLAGS) != 0)
6257-
{
6258-
// op1 must set ZF and SF flags
6259-
assert(realOp1->gtSetZSFlags());
6260-
assert(realOp1->gtSetFlags());
6261-
6262-
// Must be (in)equality against zero.
6263-
assert(tree->OperIs(GT_EQ, GT_NE));
6264-
assert(op2->IsIntegralConst(0));
6265-
assert(op2->isContained());
6266-
6267-
// Just consume the operands
6268-
genConsumeOperands(tree);
6269-
6270-
// No need to generate test instruction since
6271-
// op1 sets flags
6272-
6273-
// Are we evaluating this into a register?
6274-
if (targetReg != REG_NA)
6275-
{
6276-
genSetRegToCond(targetReg, tree);
6277-
genProduceReg(tree);
6278-
}
6279-
6280-
return;
6281-
}
6282-
62836247
genConsumeOperands(tree);
62846248

62856249
// TODO-CQ: We should be able to support swapping op1 and op2 to generate cmp reg, imm.

src/jit/lower.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ GenTree* Lowering::LowerNode(GenTree* node)
188188
case GT_TEST_EQ:
189189
case GT_TEST_NE:
190190
case GT_CMP:
191-
LowerCompare(node);
192-
break;
191+
return LowerCompare(node);
193192

194193
case GT_JTRUE:
195194
ContainCheckJTrue(node->AsOp());
@@ -2138,7 +2137,7 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
21382137
// be used for ARM as well if support for GT_TEST_EQ/GT_TEST_NE is added).
21392138
// - Transform TEST(x, LSH(1, y)) into BT(x, y) (XARCH specific)
21402139

2141-
void Lowering::LowerCompare(GenTree* cmp)
2140+
GenTree* Lowering::LowerCompare(GenTree* cmp)
21422141
{
21432142
#ifndef _TARGET_64BIT_
21442143
if (cmp->gtGetOp1()->TypeGet() == TYP_LONG)
@@ -2344,7 +2343,7 @@ void Lowering::LowerCompare(GenTree* cmp)
23442343
cmp->AsCC()->gtCondition = condition;
23452344
}
23462345

2347-
return;
2346+
return cmp->gtNext;
23482347
}
23492348
#endif
23502349

@@ -2578,7 +2577,42 @@ void Lowering::LowerCompare(GenTree* cmp)
25782577

25792578
cc->gtFlags |= GTF_USE_FLAGS | GTF_UNSIGNED;
25802579

2581-
return;
2580+
return cmp->gtNext;
2581+
}
2582+
}
2583+
else if (cmp->OperIs(GT_EQ, GT_NE))
2584+
{
2585+
GenTree* op1 = cmp->gtGetOp1();
2586+
GenTree* op2 = cmp->gtGetOp2();
2587+
LIR::Use cmpUse;
2588+
2589+
if (op1->gtSetZSFlags() && op2->IsIntegralConst(0) && (op1->gtNext == op2) && (op2->gtNext == cmp) &&
2590+
BlockRange().TryGetUse(cmp, &cmpUse))
2591+
{
2592+
genTreeOps condition = cmp->OperGet();
2593+
GenTree* next = cmp->gtNext;
2594+
GenTreeCC* cc;
2595+
2596+
if (cmpUse.User()->OperIs(GT_JTRUE))
2597+
{
2598+
cmpUse.User()->ChangeOper(GT_JCC);
2599+
cc = cmpUse.User()->AsCC();
2600+
BlockRange().Remove(cmp);
2601+
}
2602+
else
2603+
{
2604+
cmp->ChangeOper(GT_SETCC);
2605+
cc = cmp->AsCC();
2606+
}
2607+
2608+
cc->gtCondition = condition;
2609+
cc->gtFlags |= GTF_USE_FLAGS;
2610+
op1->gtFlags |= GTF_SET_FLAGS;
2611+
op1->SetUnusedValue();
2612+
2613+
BlockRange().Remove(op2);
2614+
2615+
return next;
25822616
}
25832617
}
25842618

@@ -2599,6 +2633,7 @@ void Lowering::LowerCompare(GenTree* cmp)
25992633
}
26002634
#endif // _TARGET_XARCH_
26012635
ContainCheckCompare(cmp->AsOp());
2636+
return cmp->gtNext;
26022637
}
26032638

26042639
// Lower "jmp <method>" tail call to insert PInvoke method epilog if required.

src/jit/lower.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class Lowering : public Phase
137137
// Call Lowering
138138
// ------------------------------
139139
void LowerCall(GenTree* call);
140-
void LowerCompare(GenTree* tree);
140+
GenTree* LowerCompare(GenTree* tree);
141141
void LowerJmpMethod(GenTree* jmp);
142142
void LowerRet(GenTree* ret);
143143
GenTree* LowerDelegateInvoke(GenTreeCall* call);

src/jit/lowerxarch.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,41 +1838,6 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
18381838
{
18391839
MakeSrcContained(cmp, op1);
18401840
}
1841-
// If op1 codegen sets ZF and SF flags and ==/!= against
1842-
// zero, we don't need to generate test instruction,
1843-
// provided we don't have another GenTree node between op1
1844-
// and cmp that could potentially modify flags.
1845-
//
1846-
// TODO-CQ: right now the below peep is inexpensive and
1847-
// gets the benefit in most of cases because in majority
1848-
// of cases op1, op2 and cmp would be in that order in
1849-
// execution. In general we should be able to check that all
1850-
// the nodes that come after op1 in execution order do not
1851-
// modify the flags so that it is safe to avoid generating a
1852-
// test instruction. Such a check requires that on each
1853-
// GenTree node we need to set the info whether its codegen
1854-
// will modify flags.
1855-
//
1856-
// TODO-CQ: We can optimize compare against zero in the
1857-
// following cases by generating the branch as indicated
1858-
// against each case.
1859-
// 1) unsigned compare
1860-
// < 0 - always FALSE
1861-
// <= 0 - ZF=1 and jne
1862-
// > 0 - ZF=0 and je
1863-
// >= 0 - always TRUE
1864-
//
1865-
// 2) signed compare
1866-
// < 0 - SF=1 and js
1867-
// >= 0 - SF=0 and jns
1868-
else if (cmp->OperIs(GT_EQ, GT_NE) && op1->gtSetZSFlags() && op2->IsIntegralConst(0) &&
1869-
(op1->gtNext == op2) && (op2->gtNext == cmp))
1870-
{
1871-
// Require codegen of op1 to set the flags.
1872-
assert(!op1->gtSetFlags());
1873-
op1->gtFlags |= GTF_SET_FLAGS;
1874-
cmp->gtFlags |= GTF_USE_FLAGS;
1875-
}
18761841
else
18771842
{
18781843
SetRegOptional(op1);

0 commit comments

Comments
 (0)