@@ -14942,25 +14942,32 @@ void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr *
1494214942
1494314943GenTree* 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}
0 commit comments