Skip to content
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

JIT: Add a (disabled) prototype for a generalized promotion pass #83388

Merged
merged 57 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
46e8c65
JIT: Prototype a generalized promotion pass
jakobbotsch Mar 14, 2023
faa8260
Remove some old code
jakobbotsch Mar 14, 2023
b4cf692
Fix accounting mistake
jakobbotsch Mar 14, 2023
8c602ee
Fix a JITDUMP
jakobbotsch Mar 16, 2023
294e7be
Add overlapped assignment heuristic
jakobbotsch Mar 16, 2023
9fde2ee
Fix register candidate assignment accounting
jakobbotsch Mar 16, 2023
a030d98
Add a note in the dump when known conservative copies happen
jakobbotsch Mar 16, 2023
dd3b8e3
Weighted uses
jakobbotsch Mar 16, 2023
a693d29
Add a fix to enable promotion in customer scenario
jakobbotsch Mar 17, 2023
705e419
JIT: Generalize handling of commas in block morphing
jakobbotsch Mar 17, 2023
75c3063
Write call arg uses before arg instead of call
jakobbotsch Mar 22, 2023
47f27f5
Clean up
jakobbotsch Mar 22, 2023
bcc1dd3
Change types of comma args properly in call arg morphing
jakobbotsch Mar 22, 2023
724a582
Fix write-back of local on RHS of assignment
jakobbotsch Mar 22, 2023
4d3f4ba
Run jit-format
jakobbotsch Mar 22, 2023
14113a9
Remove some layouts, change some costing, clean up
jakobbotsch Mar 22, 2023
0c7bbf3
Early out when there are no locals
jakobbotsch Mar 22, 2023
0b140bf
Run jit-format
jakobbotsch Mar 22, 2023
c4a04d7
Remove dead code
jakobbotsch Mar 22, 2023
c9974d5
Some more cleanup
jakobbotsch Mar 22, 2023
fc075a3
Add more fine-grained stress modes
jakobbotsch Mar 22, 2023
0c55c69
Add some stress modes
jakobbotsch Mar 23, 2023
91db180
Uncomment stress check
jakobbotsch Mar 23, 2023
9c7c765
Merge branch 'main' of github.com:dotnet/runtime into generalized-pro…
jakobbotsch Mar 25, 2023
8603c5f
Merge branch 'main' of github.com:dotnet/runtime into generalized-pro…
jakobbotsch Mar 28, 2023
6ec92c8
Propagate lvSuppressedZeroInit
jakobbotsch Mar 28, 2023
c8e4dcb
Comment stress mode only enabling
jakobbotsch Mar 28, 2023
31f8769
Run jit-format
jakobbotsch Mar 28, 2023
2075c61
Explicitly zero-init promoted locals with suppressed init
jakobbotsch Mar 28, 2023
d2d4401
Fix JITDUMP wrong format specifier
jakobbotsch Mar 28, 2023
3308998
Disallow tail merging from adding predecessors to the scratch BB
jakobbotsch Mar 28, 2023
1862149
Avoid picking scratch block as victim instead
jakobbotsch Mar 28, 2023
baaff75
Oops
jakobbotsch Mar 28, 2023
24773f1
Fix gtSplitTree for some void-typed commas
jakobbotsch Mar 29, 2023
43d0315
Add to jit-experimental
jakobbotsch Mar 29, 2023
d9421de
Clean up, add function headers, disable by default
jakobbotsch Mar 29, 2023
3a3950d
Fix assert, fix visit order for LHS of ASGs
jakobbotsch Mar 29, 2023
9a36a5a
Run jit-format
jakobbotsch Mar 29, 2023
9424e6f
Create some data structures lazily
jakobbotsch Mar 29, 2023
7424c03
Add GTF_DEBUG_NODE_MORPHED properly in new block morph
jakobbotsch Mar 29, 2023
1305aad
Update statement side effects on replacer changes
jakobbotsch Mar 29, 2023
9709b7b
Skip local copy prop assertions in problematic case
jakobbotsch Mar 30, 2023
e58a2d5
Merge branch 'main' of github.com:dotnet/runtime into generalized-pro…
jakobbotsch Mar 30, 2023
a22b62f
Undo accidental reversion
jakobbotsch Mar 30, 2023
7595039
Fix treatment of retbufs
jakobbotsch Mar 31, 2023
585a85a
Adjust some stress frequencies
jakobbotsch Mar 31, 2023
e8ebbb5
Fix incorrect assert
jakobbotsch Apr 4, 2023
7c8e130
Rename pass to "physical promotion"
jakobbotsch Apr 4, 2023
dbfb517
Merge branch 'main' of github.com:dotnet/runtime into generalized-pro…
jakobbotsch Apr 4, 2023
5158616
Fix after merge
jakobbotsch Apr 4, 2023
96bad09
Revert unnecessary change
jakobbotsch Apr 5, 2023
3172f37
Include headers instead of forward declarations
jakobbotsch Apr 5, 2023
0b335ff
Remove some currently unused accounting
jakobbotsch Apr 5, 2023
cbb7d84
Clean up, add some comments
jakobbotsch Apr 5, 2023
0809197
Avoid diffs
jakobbotsch Apr 5, 2023
8338272
Run jit-format
jakobbotsch Apr 5, 2023
ea2786d
Merge branch 'main' of github.com:dotnet/runtime into generalized-pro…
jakobbotsch Apr 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions eng/pipelines/common/templates/runtimes/run-test-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,8 @@ jobs:
- jitpartialcompilation
- jitpartialcompilation_pgo
- jitobjectstackallocation
- jitgeneralizedpromotion
- jitgeneralizedpromotion_full

