Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Lowering final : public Phase
void ContainCheckLclHeap(GenTreeOp* node);
void ContainCheckRet(GenTreeUnOp* ret);
#ifdef TARGET_ARM64
GenTree* TryLowerAndToCCMP(GenTreeOp* tree);
GenTree* TryLowerAndOrToCCMP(GenTreeOp* tree);
insCflags TruthifyingFlags(GenCondition cond);
void ContainCheckConditionalCompare(GenTreeCCMP* ccmp);
void ContainCheckNeg(GenTreeOp* neg);
Expand Down
119 changes: 67 additions & 52 deletions src/coreclr/jit/lowerarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,32 +457,36 @@ GenTree* Lowering::LowerMul(GenTreeOp* mul)
//
GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp)
{
if (comp->opts.OptimizationEnabled() && binOp->OperIs(GT_AND))
if (comp->opts.OptimizationEnabled())
{
GenTree* opNode = nullptr;
GenTree* notNode = nullptr;
if (binOp->gtGetOp1()->OperIs(GT_NOT))
{
notNode = binOp->gtGetOp1();
opNode = binOp->gtGetOp2();
}
else if (binOp->gtGetOp2()->OperIs(GT_NOT))
if (binOp->OperIs(GT_AND))
{
notNode = binOp->gtGetOp2();
opNode = binOp->gtGetOp1();
}
GenTree* opNode = nullptr;
GenTree* notNode = nullptr;
if (binOp->gtGetOp1()->OperIs(GT_NOT))
{
notNode = binOp->gtGetOp1();
opNode = binOp->gtGetOp2();
}
else if (binOp->gtGetOp2()->OperIs(GT_NOT))
{
notNode = binOp->gtGetOp2();
opNode = binOp->gtGetOp1();
}

if (notNode != nullptr)
{
binOp->gtOp1 = opNode;
binOp->gtOp2 = notNode->AsUnOp()->gtGetOp1();
binOp->ChangeOper(GT_AND_NOT);
BlockRange().Remove(notNode);
if (notNode != nullptr)
{
binOp->gtOp1 = opNode;
binOp->gtOp2 = notNode->AsUnOp()->gtGetOp1();
binOp->ChangeOper(GT_AND_NOT);
BlockRange().Remove(notNode);
}
}

#ifdef TARGET_ARM64
else
if (binOp->OperIs(GT_AND, GT_OR))
{
GenTree* next = TryLowerAndToCCMP(binOp);
GenTree* next = TryLowerAndOrToCCMP(binOp);
if (next != nullptr)
{
return next;
Expand Down Expand Up @@ -2268,14 +2272,14 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)

#ifdef TARGET_ARM64
//------------------------------------------------------------------------
// TryLowerAndToCCMP : Lower an and of two conditions into test + CCMP + SETCC nodes.
// TryLowerAndOrToCCMP : Lower AND/OR of two conditions into test + CCMP + SETCC nodes.
//
// Arguments:
// tree - pointer to the node
//
GenTree* Lowering::TryLowerAndToCCMP(GenTreeOp* tree)
GenTree* Lowering::TryLowerAndOrToCCMP(GenTreeOp* tree)
{
assert(tree->OperIs(GT_AND));
assert(tree->OperIs(GT_AND, GT_OR));

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

// Find out whether op2 is eligible to be converted to a conditional
if ((op1->OperIsCmpCompare() && varTypeIsIntegralOrI(op1->gtGetOp1())) ||
(op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1())))
{
JITDUMP("[%06u] is a potential candidate for CCMP:\n", Compiler::dspTreeID(tree));
DISPTREERANGE(BlockRange(), tree);
JITDUMP("\n");
}

// Find out whether an operand is eligible to be converted to a conditional
// compare. It must be a normal integral relop; for example, we cannot
// conditionally perform a floating point comparison and there is no "ctst"
// instruction that would allow us to conditionally implement
// TEST_EQ/TEST_NE.
//
if (!op2->OperIsCmpCompare() || !varTypeIsIntegral(op2->gtGetOp1()))
{
return nullptr;
}

// For op1 we can allow more arbitrary operations that set the condition
// flags; the final transformation into the flags def is done by
// TryLowerConditionToFlagsNode below, but we have a quick early out here
// too.
// For the other operand we can allow more arbitrary operations that set
// the condition flags; the final transformation into the flags def is done
// by TryLowerConditionToFlagsNode.
//
if (!op1->OperIsCompare() && !op1->OperIs(GT_SETCC))
GenCondition cond1;
if (op2->OperIsCmpCompare() && varTypeIsIntegralOrI(op2->gtGetOp1()) && IsInvariantInRange(op2, tree) &&
TryLowerConditionToFlagsNode(tree, op1, &cond1))
{
return nullptr;
// Fall through, converting op2 to the CCMP
}

JITDUMP("[%06u] is a candidate for CCMP:\n", Compiler::dspTreeID(tree));
DISPTREERANGE(BlockRange(), tree);
JITDUMP("\n");

// We leave checking invariance of op1 to tree to TryLowerConditionToFlagsNode.
if (!IsInvariantInRange(op2, tree))
else if (op1->OperIsCmpCompare() && varTypeIsIntegralOrI(op1->gtGetOp1()) && IsInvariantInRange(op1, tree) &&
TryLowerConditionToFlagsNode(tree, op2, &cond1))
{
JITDUMP(" ..cannot move [%06u], bailing\n", Compiler::dspTreeID(op2));
return nullptr;
std::swap(op1, op2);
}

GenCondition cond1;
if (!TryLowerConditionToFlagsNode(tree, op1, &cond1))
else
{
JITDUMP(" ..could not turn [%06u] into a def of flags, bailing\n", Compiler::dspTreeID(op1));
JITDUMP(" ..could not turn [%06u] or [%06u] into a def of flags, bailing\n", Compiler::dspTreeID(op1),
Compiler::dspTreeID(op2));
return nullptr;
}

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

GenTreeCCMP* ccmp = op2->AsCCMP();
ccmp->gtCondition = cond1;
// If the first comparison fails, set the condition flags to something that
// makes the second one fail as well so that the overall AND failed.
ccmp->gtFlagsVal = TruthifyingFlags(GenCondition::Reverse(cond2));

if (tree->OperIs(GT_AND))
{
// If the first comparison succeeds then do the second comparison.
ccmp->gtCondition = cond1;
// Otherwise set the condition flags to something that makes the second
// one fail.
ccmp->gtFlagsVal = TruthifyingFlags(GenCondition::Reverse(cond2));
}
else
{
// If the first comparison fails then do the second comparison.
ccmp->gtCondition = GenCondition::Reverse(cond1);
// Otherwise set the condition flags to something that makes the second
// one succeed.
ccmp->gtFlagsVal = TruthifyingFlags(cond2);
}

ContainCheckConditionalCompare(ccmp);

tree->SetOper(GT_SETCC);
Expand Down