Skip to content

Commit

Permalink
Emit mneg for mul+neg on Arm64 (#79550)
Browse files Browse the repository at this point in the history
  • Loading branch information
SwapnilGaikwad committed Jan 13, 2023
1 parent a2029fe commit 8a5b42f
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 15 deletions.
20 changes: 16 additions & 4 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3396,11 +3396,23 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
assert(targetReg != REG_NA);

GenTree* operand = tree->gtGetOp1();
assert(!operand->isContained());
// The src must be a register.
regNumber operandReg = genConsumeReg(operand);

GetEmitter()->emitIns_R_R(ins, emitActualTypeSize(tree), targetReg, operandReg);
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());
}
else
{
assert(!operand->isContained());
regNumber operandReg = genConsumeReg(operand);
GetEmitter()->emitIns_R_R(ins, emitActualTypeSize(tree), targetReg, operandReg);
}

genProduceReg(tree);
}
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ GenTree* Lowering::LowerNode(GenTree* node)
case GT_JTRUE:
return LowerJTrue(node->AsOp());

case GT_NEG:
#ifdef TARGET_ARM64
ContainCheckNeg(node->AsOp());
#endif
break;
case GT_SELECT:
ContainCheckSelect(node->AsConditional());
break;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Lowering final : public Phase
bool ContainCheckCompareChain(GenTree* child, GenTree* parent, GenTree** earliestValid);
void ContainCheckCompareChainForAnd(GenTree* tree);
void ContainCheckConditionalCompare(GenTreeOp* cmp);
void ContainCheckNeg(GenTreeOp* neg);
#endif
void ContainCheckSelect(GenTreeOp* select);
void ContainCheckBitCast(GenTree* node);
Expand Down
43 changes: 42 additions & 1 deletion src/coreclr/jit/lowerarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) co
return IsSafeToContainMem(parentNode, childNode);
}

// TODO: Handle mneg
return false;
}

Expand Down Expand Up @@ -2481,6 +2480,48 @@ void Lowering::ContainCheckSelect(GenTreeOp* node)
#endif
}

#ifdef TARGET_ARM64
//------------------------------------------------------------------------
// ContainCheckNeg : determine whether the source of a neg should be contained.
//
// Arguments:
// node - pointer to the node
//
void Lowering::ContainCheckNeg(GenTreeOp* neg)
{
if (neg->isContained())
return;

if (!varTypeIsIntegral(neg))
return;

if ((neg->gtFlags & GTF_SET_FLAGS))
return;

GenTree* childNode = neg->gtGetOp1();
if (childNode->OperIs(GT_MUL))
{
// Find - (a * b)
if (childNode->gtGetOp1()->isContained() || childNode->gtGetOp2()->isContained())
return;

if (childNode->gtOverflow())
return;

if (!varTypeIsIntegral(childNode))
return;

if ((childNode->gtFlags & GTF_SET_FLAGS))
return;

if (IsSafeToContainMem(neg, childNode))
{
MakeSrcContained(neg, childNode);
}
}
}
#endif // TARGET_ARM64

//------------------------------------------------------------------------
// ContainCheckBoundsChk: determine whether any source of a bounds check node should be contained.
//
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/jit/lsraarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,7 @@ int LinearScan::BuildNode(GenTree* tree)

case GT_NEG:
case GT_NOT:
BuildUse(tree->gtGetOp1());
srcCount = 1;
srcCount = BuildOperandUses(tree->gtGetOp1(), RBM_NONE);
assert(dstCount == 1);
BuildDef(tree);
break;
Expand Down
41 changes: 34 additions & 7 deletions src/tests/JIT/opt/InstructionCombining/NegMulOrDivToConst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,17 @@ static int CheckMulNeg()
fail = true;
}


try
{
CheckedMulNenIntMin(1);
CheckedMulNegIntMin(1);
fail = true;
}
catch
{ }

try
{
CheckedMulNenIntMin(0);
CheckedMulNegIntMin(0);

}
catch
Expand Down Expand Up @@ -81,6 +80,10 @@ static int CheckMulNeg()
catch
{ }

if (MulNegCombined(3, 4) != -12)
{
fail = true;
}

if (fail)
{
Expand All @@ -100,7 +103,7 @@ static int CheckMulNeg()
static int MulNegIntMin(int a) => -a * int.MinValue;

[MethodImpl(MethodImplOptions.NoInlining)]
static int CheckedMulNenIntMin(int a)
static int CheckedMulNegIntMin(int a)
{
checked
{
Expand Down Expand Up @@ -166,7 +169,12 @@ static int CheckNegMul()
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int NegMul7(int a) => -(a * 7);
static int NegMul7(int a)
{
//ARM64-FULL-LINE: movn {{w[0-9]+}}, #6
//ARM64-FULL-LINE-NEXT: mul {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return -(a * 7);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int NegMulIntMinValue(int a) => -(a * int.MinValue);
Expand Down Expand Up @@ -218,10 +226,29 @@ static int CheckDivNeg()
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int DivNeg11(int a) => -a / 11;
static int MulNegCombined(int a, int b)
{
//ARM64-FULL-LINE: mneg {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
return a * b * -1;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int DivNeg11(int a)
{
//ARM64-FULL-LINE: smull {{x[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}
//ARM64-FULL-LINE-NEXT: asr {{x[0-9]+}}, {{x[0-9]+}}, #32
//ARM64-FULL-LINE-NEXT: asr {{w[0-9]+}}, {{w[0-9]+}}, #1
return -a / 11;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static long LongDivNeg1000(long a) => -a / 1000;
static long LongDivNeg1000(long a)
{
//ARM64-FULL-LINE: smulh {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}
//ARM64-FULL-LINE-NEXT: asr {{x[0-9]+}}, {{x[0-9]+}}, #7
//ARM64-FULL-LINE-NEXT: add {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, LSR #63
return -a / 1000;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static int DivNegIntMinValue(int a) => -a / int.MinValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="NegMulOrDivToConst.cs" />
<Compile Include="NegMulOrDivToConst.cs">
<HasDisasmCheck>true</HasDisasmCheck>
</Compile>
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" />
<CLRTestEnvironmentVariable Include="DOTNET_JITMinOpts" Value="0" />
</ItemGroup>
</Project>

0 comments on commit 8a5b42f

Please sign in to comment.