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
92 changes: 80 additions & 12 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3369,13 +3369,40 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
// The src must be a register.
if (tree->OperIs(GT_NEG) && operand->isContained())
{
ins = INS_mneg;
GenTree* op1 = tree->gtGetOp1();
GenTree* a = op1->gtGetOp1();
GenTree* b = op1->gtGetOp2();
genConsumeRegs(op1);
assert(op1->OperGet() == GT_MUL);
GetEmitter()->emitIns_R_R_R(ins, emitActualTypeSize(tree), targetReg, a->GetRegNum(), b->GetRegNum());
genTreeOps oper = operand->OperGet();
switch (oper)
{
case GT_MUL:
{
ins = INS_mneg;
GenTree* op1 = tree->gtGetOp1();
GenTree* a = op1->gtGetOp1();
GenTree* b = op1->gtGetOp2();
genConsumeRegs(op1);
GetEmitter()->emitIns_R_R_R(ins, emitActualTypeSize(tree), targetReg, a->GetRegNum(), b->GetRegNum());
}
break;

case GT_LSH:
case GT_RSH:
case GT_RSZ:
{
assert(ins == INS_neg || ins == INS_negs);
assert(operand->gtGetOp2()->IsCnsIntOrI());
assert(operand->gtGetOp2()->isContained());

GenTree* op1 = tree->gtGetOp1();
GenTree* a = op1->gtGetOp1();
GenTree* b = op1->gtGetOp2();
genConsumeRegs(op1);
GetEmitter()->emitIns_R_R_I(ins, emitActualTypeSize(tree), targetReg, a->GetRegNum(),
b->AsIntConCommon()->IntegralValue(), ShiftOpToInsOpts(oper));
}
break;

default:
unreached();
}
}
else
{
Expand Down Expand Up @@ -4534,12 +4561,53 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
}
else if (op2->isContained())
{
assert(op2->OperIs(GT_LSH, GT_RSH, GT_RSZ));
assert(op2->gtGetOp2()->IsCnsIntOrI());
assert(op2->gtGetOp2()->isContained());
genTreeOps oper = op2->OperGet();
switch (oper)
{
case GT_NEG:
assert(ins == INS_cmp);

ins = INS_cmn;
oper = op2->gtGetOp1()->OperGet();
switch (oper)
{
case GT_LSH:
case GT_RSH:
case GT_RSZ:
{
GenTree* shiftOp1 = op2->gtGetOp1()->gtGetOp1();
GenTree* shiftOp2 = op2->gtGetOp1()->gtGetOp2();

assert(op2->gtGetOp1()->isContained());
assert(shiftOp2->IsCnsIntOrI());
assert(shiftOp2->isContained());

emit->emitIns_R_R_I(ins, cmpSize, op1->GetRegNum(), shiftOp1->GetRegNum(),
shiftOp2->AsIntConCommon()->IntegralValue(), ShiftOpToInsOpts(oper));
}
break;

default:
assert(!op2->gtGetOp1()->isContained());

emit->emitIns_R_R(ins, cmpSize, op1->GetRegNum(), op2->gtGetOp1()->GetRegNum());
break;
}
break;

case GT_LSH:
case GT_RSH:
case GT_RSZ:
assert(op2->gtGetOp2()->IsCnsIntOrI());
assert(op2->gtGetOp2()->isContained());

emit->emitIns_R_R_I(ins, cmpSize, op1->GetRegNum(), op2->gtGetOp1()->GetRegNum(),
op2->gtGetOp2()->AsIntConCommon()->IntegralValue(), ShiftOpToInsOpts(oper));
break;

emit->emitIns_R_R_I(ins, cmpSize, op1->GetRegNum(), op2->gtGetOp1()->GetRegNum(),
op2->gtGetOp2()->AsIntConCommon()->IntegralValue(), ShiftOpToInsOpts(op2->gtOper));
default:
unreached();
}
}
else
{
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3775,7 +3775,7 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue)
jtrue->AsCC()->gtCondition = condCode;
}

JITDUMP("Result:\n");
JITDUMP("Lowering JTRUE Result:\n");
DISPTREERANGE(BlockRange(), jtrue);
JITDUMP("\n");

Expand Down Expand Up @@ -3876,6 +3876,10 @@ GenTree* Lowering::LowerSelect(GenTreeConditional* select)
//
bool Lowering::TryLowerConditionToFlagsNode(GenTree* parent, GenTree* condition, GenCondition* cond)
{
JITDUMP("Lowering condition:\n");
DISPTREERANGE(BlockRange(), condition);
JITDUMP("\n");

if (condition->OperIsCompare())
{
if (!IsInvariantInRange(condition, parent))
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ class Lowering final : public Phase
}

#ifdef TARGET_ARM64
bool IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) const;
bool IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childNode) const;
#endif // TARGET_ARM64

#if defined(FEATURE_HW_INTRINSICS)
Expand Down
66 changes: 55 additions & 11 deletions src/coreclr/jit/lowerarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,28 @@ bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) const

