Skip to content

Commit 0e1585d

Browse files
committed
Add comments
1 parent c91495e commit 0e1585d

File tree

1 file changed

+112
-31
lines changed

1 file changed

+112
-31
lines changed

src/coreclr/jit/flowgraph.cpp

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,27 @@ static bool blockNeedsGCPoll(BasicBlock* block)
6262

6363
PhaseStatus Compiler::fgInsertClsInitChecks()
6464
{
65-
66-
if (!strcmp(info.compMethodName, "Test"))
67-
{
68-
fgDispBasicBlocks(true);
69-
}
70-
7165
if (!opts.OptimizationEnabled())
7266
{
7367
return PhaseStatus::MODIFIED_NOTHING;
7468
}
7569

7670
bool modified = false;
7771
BasicBlock* block;
72+
73+
BasicBlock* prevBb = nullptr;
7874
for (block = fgFirstBB; block; block = block->bbNext)
7975
{
80-
if (!block->isRunRarely() && block->bbFlags)
76+
if (!block->isRunRarely())
8177
{
8278
for (Statement* stmt : block->Statements())
8379
{
8480
for (GenTree* tree = stmt->GetTreeList(); tree != nullptr; tree = tree->gtNext)
8581
{
86-
if (!tree->IsCall())
82+
// we only need GT_CALL nodes with helper funcs
83+
if (!tree->IsCall() || (tree->gtFlags & GTF_CALL_HOISTABLE))
8784
{
85+
// TODO: remove that GTF_CALL_HOISTABLE check
8886
continue;
8987
}
9088

@@ -95,20 +93,46 @@ PhaseStatus Compiler::fgInsertClsInitChecks()
9593
}
9694

9795
CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
98-
if (helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE)
96+
if ((helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE) ||
97+
(call->fgArgInfo->ArgCount() != 2))
9998
{
10099
continue;
101100
}
102101

103-
GenTree* moduleIdArg = call->LateArgs().begin()->GetNode();
104-
GenTree* clsIdArg = call->LateArgs().begin()->GetNext()->GetNode();
102+
GenTree* moduleIdArg = call->fgArgInfo->GetArgNode(0);
103+
GenTree* clsIdArg = call->fgArgInfo->GetArgNode(1);
105104

106105
if (!moduleIdArg->IsCnsIntOrI() || !clsIdArg->IsCnsIntOrI())
107106
{
108107
// Looks like moduleId or/and clsId were passed as indirect loads
109108
continue;
110109
}
111110

111+
if (clsIdArg->AsIntCon()->IconValue() < 0)
112+
{
113+
// Unknown clsId
114+
continue;
115+
}
116+
117+
if (prevBb == nullptr)
118+
{
119+
// We're going to emit a BB in front of fgFirstBB
120+
fgEnsureFirstBBisScratch();
121+
prevBb = fgFirstBB;
122+
if (prevBb == block)
123+
{
124+
continue;
125+
}
126+
}
127+
128+
// So, we found a helper call inside the "block" - let's extract it to a
129+
// separate block "callInitBb" and guard it with a fast "isInitedBb" bb.
130+
// The final layout should look like this:
131+
132+
// BB0 "prevBb":
133+
// ...
134+
//
135+
// BB1 "isInitedBb": (preds: BB0 + %current preds of BB3%)
112136
//
113137
// * JTRUE void
114138
// \--* NE int
@@ -118,62 +142,119 @@ PhaseStatus Compiler::fgInsertClsInitChecks()
118142
// | \--* CNS_INT int isInitMask
119143
// \--* CNS_INT int 0
120144
//
145+
//
146+
// BB2 "callInitBb": (preds: BB1)
147+
//
121148
// * CALL help long HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
122149
// +--* CNS_INT long moduleIdArg
123150
// \--* CNS_INT int clsIdArg
124151
//
125-
152+
// BB3 "block" (preds: BB1, BB2)
153+
// ...
154+
//
155+
156+
157+
// Let's start from emitting that BB2 "callInitBb"
126158
BasicBlock* callInitBb = fgNewBBbefore(BBJ_NONE, block, true);
127-
fgAddRefPred(block, callInitBb);
159+
// it's executed only once so can be marked as cold
128160
callInitBb->bbSetRunRarely();
129-
callInitBb->bbFlags |= block->bbFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_HAS_CALL);
130-
161+
callInitBb->bbFlags |= (BBF_INTERNAL | BBF_HAS_CALL | BBF_HAS_LABEL);
131162
GenTree* clonedHelperCall = gtCloneExprCallHelper(call);
132163
clonedHelperCall->gtFlags |= call->gtFlags;
133-
fgInsertStmtAtEnd(callInitBb, fgNewStmtFromTree(clonedHelperCall));
134164

165+
Statement* callStmt = fgNewStmtFromTree(clonedHelperCall);
166+
if (fgStmtListThreaded)
167+
{
168+
gtSetStmtInfo(callStmt);
169+
fgSetStmtSeq(callStmt);
170+
}
171+
fgInsertStmtAtEnd(callInitBb, callStmt);
172+
gtUpdateStmtSideEffects(callStmt);
173+
174+
// BB1 "isInitedBb"
135175
BasicBlock* isInitedBb = fgNewBBbefore(BBJ_COND, callInitBb, true);
136-
fgAddRefPred(callInitBb, isInitedBb);
137-
fgAddRefPred(block, isInitedBb);
138176
isInitedBb->inheritWeight(block);
139-
isInitedBb->bbFlags |= block->bbFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_HAS_CALL);
177+
isInitedBb->bbFlags |= (BBF_INTERNAL | BBF_HAS_LABEL | BBF_HAS_JMP);
140178

141179
// TODO: ask VM for these constants:
142-
const int dataBlobOffset = 48;
143-
const int isInitMask = 1;
180+
const int dataBlobOffset = 48; // DomainLocalModule::GetOffsetOfDataBlob()
181+
const int isInitMask = 1; // ClassInitFlags::INITIALIZED_FLAG;
144182

145183
size_t address = moduleIdArg->AsIntCon()->IconValue() + dataBlobOffset + clsIdArg->AsIntCon()->IconValue();
146184
GenTree* indir = gtNewIndir(TYP_UBYTE, gtNewIconNode(address, TYP_I_IMPL));
147185
indir->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
148186

149187
GenTree* isInitedMask = gtNewOperNode(GT_AND, TYP_INT, indir, gtNewIconNode(isInitMask));
150-
GenTree* isInitedCmp = gtNewOperNode(GT_NE, TYP_INT, isInitedMask, gtNewIconNode(0));
188+
GenTree* isInitedCmp = gtNewOperNode(GT_GT, TYP_INT, isInitedMask, gtNewIconNode(0));
189+
isInitedCmp->gtFlags |= (GTF_UNSIGNED | GTF_RELOP_JMP_USED);
151190

152-
fgInsertStmtAtEnd(isInitedBb, fgNewStmtFromTree(gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp)));
191+
Statement* isInitedStmt = fgNewStmtFromTree(gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp));
192+
if (fgStmtListThreaded)
193+
{
194+
gtSetStmtInfo(isInitedStmt);
195+
fgSetStmtSeq(isInitedStmt);
196+
}
197+
198+
fgInsertStmtAtEnd(isInitedBb, isInitedStmt);
153199
isInitedBb->bbJumpDest = block;
154-
gtReplaceTree(stmt, call, gtNewNothingNode());
200+
block->bbFlags |= BBF_JMP_TARGET;
201+
202+
// Now we can remove the call from the current block
203+
// We're going to replace the call with just "moduleId" node (it's what it was supposed to return)
204+
gtReplaceTree(stmt, call, gtNewIconNode(moduleIdArg->AsIntCon()->IconValue(), call->TypeGet()));
205+
206+
// Now we need to fix all the preds:
207+
208+
// isInitedBb is a pred of callInitBb
209+
fgAddRefPred(callInitBb, isInitedBb);
210+
for (flowList* pred = block->bbPreds; pred != nullptr; pred = pred->flNext)
211+
{
212+
// Redirect all the preds from the current block to isInitedBb
213+
214+
// TODO: should I check EH region here?
215+
// TODO: should I update some loop info if I'm inside a loop?
216+
217+
BasicBlock* predBlock = pred->getBlock();
218+
if (predBlock->bbJumpDest == block)
219+
{
220+
predBlock->bbJumpDest = isInitedBb;
221+
isInitedBb->bbFlags |= BBF_JMP_TARGET;
222+
}
223+
fgRemoveRefPred(block, predBlock);
224+
fgAddRefPred(isInitedBb, predBlock);
225+
}
226+
// Both callInitBb and isInitedBb are preds of block now
227+
fgAddRefPred(block, callInitBb);
228+
fgAddRefPred(block, isInitedBb);
155229

