diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index c8fec368a6bfa6..1d5f594e13ac42 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -455,7 +455,8 @@ enum BasicBlockFlags : uint64_t // Flags to update when two blocks are compacted BBF_COMPACT_UPD = BBF_GC_SAFE_POINT | BBF_NEEDS_GCPOLL | BBF_HAS_JMP | BBF_BACKWARD_JUMP | \ - BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_MDARRAYREF | BBF_MAY_HAVE_BOUNDS_CHECKS, + BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_MDARRAYREF | BBF_MAY_HAVE_BOUNDS_CHECKS | \ + BBF_RECURSIVE_TAILCALL, // Flags a block should not have had before it is split. diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 156a5eeb910641..ecce2d80003dd9 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -4338,9 +4338,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // DoPhase(this, PHASE_INDXCALL, &Compiler::fgTransformIndirectCalls); - // Relaxed IR checks are currently only enabled through indirect call transformation. - activePhaseChecks &= ~(PhaseChecks::CHECK_IR | PhaseChecks::CHECK_IR_RELAXED); - // Cleanup un-imported BBs, cleanup un-imported or // partially imported try regions, add OSR step blocks. // @@ -4506,6 +4503,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Apply the type update to implicit byref parameters; also choose (based on address-exposed // analysis) which implicit byref promotions to keep (requires copy to initialize) or discard. // + INDEBUG(fgImplicitByRefLclFldsStale = true); DoPhase(this, PHASE_MORPH_IMPBYREF, &Compiler::fgRetypeImplicitByRefArgs); #ifdef DEBUG @@ -4516,9 +4514,13 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Morph the trees in all the blocks of the method // + INDEBUG(fgImplicitByRefLclFldsStale = false); unsigned const preMorphBBCount = fgBBcount; DoPhase(this, PHASE_MORPH_GLOBAL, &Compiler::fgMorphBlocks); + // Global morph restores the strict IR flag invariants. + activePhaseChecks &= ~PhaseChecks::CHECK_IR_RELAXED; + auto postMorphPhase = [this]() { // Fix any LclVar annotations on discarded struct promotion temps for implicit by-ref args fgMarkDemotedImplicitByRefArgs(); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index eada0554a807f1..0b17e61d65e233 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6119,6 +6119,12 @@ class Compiler bool fgGlobalMorphDone = false; +#ifdef DEBUG + // Retyping implicit byref parameters temporarily leaves existing local field + // accesses described using their pre-retyping struct types. + bool fgImplicitByRefLclFldsStale = false; +#endif + bool impBoxTempInUse; // the temp below is valid and available unsigned impBoxTemp; // a temporary that is used for boxing diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index f74c1a13418dee..5597d79d56352b 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -3377,7 +3377,12 @@ void Compiler::fgDebugCheckFlagsAndTypes(GenTree* tree, BasicBlock* block) case GT_STORE_LCL_VAR: case GT_STORE_LCL_FLD: assert((tree->gtFlags & GTF_VAR_DEF) != 0); - assert(((tree->gtFlags & GTF_VAR_USEASG) != 0) == tree->IsPartialLclFld(this)); + if (!fgImplicitByRefLclFldsStale || !tree->OperIs(GT_STORE_LCL_FLD) || + !lvaGetDesc(tree->AsLclFld())->TypeIs(TYP_BYREF) || + !lvaIsImplicitByRefLocal(tree->AsLclFld()->GetLclNum())) + { + assert(((tree->gtFlags & GTF_VAR_USEASG) != 0) == tree->IsPartialLclFld(this)); + } break; case GT_CATCH_ARG: @@ -4020,7 +4025,7 @@ void Compiler::fgDebugCheckStmtsList(BasicBlock* block) } // For each statement check that the nodes are threaded correctly - m_treeList. - if (fgNodeThreading != NodeThreading::None) + if ((fgNodeThreading == NodeThreading::AllTrees) || (fgNodeThreading == NodeThreading::LIR)) { fgDebugCheckNodeLinks(block, stmt); } diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index e71bb6ed4473ad..703d138ece8135 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -371,6 +371,10 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorgtFlags |= (*use)->gtFlags & GTF_ALL_EFFECT; + } return fgWalkResult::WALK_CONTINUE; } diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 6cafff96b2d7a7..38e976db9b48b1 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -865,9 +865,10 @@ class LocalAddressVisitor final : public GenTreeVisitor }; ArrayStack m_valueStack; - bool m_stmtModified = false; - bool m_madeChanges = false; - bool m_propagatedAddrs = false; + bool m_stmtModified = false; + bool m_stmtSideEffectsModified = false; + bool m_madeChanges = false; + bool m_propagatedAddrs = false; LocalSequencer* m_sequencer; LocalEqualsLocalAddrAssertions* m_lclAddrAssertions; @@ -907,7 +908,8 @@ class LocalAddressVisitor final : public GenTreeVisitor } #endif // DEBUG - m_stmtModified = false; + m_stmtModified = false; + m_stmtSideEffectsModified = false; if (m_sequencer != nullptr) { @@ -922,6 +924,11 @@ class LocalAddressVisitor final : public GenTreeVisitor assert(m_valueStack.Empty()); m_madeChanges |= m_stmtModified; + if (m_stmtSideEffectsModified) + { + m_compiler->gtUpdateStmtSideEffects(stmt); + } + if (m_sequencer != nullptr) { if (m_stmtModified) @@ -1493,7 +1500,7 @@ class LocalAddressVisitor final : public GenTreeVisitor unsigned lclNum = val.LclNum(); LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum); - GenTreeFlags defFlag = GTF_EMPTY; + GenTreeFlags defFlags = GTF_EMPTY; GenTreeCall* callUser = (user != nullptr) && user->IsCall() ? user->AsCall() : nullptr; bool escapeAddr = true; if ((callUser != nullptr) && m_compiler->IsValidLclAddr(lclNum, val.Offset())) @@ -1534,11 +1541,13 @@ class LocalAddressVisitor final : public GenTreeVisitor { INDEBUG(varDsc->SetDefinedViaAddress(true)); escapeAddr = false; - defFlag = GTF_VAR_DEF; + defFlags = GTF_VAR_DEF; + m_stmtSideEffectsModified |= (callUser->gtFlags & GTF_ASG) == 0; + callUser->gtFlags |= GTF_ASG; if (!m_compiler->IsEntireAccess(lclNum, val.Offset(), ValueSize(defSize))) { - defFlag |= GTF_VAR_USEASG; + defFlags |= GTF_VAR_USEASG; } } } @@ -1573,7 +1582,7 @@ class LocalAddressVisitor final : public GenTreeVisitor #endif // TARGET_64BIT MorphLocalAddress(val.Node(), lclNum, val.Offset()); - val.Node()->gtFlags |= defFlag; + val.Node()->gtFlags |= defFlags; INDEBUG(val.Consume();) } @@ -1621,6 +1630,7 @@ class LocalAddressVisitor final : public GenTreeVisitor MorphLocalAddress(node->AsIndir()->Addr(), lclNum, offset); node->gtFlags |= GTF_GLOB_REF; // GLOB_REF may not be set already in the "large offset" case. + m_stmtSideEffectsModified = true; } else { @@ -1928,8 +1938,9 @@ class LocalAddressVisitor final : public GenTreeVisitor } } - lclNode->gtFlags = lclNodeFlags; - m_stmtModified = true; + lclNode->gtFlags = lclNodeFlags; + m_stmtModified = true; + m_stmtSideEffectsModified = true; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index 6f9d08189db3f6..a9e38e5eb28988 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -2933,6 +2933,7 @@ void ObjectAllocator::RewriteUses() // indir->Addr() = actualAddr; indir->gtFlags &= ~GTF_SIDE_EFFECT; + indir->gtFlags |= GTF_IND_NONFAULTING; GenTree* const newComma = m_compiler->gtNewOperNode(GT_COMMA, indir->TypeGet(), sideEffects, indir); *use = newComma;