diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index cd74ea1c96edd6..1e349e055ef989 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6944,7 +6944,6 @@ class Compiler TypeProducerKind gtGetTypeProducerKind(GenTree* tree); bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call); bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr); - bool gtIsActiveCSE_Candidate(GenTree* tree); bool gtTreeContainsOper(GenTree* tree, genTreeOps op); ExceptionSetFlags gtCollectExceptions(GenTree* tree); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 90d78d037a45d1..68546b7259b672 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17653,11 +17653,6 @@ bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInf return helper != CORINFO_HELP_UNDEF; } -bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree) -{ - return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum)); -} - //------------------------------------------------------------------------ // gtTreeContainsOper -- check if the tree contains any subtree with the specified oper. // diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 836374eff94df0..6f76f6042ce5cf 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -451,8 +451,7 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) // Because there is no IL instruction conv.r4.un, uint/ulong -> float // casts are always imported as CAST(float <- CAST(double <- uint/ulong)). // We can eliminate the redundant intermediate cast as an optimization. - else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && oper->OperIs(GT_CAST) && - !gtIsActiveCSE_Candidate(tree) + else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && oper->OperIs(GT_CAST) #ifdef TARGET_ARM && !varTypeIsLong(oper->AsCast()->CastOp()) #endif @@ -3400,16 +3399,6 @@ void Compiler::fgMoveOpsLeft(GenTree* tree) return; } - if (gtIsActiveCSE_Candidate(op2)) - { - // If we have marked op2 as a CSE candidate, - // we can't perform a commutative reordering - // because any value numbers that we computed for op2 - // will be incorrect after performing a commutative reordering - // - return; - } - if (oper == GT_MUL && (op2->gtFlags & GTF_MUL_64RSLT)) { return; @@ -7040,11 +7029,11 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) // Try to replace CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE with a constant gc handle // pointing to a frozen segment - if (!gtIsActiveCSE_Candidate(call) && gtIsTypeHandleToRuntimeTypeHelper(call)) + if (gtIsTypeHandleToRuntimeTypeHelper(call)) { GenTree* argNode = call->AsCall()->gtArgs.GetArgByIndex(0)->GetNode(); CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(argNode); - if ((hClass != NO_CLASS_HANDLE) && !gtIsActiveCSE_Candidate(argNode)) + if (hClass != NO_CLASS_HANDLE) { CORINFO_OBJECT_HANDLE ptr = info.compCompHnd->getRuntimeTypePointer(hClass); if (ptr != NULL) @@ -7557,12 +7546,6 @@ GenTreeOp* Compiler::fgMorphCommutative(GenTreeOp* tree) return nullptr; } - if (gtIsActiveCSE_Candidate(tree) || gtIsActiveCSE_Candidate(op1)) - { - // The optimization removes 'tree' from IR and changes the value of 'op1'. - return nullptr; - } - if (tree->OperMayOverflow() && (tree->gtOverflow() || op1->gtOverflow())) { return nullptr; @@ -7576,12 +7559,6 @@ GenTreeOp* Compiler::fgMorphCommutative(GenTreeOp* tree) return nullptr; } - if (gtIsActiveCSE_Candidate(cns1) || gtIsActiveCSE_Candidate(cns2)) - { - // The optimization removes 'cns2' from IR and changes the value of 'cns1'. - return nullptr; - } - GenTree* folded = gtFoldExprConst(gtNewOperNode(oper, cns1->TypeGet(), cns1, cns2)); if (!folded->IsCnsIntOrI()) @@ -7780,7 +7757,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA break; case GT_IND: - if (opts.OptimizationEnabled() && !optValnumCSE_phase) + if (opts.OptimizationEnabled()) { GenTree* constNode = gtFoldIndirConst(tree->AsIndir()); if (constNode != nullptr) @@ -7822,8 +7799,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } // Convert DIV to UDIV if both op1 and op2 are known to be never negative - if (!gtIsActiveCSE_Candidate(tree) && varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && - op2->IsNeverNegative(this)) + if (varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && op2->IsNeverNegative(this)) { assert(tree->OperIs(GT_DIV)); tree->ChangeOper(GT_UDIV, GenTree::PRESERVE_VN); @@ -7890,8 +7866,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } // Convert MOD to UMOD if both op1 and op2 are known to be never negative - if (!gtIsActiveCSE_Candidate(tree) && varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && - op2->IsNeverNegative(this)) + if (varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && op2->IsNeverNegative(this)) { assert(tree->OperIs(GT_MOD)); tree->ChangeOper(GT_UMOD, GenTree::PRESERVE_VN); @@ -7947,29 +7922,26 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA ASSIGN_HELPER_FOR_MOD: - if (!optValnumCSE_phase) + if (tree->OperIs(GT_MOD, GT_UMOD) && (op2->IsIntegralConst(1))) { - if (tree->OperIs(GT_MOD, GT_UMOD) && (op2->IsIntegralConst(1))) + // Transformation: a % 1 = 0 + GenTree* optimizedTree = fgMorphModToZero(tree->AsOp()); + if (optimizedTree != nullptr) { - // Transformation: a % 1 = 0 - GenTree* optimizedTree = fgMorphModToZero(tree->AsOp()); - if (optimizedTree != nullptr) - { - tree = optimizedTree; + tree = optimizedTree; - if (tree->OperIs(GT_COMMA)) - { - op1 = tree->gtGetOp1(); - op2 = tree->gtGetOp2(); - } - else - { - assert(tree->IsIntegralConst()); - op1 = nullptr; - op2 = nullptr; - } - break; + if (tree->OperIs(GT_COMMA)) + { + op1 = tree->gtGetOp1(); + op2 = tree->gtGetOp2(); } + else + { + assert(tree->IsIntegralConst()); + op1 = nullptr; + op2 = nullptr; + } + break; } } @@ -7997,33 +7969,30 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA #endif #endif // !TARGET_64BIT - if (!optValnumCSE_phase) + if (tree->OperIs(GT_UMOD) && op2->IsIntegralConstUnsignedPow2()) { - if (tree->OperIs(GT_UMOD) && op2->IsIntegralConstUnsignedPow2()) - { - // Transformation: a % b = a & (b - 1); - tree = fgMorphUModToAndSub(tree->AsOp()); - op1 = tree->AsOp()->gtOp1; - op2 = tree->AsOp()->gtOp2; - } + // Transformation: a % b = a & (b - 1); + tree = fgMorphUModToAndSub(tree->AsOp()); + op1 = tree->AsOp()->gtOp1; + op2 = tree->AsOp()->gtOp2; + } #ifdef TARGET_ARM64 - // ARM64 architecture manual suggests this transformation - // for the mod operator. - else + // ARM64 architecture manual suggests this transformation + // for the mod operator. + else #else - // XARCH only applies this transformation if we know - // that magic division will be used - which is determined - // when 'b' is not a power of 2 constant and mod operator is signed. - // Lowering for XARCH does this optimization already, - // but is also done here to take advantage of CSE. - else if (tree->OperIs(GT_MOD) && op2->IsIntegralConst() && !op2->IsIntegralConstAbsPow2()) + // XARCH only applies this transformation if we know + // that magic division will be used - which is determined + // when 'b' is not a power of 2 constant and mod operator is signed. + // Lowering for XARCH does this optimization already, + // but is also done here to take advantage of CSE. + else if (tree->OperIs(GT_MOD) && op2->IsIntegralConst() && !op2->IsIntegralConstAbsPow2()) #endif - { - // Transformation: a % b = a - (a / b) * b; - tree = fgMorphModToSubMulDiv(tree->AsOp()); - op1 = tree->AsOp()->gtOp1; - op2 = tree->AsOp()->gtOp2; - } + { + // Transformation: a % b = a - (a / b) * b; + tree = fgMorphModToSubMulDiv(tree->AsOp()); + op1 = tree->AsOp()->gtOp1; + op2 = tree->AsOp()->gtOp2; } break; @@ -8135,7 +8104,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // => // a & (c - 1) ==/!= 0 // For integer `a`, even if negative. - if (opts.OptimizationEnabled() && !optValnumCSE_phase) + if (opts.OptimizationEnabled()) { assert(tree->OperIs(GT_EQ, GT_NE)); if (op1->OperIs(GT_MOD) && varTypeIsIntegral(op1) && op2->IsIntegralConst(0)) @@ -8430,7 +8399,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA case GT_EQ: case GT_NE: // It is not safe to reorder/delete CSE's - if (!optValnumCSE_phase && op2->IsIntegralConst()) + if (op2->IsIntegralConst()) { tree = fgOptimizeEqualityComparisonWithConst(tree->AsOp()); assert(tree->OperIsCompare()); @@ -8446,7 +8415,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA case GT_GE: case GT_GT: // Change "CNS relop op2" to "op2 relop* CNS" - if (!optValnumCSE_phase && op1->IsIntegralConst() && tree->OperIsCompare() && gtCanSwapOrder(op1, op2)) + if (op1->IsIntegralConst() && tree->OperIsCompare() && gtCanSwapOrder(op1, op2)) { std::swap(tree->AsOp()->gtOp1, tree->AsOp()->gtOp2); tree->gtOper = GenTree::SwapRelop(tree->OperGet()); @@ -8456,7 +8425,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA op2 = tree->gtGetOp2(); } - if (!optValnumCSE_phase && (op1->OperIs(GT_CAST) || op2->OperIs(GT_CAST))) + if (op1->OperIs(GT_CAST) || op2->OperIs(GT_CAST)) { tree = fgOptimizeRelationalComparisonWithCasts(tree->AsOp()); oper = tree->OperGet(); @@ -8465,7 +8434,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } // op2's value may be changed, so it cannot be a CSE candidate. - if (op2->IsIntegralConst() && !gtIsActiveCSE_Candidate(op2)) + if (op2->IsIntegralConst()) { tree = fgOptimizeRelationalComparisonWithConst(tree->AsOp()); oper = tree->OperGet(); @@ -8706,8 +8675,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA // Consider for example the following expression: NEG(NEG(OP)), where any // NEG is a CSE candidate. Were we to morph this to just OP, CSE would fail to find // the original NEG in the statement. - if (op1->OperIs(oper) && opts.OptimizationEnabled() && !gtIsActiveCSE_Candidate(tree) && - !gtIsActiveCSE_Candidate(op1)) + if (op1->OperIs(oper) && opts.OptimizationEnabled()) { JITDUMP("Remove double negation/not\n") GenTree* op1op1 = op1->gtGetOp1(); @@ -8717,8 +8685,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } // Distribute negation over simple multiplication/division expressions - if (opts.OptimizationEnabled() && !optValnumCSE_phase && tree->OperIs(GT_NEG) && - op1->OperIs(GT_MUL, GT_DIV)) + if (opts.OptimizationEnabled() && tree->OperIs(GT_NEG) && op1->OperIs(GT_MUL, GT_DIV)) { GenTreeOp* mulOrDiv = op1->AsOp(); GenTree* op1op1 = mulOrDiv->gtGetOp1(); @@ -8747,8 +8714,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA } /* Any constant cases should have been folded earlier */ - noway_assert(!op1->OperIsConst() || op1->IsIconHandle() || opts.OptimizationDisabled() || - optValnumCSE_phase); + noway_assert(!op1->OperIsConst() || op1->IsIconHandle() || opts.OptimizationDisabled()); break; case GT_CKFINITE: @@ -8847,7 +8813,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA break; case GT_NULLCHECK: - if (opts.OptimizationEnabled() && !optValnumCSE_phase && !tree->OperMayThrow(this)) + if (opts.OptimizationEnabled() && !tree->OperMayThrow(this)) { JITDUMP("\nNULLCHECK on [%06u] will always succeed\n", dspTreeID(op1)); if ((op1->gtFlags & GTF_SIDE_EFFECT) != 0) @@ -8874,52 +8840,46 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA break; case GT_COMMA: - + { /* Special case: trees that don't produce a value */ if (op2->OperIsStore() || (op2->OperGet() == GT_COMMA && op2->TypeGet() == TYP_VOID) || fgIsThrow(op2)) { typ = tree->gtType = TYP_VOID; } - // If we are in the Valuenum CSE phase then don't morph away anything as these - // nodes may have CSE defs/uses in them. - // - if (!optValnumCSE_phase) - { - // Extract the side effects from the left side of the comma. Since they don't "go" anywhere, this - // is all we need. + // Extract the side effects from the left side of the comma. Since they don't "go" anywhere, this + // is all we need. - GenTree* op1SideEffects = nullptr; - // The addition of "GTF_MAKE_CSE" below prevents us from throwing away (for example) - // hoisted expressions in loops. - gtExtractSideEffList(op1, &op1SideEffects, (GTF_SIDE_EFFECT | GTF_MAKE_CSE)); - if (op1SideEffects) - { - // Replace the left hand side with the side effect list. - op1 = op1SideEffects; - tree->AsOp()->gtOp1 = op1SideEffects; - gtUpdateNodeSideEffects(tree); - } - else - { - op2->gtFlags |= (tree->gtFlags & GTF_DONT_CSE); - DEBUG_DESTROY_NODE(tree); - DEBUG_DESTROY_NODE(op1); - return op2; - } - - // If the right operand is just a void nop node, throw it away. Unless this is a - // comma throw, in which case we want the top-level morphing loop to recognize it. - if (op2->IsNothingNode() && op1->TypeIs(TYP_VOID) && !fgIsCommaThrow(tree)) - { - op1->gtFlags |= (tree->gtFlags & GTF_DONT_CSE); - DEBUG_DESTROY_NODE(tree); - DEBUG_DESTROY_NODE(op2); - return op1; - } + GenTree* op1SideEffects = nullptr; + // The addition of "GTF_MAKE_CSE" below prevents us from throwing away (for example) + // hoisted expressions in loops. + gtExtractSideEffList(op1, &op1SideEffects, (GTF_SIDE_EFFECT | GTF_MAKE_CSE)); + if (op1SideEffects) + { + // Replace the left hand side with the side effect list. + op1 = op1SideEffects; + tree->AsOp()->gtOp1 = op1SideEffects; + gtUpdateNodeSideEffects(tree); + } + else + { + op2->gtFlags |= (tree->gtFlags & GTF_DONT_CSE); + DEBUG_DESTROY_NODE(tree); + DEBUG_DESTROY_NODE(op1); + return op2; } + // If the right operand is just a void nop node, throw it away. Unless this is a + // comma throw, in which case we want the top-level morphing loop to recognize it. + if (op2->IsNothingNode() && op1->TypeIs(TYP_VOID) && !fgIsCommaThrow(tree)) + { + op1->gtFlags |= (tree->gtFlags & GTF_DONT_CSE); + DEBUG_DESTROY_NODE(tree); + DEBUG_DESTROY_NODE(op2); + return op1; + } break; + } case GT_JTRUE: @@ -8964,9 +8924,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA if (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant) { - // Should be expanded by the time it reaches CSE phase - assert(!optValnumCSE_phase); - JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to "); if (op1->OperIsConst() || gtIsTypeof(op1)) { @@ -9120,7 +9077,7 @@ GenTree* Compiler::fgMorphFinalizeIndir(GenTreeIndir* indir) } #endif // TARGET_ARM - if (!indir->IsVolatile() && !indir->TypeIs(TYP_STRUCT) && addr->OperIs(GT_LCL_ADDR) && !optValnumCSE_phase) + if (!indir->IsVolatile() && !indir->TypeIs(TYP_STRUCT) && addr->OperIs(GT_LCL_ADDR)) { unsigned size = indir->Size(); unsigned offset = addr->AsLclVarCommon()->GetLclOffs(); @@ -9175,11 +9132,6 @@ GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast) { GenTree* src = cast->CastOp(); - if (gtIsActiveCSE_Candidate(cast) || gtIsActiveCSE_Candidate(src)) - { - return cast; - } - // See if we can discard the cast. if (varTypeIsIntegral(cast) && varTypeIsIntegral(src)) { @@ -9297,16 +9249,10 @@ GenTree* Compiler::fgOptimizeCastOnStore(GenTree* store) if (src->gtOverflow()) return store; - if (gtIsActiveCSE_Candidate(src)) - return store; - GenTreeCast* cast = src->AsCast(); var_types castToType = cast->CastToType(); var_types castFromType = cast->CastFromType(); - if (gtIsActiveCSE_Candidate(cast->CastOp())) - return store; - if (!varTypeIsSmall(store)) return store; @@ -9352,7 +9298,7 @@ GenTree* Compiler::fgOptimizeCastOnStore(GenTree* store) // GenTree* Compiler::fgOptimizeBitCast(GenTreeUnOp* bitCast) { - if (opts.OptimizationDisabled() || optValnumCSE_phase) + if (opts.OptimizationDisabled()) { return nullptr; } @@ -9382,7 +9328,6 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) { assert(cmp->OperIs(GT_EQ, GT_NE)); assert(cmp->gtGetOp2()->IsIntegralConst()); - assert(!optValnumCSE_phase); GenTree* op1 = cmp->gtGetOp1(); GenTreeIntConCommon* op2 = cmp->gtGetOp2()->AsIntConCommon(); @@ -9758,7 +9703,6 @@ GenTree* Compiler::fgOptimizeRelationalComparisonWithConst(GenTreeOp* cmp) { assert(cmp->OperIs(GT_LE, GT_LT, GT_GE, GT_GT)); assert(cmp->gtGetOp2()->IsIntegralConst()); - assert(!gtIsActiveCSE_Candidate(cmp->gtGetOp2())); GenTree* op1 = cmp->gtGetOp1(); GenTreeIntConCommon* op2 = cmp->gtGetOp2()->AsIntConCommon(); @@ -9872,11 +9816,6 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) } } - if (optValnumCSE_phase) - { - return node; - } - NamedIntrinsic intrinsicId = node->GetHWIntrinsicId(); var_types retType = node->TypeGet(); CorInfoType simdBaseJitType = node->GetSimdBaseJitType(); @@ -10427,25 +10366,12 @@ GenTree* Compiler::fgOptimizeHWIntrinsicAssociative(GenTreeHWIntrinsic* tree) return nullptr; } - if (gtIsActiveCSE_Candidate(tree) || gtIsActiveCSE_Candidate(effectiveOp1)) - { - // In the case op1 is a comma, the optimization removes 'tree' from IR and changes - // the value of op1 and otherwise we're changing the value of 'tree' instead - return nullptr; - } - GenTreeVecCon* cns1 = intrinOp1->Op(2)->AsVecCon(); GenTreeVecCon* cns2 = tree->Op(2)->AsVecCon(); assert(cns1->TypeIs(simdType)); assert(cns2->TypeIs(simdType)); - if (gtIsActiveCSE_Candidate(cns1) || gtIsActiveCSE_Candidate(cns2)) - { - // The optimization removes 'cns2' from IR and changes the value of 'cns1'. - return nullptr; - } - GenTree* res = gtNewSimdHWIntrinsicNode(simdType, cns1, cns2, intrinsicId, simdBaseJitType, simdSize); res = gtFoldExprHWIntrinsic(res->AsHWIntrinsic()); @@ -10525,30 +10451,27 @@ GenTree* Compiler::fgOptimizeCommutativeArithmetic(GenTreeOp* tree) } } - if (!optValnumCSE_phase) + GenTree* optimizedTree = nullptr; + if (tree->OperIs(GT_ADD)) { - GenTree* optimizedTree = nullptr; - if (tree->OperIs(GT_ADD)) - { - optimizedTree = fgOptimizeAddition(tree); - } - else if (tree->OperIs(GT_MUL)) - { - optimizedTree = fgOptimizeMultiply(tree); - } - else if (tree->OperIs(GT_AND)) - { - optimizedTree = fgOptimizeBitwiseAnd(tree); - } - else if (tree->OperIs(GT_XOR)) - { - optimizedTree = fgOptimizeBitwiseXor(tree); - } + optimizedTree = fgOptimizeAddition(tree); + } + else if (tree->OperIs(GT_MUL)) + { + optimizedTree = fgOptimizeMultiply(tree); + } + else if (tree->OperIs(GT_AND)) + { + optimizedTree = fgOptimizeBitwiseAnd(tree); + } + else if (tree->OperIs(GT_XOR)) + { + optimizedTree = fgOptimizeBitwiseXor(tree); + } - if (optimizedTree != nullptr) - { - return optimizedTree; - } + if (optimizedTree != nullptr) + { + return optimizedTree; } return tree; @@ -10567,7 +10490,6 @@ GenTree* Compiler::fgOptimizeCommutativeArithmetic(GenTreeOp* tree) GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) { assert(add->OperIs(GT_ADD) && !add->gtOverflow()); - assert(!optValnumCSE_phase); GenTree* op1 = add->gtGetOp1(); GenTree* op2 = add->gtGetOp2(); @@ -10694,7 +10616,6 @@ GenTree* Compiler::fgOptimizeMultiply(GenTreeOp* mul) assert(mul->OperIs(GT_MUL)); assert(varTypeIsIntOrI(mul) || varTypeIsFloating(mul)); assert(!mul->gtOverflow()); - assert(!optValnumCSE_phase); GenTree* op1 = mul->gtGetOp1(); GenTree* op2 = mul->gtGetOp2(); @@ -10848,7 +10769,6 @@ GenTree* Compiler::fgOptimizeMultiply(GenTreeOp* mul) GenTree* Compiler::fgOptimizeBitwiseAnd(GenTreeOp* andOp) { assert(andOp->OperIs(GT_AND)); - assert(!optValnumCSE_phase); GenTree* op1 = andOp->gtGetOp1(); GenTree* op2 = andOp->gtGetOp2(); @@ -10902,7 +10822,6 @@ GenTree* Compiler::fgOptimizeBitwiseAnd(GenTreeOp* andOp) GenTree* Compiler::fgOptimizeRelationalComparisonWithCasts(GenTreeOp* cmp) { assert(cmp->OperIs(GT_LE, GT_LT, GT_GE, GT_GT)); - assert(!optValnumCSE_phase); GenTree* op1 = cmp->gtGetOp1(); GenTree* op2 = cmp->gtGetOp2(); @@ -11011,7 +10930,6 @@ GenTree* Compiler::fgOptimizeRelationalComparisonWithCasts(GenTreeOp* cmp) GenTree* Compiler::fgOptimizeBitwiseXor(GenTreeOp* xorOp) { assert(xorOp->OperIs(GT_XOR)); - assert(!optValnumCSE_phase); GenTree* op1 = xorOp->gtGetOp1(); GenTree* op2 = xorOp->gtGetOp2(); @@ -11274,13 +11192,6 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree, bool* optAssertionPropD case GT_STORE_BLK: case GT_STORE_LCL_VAR: case GT_STORE_LCL_FLD: - // Make sure we're allowed to do this. - if (optValnumCSE_phase) - { - // It is not safe to reorder/delete CSE's - break; - } - if (varTypeIsStruct(typ) && !tree->IsPhiDefn()) { // Block ops handle assertion kill/gen specially. @@ -11397,7 +11308,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree, bool* optAssertionPropD /* Check for the case "(val + icon) << icon" */ - if (!optValnumCSE_phase && op2->IsCnsIntOrI() && op1->gtOper == GT_ADD && !op1->gtOverflow()) + if (op2->IsCnsIntOrI() && op1->gtOper == GT_ADD && !op1->gtOverflow()) { GenTree* cns = op1->AsOp()->gtOp2; @@ -11534,7 +11445,7 @@ GenTree* Compiler::fgMorphHWIntrinsic(GenTreeHWIntrinsic* tree) std::swap(op1, tree->Op(2)); } } - else if (!optValnumCSE_phase) + else { bool isScalar = false; genTreeOps oper = tree->GetOperForHWIntrinsicId(&isScalar); @@ -12952,55 +12863,41 @@ bool Compiler::fgMorphBlockStmt(BasicBlock* block, Statement* stmt DEBUGARG(cons GenTree* morph = fgMorphTree(stmt->GetRootNode()); - // Bug 1106830 - During the CSE phase we can't just remove - // morph->AsOp()->gtOp2 as it could contain CSE expressions. - // This leads to a noway_assert in OptCSE.cpp when - // searching for the removed CSE ref. (using gtFindLink) - // - if (!optValnumCSE_phase) + // Check for morph as a GT_COMMA with an unconditional throw + if (fgIsCommaThrow(morph, true)) { - // Check for morph as a GT_COMMA with an unconditional throw - if (fgIsCommaThrow(morph, true)) - { #ifdef DEBUG - if (verbose) - { - printf("Folding a top-level fgIsCommaThrow stmt\n"); - printf("Removing op2 as unreachable:\n"); - gtDispTree(morph->AsOp()->gtOp2); - printf("\n"); - } -#endif - // Use the call as the new stmt - morph = morph->AsOp()->gtOp1; - noway_assert(morph->gtOper == GT_CALL); + if (verbose) + { + printf("Folding a top-level fgIsCommaThrow stmt\n"); + printf("Removing op2 as unreachable:\n"); + gtDispTree(morph->AsOp()->gtOp2); + printf("\n"); } +#endif + // Use the call as the new stmt + morph = morph->AsOp()->gtOp1; + noway_assert(morph->gtOper == GT_CALL); + } - // we can get a throw as a statement root - if (fgIsThrow(morph)) - { + // we can get a throw as a statement root + if (fgIsThrow(morph)) + { #ifdef DEBUG - if (verbose) - { - printf("We have a top-level fgIsThrow stmt\n"); - printf("Removing the rest of block as unreachable:\n"); - } -#endif - noway_assert((morph->gtFlags & GTF_COLON_COND) == 0); - fgRemoveRestOfBlock = true; + if (verbose) + { + printf("We have a top-level fgIsThrow stmt\n"); + printf("Removing the rest of block as unreachable:\n"); } +#endif + noway_assert((morph->gtFlags & GTF_COLON_COND) == 0); + fgRemoveRestOfBlock = true; } stmt->SetRootNode(morph); // Can the entire tree be removed? - bool removedStmt = false; - - // Defer removing statements during CSE so we don't inadvertently remove any CSE defs. - if (!optValnumCSE_phase) - { - removedStmt = fgCheckRemoveStmt(block, stmt); - } + bool removedStmt = fgCheckRemoveStmt(block, stmt); // Or this is the last statement of a conditional branch that was just folded? if (!removedStmt && (stmt->GetNextStmt() == nullptr) && !fgRemoveRestOfBlock) @@ -13221,7 +13118,7 @@ void Compiler::fgMorphStmts(BasicBlock* block) #endif /* Check for morphedTree as a GT_COMMA with an unconditional throw */ - if (!gtIsActiveCSE_Candidate(morphedTree) && fgIsCommaThrow(morphedTree, true)) + if (fgIsCommaThrow(morphedTree, true)) { /* Use the call as the new stmt */ morphedTree = morphedTree->AsOp()->gtOp1; diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index 0d67ffd7a956a5..c7fb0fe6f4fb7c 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -5298,10 +5298,9 @@ void CSE_HeuristicCommon::PerformCSE(CSE_Candidate* successfulCandidate) // *link = cse; - assert(m_pCompiler->fgRemoveRestOfBlock == false); - - /* re-morph the statement */ - m_pCompiler->fgMorphBlockStmt(blk, stmt DEBUGARG("optValnumCSE")); + m_pCompiler->gtSetStmtInfo(stmt); + m_pCompiler->fgSetStmtSeq(stmt); + m_pCompiler->gtUpdateStmtSideEffects(stmt); } while (lst != nullptr); } diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index f9880026eab268..9bbf8966de5069 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -3251,7 +3251,7 @@ bool Compiler::optNarrowTree(GenTree* tree, var_types srct, var_types dstt, Valu // If 'dstt' is unsigned and one of the operands can be narrowed into 'dsst', // the result of the GT_AND will also fit into 'dstt' and can be narrowed. // The same is true if one of the operands is an int const and can be narrowed into 'dsst'. - if (!gtIsActiveCSE_Candidate(op2) && ((op2->gtOper == GT_CNS_INT) || varTypeIsUnsigned(dstt))) + if ((op2->gtOper == GT_CNS_INT) || varTypeIsUnsigned(dstt)) { if (optNarrowTree(op2, srct, dstt, NoVNPair, false)) { @@ -3264,8 +3264,7 @@ bool Compiler::optNarrowTree(GenTree* tree, var_types srct, var_types dstt, Valu } } - if ((opToNarrow == nullptr) && !gtIsActiveCSE_Candidate(op1) && - ((op1->gtOper == GT_CNS_INT) || varTypeIsUnsigned(dstt))) + if ((opToNarrow == nullptr) && ((op1->gtOper == GT_CNS_INT) || varTypeIsUnsigned(dstt))) { if (optNarrowTree(op1, srct, dstt, NoVNPair, false)) { @@ -3325,8 +3324,7 @@ bool Compiler::optNarrowTree(GenTree* tree, var_types srct, var_types dstt, Valu noway_assert(genActualType(tree->gtType) == genActualType(op1->gtType)); noway_assert(genActualType(tree->gtType) == genActualType(op2->gtType)); COMMON_BINOP: - if (gtIsActiveCSE_Candidate(op1) || gtIsActiveCSE_Candidate(op2) || - !optNarrowTree(op1, srct, dstt, NoVNPair, doit) || !optNarrowTree(op2, srct, dstt, NoVNPair, doit)) + if (!optNarrowTree(op1, srct, dstt, NoVNPair, doit) || !optNarrowTree(op2, srct, dstt, NoVNPair, doit)) { noway_assert(doit == false); return false; @@ -3412,7 +3410,7 @@ bool Compiler::optNarrowTree(GenTree* tree, var_types srct, var_types dstt, Valu return false; case GT_COMMA: - if (!gtIsActiveCSE_Candidate(op2) && optNarrowTree(op2, srct, dstt, vnpNarrow, doit)) + if (optNarrowTree(op2, srct, dstt, vnpNarrow, doit)) { /* Simply change the type of the tree */