From 55f0552d36ac75cf0089cfd169b6e946fe561b19 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 4 Apr 2026 13:52:50 +0300 Subject: [PATCH] Remove compLvFrameListRoot special-casing from liveness This is referenced explicitly from IR generated by lowering. --- src/coreclr/jit/compiler.cpp | 4 -- src/coreclr/jit/gentree.cpp | 5 -- src/coreclr/jit/gentree.h | 1 - src/coreclr/jit/lclvars.cpp | 16 ----- src/coreclr/jit/liveness.cpp | 126 +---------------------------------- 5 files changed, 1 insertion(+), 151 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 77758b9f3cb9ce..34714c2b4c5aa8 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -9925,10 +9925,6 @@ JITDBGAPI void __cdecl cTreeFlags(Compiler* comp, GenTree* tree) } } - if (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH) - { - chars += printf("[CALL_M_FRAME_VAR_DEATH]"); - } if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_JIT_HELPER) { chars += printf("[CALL_M_TAILCALL_VIA_JIT_HELPER]"); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 5a65ddcadf0943..57a953a23420c9 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -13145,11 +13145,6 @@ void Compiler::gtDispTree(GenTree* tree, printf(" (async)"); } - if ((call->gtFlags & GTF_CALL_UNMANAGED) && (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH)) - { - printf(" (FramesRoot last use)"); - } - if ((call->gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0) { InlineCandidateInfo* inlineInfo; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index ed72dd9f8c87a5..07b79440e73e6f 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -4356,7 +4356,6 @@ enum GenTreeCallFlags : unsigned int // in special cases. Used to optimize fast way out in morphing GTF_CALL_M_VIRTSTUB_REL_INDIRECT = 0x00000020, // the virtstub is indirected through a relative address (only for GTF_CALL_VIRT_STUB) GTF_CALL_M_NONVIRT_SAME_THIS = 0x00000020, // callee "this" pointer is equal to caller this pointer (only for GTF_CALL_NONVIRT) - GTF_CALL_M_FRAME_VAR_DEATH = 0x00000040, // the compLvFrameListRoot variable dies here (last use) GTF_CALL_M_TAILCALL = 0x00000080, // the call is a tailcall GTF_CALL_M_EXPLICIT_TAILCALL = 0x00000100, // the call is "tail" prefixed and importer has performed tail call checks diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 49e339fcbf479a..473497b9237b8a 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3162,22 +3162,6 @@ bool LclVarDsc::CanBeReplacedWithItsField(Compiler* comp) const void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt) { const weight_t weight = block->getBBWeight(this); - - /* Is this a call to unmanaged code ? */ - if (tree->IsCall() && compMethodRequiresPInvokeFrame()) - { - assert(!opts.ShouldUsePInvokeHelpers() || (info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!opts.ShouldUsePInvokeHelpers()) - { - /* Get the special variable descriptor */ - LclVarDsc* varDsc = lvaGetDesc(info.compLvFrameListRoot); - - /* Increment the ref counts twice */ - varDsc->incRefCnts(weight, this); - varDsc->incRefCnts(weight, this); - } - } - if (tree->OperIs(GT_LCL_ADDR)) { LclVarDsc* varDsc = lvaGetDesc(tree->AsLclVarCommon()); diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index 81591b415cfe06..beb19eb55238a6 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -718,34 +718,6 @@ void Liveness::PerBlockLocalVarLiveness() } } - // Mark the FrameListRoot as used, if applicable. - - if (block->KindIs(BBJ_RETURN) && m_compiler->compMethodRequiresPInvokeFrame()) - { - assert(!m_compiler->opts.ShouldUsePInvokeHelpers() || - (m_compiler->info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!m_compiler->opts.ShouldUsePInvokeHelpers()) - { - // 32-bit targets always pop the frame in the epilog. - // For 64-bit targets, we only do this in the epilog for IL stubs; - // for non-IL stubs the frame is popped after every PInvoke call. -#ifdef TARGET_64BIT - if (m_compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB)) -#endif - { - LclVarDsc* varDsc = m_compiler->lvaGetDesc(m_compiler->info.compLvFrameListRoot); - - if (varDsc->lvTracked) - { - if (!VarSetOps::IsMember(m_compiler, m_curDefSet, varDsc->lvVarIndex)) - { - VarSetOps::AddElemD(m_compiler, m_curUseSet, varDsc->lvVarIndex); - } - } - } - } - } - VarSetOps::Assign(m_compiler, block->bbVarUse, m_curUseSet); VarSetOps::Assign(m_compiler, block->bbVarDef, m_curDefSet); @@ -933,33 +905,6 @@ void Liveness::PerNodeLocalVarLiveness(GenTree* tree) } } - // If this is a p/invoke unmanaged call or if this is a tail-call via helper, - // and we have an unmanaged p/invoke call in the method, - // then we're going to run the p/invoke epilog. - // So we mark the FrameRoot as used by this instruction. - // This ensures that the block->bbVarUse will contain - // the FrameRoot local var if is it a tracked variable. - - if ((call->IsUnmanaged() || call->IsTailCallViaJitHelper()) && m_compiler->compMethodRequiresPInvokeFrame()) - { - assert(!m_compiler->opts.ShouldUsePInvokeHelpers() || - (m_compiler->info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!m_compiler->opts.ShouldUsePInvokeHelpers() && !call->IsSuppressGCTransition()) - { - // Get the FrameRoot local and mark it as used. - - LclVarDsc* varDsc = m_compiler->lvaGetDesc(m_compiler->info.compLvFrameListRoot); - - if (varDsc->lvTracked) - { - if (!VarSetOps::IsMember(m_compiler, m_curDefSet, varDsc->lvVarIndex)) - { - VarSetOps::AddElemD(m_compiler, m_curUseSet, varDsc->lvVarIndex); - } - } - } - } - auto visitDef = [=](GenTreeLclVarCommon* lcl) { MarkUseDef(lcl); return GenTree::VisitResult::Continue; @@ -1767,67 +1712,8 @@ GenTreeLclVarCommon* Liveness::ComputeLifeCall(VARSET_TP& life, GenTreeCall* call) { assert(call != nullptr); - // If this is a tail-call via helper, and we have any unmanaged p/invoke calls in - // the method, then we're going to run the p/invoke epilog - // So we mark the FrameRoot as used by this instruction. - // This ensure that this variable is kept alive at the tail-call - if (call->IsTailCallViaJitHelper() && m_compiler->compMethodRequiresPInvokeFrame()) - { - assert(!m_compiler->opts.ShouldUsePInvokeHelpers() || (m_compiler->info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!m_compiler->opts.ShouldUsePInvokeHelpers()) - { - // Get the FrameListRoot local and make it live. - - LclVarDsc* frameVarDsc = m_compiler->lvaGetDesc(m_compiler->info.compLvFrameListRoot); - - if (frameVarDsc->lvTracked) - { - VarSetOps::AddElemD(m_compiler, life, frameVarDsc->lvVarIndex); - } - } - } - - // TODO: we should generate the code for saving to/restoring - // from the inlined PInvoke frame instead. - - /* Is this call to unmanaged code? */ - if (call->IsUnmanaged() && m_compiler->compMethodRequiresPInvokeFrame()) - { - // Get the FrameListRoot local and make it live. - assert(!m_compiler->opts.ShouldUsePInvokeHelpers() || (m_compiler->info.compLvFrameListRoot == BAD_VAR_NUM)); - if (!m_compiler->opts.ShouldUsePInvokeHelpers() && !call->IsSuppressGCTransition()) - { - LclVarDsc* frameVarDsc = m_compiler->lvaGetDesc(m_compiler->info.compLvFrameListRoot); - - if (frameVarDsc->lvTracked) - { - unsigned varIndex = frameVarDsc->lvVarIndex; - noway_assert(varIndex < m_compiler->lvaTrackedCount); - - // Is the variable already known to be alive? - // - if (VarSetOps::IsMember(m_compiler, life, varIndex)) - { - // Since we may call this multiple times, clear the GTF_CALL_M_FRAME_VAR_DEATH if set. - // - call->gtCallMoreFlags &= ~GTF_CALL_M_FRAME_VAR_DEATH; - } - else - { - // The variable is just coming to life - // Since this is a backwards walk of the trees - // that makes this change in liveness a 'last-use' - // - VarSetOps::AddElemD(m_compiler, life, varIndex); - call->gtCallMoreFlags |= GTF_CALL_M_FRAME_VAR_DEATH; - } - } - } - } - GenTreeLclVarCommon* partialDef = nullptr; - - auto visitDef = [&](const LocalDef& def) { + auto visitDef = [&](const LocalDef& def) { if (!def.IsEntire) { assert(partialDef == nullptr); @@ -2371,16 +2257,6 @@ void Liveness::ComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VAR }); blockRange.Remove(node); - - // Removing a call does not affect liveness unless it is a tail call in a method with P/Invokes or - // is itself a P/Invoke, in which case it may affect the liveness of the frame root variable. - if (!m_compiler->opts.ShouldUsePInvokeHelpers() && - ((call->IsTailCall() && m_compiler->compMethodRequiresPInvokeFrame()) || - (call->IsUnmanaged() && !call->IsSuppressGCTransition())) && - m_compiler->lvaTable[m_compiler->info.compLvFrameListRoot].lvTracked) - { - m_compiler->fgStmtRemoved = true; - } } else {