Skip to content

JIT: Preparatory refactoring to support multiple defs per single node #117662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 17, 2025

Conversation

jakobbotsch
Copy link
Member

Replace GenTree::DefinesLocal by a GenTree::VisitLocalDefs to prepare for being able to allow a single node to have multiple definitions. Update uses to use the new function.

I want to use this allow async calls to define a new value that represents whether the call suspended or not. This is necessary because runtime async calls should save and restore Thread.CurrentThread._synchronizationContext, but the restore should only happen when the call finishes synchronously (with an exception or not). I need a proper representation in the JIT IR of these conditions to properly be able to model these conditions in the face of inlining.

In a future change I expect to add a LCL_ADDR node as a new well-known argument to async calls that will be a definition that works similar to ret buffers. The async transformation will later expand the definition out in the resumption path.

Replace `GenTree::DefinesLocal` by a `GenTree::VisitLocalDefs` to
prepare for being able to allow a single node to have multiple
definitions. Update uses to use the new function.
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 15, 2025
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr superpmi-diffs

@jakobbotsch jakobbotsch marked this pull request as ready for review July 15, 2025 21:04
@Copilot Copilot AI review requested due to automatic review settings July 15, 2025 21:04
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member Author

cc @dotnet/jit-contrib PTAL @AndyAyersMS

No diffs are expected, but the diffs run didn't succeed because of a JIT-EE GUID change. Kicked it off again.

@jakobbotsch jakobbotsch requested a review from AndyAyersMS July 15, 2025 21:05
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request refactors how the JIT handles local variable definitions by replacing the single-definition method GenTree::DefinesLocal with a visitor pattern method GenTree::VisitLocalDefs. This change prepares the JIT infrastructure to support multiple definitions per node, which will be needed for async call optimizations where calls need to define both the return value and a suspension state indicator.

Key changes include:

  • Introduces a new LocalDef struct to encapsulate definition metadata (local, entirety, offset, size)
  • Replaces DefinesLocal calls with VisitLocalDefs throughout the codebase
  • Updates SSA builder, value numbering, liveness analysis, and other passes to use the visitor pattern

Reviewed Changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/coreclr/jit/gentree.h Defines LocalDef struct and VisitLocalDefs interface
src/coreclr/jit/compiler.hpp Implements VisitLocalDefs template method and HasAnyLocalDefs helper
src/coreclr/jit/gentree.cpp Removes old DefinesLocal method implementation
src/coreclr/jit/valuenum.cpp Updates value numbering to use visitor pattern for call definitions
src/coreclr/jit/ssabuilder.cpp Refactors SSA renaming to handle multiple definitions via visitor
src/coreclr/jit/liveness.cpp Updates liveness analysis to use visitor pattern for call definitions
src/coreclr/jit/morph.cpp Updates variable definition flagging to use visitor pattern
src/coreclr/jit/copyprop.cpp Updates copy propagation to use visitor pattern for definitions
src/coreclr/jit/treelifeupdater.cpp Updates tree life updater to use visitor for call definitions
src/coreclr/jit/lower.cpp Updates lowering to use visitor for tracking stored locals
src/coreclr/jit/flowgraph.cpp Updates flow graph analysis to use visitor pattern
src/coreclr/jit/fgdiagnostic.cpp Updates SSA diagnostics to use visitor pattern

@jakobbotsch
Copy link
Member Author

Some somewhat substantial TP regressions (~0.5%). Detailed TP diff shows:

Base: 361880161367, Diff: 363292788374, +0.3904%