${{ if in(parameters.testGroup, 'jit-cfg') }}:
scenarios:
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ set( JIT_SOURCES
optimizer.cpp
patchpoint.cpp
phase.cpp
promotion.cpp
rangecheck.cpp
rationalize.cpp
redundantbranchopts.cpp
Expand Down Expand Up @@ -336,6 +337,7 @@ set( JIT_HEADERS
objectalloc.h
opcode.h
phase.h
promotion.h
rangecheck.h
rationalize.h
regalloc.h
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,22 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
goto DONE_ASSERTION; // Don't make an assertion
}

// We process locals when we see the LCL_VAR node instead
// of at its actual use point (its parent). That opens us
// up to problems in a case like the following, assuming we
// allowed creating an assertion like V10 = V35:
//
// └──▌ ADD int
// ├──▌ LCL_VAR int V10 tmp6 -> copy propagated to [V35 tmp31]
// └──▌ COMMA int
// ├──▌ ASG int
// │ ├──▌ LCL_VAR int V35 tmp31
// │ └──▌ LCL_FLD int V03 loc1 [+4]
if (lclVar2->lvRedefinedInEmbeddedStatement)
{
goto DONE_ASSERTION; // Don't make an assertion
}

assertion.op2.kind = O2K_LCLVAR_COPY;
assertion.op2.vn = optConservativeNormalVN(op2);
assertion.op2.lcl.lclNum = lclNum2;
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4722,6 +4722,10 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
//
DoPhase(this, PHASE_EARLY_LIVENESS, &Compiler::fgEarlyLiveness);

// Promote struct locals based on primitive access patterns
//
DoPhase(this, PHASE_PHYSICAL_PROMOTION, &Compiler::PhysicalPromotion);

// Run a simple forward substitution pass.
//
DoPhase(this, PHASE_FWD_SUB, &Compiler::fgForwardSub);
Expand Down
14 changes: 12 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,8 @@ class LclVarDsc

unsigned char lvIsOSRExposedLocal : 1; // OSR local that was address exposed in Tier0

unsigned char lvRedefinedInEmbeddedStatement : 1; // Local has redefinitions inside embedded statements that
// disqualify it from local copy prop.
private:
unsigned char lvIsNeverNegative : 1; // The local is known to be never negative

Expand Down Expand Up @@ -2024,6 +2026,9 @@ class Compiler
friend class CallArgs;
friend class IndirectCallTransformer;
friend class ProfileSynthesis;
friend class LocalsUseVisitor;
friend class Promotion;
friend class ReplaceVisitor;

#ifdef FEATURE_HW_INTRINSICS
friend struct HWIntrinsicInfo;
Expand Down Expand Up @@ -2443,7 +2448,7 @@ class Compiler
GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1);

// For binary opers.
GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
GenTreeOp* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);

GenTreeCC* gtNewCC(genTreeOps oper, var_types type, GenCondition cond);
GenTreeOpCC* gtNewOperCC(genTreeOps oper, var_types type, GenCondition cond, GenTree* op1, GenTree* op2);
Expand Down Expand Up @@ -5760,9 +5765,9 @@ class Compiler
private:
void fgInsertStmtNearEnd(BasicBlock* block, Statement* stmt);
void fgInsertStmtAtBeg(BasicBlock* block, Statement* stmt);
void fgInsertStmtAfter(BasicBlock* block, Statement* insertionPoint, Statement* stmt);

public:
void fgInsertStmtAfter(BasicBlock* block, Statement* insertionPoint, Statement* stmt);
void fgInsertStmtBefore(BasicBlock* block, Statement* insertionPoint, Statement* stmt);

private:
Expand Down Expand Up @@ -6098,6 +6103,8 @@ class Compiler
PhaseStatus fgMarkAddressExposedLocals();
void fgSequenceLocals(Statement* stmt);

PhaseStatus PhysicalPromotion();

