diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index db5b6a6c97006f..d546476dfa9f64 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1121,7 +1121,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, // // Set op1 to the instance pointer of the indirection // - op1 = op1->gtEffectiveVal(/* commaOnly */ true); + op1 = op1->gtEffectiveVal(); ssize_t offset = 0; while ((op1->gtOper == GT_ADD) && (op1->gtType == TYP_BYREF)) @@ -1129,12 +1129,12 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, if (op1->gtGetOp2()->IsCnsIntOrI()) { offset += op1->gtGetOp2()->AsIntCon()->gtIconVal; - op1 = op1->gtGetOp1()->gtEffectiveVal(/* commaOnly */ true); + op1 = op1->gtGetOp1()->gtEffectiveVal(); } else if (op1->gtGetOp1()->IsCnsIntOrI()) { offset += op1->gtGetOp1()->AsIntCon()->gtIconVal; - op1 = op1->gtGetOp2()->gtEffectiveVal(/* commaOnly */ true); + op1 = op1->gtGetOp2()->gtEffectiveVal(); } else { @@ -4533,7 +4533,7 @@ bool Compiler::optAssertionIsNonNull(GenTree* op, return true; } - op = op->gtEffectiveVal(/* commaOnly */ true); + op = op->gtEffectiveVal(); if (!op->OperIs(GT_LCL_VAR)) { diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index ed9ab2791455bc..ced74b790398bd 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -1262,11 +1262,6 @@ bool CodeGen::genCreateAddrMode( break; #endif // !TARGET_ARMARCH && !TARGET_LOONGARCH64 && !TARGET_RISCV64 - case GT_NOP: - - op1 = op1->AsOp()->gtOp1; - goto AGAIN; - case GT_COMMA: op1 = op1->AsOp()->gtOp2; @@ -1341,11 +1336,6 @@ bool CodeGen::genCreateAddrMode( break; #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64 - case GT_NOP: - - op2 = op2->AsOp()->gtOp1; - goto AGAIN; - case GT_COMMA: op2 = op2->AsOp()->gtOp2; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 762a445ef7ae9e..ead507338212ca 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -11397,6 +11397,7 @@ class GenTreeVisitor case GT_PINVOKE_PROLOG: case GT_PINVOKE_EPILOG: case GT_IL_OFFSET: + case GT_NOP: break; // Lclvar unary operators @@ -11437,7 +11438,6 @@ class GenTreeVisitor case GT_PUTARG_REG: case GT_PUTARG_STK: case GT_RETURNTRAP: - case GT_NOP: case GT_FIELD_ADDR: case GT_RETURN: case GT_RETFILT: diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index d6b70cf96eb2a1..5492577d3b77e7 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -1242,7 +1242,7 @@ inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0); assert((GenTree::OperKind(oper) & GTK_EXOP) == 0); // Can't use this to construct any types that extend unary/binary operator. - assert(op1 != nullptr || oper == GT_RETFILT || oper == GT_NOP || (oper == GT_RETURN && type == TYP_VOID)); + assert(op1 != nullptr || oper == GT_RETFILT || (oper == GT_RETURN && type == TYP_VOID)); GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, nullptr); @@ -1602,7 +1602,7 @@ inline GenTree* Compiler::gtNewNullCheck(GenTree* addr, BasicBlock* basicBlock) inline GenTree* Compiler::gtNewNothingNode() { - return new (this, GT_NOP) GenTreeOp(GT_NOP, TYP_VOID); + return new (this, GT_NOP) GenTree(GT_NOP, TYP_VOID); } /*****************************************************************************/ @@ -1620,10 +1620,7 @@ inline bool GenTree::IsNothingNode() const inline void GenTree::gtBashToNOP() { ChangeOper(GT_NOP); - - gtType = TYP_VOID; - AsOp()->gtOp1 = AsOp()->gtOp2 = nullptr; - + gtType = TYP_VOID; gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS); } @@ -4415,10 +4412,10 @@ void GenTree::VisitOperands(TVisitor visitor) case GT_PINVOKE_PROLOG: case GT_PINVOKE_EPILOG: case GT_IL_OFFSET: + case GT_NOP: return; // Unary operators with an optional operand - case GT_NOP: case GT_FIELD_ADDR: case GT_RETURN: case GT_RETFILT: diff --git a/src/coreclr/jit/earlyprop.cpp b/src/coreclr/jit/earlyprop.cpp index 8233f8f521a415..e8d74fbb9136ff 100644 --- a/src/coreclr/jit/earlyprop.cpp +++ b/src/coreclr/jit/earlyprop.cpp @@ -577,8 +577,7 @@ GenTree* Compiler::optFindNullCheckToFold(GenTree* tree, LocalNumberToNullCheckT return nullptr; } - const bool commaOnly = true; - GenTree* commaOp1EffectiveValue = defValue->gtGetOp1()->gtEffectiveVal(commaOnly); + GenTree* commaOp1EffectiveValue = defValue->gtGetOp1()->gtEffectiveVal(); if (commaOp1EffectiveValue->OperGet() != GT_NULLCHECK) { diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 6a88ccb866fe44..b2b69bbd0c76a3 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -2567,19 +2567,20 @@ Compiler::fgWalkResult Compiler::fgStress64RsltMulCB(GenTree** pTree, fgWalkData return WALK_CONTINUE; } - JITDUMP("STRESS_64RSLT_MUL before:\n"); - DISPTREE(tree); + JITDUMP("STRESS_64RSLT_MUL before:\n") + DISPTREE(tree) - // To ensure optNarrowTree() doesn't fold back to the original tree. - tree->AsOp()->gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->AsOp()->gtOp1, false, TYP_LONG); - tree->AsOp()->gtOp1 = pComp->gtNewOperNode(GT_NOP, TYP_LONG, tree->AsOp()->gtOp1); - tree->AsOp()->gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->AsOp()->gtOp1, false, TYP_LONG); - tree->AsOp()->gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->AsOp()->gtOp2, false, TYP_LONG); + tree->AsOp()->gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtGetOp1(), false, TYP_LONG); + tree->AsOp()->gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtGetOp2(), false, TYP_LONG); tree->gtType = TYP_LONG; *pTree = pComp->gtNewCastNode(TYP_INT, tree, false, TYP_INT); - JITDUMP("STRESS_64RSLT_MUL after:\n"); - DISPTREE(*pTree); + // To ensure optNarrowTree() doesn't fold back to the original tree. + tree->gtGetOp1()->gtDebugFlags |= GTF_DEBUG_CAST_DONT_FOLD; + tree->gtGetOp2()->gtDebugFlags |= GTF_DEBUG_CAST_DONT_FOLD; + + JITDUMP("STRESS_64RSLT_MUL after:\n") + DISPTREE(*pTree) return WALK_SKIP_SUBTREES; } @@ -3246,6 +3247,11 @@ void Compiler::fgDebugCheckTypes(GenTree* tree) assert(!"TYP_ULONG and TYP_UINT are not legal in IR"); } + if (node->OperIs(GT_NOP)) + { + assert(node->TypeIs(TYP_VOID) && "GT_NOP should be TYP_VOID."); + } + if (varTypeIsSmall(node)) { if (node->OperIs(GT_COMMA)) diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 8910902b173611..f1d634fe27da25 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -259,7 +259,7 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorOperGet() == GT_COMMA) { - GenTree* effectiveValue = value->gtEffectiveVal(/*commaOnly*/ true); + GenTree* effectiveValue = value->gtEffectiveVal(); noway_assert( !varTypeIsStruct(effectiveValue) || (effectiveValue->OperGet() != GT_RET_EXPR) || diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index c6e10c1a071126..2a6505d973b346 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2763,6 +2763,7 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) } return true; + case GT_NOP: case GT_LABEL: return true; @@ -4512,7 +4513,7 @@ bool Compiler::gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode) bool Compiler::gtMarkAddrMode(GenTree* addr, int* pCostEx, int* pCostSz, var_types type) { GenTree* addrComma = addr; - addr = addr->gtEffectiveVal(/* commaOnly */ true); + addr = addr->gtEffectiveVal(); // These are "out" parameters on the call to genCreateAddrMode(): bool rev; // This will be true if the operands will need to be reversed. At this point we @@ -5334,6 +5335,12 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) costSz = 0; break; + case GT_NOP: + level = 0; + costEx = 0; + costSz = 0; + break; + default: level = 1; costEx = 1; @@ -5449,11 +5456,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) break; - case GT_NOP: - costEx = 0; - costSz = 0; - break; - case GT_INTRINSIC: intrinsic = tree->AsIntrinsic(); // named intrinsic @@ -6444,6 +6446,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_PINVOKE_PROLOG: case GT_PINVOKE_EPILOG: case GT_IL_OFFSET: + case GT_NOP: return false; // Standard unary operators @@ -6473,7 +6476,6 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_PUTARG_REG: case GT_PUTARG_STK: case GT_RETURNTRAP: - case GT_NOP: case GT_RETURN: case GT_RETFILT: case GT_BSWAP: @@ -8641,8 +8643,8 @@ bool GenTreeOp::UsesDivideByConstOptimized(Compiler* comp) #endif // TARGET_ARM64 bool isSignedDivide = OperIs(GT_DIV, GT_MOD); - GenTree* dividend = gtGetOp1()->gtEffectiveVal(/*commaOnly*/ true); - GenTree* divisor = gtGetOp2()->gtEffectiveVal(/*commaOnly*/ true); + GenTree* dividend = gtGetOp1()->gtEffectiveVal(); + GenTree* divisor = gtGetOp2()->gtEffectiveVal(); #if !defined(TARGET_64BIT) if (dividend->OperIs(GT_LONG)) @@ -8764,7 +8766,7 @@ void GenTreeOp::CheckDivideByConstOptimized(Compiler* comp) { // Now set DONT_CSE on the GT_CNS_INT divisor, note that // with ValueNumbering we can have a non GT_CNS_INT divisor - GenTree* divisor = gtGetOp2()->gtEffectiveVal(/*commaOnly*/ true); + GenTree* divisor = gtGetOp2()->gtEffectiveVal(); if (divisor->OperIs(GT_CNS_INT)) { divisor->gtFlags |= GTF_DONT_CSE; @@ -9211,6 +9213,7 @@ GenTree* Compiler::gtCloneExpr( case GT_CATCH_ARG: case GT_NO_OP: + case GT_NOP: case GT_LABEL: copy = new (this, oper) GenTree(oper, tree->gtType); goto DONE; @@ -10099,6 +10102,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) case GT_PINVOKE_PROLOG: case GT_PINVOKE_EPILOG: case GT_IL_OFFSET: + case GT_NOP: m_state = -1; return; @@ -10142,7 +10146,6 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) return; // Unary operators with an optional operand - case GT_NOP: case GT_FIELD_ADDR: case GT_RETURN: case GT_RETFILT: @@ -12126,6 +12129,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack) // Vanilla leaves. No qualifying information available. So do nothing + case GT_NOP: case GT_NO_OP: case GT_START_NONGC: case GT_START_PREEMPTGC: @@ -14012,12 +14016,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree) { CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE; - // Walk through any wrapping nop. - if ((tree->gtOper == GT_NOP) && (tree->gtType == TYP_I_IMPL)) - { - tree = tree->AsOp()->gtOp1; - } - // The handle could be a literal constant if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL)) { @@ -18239,7 +18237,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b } // Tunnel through commas. - GenTree* obj = tree->gtEffectiveVal(false); + GenTree* obj = tree->gtEffectiveVal(); const genTreeOps objOp = obj->OperGet(); switch (objOp) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index f312199dd05820..ceb73997663842 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -618,6 +618,7 @@ enum GenTreeDebugFlags : unsigned int GTF_DEBUG_NODE_MASK = 0x0000003F, // These flags are all node (rather than operation) properties. GTF_DEBUG_VAR_CSE_REF = 0x00800000, // GT_LCL_VAR -- This is a CSE LCL_VAR node + GTF_DEBUG_CAST_DONT_FOLD = 0x00400000, // GT_CAST -- Try to prevent this cast from being folded }; inline constexpr GenTreeDebugFlags operator ~(GenTreeDebugFlags a) @@ -1723,7 +1724,6 @@ struct GenTree { case GT_LEA: case GT_RETFILT: - case GT_NOP: case GT_FIELD_ADDR: return true; case GT_RETURN: @@ -1816,7 +1816,7 @@ struct GenTree void ReplaceOperand(GenTree** useEdge, GenTree* replacement); - inline GenTree* gtEffectiveVal(bool commaOnly = false); + inline GenTree* gtEffectiveVal(); inline GenTree* gtCommaStoreVal(); @@ -2995,7 +2995,7 @@ struct GenTreeOp : public GenTreeUnOp : GenTreeUnOp(oper, type DEBUGARG(largeNode)), gtOp2(nullptr) { // Unary operators with optional arguments: - assert(oper == GT_NOP || oper == GT_RETURN || oper == GT_RETFILT || OperIsBlk(oper)); + assert(oper == GT_RETURN || oper == GT_RETFILT || OperIsBlk(oper)); } // returns true if we will use the division by constant optimization for this node. @@ -9239,18 +9239,14 @@ inline GenTree*& GenTree::Data() return OperIsLocalStore() ? AsLclVarCommon()->Data() : AsIndir()->Data(); } -inline GenTree* GenTree::gtEffectiveVal(bool commaOnly /* = false */) +inline GenTree* GenTree::gtEffectiveVal() { GenTree* effectiveVal = this; while (true) { - if (effectiveVal->gtOper == GT_COMMA) + if (effectiveVal->OperIs(GT_COMMA)) { - effectiveVal = effectiveVal->AsOp()->gtGetOp2(); - } - else if (!commaOnly && (effectiveVal->gtOper == GT_NOP) && (effectiveVal->AsOp()->gtOp1 != nullptr)) - { - effectiveVal = effectiveVal->AsOp()->gtOp1; + effectiveVal = effectiveVal->gtGetOp2(); } else { diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index 3a72204d39e33e..597a9e471d5b1f 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -53,7 +53,7 @@ GTNODE(CNS_VEC , GenTreeVecCon ,0,0,GTK_LEAF) //----------------------------------------------------------------------------- GTNODE(NOT , GenTreeOp ,0,0,GTK_UNOP) -GTNODE(NOP , GenTree ,0,0,GTK_UNOP|DBK_NOCONTAIN) +GTNODE(NOP , GenTree ,0,1,GTK_LEAF|DBK_NOCONTAIN) GTNODE(NEG , GenTreeOp ,0,0,GTK_UNOP) GTNODE(INTRINSIC , GenTreeIntrinsic ,0,0,GTK_BINOP|GTK_EXOP) diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 633197f6e3e010..434656d520c597 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -340,10 +340,6 @@ bool OptIfConversionDsc::IfConvertCheckStmts(BasicBlock* fromBlock, IfConvertOpe // These do not need conditional execution. case GT_NOP: - if (tree->gtGetOp1() != nullptr || (tree->gtFlags & (GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF)) != 0) - { - return false; - } break; // Cannot optimise this block. diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 538c55f9fbbc05..336b52a2b618cd 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -6875,7 +6875,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // See what we know about the type of 'this' in the call. assert(call->gtArgs.HasThisPointer()); CallArg* thisArg = call->gtArgs.GetThisArg(); - GenTree* thisObj = thisArg->GetEarlyNode()->gtEffectiveVal(false); + GenTree* thisObj = thisArg->GetEarlyNode()->gtEffectiveVal(); bool isExact = false; bool objIsNonNull = false; CORINFO_CLASS_HANDLE objClass = gtGetClassHandle(thisObj, &isExact, &objIsNonNull); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ef85c7b1adcf2b..ce9df6cc74cbed 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -2351,7 +2351,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call if (isStructArg) { - GenTree* actualArg = argx->gtEffectiveVal(true /* Commas only */); + GenTree* actualArg = argx->gtEffectiveVal(); // Here we look at "actualArg" to avoid calling "getClassSize". structSize = actualArg->TypeIs(TYP_STRUCT) ? actualArg->GetLayout(comp)->GetSize() : genTypeSize(actualArg); @@ -3188,7 +3188,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) } bool isStructArg = varTypeIsStruct(arg.GetSignatureType()); - GenTree* argObj = argx->gtEffectiveVal(true /*commaOnly*/); + GenTree* argObj = argx->gtEffectiveVal(); bool makeOutArgCopy = false; if (isStructArg && !reMorphing && !argObj->OperIs(GT_MKREFANY)) @@ -6384,10 +6384,10 @@ void Compiler::fgValidateIRForTailCall(GenTreeCall* call) return WALK_ABORT; } - // GT_NOP might appear due to stores that end up as - // self-stores, which get morphed to GT_NOP. if (tree->OperIs(GT_NOP)) { + // GT_NOP might appear due to stores that end up as + // self-stores, which get morphed to GT_NOP. } // We might see arbitrary chains of stores that trivially // propagate the result. Example: @@ -8225,7 +8225,7 @@ GenTreeOp* Compiler::fgMorphCommutative(GenTreeOp* tree) // op1 can be GT_COMMA, in this case we're going to fold // "(op (COMMA(... (op X C1))) C2)" to "(COMMA(... (op X C3)))" - GenTree* op1 = tree->gtGetOp1()->gtEffectiveVal(true); + GenTree* op1 = tree->gtGetOp1()->gtEffectiveVal(); genTreeOps oper = tree->OperGet(); if (!op1->OperIs(oper) || !tree->gtGetOp2()->IsCnsIntOrI() || !op1->gtGetOp2()->IsCnsIntOrI() || @@ -9041,6 +9041,10 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA { return tree; } + else if (tree->IsNothingNode()) + { + return tree; + } /* gtFoldExpr could have used setOper to change the oper */ oper = tree->OperGet(); @@ -9775,7 +9779,7 @@ GenTree* Compiler::fgMorphFinalizeIndir(GenTreeIndir* indir) if (varTypeIsFloating(indir)) { // Check for a misaligned floating point indirection. - GenTree* effAddr = addr->gtEffectiveVal(true); + GenTree* effAddr = addr->gtEffectiveVal(); target_ssize_t offset; gtPeelOffsets(&effAddr, &offset); @@ -13146,7 +13150,7 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) GenTree* condTree; condTree = lastStmt->GetRootNode()->AsOp()->gtOp1; GenTree* cond; - cond = condTree->gtEffectiveVal(true); + cond = condTree->gtEffectiveVal(); if (cond->OperIsConst()) { @@ -13370,7 +13374,7 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) noway_assert(lastStmt->GetRootNode()->AsOp()->gtOp1); GenTree* condTree = lastStmt->GetRootNode()->AsOp()->gtOp1; - GenTree* cond = condTree->gtEffectiveVal(true); + GenTree* cond = condTree->gtEffectiveVal(); if (cond->OperIsConst()) { diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index 9ad785a1257dc1..90cf731c323d70 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -3150,7 +3150,7 @@ class CSE_Heuristic { // This can only be the case for a struct in which the 'val' was a COMMA, so // the assignment is sunk below it. - store = store->gtEffectiveVal(true); + store = store->gtEffectiveVal(); noway_assert(origStore->OperIs(GT_COMMA) && (origStore == val)); } else diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 78817da2b9ea40..6d3ea59c326f87 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -5995,6 +5995,13 @@ bool Compiler::optNarrowTree(GenTree* tree, var_types srct, var_types dstt, Valu case GT_CAST: { +#ifdef DEBUG + if ((tree->gtDebugFlags & GTF_DEBUG_CAST_DONT_FOLD) != 0) + { + return false; + } +#endif + if ((tree->CastToType() != srct) || tree->gtOverflow()) { return false; @@ -8557,7 +8564,7 @@ bool Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) continue; } - GenTree* addr = tree->AsIndir()->Addr()->gtEffectiveVal(/*commaOnly*/ true); + GenTree* addr = tree->AsIndir()->Addr()->gtEffectiveVal(); if (addr->TypeGet() == TYP_BYREF && addr->OperGet() == GT_LCL_VAR) { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index f0c7b6ad56909a..e6ea3c49ea5943 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -9401,6 +9401,7 @@ static genTreeOps genTreeOpsIllegalAsVNFunc[] = {GT_IND, // When we do heap memo GT_MDARR_LENGTH, GT_MDARR_LOWER_BOUND, // 'dim' value must be considered GT_BITCAST, // Needs to encode the target type. + GT_NOP, // These control-flow operations need no values. GT_JTRUE, GT_RETURN, GT_SWITCH, GT_RETFILT, GT_CKFINITE}; @@ -11165,6 +11166,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) // These do not represent values. case GT_NO_OP: + case GT_NOP: case GT_JMP: // Control flow case GT_LABEL: // Control flow #if !defined(FEATURE_EH_FUNCLETS) @@ -11367,34 +11369,21 @@ void Compiler::fgValueNumberTree(GenTree* tree) { if (GenTree::OperIsUnary(oper)) { - if (tree->AsOp()->gtOp1 != nullptr) - { - ValueNumPair op1VNP; - ValueNumPair op1VNPx; - vnStore->VNPUnpackExc(tree->AsOp()->gtOp1->gtVNPair, &op1VNP, &op1VNPx); - - // If we are fetching the array length for an array ref that came from global memory - // then for CSE safety we must use the conservative value number for both - // - if (tree->OperIsArrLength() && ((tree->AsOp()->gtOp1->gtFlags & GTF_GLOB_REF) != 0)) - { - // use the conservative value number for both when computing the VN for the ARR_LENGTH - op1VNP.SetBoth(op1VNP.GetConservative()); - } + assert(tree->gtGetOp1() != nullptr); + ValueNumPair op1VNP; + ValueNumPair op1VNPx; + vnStore->VNPUnpackExc(tree->AsOp()->gtOp1->gtVNPair, &op1VNP, &op1VNPx); - tree->gtVNPair = - vnStore->VNPWithExc(vnStore->VNPairForFunc(tree->TypeGet(), vnf, op1VNP), op1VNPx); - } - else // Is actually nullary. + // If we are fetching the array length for an array ref that came from global memory + // then for CSE safety we must use the conservative value number for both + // + if (tree->OperIsArrLength() && ((tree->AsOp()->gtOp1->gtFlags & GTF_GLOB_REF) != 0)) { - // Mostly we'll leave these without a value number, assuming we'll detect these as VN failures - // if they actually need to have values. With the exception of NOPs, which can sometimes have - // meaning. - if (tree->OperGet() == GT_NOP) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - } + // use the conservative value number for both when computing the VN for the ARR_LENGTH + op1VNP.SetBoth(op1VNP.GetConservative()); } + + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPairForFunc(tree->TypeGet(), vnf, op1VNP), op1VNPx); } else // we have a binary oper {