Skip to content

Commit ceb2344

Browse files
authored
JIT: Support converting OR(condition, condition) -> CCMP (#83089)
Also support generating ccmp for GC pointers, which fixes #82703. Also makes the handling of operands symmetrical, so that the ccmp can be generated for either op1 or op2 of the AND/OR.
1 parent 2b5f342 commit ceb2344

File tree

2 files changed

+68
-53
lines changed

2 files changed

+68
-53
lines changed

src/coreclr/jit/lower.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class Lowering final : public Phase
8585
void ContainCheckLclHeap(GenTreeOp* node);
8686
void ContainCheckRet(GenTreeUnOp* ret);
8787
#ifdef TARGET_ARM64
88-
GenTree* TryLowerAndToCCMP(GenTreeOp* tree);
88+
GenTree* TryLowerAndOrToCCMP(GenTreeOp* tree);
8989
insCflags TruthifyingFlags(GenCondition cond);
9090
void ContainCheckConditionalCompare(GenTreeCCMP* ccmp);
9191
void ContainCheckNeg(GenTreeOp* neg);

src/coreclr/jit/lowerarmarch.cpp

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -457,32 +457,36 @@ GenTree* Lowering::LowerMul(GenTreeOp* mul)
457457
//
458458
GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp)
459459
{
460-
if (comp->opts.OptimizationEnabled() && binOp->OperIs(GT_AND))
460+
if (comp->opts.OptimizationEnabled())
461461
{
462-
GenTree* opNode = nullptr;
463-
GenTree* notNode = nullptr;
464-
if (binOp->gtGetOp1()->OperIs(GT_NOT))
465-
{
466-
notNode = binOp->gtGetOp1();
467-
opNode = binOp->gtGetOp2();
468-
}
469-
else if (binOp->gtGetOp2()->OperIs(GT_NOT))
462+
if (binOp->OperIs(GT_AND))
470463
{
471-
notNode = binOp->gtGetOp2();
472-
opNode = binOp->gtGetOp1();
473-
}
464+
GenTree* opNode = nullptr;
465+
GenTree* notNode = nullptr;
466+
if (binOp->gtGetOp1()->OperIs(GT_NOT))
467+
{
468+
notNode = binOp->gtGetOp1();
469+
opNode = binOp->gtGetOp2();
470+
}
471+
else if (binOp->gtGetOp2()->OperIs(GT_NOT))
472+
{
473+
notNode = binOp->gtGetOp2();
474+
opNode = binOp->gtGetOp1();
475+
}
474476

475-
if (notNode != nullptr)
476-
{
477-
binOp->gtOp1 = opNode;
478-
binOp->gtOp2 = notNode->AsUnOp()->gtGetOp1();
479-
binOp->ChangeOper(GT_AND_NOT);
480-
BlockRange().Remove(notNode);
477+
if (notNode != nullptr)
478+
{
479+
binOp->gtOp1 = opNode;
480+
binOp->gtOp2 = notNode->AsUnOp()->gtGetOp1();
481+
binOp->ChangeOper(GT_AND_NOT);
482+
BlockRange().Remove(notNode);
483+
}
481484
}
485+
482486
#ifdef TARGET_ARM64
483-
else
487+
if (binOp->OperIs(GT_AND, GT_OR))
484488
{
485-
GenTree* next = TryLowerAndToCCMP(binOp);
489+
GenTree* next = TryLowerAndOrToCCMP(binOp);
486490
if (next != nullptr)
487491
{
488492
return next;
@@ -2268,14 +2272,14 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
22682272

22692273
#ifdef TARGET_ARM64
22702274
//------------------------------------------------------------------------
2271-
// TryLowerAndToCCMP : Lower an and of two conditions into test + CCMP + SETCC nodes.
2275+
// TryLowerAndOrToCCMP : Lower AND/OR of two conditions into test + CCMP + SETCC nodes.
22722276
//
22732277
// Arguments:
22742278
// tree - pointer to the node
22752279
//
2276-
GenTree* Lowering::TryLowerAndToCCMP(GenTreeOp* tree)
2280+
GenTree* Lowering::TryLowerAndOrToCCMP(GenTreeOp* tree)
22772281
{
2278-
assert(tree->OperIs(GT_AND));
2282+
assert(tree->OperIs(GT_AND, GT_OR));
22792283

22802284
if (!comp->opts.OptimizationEnabled())
22812285
{
@@ -2285,42 +2289,39 @@ GenTree* Lowering::TryLowerAndToCCMP(GenTreeOp* tree)
22852289
GenTree* op1 = tree->gtGetOp1();
22862290
GenTree* op2 = tree->gtGetOp2();
22872291

2288-
// Find out whether op2 is eligible to be converted to a conditional
2292+
if ((op1->OperIsCmpCompare() && varTypeIsIntegralOrI(op1->gtGetOp1())) ||
2293+
(op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1())))
2294+
{
2295+
JITDUMP("[%06u] is a potential candidate for CCMP:\n", Compiler::dspTreeID(tree));
2296+
DISPTREERANGE(BlockRange(), tree);
2297+
JITDUMP("\n");
2298+
}
2299+
2300+
// Find out whether an operand is eligible to be converted to a conditional
22892301
// compare. It must be a normal integral relop; for example, we cannot
22902302
// conditionally perform a floating point comparison and there is no "ctst"
22912303
// instruction that would allow us to conditionally implement
22922304
// TEST_EQ/TEST_NE.
22932305
//
2294-
if (!op2->OperIsCmpCompare() || !varTypeIsIntegral(op2->gtGetOp1()))
2295-
{
2296-
return nullptr;
2297-
}
2298-
2299-
// For op1 we can allow more arbitrary operations that set the condition
2300-
// flags; the final transformation into the flags def is done by
2301-
// TryLowerConditionToFlagsNode below, but we have a quick early out here
2302-
// too.
2306+
// For the other operand we can allow more arbitrary operations that set
2307+
// the condition flags; the final transformation into the flags def is done
2308+
// by TryLowerConditionToFlagsNode.
23032309
//
2304-
if (!op1->OperIsCompare() && !op1->OperIs(GT_SETCC))
2310+
GenCondition cond1;
2311+
if (op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1()) && IsInvariantInRange(op2, tree) &&
2312+
TryLowerConditionToFlagsNode(tree, op1, &cond1))
23052313
{
2306-
return nullptr;
2314+
// Fall through, converting op2 to the CCMP
23072315
}
2308-
2309-
JITDUMP("[%06u] is a candidate for CCMP:\n", Compiler::dspTreeID(tree));
2310-
DISPTREERANGE(BlockRange(), tree);
2311-
JITDUMP("\n");
2312-
2313-
// We leave checking invariance of op1 to tree to TryLowerConditionToFlagsNode.
2314-
if (!IsInvariantInRange(op2, tree))
2316+
else if (op1->OperIsCmpCompare() && varTypeIsIntegralOrI(op1->gtGetOp1()) && IsInvariantInRange(op1, tree) &&
2317+
TryLowerConditionToFlagsNode(tree, op2, &cond1))
23152318
{
2316-
JITDUMP(" ..cannot move [%06u], bailing\n", Compiler::dspTreeID(op2));
2317-
return nullptr;
2319+
std::swap(op1, op2);
23182320
}
2319-
2320-
GenCondition cond1;
2321-
if (!TryLowerConditionToFlagsNode(tree, op1, &cond1))
2321+
else
23222322
{
2323-
JITDUMP(" ..could not turn [%06u] into a def of flags, bailing\n", Compiler::dspTreeID(op1));
2323+
JITDUMP(" ..could not turn [%06u] or [%06u] into a def of flags, bailing\n", Compiler::dspTreeID(op1),
2324+
Compiler::dspTreeID(op2));
23242325
return nullptr;
23252326
}
23262327

@@ -2336,10 +2337,24 @@ GenTree* Lowering::TryLowerAndToCCMP(GenTreeOp* tree)
23362337
op2->gtGetOp2()->ClearContained();
23372338

23382339
GenTreeCCMP* ccmp = op2->AsCCMP();
2339-
ccmp->gtCondition = cond1;
2340-
// If the first comparison fails, set the condition flags to something that
2341-
// makes the second one fail as well so that the overall AND failed.
2342-
ccmp->gtFlagsVal = TruthifyingFlags(GenCondition::Reverse(cond2));
2340+
2341+
if (tree->OperIs(GT_AND))
2342+
{
2343+
// If the first comparison succeeds then do the second comparison.
2344+
ccmp->gtCondition = cond1;
2345+
// Otherwise set the condition flags to something that makes the second
2346+
// one fail.
2347+
ccmp->gtFlagsVal = TruthifyingFlags(GenCondition::Reverse(cond2));
2348+
}
2349+
else
2350+
{
2351+
// If the first comparison fails then do the second comparison.
2352+
ccmp->gtCondition = GenCondition::Reverse(cond1);
2353+
// Otherwise set the condition flags to something that makes the second
2354+
// one succeed.
2355+
ccmp->gtFlagsVal = TruthifyingFlags(cond2);
2356+
}
2357+
23432358
ContainCheckConditionalCompare(ccmp);
23442359

23452360
tree->SetOper(GT_SETCC);

0 commit comments

Comments
 (0)