@@ -1454,13 +1454,14 @@ extern const char* PhaseEnums[];
1454
1454
// clang-format off
1455
1455
enum class PhaseChecks : unsigned int
1456
1456
{
1457
- CHECK_NONE = 0 ,
1458
- CHECK_IR = 1 << 0 , // ir flags, etc
1459
- CHECK_UNIQUE = 1 << 1 , // tree node uniqueness
1460
- CHECK_FG = 1 << 2 , // flow graph integrity
1461
- CHECK_EH = 1 << 3 , // eh table integrity
1462
- CHECK_LOOPS = 1 << 4 , // loop table integrity
1463
- CHECK_PROFILE = 1 << 5 , // profile data integrity
1457
+ CHECK_NONE = 0 ,
1458
+ CHECK_IR = 1 << 0 , // ir flags, etc
1459
+ CHECK_UNIQUE = 1 << 1 , // tree node uniqueness
1460
+ CHECK_FG = 1 << 2 , // flow graph integrity
1461
+ CHECK_EH = 1 << 3 , // eh table integrity
1462
+ CHECK_LOOPS = 1 << 4 , // loop table integrity
1463
+ CHECK_PROFILE = 1 << 5 , // profile data integrity
1464
+ CHECK_LINKED_LOCALS = 1 << 6 , // check linked list of locals
1464
1465
};
1465
1466
1466
1467
inline constexpr PhaseChecks operator ~(PhaseChecks a)
@@ -1860,6 +1861,16 @@ struct RichIPMapping
1860
1861
DebugInfo debugInfo;
1861
1862
};
1862
1863
1864
+ // Current kind of node threading stored in GenTree::gtPrev and GenTree::gtNext.
1865
+ // See fgNodeThreading for more information.
1866
+ enum class NodeThreading
1867
+ {
1868
+ None,
1869
+ AllLocals, // Locals are threaded (after local morph when optimizing)
1870
+ AllTrees, // All nodes are threaded (after gtSetBlockOrder)
1871
+ LIR, // Nodes are in LIR form (after rationalization)
1872
+ };
1873
+
1863
1874
/*
1864
1875
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1865
1876
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -1910,6 +1921,7 @@ class Compiler
1910
1921
friend class LIR ;
1911
1922
friend class ObjectAllocator ;
1912
1923
friend class LocalAddressVisitor ;
1924
+ friend struct Statement ;
1913
1925
friend struct GenTree ;
1914
1926
friend class MorphInitBlockHelper ;
1915
1927
friend class MorphCopyBlockHelper ;
@@ -2789,7 +2801,7 @@ class Compiler
2789
2801
// is #of nodes in subtree) of "tree" is greater than "limit".
2790
2802
// (This is somewhat redundant with the "GetCostEx()/GetCostSz()" fields, but can be used
2791
2803
// before they have been set.)
2792
- bool gtComplexityExceeds (GenTree** tree, unsigned limit);
2804
+ bool gtComplexityExceeds (GenTree* tree, unsigned limit);
2793
2805
2794
2806
GenTree* gtReverseCond (GenTree* tree);
2795
2807
@@ -4448,30 +4460,47 @@ class Compiler
4448
4460
bool fgRemoveRestOfBlock; // true if we know that we will throw
4449
4461
bool fgStmtRemoved; // true if we remove statements -> need new DFA
4450
4462
4451
- // There are two modes for ordering of the trees.
4452
- // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4453
- // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4454
- // by traversing the tree according to the order of the operands.
4455
- // - In FGOrderLinear, the dominant ordering is the linear order.
4456
-
4457
4463
enum FlowGraphOrder
4458
4464
{
4459
4465
FGOrderTree,
4460
4466
FGOrderLinear
4461
4467
};
4468
+ // There are two modes for ordering of the trees.
4469
+ // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4470
+ // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4471
+ // by traversing the tree according to the order of the operands.
4472
+ // - In FGOrderLinear, the dominant ordering is the linear order.
4462
4473
FlowGraphOrder fgOrder;
4463
4474
4464
- // The following are boolean flags that keep track of the state of internal data structures
4465
-
4466
- bool fgStmtListThreaded; // true if the node list is now threaded
4467
- bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4468
- bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4469
- bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4470
- bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4471
- bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4472
- weight_t fgCalledCount; // count of the number of times this method was called
4473
- // This is derived from the profile data
4474
- // or is BB_UNITY_WEIGHT when we don't have profile data
4475
+ // The following are flags that keep track of the state of internal data structures
4476
+
4477
+ // Even in tree form (fgOrder == FGOrderTree) the trees are threaded in a
4478
+ // doubly linked lists during certain phases of the compilation.
4479
+ // - Local morph threads all locals to be used for early liveness and
4480
+ // forward sub when optimizing. This is kept valid until after forward sub.
4481
+ // The first local is kept in Statement::GetRootNode()->gtNext and the last
4482
+ // local in Statement::GetRootNode()->gtPrev. fgSequenceLocals can be used
4483
+ // to (re-)sequence a statement into this form, and
4484
+ // Statement::LocalsTreeList for range-based iteration. The order must
4485
+ // match tree order.
4486
+ //
4487
+ // - fgSetBlockOrder threads all nodes. This is kept valid until LIR form.
4488
+ // In this form the first node is given by Statement::GetTreeList and the
4489
+ // last node is given by Statement::GetRootNode(). fgSetStmtSeq can be used
4490
+ // to (re-)sequence a statement into this form, and Statement::TreeList for
4491
+ // range-based iteration. The order must match tree order.
4492
+ //
4493
+ // - Rationalization links all nodes into linear form which is kept until
4494
+ // the end of compilation. The first and last nodes are stored in the block.
4495
+ NodeThreading fgNodeThreading;
4496
+ bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4497
+ bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4498
+ bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4499
+ bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4500
+ bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4501
+ weight_t fgCalledCount; // count of the number of times this method was called
4502
+ // This is derived from the profile data
4503
+ // or is BB_UNITY_WEIGHT when we don't have profile data
4475
4504
4476
4505
#if defined(FEATURE_EH_FUNCLETS)
4477
4506
bool fgFuncletsCreated; // true if the funclet creation phase has been run
@@ -4724,6 +4753,8 @@ class Compiler
4724
4753
GenTreeLclVarCommon* lclVarNode);
4725
4754
bool fgComputeLifeLocal (VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode);
4726
4755
4756
+ GenTree* fgTryRemoveDeadStoreEarly (Statement* stmt, GenTreeLclVarCommon* dst);
4757
+
4727
4758
void fgComputeLife (VARSET_TP& life,
4728
4759
GenTree* startNode,
4729
4760
GenTree* endNode,
@@ -5419,6 +5450,7 @@ class Compiler
5419
5450
void fgDebugCheckLinks (bool morphTrees = false );
5420
5451
void fgDebugCheckStmtsList (BasicBlock* block, bool morphTrees);
5421
5452
void fgDebugCheckNodeLinks (BasicBlock* block, Statement* stmt);
5453
+ void fgDebugCheckLinkedLocals ();
5422
5454
void fgDebugCheckNodesUniqueness ();
5423
5455
void fgDebugCheckLoopTable ();
5424
5456
void fgDebugCheckSsa ();
@@ -5835,6 +5867,8 @@ class Compiler
5835
5867
5836
5868
bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
5837
5869
5870
+ PhaseStatus fgEarlyLiveness ();
5871
+
5838
5872
void fgMarkUseDef (GenTreeLclVarCommon* tree);
5839
5873
5840
5874
void fgBeginScopeLife (VARSET_TP* inScope, VarScopeDsc* var);
@@ -5926,11 +5960,12 @@ class Compiler
5926
5960
void fgMarkDemotedImplicitByRefArgs ();
5927
5961
5928
5962
PhaseStatus fgMarkAddressExposedLocals ();
5929
- void fgMarkAddressExposedLocals (Statement* stmt);
5963
+ void fgSequenceLocals (Statement* stmt);
5930
5964
5931
5965
PhaseStatus fgForwardSub ();
5932
5966
bool fgForwardSubBlock (BasicBlock* block);
5933
5967
bool fgForwardSubStatement (Statement* statement);
5968
+ void fgForwardSubUpdateLiveness (GenTree* newSubListFirst, GenTree* newSubListLast);
5934
5969
5935
5970
// The given local variable, required to be a struct variable, is being assigned via
5936
5971
// a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
@@ -9049,6 +9084,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9049
9084
9050
9085
bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
9051
9086
bool fgLocalVarLivenessChanged;
9087
+ bool fgIsDoingEarlyLiveness;
9088
+ bool fgDidEarlyLiveness;
9052
9089
bool compLSRADone;
9053
9090
bool compRationalIRForm;
9054
9091
@@ -10991,7 +11028,6 @@ class GenTreeVisitor
10991
11028
if (TVisitor::UseExecutionOrder && node->IsReverseOp ())
10992
11029
{
10993
11030
assert (node->AsMultiOp ()->GetOperandCount () == 2 );
10994
-
10995
11031
result = WalkTree (&node->AsMultiOp ()->Op (2 ), node);
10996
11032
if (result == fgWalkResult::WALK_ABORT)
10997
11033
{
0 commit comments