#ifdef TARGET_ARM64
//------------------------------------------------------------------------
// IsContainableBinaryOp: Is the child node a binary op that is containable from the parent node?
// IsContainableUnaryOrBinaryOp: Is the child node a unary/binary op that is containable from the parent node?
//
// Return Value:
// True if the child node can be contained.
//
// Notes:
// This can handle the decision to emit 'madd' or 'msub'.
//
bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) const
bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childNode) const
{
#ifdef DEBUG
// The node we're checking should be one of the two child nodes
assert((parentNode->gtGetOp1() == childNode) || (parentNode->gtGetOp2() == childNode));
if (parentNode->OperIsBinary())
{
assert((parentNode->gtGetOp1() == childNode) || (parentNode->gtGetOp2() == childNode));
}
else
{
assert(parentNode->OperIsUnary());
assert((parentNode->gtGetOp1() == childNode));
}
#endif // DEBUG

// We cannot contain if the parent node
// * is contained
Expand All @@ -173,7 +183,7 @@ bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) co
if (!varTypeIsIntegral(parentNode))
return false;

if (parentNode->gtGetOp1()->isContained() || parentNode->gtGetOp2()->isContained())
if (parentNode->gtGetOp1()->isContained() || (parentNode->OperIsBinary() && parentNode->gtGetOp2()->isContained()))
return false;

if (parentNode->OperMayOverflow() && parentNode->gtOverflow())
Expand Down Expand Up @@ -252,7 +262,7 @@ bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) co
return false;
}

if (parentNode->OperIs(GT_ADD, GT_SUB, GT_AND))
if (parentNode->OperIs(GT_ADD, GT_SUB, GT_AND, GT_NEG))
{
// These operations can still report flags

Expand Down Expand Up @@ -282,6 +292,32 @@ bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) co
return false;
}

if (childNode->OperIs(GT_NEG))
{
// If we have a contained LSH, RSH or RSZ, we can still contain NEG if the parent is a CMP or comparison op.
if (childNode->gtGetOp1()->isContained() && !childNode->gtGetOp1()->OperIs(GT_LSH, GT_RSH, GT_RSZ))
{
// Cannot contain if the childs op1 is already contained
return false;
}

if ((parentNode->gtFlags & GTF_SET_FLAGS) != 0)
{
// Cannot contain if the parent operation needs to set flags
return false;
}

if (parentNode->OperIs(GT_CMP) || parentNode->OperIsCompare())
{
if (IsInvariantInRange(childNode, parentNode))
{
return true;
}
}

return false;
}

if (childNode->OperIs(GT_CAST))
{
// Find "a op cast(b)"
Expand Down Expand Up @@ -2027,7 +2063,7 @@ void Lowering::ContainCheckBinary(GenTreeOp* node)
#ifdef TARGET_ARM64
if (comp->opts.OptimizationEnabled())
{
if (IsContainableBinaryOp(node, op2))
if (IsContainableUnaryOrBinaryOp(node, op2))
{
if (op2->OperIs(GT_CAST))
{
Expand All @@ -2039,7 +2075,7 @@ void Lowering::ContainCheckBinary(GenTreeOp* node)
return;
}

if (node->OperIsCommutative() && IsContainableBinaryOp(node, op1))
if (node->OperIsCommutative() && IsContainableUnaryOrBinaryOp(node, op1))
{
if (op1->OperIs(GT_CAST))
{
Expand Down Expand Up @@ -2259,19 +2295,22 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
}

#ifdef TARGET_ARM64
if (comp->opts.OptimizationEnabled() && cmp->OperIsCompare())
if (comp->opts.OptimizationEnabled() && (cmp->OperIsCompare() || cmp->OperIs(GT_CMP)))
{
if (IsContainableBinaryOp(cmp, op2))
if (IsContainableUnaryOrBinaryOp(cmp, op2))
{
MakeSrcContained(cmp, op2);
return;
}

if (IsContainableBinaryOp(cmp, op1))
if (IsContainableUnaryOrBinaryOp(cmp, op1))
{
MakeSrcContained(cmp, op1);
std::swap(cmp->gtOp1, cmp->gtOp2);
cmp->SetOper(cmp->SwapRelop(cmp->gtOper));
if (cmp->OperIsCompare())
{
cmp->SetOper(cmp->SwapRelop(cmp->gtOper));
}
return;
}
}
Expand Down Expand Up @@ -2501,6 +2540,11 @@ void Lowering::ContainCheckNeg(GenTreeOp* neg)
MakeSrcContained(neg, childNode);
}
}
else if (comp->opts.OptimizationEnabled() && childNode->OperIs(GT_LSH, GT_RSH, GT_RSZ) &&
IsContainableUnaryOrBinaryOp(neg, childNode))
{
MakeSrcContained(neg, childNode);
}
}

//----------------------------------------------------------------------------------------------
Expand Down