Skip to content

Commit 18839c0

Browse files
author
Quantum Hu
committed
Optimize 'x & cns == cns' pattern
1 parent 60d67b8 commit 18839c0

File tree

3 files changed

+56
-9
lines changed

3 files changed

+56
-9
lines changed

src/coreclr/jit/codegenarm.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,14 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
12711271
{
12721272
assert(!varTypeIsFloating(op2Type));
12731273
var_types cmpType = (op1Type == op2Type) ? op1Type : TYP_INT;
1274-
emit->emitInsBinary(INS_cmp, emitTypeSize(cmpType), op1, op2);
1274+
1275+
// When comparing to constant zero, and descendant node (op1) set the flags, we can skip emitting the cmp
1276+
bool skipGenCmp = ((op1->gtFlags & GTF_SET_FLAGS) != 0) && op2->IsIntegralConst(0);
1277+
1278+
if (!skipGenCmp)
1279+
{
1280+
emit->emitInsBinary(INS_cmp, emitTypeSize(cmpType), op1, op2);
1281+
}
12751282
}
12761283

12771284
// Are we evaluating this into a register?

src/coreclr/jit/codegenarm64.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4992,9 +4992,20 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree)
49924992
{
49934993
assert(op2->IsIntegralConst(0));
49944994

4995-
instruction ins = (cc.GetCode() == GenCondition::EQ) ? INS_cbz : INS_cbnz;
4995+
// It's possible the descendant node (op1) set the flags. If so, we don't need to compare again
4996+
bool genBranchOnly = (op1->gtFlags & GTF_SET_FLAGS) != 0;
49964997

4997-
GetEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->GetTrueTarget(), reg);
4998+
instruction ins;
4999+
if (!genBranchOnly)
5000+
{
5001+
ins = (cc.GetCode() == GenCondition::EQ) ? INS_cbz : INS_cbnz;
5002+
GetEmitter()->emitIns_J_R(ins, attr, compiler->compCurBB->GetTrueTarget(), reg);
5003+
}
5004+
else
5005+
{
5006+
ins = (cc.GetCode() == GenCondition::EQ) ? INS_beq : INS_bne;
5007+
GetEmitter()->emitIns_J(ins, compiler->compCurBB->GetTrueTarget());
5008+
}
49985009
}
49995010

50005011
// If we cannot fall into the false target, emit a jump to it

src/coreclr/jit/morph.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8075,15 +8075,16 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
80758075
}
80768076
}
80778077

8078-
// Pattern-matching optimization:
8079-
// (a % c) ==/!= 0
8080-
// for power-of-2 constant `c`
8081-
// =>
8082-
// a & (c - 1) ==/!= 0
8083-
// For integer `a`, even if negative.
80848078
if (opts.OptimizationEnabled() && !optValnumCSE_phase)
80858079
{
80868080
assert(tree->OperIs(GT_EQ, GT_NE));
8081+
8082+
// Pattern-matching optimization:
8083+
// (a % c) ==/!= 0
8084+
// for power-of-2 constant `c`
8085+
// =>
8086+
// a & (c - 1) ==/!= 0
8087+
// For integer `a`, even if negative.
80878088
if (op1->OperIs(GT_MOD) && varTypeIsIntegral(op1) && op2->IsIntegralConst(0))
80888089
{
80898090
GenTree* op1op2 = op1->AsOp()->gtOp2;
@@ -8104,6 +8105,34 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
81048105
}
81058106
}
81068107
}
8108+
8109+
// Optimization for:
8110+
// a & c ==/!= c
8111+
// =>
8112+
// ~a & c ==/!= 0
8113+
// where c is a constant
8114+
// The optimization could also take the form of a & ~c but the comparison would have to switch between EQ to NE/NE to EQ
8115+
if (op1->OperIs(GT_AND) && varTypeIsIntegral(op1) && op2->IsIntegralConst())
8116+
{
8117+
GenTree* andOp1 = op1->AsOp()->gtOp1;
8118+
GenTree* andOp2 = op1->AsOp()->gtOp2;
8119+
8120+
ssize_t cnsVal = op2->AsIntCon()->IconValue();
8121+
8122+
if (andOp1->TypeIs(TYP_INT, TYP_LONG) && andOp2->IsIntegralConst() && andOp2->AsIntCon()->IconValue() == cnsVal)
8123+
{
8124+
// Want GT_AND to look like AND(NOT(a), c) ==/!= a. The non-matching constant must be the one wrapped in NOT node
8125+
// so 2nd andOp will be the constant, so 1st andOp will have the NOT
8126+
GenTree* tmpNode = andOp2;
8127+
op1->AsOp()->gtOp2 = gtNewOperNode(GT_NOT, andOp1->TypeGet(), andOp1);
8128+
op1->AsOp()->gtOp1 = tmpNode;
8129+
op2->AsIntConCommon()->SetIconValue(0);
8130+
#if defined(TARGET_ARM) || defined(TARGET_ARM64)
8131+
// If set for XARCH it will prevent ANDN instruction from being emitted
8132+
op1->gtFlags |= GTF_SET_FLAGS;
8133+
#endif
8134+
}
8135+
}
81078136
}
81088137
}
81098138

0 commit comments

Comments
 (0)