@@ -146,8 +146,6 @@ class SILGlobalOpt {
146
146
SILFunction *ParentF,
147
147
llvm::DenseMap<SILFunction *, ApplyInst *> &ParentFuncs);
148
148
149
- void placeInitializers (SILFunction *InitF, ArrayRef<ApplyInst *> Calls);
150
-
151
149
// / Update UnhandledOnceCallee and InitializerCount by going through all
152
150
// / "once" calls.
153
151
void collectOnceCall (BuiltinInst *AI);
@@ -275,6 +273,25 @@ void SILGlobalOpt::collectOnceCall(BuiltinInst *BI) {
275
273
InitializerCount[Callee]++;
276
274
}
277
275
276
+ static bool isPotentialStore (SILInstruction *inst) {
277
+ switch (inst->getKind ()) {
278
+ case SILInstructionKind::LoadInst:
279
+ return false ;
280
+ case SILInstructionKind::PointerToAddressInst:
281
+ case SILInstructionKind::StructElementAddrInst:
282
+ case SILInstructionKind::TupleElementAddrInst:
283
+ for (Operand *op : cast<SingleValueInstruction>(inst)->getUses ()) {
284
+ if (isPotentialStore (op->getUser ()))
285
+ return true ;
286
+ }
287
+ return false ;
288
+ case SILInstructionKind::BeginAccessInst:
289
+ return cast<BeginAccessInst>(inst)->getAccessKind () != SILAccessKind::Read;
290
+ default :
291
+ return true ;
292
+ }
293
+ }
294
+
278
295
// / return true if this block is inside a loop.
279
296
bool SILGlobalOpt::isInLoop (SILBasicBlock *CurBB) {
280
297
SILFunction *F = CurBB->getParent ();
@@ -292,164 +309,25 @@ bool SILGlobalOpt::isInLoop(SILBasicBlock *CurBB) {
292
309
return LoopBlocks.count (CurBB);
293
310
}
294
311
295
- // / Returns true if the block \p BB is terminated with a cond_br based on an
296
- // / availability check.
297
- static bool isAvailabilityCheck (SILBasicBlock *BB) {
298
- auto *CBR = dyn_cast<CondBranchInst>(BB->getTerminator ());
299
- if (!CBR)
300
- return false ;
301
-
302
- auto *AI = dyn_cast<ApplyInst>(CBR->getCondition ());
303
- if (!AI)
304
- return false ;
305
-
306
- SILFunction *F = AI->getReferencedFunctionOrNull ();
307
- if (!F || !F->hasSemanticsAttrs ())
308
- return false ;
309
-
310
- return F->hasSemanticsAttrThatStartsWith (" availability" );
311
- }
312
-
313
- // / Returns true if there are any availability checks along the dominator tree
314
- // / from \p From to \p To.
315
- static bool isAvailabilityCheckOnDomPath (SILBasicBlock *From, SILBasicBlock *To,
316
- DominanceInfo *DT) {
317
- if (From == To)
318
- return false ;
319
-
320
- auto *Node = DT->getNode (To)->getIDom ();
321
- for (;;) {
322
- SILBasicBlock *BB = Node->getBlock ();
323
- if (isAvailabilityCheck (BB))
324
- return true ;
325
- if (BB == From)
326
- return false ;
327
- Node = Node->getIDom ();
328
- assert (Node && " Should have hit To-block" );
329
- }
330
- }
331
-
332
- ApplyInst *SILGlobalOpt::getHoistedApplyForInitializer (
333
- ApplyInst *AI, DominanceInfo *DT, SILFunction *InitF, SILFunction *ParentF,
334
- llvm::DenseMap<SILFunction *, ApplyInst *> &ParentFuncs) {
335
- auto PFI = ParentFuncs.find (ParentF);
336
- if (PFI == ParentFuncs.end ()) {
337
- ParentFuncs[ParentF] = AI;
338
-
339
- // It's the first time we found a call to InitF in this function, so we
340
- // try to hoist it out of any loop.
341
- return AI;
342
- }
343
-
344
- // Found a replacement for this init call. Ensure the replacement dominates
345
- // the original call site.
346
- ApplyInst *CommonAI = PFI->second ;
347
- assert (cast<FunctionRefInst>(CommonAI->getCallee ())
348
- ->getReferencedFunctionOrNull () == InitF &&
349
- " ill-formed global init call" );
350
- SILBasicBlock *DomBB =
351
- DT->findNearestCommonDominator (AI->getParent (), CommonAI->getParent ());
352
-
353
- // We must not move initializers around availability-checks.
354
- if (isAvailabilityCheckOnDomPath (DomBB, CommonAI->getParent (), DT))
355
- return nullptr ;
356
-
357
- ApplyInst *Result = nullptr ;
358
- if (DomBB != CommonAI->getParent ()) {
359
- CommonAI->moveBefore (&*DomBB->begin ());
360
- placeFuncRef (CommonAI, DT);
361
-
362
- // Try to hoist the existing AI again if we move it to another block,
363
- // e.g. from a loop exit into the loop.
364
- Result = CommonAI;
365
- }
366
-
367
- AI->replaceAllUsesWith (CommonAI);
368
- AI->eraseFromParent ();
369
- HasChanged = true ;
370
- return Result;
371
- }
372
-
373
- // / Optimize placement of initializer calls given a list of calls to the
374
- // / same initializer. All original initialization points must be dominated by
375
- // / the final initialization calls.
376
- // /
377
- // / The current heuristic hoists all initialization points within a function to
378
- // / a single dominating call in the outer loop preheader.
379
- void SILGlobalOpt::placeInitializers (SILFunction *InitF,
380
- ArrayRef<ApplyInst *> Calls) {
381
- LLVM_DEBUG (llvm::dbgs () << " GlobalOpt: calls to "
382
- << Demangle::demangleSymbolAsString (InitF->getName ())
383
- << " : " << Calls.size () << " \n " );
384
- // Map each initializer-containing function to its final initializer call.
385
- llvm::DenseMap<SILFunction *, ApplyInst *> ParentFuncs;
386
- for (auto *AI : Calls) {
387
- assert (AI->getNumArguments () == 0 && " ill-formed global init call" );
388
- assert (
389
- cast<FunctionRefInst>(AI->getCallee ())->getReferencedFunctionOrNull () ==
390
- InitF &&
391
- " wrong init call" );
392
- SILFunction *ParentF = AI->getFunction ();
393
- DominanceInfo *DT = DA->get (ParentF);
394
- ApplyInst *HoistAI =
395
- getHoistedApplyForInitializer (AI, DT, InitF, ParentF, ParentFuncs);
396
-
397
- // If we were unable to find anything, just go onto the next apply.
398
- if (!HoistAI) {
399
- continue ;
400
- }
401
-
402
- // Otherwise, move this call to the outermost loop preheader.
403
- SILBasicBlock *BB = HoistAI->getParent ();
404
- typedef llvm::DomTreeNodeBase<SILBasicBlock> DomTreeNode;
405
- DomTreeNode *Node = DT->getNode (BB);
406
- while (Node) {
407
- SILBasicBlock *DomParentBB = Node->getBlock ();
408
- if (isAvailabilityCheck (DomParentBB)) {
409
- LLVM_DEBUG (llvm::dbgs () << " don't hoist above availability check "
410
- " at bb"
411
- << DomParentBB->getDebugID () << " \n " );
412
- break ;
413
- }
414
- BB = DomParentBB;
415
- if (!isInLoop (BB))
416
- break ;
417
- Node = Node->getIDom ();
418
- }
419
-
420
- if (BB == HoistAI->getParent ()) {
421
- // BB is either unreachable or not in a loop.
422
- LLVM_DEBUG (llvm::dbgs () << " skipping (not in a loop): " << *HoistAI
423
- << " in " << HoistAI->getFunction ()->getName ()
424
- << " \n " );
425
- continue ;
426
- }
427
-
428
- LLVM_DEBUG (llvm::dbgs () << " hoisting: " << *HoistAI << " in "
429
- << HoistAI->getFunction ()->getName () << " \n " );
430
- HoistAI->moveBefore (&*BB->begin ());
431
- placeFuncRef (HoistAI, DT);
432
- HasChanged = true ;
433
- }
434
- }
435
-
436
312
bool SILGlobalOpt::isAssignedOnlyOnceInInitializer (SILGlobalVariable *SILG,
437
313
SILFunction *globalAddrF) {
438
314
if (SILG->isLet ())
439
315
return true ;
440
316
441
317
// If we should skip this, it is probably because there are multiple stores.
442
318
// Return false if there are multiple stores or no stores.
443
- if (GlobalVarSkipProcessing.count (SILG) || !GlobalVarStore.count (SILG) ||
444
- // Check if there is more than one use the global addr function. If there
445
- // is only one use, it must be the use that we are trying to optimize, so
446
- // that is OK. If there is more than one use, one of the other uses may
447
- // have a store attached to it which means there may be more than one
448
- // assignment, so return false.
449
- (GlobalInitCallMap.count (globalAddrF) &&
450
- GlobalInitCallMap[globalAddrF].size () != 1 ))
319
+ if (GlobalVarSkipProcessing.count (SILG) || !GlobalVarStore.count (SILG))
451
320
return false ;
452
321
322
+ if (GlobalInitCallMap.count (globalAddrF)) {
323
+ for (ApplyInst *initCall : GlobalInitCallMap[globalAddrF]) {
324
+ for (auto *Op : getNonDebugUses (initCall)) {
325
+ if (isPotentialStore (Op->getUser ()))
326
+ return false ;
327
+ }
328
+ }
329
+ }
330
+
453
331
// Otherwise, return true if this can't be used externally (false, otherwise).
454
332
return !isPossiblyUsedExternally (SILG->getLinkage (),
455
333
SILG->getModule ().isWholeModule ());
@@ -727,24 +605,6 @@ bool SILGlobalOpt::tryRemoveUnusedGlobal(SILGlobalVariable *global) {
727
605
return true ;
728
606
}
729
607
730
- static bool isPotentialStore (SILInstruction *inst) {
731
- switch (inst->getKind ()) {
732
- case SILInstructionKind::LoadInst:
733
- case SILInstructionKind::EndAccessInst:
734
- return false ;
735
- case SILInstructionKind::StructElementAddrInst:
736
- case SILInstructionKind::TupleElementAddrInst:
737
- case SILInstructionKind::BeginAccessInst:
738
- for (Operand *op : cast<SingleValueInstruction>(inst)->getUses ()) {
739
- if (isPotentialStore (op->getUser ()))
740
- return true ;
741
- }
742
- return false ;
743
- default :
744
- return true ;
745
- }
746
- }
747
-
748
608
// / If this is a read from a global let variable, map it.
749
609
void SILGlobalOpt::collectGlobalAccess (GlobalAddrInst *GAI) {
750
610
auto *SILG = GAI->getReferencedGlobal ();
@@ -921,10 +781,6 @@ bool SILGlobalOpt::run() {
921
781
}
922
782
} while (changed);
923
783
924
- for (auto &InitCalls : GlobalInitCallMap) {
925
- placeInitializers (InitCalls.first , InitCalls.second );
926
- }
927
-
928
784
// This is similiar to optimizeInitializer, but it's for globals which are
929
785
// initialized in the "main" function and not by an initializer function.
930
786
for (auto &Init : GlobalVarStore) {
0 commit comments