Skip to content

Commit 017db9b

Browse files
authored
JIT: Add some more constant folding in lowering (dotnet#113301)
* JIT: Introduce `LclVarDsc::lvIsMultiRegDest` With recent work to expand returned promoted locals into `FIELD_LIST` the only "whole references" of promoted locals we should see is when stored from a multi-reg node. This is the only knowledge the backend should need for correctness purposes, so introduce a bit to track this property, and switch the backend to check this instead. The existing `lvIsMultiRegRet` is essentially this + whether the local is returned. We should be able to remove this, but it is currently used for some heuristics in old promotion, so keep it around for now. * JIT: Add some more constant folding in lowering Add folding for shifts and certain binops that are now getting produced late due to returned `FIELD_LIST` nodes. win-arm64 example: ```csharp [MethodImpl(MethodImplOptions.NoInlining)] static ValueTask<byte> Foo() { return new ValueTask<byte>(123); } ``` ```diff G_M17084_IG02: ;; offset=0x0008 mov x0, xzr - mov w1, #1 - mov w2, wzr - mov w3, dotnet#123 - orr w2, w2, w3, LSL #16 - orr w1, w2, w1, LSL dotnet#24 - ;; size=24 bbWeight=1 PerfScore 4.00 + mov w1, #0x17B0000 + ;; size=8 bbWeight=1 PerfScore 1.00 ``` * Feedback
1 parent cc80345 commit 017db9b

File tree

2 files changed

+93
-9
lines changed

2 files changed

+93
-9
lines changed

src/coreclr/jit/lower.cpp

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -437,14 +437,20 @@ GenTree* Lowering::LowerNode(GenTree* node)
437437
case GT_OR:
438438
case GT_XOR:
439439
{
440-
if (comp->opts.OptimizationEnabled() && node->OperIs(GT_AND))
440+
if (comp->opts.OptimizationEnabled())
441441
{
442442
GenTree* nextNode = nullptr;
443-
if (TryLowerAndNegativeOne(node->AsOp(), &nextNode))
443+
if (node->OperIs(GT_AND) && TryLowerAndNegativeOne(node->AsOp(), &nextNode))
444444
{
445445
return nextNode;
446446
}
447447
assert(nextNode == nullptr);
448+
449+
nextNode = node->gtNext;
450+
if (node->OperIs(GT_AND, GT_OR, GT_XOR) && TryFoldBinop(node->AsOp()))
451+
{
452+
return nextNode;
453+
}
448454
}
449455

450456
return LowerBinaryArithmetic(node->AsOp());
@@ -538,13 +544,16 @@ GenTree* Lowering::LowerNode(GenTree* node)
538544

539545
case GT_CAST:
540546
{
541-
if (!TryRemoveCast(node->AsCast()))
547+
GenTree* nextNode = node->gtNext;
548+
if (TryRemoveCast(node->AsCast()))
542549
{
543-
GenTree* nextNode = LowerCast(node);
544-
if (nextNode != nullptr)
545-
{
546-
return nextNode;
547-
}
550+
return nextNode;
551+
}
552+
553+
nextNode = LowerCast(node);
554+
if (nextNode != nullptr)
555+
{
556+
return nextNode;
548557
}
549558
}
550559
break;
@@ -567,8 +576,16 @@ GenTree* Lowering::LowerNode(GenTree* node)
567576

568577
case GT_ROL:
569578
case GT_ROR:
579+
{
580+
GenTree* next = node->gtNext;
581+
if (comp->opts.OptimizationEnabled() && TryFoldBinop(node->AsOp()))
582+
{
583+
return next;
584+
}
585+
570586
LowerRotate(node);
571587
break;
588+
}
572589

573590
#ifndef TARGET_64BIT
574591
case GT_LSH_HI:
@@ -580,12 +597,20 @@ GenTree* Lowering::LowerNode(GenTree* node)
580597
case GT_LSH:
581598
case GT_RSH:
582599
case GT_RSZ:
600+
{
601+
GenTree* next = node->gtNext;
602+
if (comp->opts.OptimizationEnabled() && TryFoldBinop(node->AsOp()))
603+
{
604+
return next;
605+
}
606+
583607
#if defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
584608
LowerShift(node->AsOp());
585609
#else
586610
ContainCheckShiftRotate(node->AsOp());
587611
#endif
588612
break;
613+
}
589614

590615
case GT_STORE_BLK:
591616
if (node->AsBlk()->Data()->IsCall())
@@ -7752,6 +7777,64 @@ GenTree* Lowering::LowerSignedDivOrMod(GenTree* node)
77527777
return node->gtNext;
77537778
}
77547779

7780+
//------------------------------------------------------------------------
7781+
// TryFoldBinop: Try removing a binop node by constant folding.
7782+
//
7783+
// Parameters:
7784+
// node - the node
7785+
//
7786+
// Returns:
7787+
// True if the node was removed
7788+
//
7789+
bool Lowering::TryFoldBinop(GenTreeOp* node)
7790+
{
7791+
if (node->gtSetFlags())
7792+
{
7793+
return false;
7794+
}
7795+
7796+
GenTree* op1 = node->gtGetOp1();
7797+
GenTree* op2 = node->gtGetOp2();
7798+
7799+
if (op1->IsIntegralConst() && op2->IsIntegralConst())
7800+
{
7801+
GenTree* folded = comp->gtFoldExprConst(node);
7802+
assert(folded == node);
7803+
if (!folded->OperIsConst())
7804+
{
7805+
return false;
7806+
}
7807+
7808+
BlockRange().Remove(op1);
7809+
BlockRange().Remove(op2);
7810+
return true;
7811+
}
7812+
7813+
if (node->OperIs(GT_LSH, GT_RSH, GT_RSZ, GT_ROL, GT_ROR, GT_OR, GT_XOR) &&
7814+
(op1->IsIntegralConst(0) || op2->IsIntegralConst(0)))
7815+
{
7816+
GenTree* zeroOp = op1->IsIntegralConst(0) ? op1 : op2;
7817+
GenTree* otherOp = zeroOp == op1 ? op2 : op1;
7818+
7819+
LIR::Use use;
7820+
if (BlockRange().TryGetUse(node, &use))
7821+
{
7822+
use.ReplaceWith(otherOp);
7823+
}
7824+
else
7825+
{
7826+
otherOp->SetUnusedValue();
7827+
}
7828+
7829+
BlockRange().Remove(node);
7830+
BlockRange().Remove(zeroOp);
7831+
7832+
return true;
7833+
}
7834+
7835+
return false;
7836+
}
7837+
77557838
//------------------------------------------------------------------------
77567839
// LowerShift: Lower shift nodes
77577840
//
@@ -7761,7 +7844,7 @@ GenTree* Lowering::LowerSignedDivOrMod(GenTree* node)
77617844
// Notes:
77627845
// Remove unnecessary shift count masking, xarch shift instructions
77637846
// mask the shift count to 5 bits (or 6 bits for 64 bit operations).
7764-
7847+
//
77657848
void Lowering::LowerShift(GenTreeOp* shift)
77667849
{
77677850
assert(shift->OperIs(GT_LSH, GT_RSH, GT_RSZ));

src/coreclr/jit/lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ class Lowering final : public Phase
432432
GenTree* LowerStoreLoc(GenTreeLclVarCommon* tree);
433433
void LowerRotate(GenTree* tree);
434434
void LowerShift(GenTreeOp* shift);
435+
bool TryFoldBinop(GenTreeOp* node);
435436
#ifdef FEATURE_HW_INTRINSICS
436437
GenTree* LowerHWIntrinsic(GenTreeHWIntrinsic* node);
437438
void LowerHWIntrinsicCC(GenTreeHWIntrinsic* node, NamedIntrinsic newIntrinsicId, GenCondition condition);

0 commit comments

Comments
 (0)