From 960870a6b8a3fd744be3588e66ce641a2e995a8b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 12 Jun 2024 16:10:36 -0700 Subject: [PATCH] Allow gtFoldExprSpecial to handle side effects --- src/coreclr/jit/gentree.cpp | 91 +++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ab5798358ed81b..d9c84426609d06 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -14322,15 +14322,12 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) val = cons->AsIntConCommon()->IconValue(); - // Transforms that would drop op cannot be performed if op has side effects - bool opHasSideEffects = (op->gtFlags & GTF_SIDE_EFFECT) != 0; - // Helper function that creates a new IntCon node and morphs it, if required auto NewMorphedIntConNode = [&](int value) -> GenTreeIntCon* { GenTreeIntCon* icon = gtNewIconNode(value); if (fgGlobalMorph) { - fgMorphTreeDone(icon); + INDEBUG(icon->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); } return icon; }; @@ -14365,43 +14362,52 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) switch (oper) { case GT_LE: - if (tree->IsUnsigned() && (val == 0) && (op1 == cons) && !opHasSideEffects) + { + if (tree->IsUnsigned() && (val == 0) && (op1 == cons)) { // unsigned (0 <= x) is always true - op = NewMorphedIntConNode(1); + op = gtWrapWithSideEffects(NewMorphedIntConNode(1), op, GTF_ALL_EFFECT); goto DONE_FOLD; } break; + } case GT_GE: - if (tree->IsUnsigned() && (val == 0) && (op2 == cons) && !opHasSideEffects) + { + if (tree->IsUnsigned() && (val == 0) && (op2 == cons)) { // unsigned (x >= 0) is always true - op = NewMorphedIntConNode(1); + op = gtWrapWithSideEffects(NewMorphedIntConNode(1), op, GTF_ALL_EFFECT); goto DONE_FOLD; } break; + } case GT_LT: - if (tree->IsUnsigned() && (val == 0) && (op2 == cons) && !opHasSideEffects) + { + if (tree->IsUnsigned() && (val == 0) && (op2 == cons)) { // unsigned (x < 0) is always false - op = NewMorphedIntConNode(0); + op = gtWrapWithSideEffects(NewMorphedIntConNode(0), op, GTF_ALL_EFFECT); goto DONE_FOLD; } break; + } case GT_GT: - if (tree->IsUnsigned() && (val == 0) && (op1 == cons) && !opHasSideEffects) + { + if (tree->IsUnsigned() && (val == 0) && (op1 == cons)) { // unsigned (0 > x) is always false - op = NewMorphedIntConNode(0); + op = gtWrapWithSideEffects(NewMorphedIntConNode(0), op, GTF_ALL_EFFECT); goto DONE_FOLD; } + } FALLTHROUGH; + case GT_EQ: case GT_NE: - + { // Optimize boxed value classes; these are always false. This IL is // generated when a generic value is tested against null: // ... foo(T x) { ... if ((object)x == null) ... @@ -14463,57 +14469,59 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) { return gtFoldBoxNullable(tree); } - break; + } case GT_ADD: + { if (val == 0) { goto DONE_FOLD; } break; + } case GT_MUL: + { if (val == 1) { goto DONE_FOLD; } else if (val == 0) { - /* Multiply by zero - return the 'zero' node, but not if side effects */ - if (!opHasSideEffects) - { - op = cons; - goto DONE_FOLD; - } + // Multiply by zero - return the 'zero' node + op = gtWrapWithSideEffects(cons, op, GTF_ALL_EFFECT); + goto DONE_FOLD; } break; + } case GT_DIV: case GT_UDIV: + { if ((op2 == cons) && (val == 1) && !op1->OperIsConst()) { goto DONE_FOLD; } break; + } case GT_SUB: + { if ((op2 == cons) && (val == 0) && !op1->OperIsConst()) { goto DONE_FOLD; } break; + } case GT_AND: + { if (val == 0) { - /* AND with zero - return the 'zero' node, but not if side effects */ - - if (!opHasSideEffects) - { - op = cons; - goto DONE_FOLD; - } + // AND with zero - return the 'zero' node + op = gtWrapWithSideEffects(cons, op, GTF_ALL_EFFECT); + goto DONE_FOLD; } else if (val == 0xFF) { @@ -14546,8 +14554,10 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) } } break; + } case GT_OR: + { if (val == 0) { goto DONE_FOLD; @@ -14558,34 +14568,33 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) assert(val == 1); - /* OR with one - return the 'one' node, but not if side effects */ - - if (!opHasSideEffects) - { - op = cons; - goto DONE_FOLD; - } + // OR with one - return the 'one' node + op = gtWrapWithSideEffects(cons, op, GTF_ALL_EFFECT); + goto DONE_FOLD; } break; + } case GT_LSH: case GT_RSH: case GT_RSZ: case GT_ROL: case GT_ROR: + { if (val == 0) { if (op2 == cons) { goto DONE_FOLD; } - else if (!opHasSideEffects) + else { - op = cons; + op = gtWrapWithSideEffects(cons, op, GTF_ALL_EFFECT); goto DONE_FOLD; } } break; + } case GT_QMARK: { @@ -14608,9 +14617,8 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) { fgWalkTreePre(&op, gtClearColonCond); } - } - goto DONE_FOLD; + } default: break; @@ -14627,6 +14635,13 @@ GenTree* Compiler::gtFoldExprSpecial(GenTree* tree) JITDUMP("Transformed into:\n"); DISPTREE(op); + if (fgGlobalMorph) + { + // We can sometimes produce a comma over the constant if the original op + // had a side effect, so just ensure we set the flag (which will be already + // set for the operands otherwise). + INDEBUG(op->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + } return op; }