932448943  : NA       : 22.80% : +0.2577% : private: void __cdecl Compiler::fgMorphTreeDone(struct GenTree *, bool)                                                                                                                                                                                                                   
344680072  : NA       : 8.43%  : +0.0952% : private: void __cdecl TreeLifeUpdater<0>::UpdateLifeVar(struct GenTree *, struct GenTreeLclVarCommon *)                                                                                                                                                                                   
204970545  : +48.21%  : 5.01%  : +0.0566% : protected: void __cdecl CodeGenInterface::genUpdateLife(struct GenTree *)                                                                                                                                                                                                                 
160776041  : NA       : 3.93%  : +0.0444% : GenTree::VisitLocalDefs<`SsaBuilder::RenameDef'::`2'::<lambda_1> >                                                                                                                                                                                                                        
153812573  : NA       : 3.76%  : +0.0425% : public: void __cdecl Compiler::optCopyPropPushDef(struct GenTreeLclVarCommon *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)                  
152933619  : NA       : 3.74%  : +0.0423% : GenTree::VisitLocalDefs<`Compiler::optBlockCopyPropPopStacks'::`10'::<lambda_2> >                                                                                                                                                                                                         
134316826  : NA       : 3.28%  : +0.0371% : `Compiler::optBlockCopyPropPopStacks'::`2'::<lambda_1>::operator()                                                                                                                                                                                                                        
123004353  : +11.96%  : 3.01%  : +0.0340% : private: void __cdecl SsaBuilder::BlockRenameVariables(struct BasicBlock *)                                                                                                                                                                                                               
119085957  : NA       : 2.91%  : +0.0329% : `SsaBuilder::RenameDef'::`2'::<lambda_1>::operator()                                                                                                                                                                                                                                      
79005736   : NA       : 1.93%  : +0.0218% : GenTree::VisitLocalDefs<`Compiler::fgComputeLifeCall'::`2'::<lambda_1> >                                                                                                                                                                                                                  
73832950   : NA       : 1.81%  : +0.0204% : `Compiler::optBlockCopyPropPopStacks'::`10'::<lambda_2>::operator()                                                                                                                                                                                                                       
31860613   : NA       : 0.78%  : +0.0088% : GenTree::VisitLocalDefs<`Compiler::fgAssignSetVarDef'::`2'::<lambda_1> >                                                                                                                                                                                                                  
31742868   : +5.73%   : 0.78%  : +0.0088% : public: void __cdecl Compiler::fgPerNodeLocalVarLiveness<0>(struct GenTree *)                                                                                                                                                                                                             
30971778   : NA       : 0.76%  : +0.0086% : GenTree::VisitLocalDefs<`Compiler::fgValueNumberCall'::`2'::<lambda_1> >                                                                                                                                                                                                                  
27867899   : NA       : 0.68%  : +0.0077% : `FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::HasDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit                                                                                                                                                                 
26916125   : NA       : 0.66%  : +0.0074% : GenTree::VisitLocalDefs<``FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit'::`2'::<lambda_1> >                                                                                                                   
21575825   : +1.08%   : 0.53%  : +0.0060% : public: void __cdecl Compiler::fgValueNumberTree(struct GenTree *)                                                                                                                                                                                                                        
14860821   : +0.38%   : 0.36%  : +0.0041% : private: struct GenTree * __cdecl Compiler::fgMorphSmpOp(struct GenTree *, struct Compiler::MorphAddrContext *, bool *)                                                                                                                                                                   
13837311   : NA       : 0.34%  : +0.0038% : private: void __cdecl SsaBuilder::RenamePushMemoryDef(struct GenTree *, struct BasicBlock *)                                                                                                                                                                                              
13227273   : +10.96%  : 0.32%  : +0.0037% : GenTreeVisitor<`FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor>::WalkTree                                                                                                                                                     
11444636   : +1.18%   : 0.28%  : +0.0032% : public: void __cdecl Compiler::fgPerNodeLocalVarLiveness<1>(struct GenTree *)                                                                                                                                                                                                             
10770794   : +1.04%   : 0.26%  : +0.0030% : public: void __cdecl Compiler::fgComputeLife(unsigned __int64 *&, struct GenTree *, struct GenTree *, unsigned __int64 *const &, bool *)                                                                                                                                                  
10051486   : +1.43%   : 0.25%  : +0.0028% : public: void __cdecl Compiler::fgComputeLifeTrackedLocalUse(unsigned __int64 *&, class LclVarDsc &, struct GenTreeLclVarCommon *)                                                                                                                                                         
9180938    : +12.20%  : 0.22%  : +0.0025% : public: struct GenTreeLclVarCommon * __cdecl Compiler::fgComputeLifeCall(unsigned __int64 *&, unsigned __int64 *const &, struct GenTreeCall *)                                                                                                                                            
-5569843   : -8.69%   : 0.14%  : -0.0015% : GenTreeVisitor<`FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::HasDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor>::WalkTree                                                                                                                                                      
-6401775   : -100.00% : 0.16%  : -0.0018% : private: void __cdecl Compiler::fgMorphTreeDone(struct GenTree *)                                                                                                                                                                                                                         
-16608636  : -5.47%   : 0.41%  : -0.0046% : private: struct GenTree * __cdecl Compiler::fgMorphCall(struct GenTreeCall *)                                                                                                                                                                                                             
-22280998  : -2.63%   : 0.54%  : -0.0062% : public: bool __cdecl Compiler::optBlockCopyProp(struct BasicBlock *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)                             
-42685735  : -100.00% : 1.04%  : -0.0118% : `FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit                                                                                                                                                                
-51896579  : -100.00% : 1.27%  : -0.0143% : public: void __cdecl Compiler::fgValueNumberCall(struct GenTreeCall *)                                                                                                                                                                                                                    
-62800730  : -99.88%  : 1.54%  : -0.0174% : public: struct GenTreeLclVarCommon * __cdecl Compiler::gtCallGetDefinedRetBufLclAddr(struct GenTreeCall *)                                                                                                                                                                                
-118403151 : -20.47%  : 2.90%  : -0.0327% : public: enum PhaseStatus __cdecl Compiler::optVnCopyProp(void)                                                                                                                                                                                                                            
-145981378 : -17.96%  : 3.57%  : -0.0403% : public: void __cdecl TreeLifeUpdater<0>::UpdateLife(struct GenTree *)                                                                                                                                                                                                                     
-157299587 : -100.00% : 3.85%  : -0.0435% : public: void __cdecl Compiler::optCopyPropPushDef(struct GenTree *, struct GenTreeLclVarCommon *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)
-272428263 : -100.00% : 6.66%  : -0.0753% : private: void __cdecl SsaBuilder::RenameDef(struct GenTree *, struct BasicBlock *)                                                                                                                                                                                                        
-430120612 : -17.06%  : 10.52% : -0.1189% : public: struct GenTree * __cdecl Compiler::fgMorphTree(struct GenTree *, struct Compiler::MorphAddrContext *)                                                                                                                                                                             

Pushed a commit that mitigates it somewhat by introducing some slight duplication. There is now both a GenTree::VisitLocalDefs and GenTree::VisitLocalDefNodes, with the latter only calling the callback on the GenTreeLclVarCommon* representing the def. Most places care only about that. New detailed TP regressions are:

Base: 361880161367, Diff: 362523114870, +0.1777%

929565931  : NA       : 16.70% : +0.2569% : private: void __cdecl Compiler::fgMorphTreeDone(struct GenTree *, bool)                                                                                                                                                                                                                   
465768584  : NA       : 8.37%  : +0.1287% : DomTreeVisitor<`Compiler::optVnCopyProp'::`2'::CopyPropDomTreeVisitor>::WalkTree                                                                                                                                                                                                          
344680072  : NA       : 6.19%  : +0.0952% : private: void __cdecl TreeLifeUpdater<0>::UpdateLifeVar(struct GenTree *, struct GenTreeLclVarCommon *)                                                                                                                                                                                   
291414505  : +34.46%  : 5.23%  : +0.0805% : public: bool __cdecl Compiler::optBlockCopyProp(struct BasicBlock *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)                             
160776041  : NA       : 2.89%  : +0.0444% : GenTree::VisitLocalDefs<`SsaBuilder::RenameDef'::`2'::<lambda_1> >                                                                                                                                                                                                                        
153812573  : NA       : 2.76%  : +0.0425% : public: void __cdecl Compiler::optCopyPropPushDef(struct GenTreeLclVarCommon *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)                  
134316826  : NA       : 2.41%  : +0.0371% : `Compiler::optBlockCopyPropPopStacks'::`2'::<lambda_1>::operator()                                                                                                                                                                                                                        
123004353  : +11.96%  : 2.21%  : +0.0340% : private: void __cdecl SsaBuilder::BlockRenameVariables(struct BasicBlock *)                                                                                                                                                                                                               
119085957  : NA       : 2.14%  : +0.0329% : `SsaBuilder::RenameDef'::`2'::<lambda_1>::operator()                                                                                                                                                                                                                                      
79005736   : NA       : 1.42%  : +0.0218% : GenTree::VisitLocalDefs<`Compiler::fgComputeLifeCall'::`2'::<lambda_1> >                                                                                                                                                                                                                  
59988264   : NA       : 1.08%  : +0.0166% : `Compiler::optBlockCopyPropPopStacks'::`10'::<lambda_2>::operator()                                                                                                                                                                                                                       
31860613   : NA       : 0.57%  : +0.0088% : GenTree::VisitLocalDefs<`Compiler::fgAssignSetVarDef'::`2'::<lambda_1> >                                                                                                                                                                                                                  
31647577   : +5.72%   : 0.57%  : +0.0087% : public: void __cdecl Compiler::fgPerNodeLocalVarLiveness<0>(struct GenTree *)                                                                                                                                                                                                             
30971778   : NA       : 0.56%  : +0.0086% : GenTree::VisitLocalDefs<`Compiler::fgValueNumberCall'::`2'::<lambda_1> >                                                                                                                                                                                                                  
26785279   : +2.77%   : 0.48%  : +0.0074% : public: void __cdecl Compiler::fgPerNodeLocalVarLiveness<1>(struct GenTree *)                                                                                                                                                                                                             
21575825   : +1.08%   : 0.39%  : +0.0060% : public: void __cdecl Compiler::fgValueNumberTree(struct GenTree *)                                                                                                                                                                                                                        
16577396   : NA       : 0.30%  : +0.0046% : GenTree::VisitLocalDefNodes<``FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit'::`2'::<lambda_1> >                                                                                                               
14860821   : +0.38%   : 0.27%  : +0.0041% : private: struct GenTree * __cdecl Compiler::fgMorphSmpOp(struct GenTree *, struct Compiler::MorphAddrContext *, bool *)                                                                                                                                                                   
13837311   : NA       : 0.25%  : +0.0038% : private: void __cdecl SsaBuilder::RenamePushMemoryDef(struct GenTree *, struct BasicBlock *)                                                                                                                                                                                              
11803462   : +9.78%   : 0.21%  : +0.0033% : GenTreeVisitor<`FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor>::WalkTree                                                                                                                                                     
10770794   : +1.04%   : 0.19%  : +0.0030% : public: void __cdecl Compiler::fgComputeLife(unsigned __int64 *&, struct GenTree *, struct GenTree *, unsigned __int64 *const &, bool *)                                                                                                                                                  
10051486   : +1.43%   : 0.18%  : +0.0028% : public: void __cdecl Compiler::fgComputeLifeTrackedLocalUse(unsigned __int64 *&, class LclVarDsc &, struct GenTreeLclVarCommon *)                                                                                                                                                         
9180938    : +12.20%  : 0.16%  : +0.0025% : public: struct GenTreeLclVarCommon * __cdecl Compiler::fgComputeLifeCall(unsigned __int64 *&, unsigned __int64 *const &, struct GenTreeCall *)                                                                                                                                            
8392134    : NA       : 0.15%  : +0.0023% : GenTree::VisitLocalDefNodes<``FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::HasDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit'::`2'::<lambda_1> >                                                                                                                
-6401775   : -100.00% : 0.11%  : -0.0018% : private: void __cdecl Compiler::fgMorphTreeDone(struct GenTree *)                                                                                                                                                                                                                         
-7221568   : -1.70%   : 0.13%  : -0.0020% : protected: void __cdecl CodeGenInterface::genUpdateLife(struct GenTree *)                                                                                                                                                                                                                 
-16608636  : -5.47%   : 0.30%  : -0.0046% : private: struct GenTree * __cdecl Compiler::fgMorphCall(struct GenTreeCall *)                                                                                                                                                                                                             
-17186196  : -0.53%   : 0.31%  : -0.0047% : memset                                                                                                                                                                                                                                                                                    
-42685735  : -100.00% : 0.77%  : -0.0118% : `FlowGraphNaturalLoop::VisitDefs<`FlowGraphNaturalLoop::FindDef'::`2'::<lambda_1> >'::`2'::VisitDefsVisitor::PreOrderVisit                                                                                                                                                                
-51896579  : -100.00% : 0.93%  : -0.0143% : public: void __cdecl Compiler::fgValueNumberCall(struct GenTreeCall *)                                                                                                                                                                                                                    
-62800730  : -99.88%  : 1.13%  : -0.0174% : public: struct GenTreeLclVarCommon * __cdecl Compiler::gtCallGetDefinedRetBufLclAddr(struct GenTreeCall *)                                                                                                                                                                                
-157299587 : -100.00% : 2.83%  : -0.0435% : public: void __cdecl Compiler::optCopyPropPushDef(struct GenTree *, struct GenTreeLclVarCommon *, class JitHashTable<unsigned int, struct JitSmallPrimitiveKeyFuncs<unsigned int>, class ArrayStack<class Compiler::CopyPropSsaDef> *, class CompAllocator, class JitHashTableBehavior> *)
-272428263 : -100.00% : 4.89%  : -0.0753% : private: void __cdecl SsaBuilder::RenameDef(struct GenTree *, struct BasicBlock *)                                                                                                                                                                                                        
-430120612 : -17.06%  : 7.73%  : -0.1189% : public: struct GenTree * __cdecl Compiler::fgMorphTree(struct GenTree *, struct Compiler::MorphAddrContext *)                                                                                                                                                                             
-575070918 : -99.43%  : 10.33% : -0.1589% : public: enum PhaseStatus __cdecl Compiler::optVnCopyProp(void)                                                                                                                                                                                                                            
-812899306 : -100.00% : 14.60% : -0.2246% : public: void __cdecl TreeLifeUpdater<0>::UpdateLife(struct GenTree *)                                                                                                                                                                                                                     

That mostly seems like changes in inlining, so I think we should take it as is.

@jakobbotsch
Copy link
Member Author

/ba-g Android timeout and rest of failures are known

@jakobbotsch jakobbotsch merged commit 23323e9 into dotnet:main Jul 17, 2025
106 of 111 checks passed
@jakobbotsch jakobbotsch deleted the multiple-defs-per-node branch July 17, 2025 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants