Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
118 changes: 66 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,38 @@ 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;
}

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 +2336,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