230+
// Make sure all three basic blocks are in the same EH region:
231+
BasicBlock::sameEHRegion(callInitBb, block);
232+
BasicBlock::sameEHRegion(isInitedBb, block);
156233

157234
modified = true;
158235
}
159236
if (modified)
160237
{
161-
// clear GTF_CALL and GTF_EXC flags
238+
// clear GTF_CALL and GTF_EXC flags (we've just removed a call)
162239
gtUpdateStmtSideEffects(stmt);
163240
}
164241
}
165242
}
166-
}
167-
168-
if (!strcmp(info.compMethodName, "Test"))
169-
{
170-
fgDispBasicBlocks(true);
243+
prevBb = block;
171244
}
172245

173246
if (modified)
174247
{
248+
#ifdef DEBUG
249+
if (verbose)
250+
{
251+
printf("\nAfter fgInsertClsInitChecks:");
252+
fgDispBasicBlocks(true);
253+
}
254+
#endif // DEBUG
175255
fgReorderBlocks();
176-
fgUpdateChangedFlowGraph(false);
256+
constexpr bool computeDoms = false;
257+
fgUpdateChangedFlowGraph(computeDoms);
177258
return PhaseStatus::MODIFIED_EVERYTHING;
178259
}
179260
return PhaseStatus::MODIFIED_NOTHING;

0 commit comments

Comments
 (0)