PhaseStatus fgForwardSub();
bool fgForwardSubBlock(BasicBlock* block);
bool fgForwardSubStatement(Statement* statement);
Expand Down Expand Up @@ -9853,6 +9860,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
STRESS_MODE(SSA_INFO) /* Select lower thresholds for "complex" SSA num encoding */ \
STRESS_MODE(SPLIT_TREES_RANDOMLY) /* Split all statements at a random tree */ \
STRESS_MODE(SPLIT_TREES_REMOVE_COMMAS) /* Remove all GT_COMMA nodes */ \
STRESS_MODE(NO_OLD_PROMOTION) /* Do not use old promotion */ \
STRESS_MODE(PHYSICAL_PROMOTION) /* Use physical promotion */ \
STRESS_MODE(PHYSICAL_PROMOTION_COST) \
\
/* After COUNT_VARN, stress level 2 does all of these all the time */ \
\
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compmemkind.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CompMemKindMacro(LoopHoist)
CompMemKindMacro(Unknown)
CompMemKindMacro(RangeCheck)
CompMemKindMacro(CopyProp)
CompMemKindMacro(Promotion)
CompMemKindMacro(SideEffects)
CompMemKindMacro(ObjectAllocator)
CompMemKindMacro(VariableLiveRanges)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compphases.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ CompPhaseNameMacro(PHASE_UPDATE_FINALLY_FLAGS, "Update finally target flag
CompPhaseNameMacro(PHASE_EARLY_UPDATE_FLOW_GRAPH, "Update flow graph early pass", false, -1, false)
CompPhaseNameMacro(PHASE_STR_ADRLCL, "Morph - Structs/AddrExp", false, -1, false)
CompPhaseNameMacro(PHASE_EARLY_LIVENESS, "Early liveness", false, -1, false)
CompPhaseNameMacro(PHASE_PHYSICAL_PROMOTION, "Physical promotion", false, -1, false)
CompPhaseNameMacro(PHASE_FWD_SUB, "Forward Substitution", false, -1, false)
CompPhaseNameMacro(PHASE_MORPH_IMPBYREF, "Morph - ByRefs", false, -1, false)
CompPhaseNameMacro(PHASE_PROMOTE_STRUCTS, "Morph - Promote Structs", false, -1, false)
Expand Down
67 changes: 37 additions & 30 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6771,45 +6771,52 @@ PhaseStatus Compiler::fgTailMerge()
//
for (BasicBlock* const predBlock : block->PredBlocks())
{
if ((predBlock->GetUniqueSucc() == block) && BasicBlock::sameEHRegion(block, predBlock))
if (predBlock->GetUniqueSucc() != block)
{
Statement* lastStmt = predBlock->lastStmt();
continue;
}

// Block might be empty.
//
if (lastStmt == nullptr)
{
continue;
}
if (!BasicBlock::sameEHRegion(block, predBlock))
{
continue;
}

// Walk back past any GT_NOPs.
//
Statement* const firstStmt = predBlock->firstStmt();
while (lastStmt->GetRootNode()->OperIs(GT_NOP))
{
if (lastStmt == firstStmt)
{
// predBlock is evidently all GT_NOP.
//
lastStmt = nullptr;
break;
}
Statement* lastStmt = predBlock->lastStmt();

lastStmt = lastStmt->GetPrevStmt();
}
// Block might be empty.
//
if (lastStmt == nullptr)
{
continue;
}

// Block might be effectively empty.
//
if (lastStmt == nullptr)
// Walk back past any GT_NOPs.
//
Statement* const firstStmt = predBlock->firstStmt();
while (lastStmt->GetRootNode()->OperIs(GT_NOP))
{
if (lastStmt == firstStmt)
{
continue;
// predBlock is evidently all GT_NOP.
//
lastStmt = nullptr;
break;
}

// We don't expect to see PHIs but watch for them anyways.
//
assert(!lastStmt->IsPhiDefnStmt());
predInfo.Emplace(predBlock, lastStmt);
lastStmt = lastStmt->GetPrevStmt();
}

// Block might be effectively empty.
//
if (lastStmt == nullptr)
{
continue;
}

// We don't expect to see PHIs but watch for them anyways.
//
assert(!lastStmt->IsPhiDefnStmt());
predInfo.Emplace(predBlock, lastStmt);
}

// Are there enough preds to make it interesting?
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/fgstmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,15 @@ Statement* Compiler::fgNewStmtFromTree(GenTree* tree, BasicBlock* block, const D
{
Statement* stmt = gtNewStmt(tree, di);

if (fgNodeThreading != NodeThreading::None)
if (fgNodeThreading == NodeThreading::AllTrees)
{
gtSetStmtInfo(stmt);
fgSetStmtSeq(stmt);
}
else if (fgNodeThreading == NodeThreading::AllLocals)
{
fgSequenceLocals(stmt);
}

#if DEBUG
if (block != nullptr)
Expand Down
37 changes: 32 additions & 5 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6978,7 +6978,7 @@ void GenTree::SetVtableForOper(genTreeOps oper)
}
#endif // DEBUGGABLE_GENTREE

GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
GenTreeOp* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
{
assert(op1 != nullptr);
assert(op2 != nullptr);
Expand All @@ -6987,7 +6987,7 @@ GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1,
// should call the appropriate constructor for the extended type.
assert(!GenTree::IsExOp(GenTree::OperKind(oper)));

GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
GenTreeOp* node = new (this, oper) GenTreeOp(oper, type, op1, op2);

return node;
}
Expand Down Expand Up @@ -8459,7 +8459,7 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
return nullptr;
}

if (tree->gtOper == GT_FIELD)
if (tree->OperIs(GT_FIELD))
{
GenTree* objp = nullptr;

Expand Down Expand Up @@ -16333,6 +16333,34 @@ bool Compiler::gtSplitTree(
return false;
}

bool IsValue(const UseInfo& useInf)
{
GenTree* node = (*useInf.Use)->gtEffectiveVal();
if (!node->IsValue())
{
return false;
}

if (node->OperIs(GT_ASG))
{
return false;
}

GenTree* user = useInf.User;

if (user == nullptr)
{
return false;
}

if (user->OperIs(GT_COMMA) && (&user->AsOp()->gtOp1 == useInf.Use))
{
return false;
}

return true;
}

void SplitOutUse(const UseInfo& useInf, bool userIsReturned)
{
GenTree** use = useInf.Use;
Expand Down Expand Up @@ -16398,8 +16426,7 @@ bool Compiler::gtSplitTree(
}

Statement* stmt = nullptr;
if (!(*use)->IsValue() || (*use)->gtEffectiveVal()->OperIs(GT_ASG) || (user == nullptr) ||
(user->OperIs(GT_COMMA) && (user->gtGetOp1() == *use)))
if (!IsValue(useInf))
{
GenTree* sideEffects = nullptr;
m_compiler->gtExtractSideEffList(*use, &sideEffects);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ CONFIG_STRING(JitEnableVNBasedDeadStoreRemovalRange, W("JitEnableVNBasedDeadStor
CONFIG_STRING(JitEnableEarlyLivenessRange, W("JitEnableEarlyLivenessRange"))
CONFIG_STRING(JitOnlyOptimizeRange,
W("JitOnlyOptimizeRange")) // If set, all methods that do _not_ match are forced into MinOpts
CONFIG_STRING(JitEnablePhysicalPromotionRange, W("JitEnablePhysicalPromotionRange"))

CONFIG_INTEGER(JitDoSsa, W("JitDoSsa"), 1) // Perform Static Single Assignment (SSA) numbering on the variables
CONFIG_INTEGER(JitDoValueNumber, W("JitDoValueNumber"), 1) // Perform value numbering on method expressions
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/jitstd/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ void vector<T, Allocator>::insert_elements_helper(iterator iter, size_type size,

ensure_capacity(m_nSize + size);

for (int src = m_nSize - 1, dst = m_nSize + size - 1; src >= (int) pos; --src, --dst)
for (int src = (int)(m_nSize - 1), dst = (int)(m_nSize + size - 1); src >= (int) pos; --src, --dst)
{
m_pArray[dst] = m_pArray[src];
}
Expand Down
12 changes: 10 additions & 2 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3339,7 +3339,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)

if (argLclNum != BAD_VAR_NUM)
{
argObj->ChangeType(argVarDsc->TypeGet());
argx->ChangeType(argVarDsc->TypeGet());
Copy link
Member Author

Choose a reason for hiding this comment

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

This was wrong for commas, we were changing the type of the effective node but not the entire comma tree.

argObj->SetOper(GT_LCL_VAR);
argObj->AsLclVar()->SetLclNum(argLclNum);
}
Expand All @@ -3357,7 +3357,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
{
// TODO-CQ: perform this transformation in lowering instead of here and
// avoid marking enregisterable structs DNER.
argObj->ChangeType(structBaseType);
argx->ChangeType(structBaseType);
if (argObj->OperIs(GT_LCL_VAR))
{
argObj->SetOper(GT_LCL_FLD);
Expand Down Expand Up @@ -14759,6 +14759,14 @@ PhaseStatus Compiler::fgPromoteStructs()
return PhaseStatus::MODIFIED_NOTHING;
}

#ifdef DEBUG
if (compStressCompile(STRESS_NO_OLD_PROMOTION, 10))
{
JITDUMP(" skipping due to stress\n");
return PhaseStatus::MODIFIED_NOTHING;
}
#endif

#if 0
// The code in this #if has been useful in debugging struct promotion issues, by
// enabling selective enablement of the struct promotion optimization according to
Expand Down