Skip to content

Commit f595fa3

Browse files
Move the folding of double not/neg to gtFoldExpr (#128187)
This moves some of the folding for not/neg from morph to gtFoldExpr, allowing earlier elimination of trivially unnecessary nodes. It provides some measurable TP improvements -- noting that I'd guess most of that might be attributed to the reordering of checks in `gtFoldExpr` to enable `gtFoldExprUnary` existing, but there is benefit as is showcased from the SPMI numbers between T0 and FullOpts
1 parent 1acc89c commit f595fa3

3 files changed

Lines changed: 117 additions & 57 deletions

File tree

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3940,6 +3940,8 @@ class Compiler
39403940
//-------------------------------------------------------------------------
39413941

39423942
GenTree* gtFoldExpr(GenTree* tree);
3943+
GenTree* gtFoldExprUnary(GenTreeUnOp* tree);
3944+
GenTree* gtFoldExprBinary(GenTreeOp* tree);
39433945
GenTree* gtFoldExprConst(GenTree* tree);
39443946
GenTree* gtFoldIndirConst(GenTreeIndir* indir);
39453947
GenTree* gtFoldExprSpecial(GenTree* tree);

src/coreclr/jit/gentree.cpp

Lines changed: 115 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14942,25 +14942,32 @@ void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr *
1494214942

1494314943
GenTree* Compiler::gtFoldExpr(GenTree* tree)
1494414944
{
14945-
unsigned kind = tree->OperKind();
14946-
14947-
/* We must have a simple operation to fold */
14945+
// We should never be called from CSE. Various optimizations below
14946+
// assume that it is safe to swap operands if one is a constant.
14947+
assert(!optValnumCSE_phase);
1494814948

14949-
// If we're in CSE, it's not safe to perform tree
14950-
// folding given that it can will potentially
14951-
// change considered CSE candidates.
14952-
if (optValnumCSE_phase)
14949+
if (!opts.Tier0OptimizationEnabled())
1495314950
{
1495414951
return tree;
1495514952
}
1495614953

14957-
if (!opts.Tier0OptimizationEnabled())
14954+
if (tree->OperIsLeaf())
1495814955
{
14956+
// Nothing to fold
1495914957
return tree;
1496014958
}
14961-
14962-
if (!(kind & GTK_SMPOP))
14959+
else if (tree->OperIsBinary())
14960+
{
14961+
return gtFoldExprBinary(tree->AsOp());
14962+
}
14963+
else if (tree->OperIsUnary())
14964+
{
14965+
return gtFoldExprUnary(tree->AsUnOp());
14966+
}
14967+
else
1496314968
{
14969+
assert(tree->OperIsSpecial());
14970+
1496414971
if (tree->OperIsConditional())
1496514972
{
1496614973
return gtFoldExprConditional(tree);
@@ -14975,65 +14982,126 @@ GenTree* Compiler::gtFoldExpr(GenTree* tree)
1497514982

1497614983
return tree;
1497714984
}
14985+
}
1497814986

14979-
GenTree* op1 = tree->AsOp()->gtOp1;
14987+
//------------------------------------------------------------------------
14988+
// gtFoldExprUnary: see if an unary operation is foldable
14989+
//
14990+
// Arguments:
14991+
// tree - tree to examine
14992+
//
14993+
// Returns:
14994+
// The original tree if no folding happened.
14995+
// An alternative tree if folding happens.
14996+
//
14997+
GenTree* Compiler::gtFoldExprUnary(GenTreeUnOp* tree)
14998+
{
14999+
assert(tree->OperIsUnary());
15000+
assert(!optValnumCSE_phase);
15001+
assert(opts.Tier0OptimizationEnabled());
1498015002

14981-
/* Filter out non-foldable trees that can have constant children */
15003+
GenTree* op1 = tree->gtGetOp1();
1498215004

14983-
assert(kind & (GTK_UNOP | GTK_BINOP));
14984-
switch (tree->gtOper)
15005+
if ((op1 == nullptr) || tree->OperIs(GT_RETFILT, GT_RETURN, GT_IND))
1498515006
{
14986-
case GT_RETFILT:
14987-
case GT_RETURN:
14988-
case GT_IND:
14989-
return tree;
14990-
default:
14991-
break;
15007+
// Filter out non-foldable trees
15008+
return tree;
15009+
}
15010+
15011+
if (op1->OperIsConst())
15012+
{
15013+
return gtFoldExprConst(tree);
1499215014
}
1499315015

14994-
/* try to fold the current node */
15016+
genTreeOps oper = tree->OperGet();
15017+
15018+
// We intentionally do not destroy the nodes as some places check if
15019+
// folding produces a constant and throws the result away otherwise
1499515020

14996-
if ((kind & GTK_UNOP) && op1)
15021+
switch (oper)
1499715022
{
14998-
if (op1->OperIsConst())
15023+
case GT_NOT:
1499915024
{
15000-
return gtFoldExprConst(tree);
15025+
if (op1->OperIs(oper))
15026+
{
15027+
JITDUMP("Folding ~(~a) => a\n")
15028+
return op1->gtGetOp1();
15029+
}
15030+
break;
15031+
}
15032+
15033+
case GT_NEG:
15034+
{
15035+
if (op1->OperIs(oper))
15036+
{
15037+
JITDUMP("Folding -(-a) => a\n")
15038+
return op1->gtGetOp1();
15039+
}
15040+
break;
15041+
}
15042+
15043+
default:
15044+
{
15045+
break;
1500115046
}
1500215047
}
15003-
else if ((kind & GTK_BINOP) && op1 && tree->AsOp()->gtOp2)
15048+
15049+
return tree;
15050+
}
15051+
15052+
//------------------------------------------------------------------------
15053+
// gtFoldExprBinary: see if a binary operation is foldable
15054+
//
15055+
// Arguments:
15056+
// tree - tree to examine
15057+
//
15058+
// Returns:
15059+
// The original tree if no folding happened.
15060+
// An alternative tree if folding happens.
15061+
//
15062+
GenTree* Compiler::gtFoldExprBinary(GenTreeOp* tree)
15063+
{
15064+
assert(tree->OperIsBinary());
15065+
assert(!optValnumCSE_phase);
15066+
assert(opts.Tier0OptimizationEnabled());
15067+
15068+
GenTree* op1 = tree->gtGetOp1();
15069+
GenTree* op2 = tree->gtGetOp2();
15070+
15071+
if ((op1 == nullptr) || (op2 == nullptr) || tree->OperIsAtomicOp())
1500415072
{
15005-
GenTree* op2 = tree->AsOp()->gtOp2;
15073+
// Filter out non-foldable trees
15074+
// The atomic operations are exempted here because they are never computable statically; one of their arguments
15075+
// is an address.
15076+
return tree;
15077+
}
1500615078

15007-
// The atomic operations are exempted here because they are never computable statically;
15008-
// one of their arguments is an address.
15009-
if (op1->OperIsConst() && op2->OperIsConst() && !tree->OperIsAtomicOp())
15079+
if (op1->OperIsConst())
15080+
{
15081+
if (op2->OperIsConst())
1501015082
{
15011-
/* both nodes are constants - fold the expression */
15083+
// both nodes are constants - fold the expression
1501215084
return gtFoldExprConst(tree);
1501315085
}
15014-
else if (op1->OperIsConst() || op2->OperIsConst())
15086+
else if (opts.OptimizationEnabled())
1501515087
{
15016-
// At least one is a constant - see if we have a
15017-
// special operator that can use only one constant
15018-
// to fold - e.g. booleans
15019-
15020-
if (opts.OptimizationDisabled())
15021-
{
15022-
// Too heavy for tier0
15023-
return tree;
15024-
}
15025-
15088+
// Too heavy for tier0, so only do when opts are enabled
1502615089
return gtFoldExprSpecial(tree);
1502715090
}
15028-
else if (tree->OperIsCompare())
15091+
}
15092+
else if (op2->OperIsConst())
15093+
{
15094+
if (opts.OptimizationEnabled())
1502915095
{
15030-
/* comparisons of two local variables can sometimes be folded */
15031-
15032-
return gtFoldExprCompare(tree);
15096+
// Too heavy for tier0, so only do when opts are enabled
15097+
return gtFoldExprSpecial(tree);
1503315098
}
1503415099
}
15035-
15036-
/* Return the original node (folded/bashed or not) */
15100+
else if (tree->OperIsCompare())
15101+
{
15102+
// comparisons of two local variables can sometimes be folded
15103+
return gtFoldExprCompare(tree);
15104+
}
1503715105

1503815106
return tree;
1503915107
}

src/coreclr/jit/morph.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8174,16 +8174,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, bool* optAssertionPropDone)
81748174
break;
81758175
}
81768176

8177-
// Remove double negation/not.
8178-
if (op1->OperIs(oper))
8179-
{
8180-
JITDUMP("Remove double negation/not\n")
8181-
GenTree* op1op1 = op1->gtGetOp1();
8182-
DEBUG_DESTROY_NODE(tree);
8183-
DEBUG_DESTROY_NODE(op1);
8184-
return op1op1;
8185-
}
8186-
81878177
// Distribute negation over simple multiplication/division expressions
81888178
if (tree->OperIs(GT_NEG) && op1->OperIs(GT_MUL, GT_DIV))
81898179
{

0 commit comments

Comments
 (0)