Skip to content

Commit c9c7619

Browse files
committed
DefiniteInitialization: use BasicBlockData instead of a map.
And reuse this block data for all memory objects which are analyzed. This is more efficient and avoids memory allocations.
1 parent 6713c0f commit c9c7619

File tree

1 file changed

+36
-18
lines changed

1 file changed

+36
-18
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "swift/AST/Expr.h"
1818
#include "swift/AST/Stmt.h"
1919
#include "swift/ClangImporter/ClangModule.h"
20+
#include "swift/SIL/BasicBlockData.h"
21+
#include "swift/SIL/SILBitfield.h"
2022
#include "swift/SIL/SILValue.h"
2123
#include "swift/SIL/InstructionUtils.h"
2224
#include "swift/SIL/SILArgument.h"
@@ -136,7 +138,12 @@ namespace {
136138
// T,F -> Partial
137139
SmallBitVector Data;
138140
public:
139-
AvailabilitySet(unsigned NumElts) {
141+
AvailabilitySet() {}
142+
143+
AvailabilitySet(unsigned NumElts) { init(NumElts); }
144+
145+
void init(unsigned NumElts) {
146+
Data.set();
140147
Data.resize(NumElts*2, true);
141148
}
142149

@@ -270,11 +277,15 @@ namespace {
270277
/// plus the information merged-in from the predecessor blocks.
271278
Optional<DIKind> OutSelfInitialized;
272279

273-
LiveOutBlockState(unsigned NumElements)
274-
: HasNonLoadUse(false),
275-
isInWorkList(false),
276-
LocalAvailability(NumElements),
277-
OutAvailability(NumElements) {
280+
LiveOutBlockState() { init(0); }
281+
282+
void init(unsigned NumElements) {
283+
HasNonLoadUse = false;
284+
isInWorkList = false;
285+
LocalAvailability.init(NumElements);
286+
OutAvailability.init(NumElements);
287+
LocalSelfInitialized = None;
288+
OutSelfInitialized = None;
278289
}
279290

280291
/// Sets all unknown elements to not-available.
@@ -371,9 +382,8 @@ namespace {
371382
DIKind SelfInitialized;
372383
};
373384

374-
} // end anonymous namespace
385+
using BlockStates = BasicBlockData<LiveOutBlockState>;
375386

376-
namespace {
377387
/// LifetimeChecker - This is the main heavy lifting for definite
378388
/// initialization checking of a memory object.
379389
class LifetimeChecker {
@@ -390,7 +400,8 @@ namespace {
390400
SmallVector<unsigned, 8> NeedsUpdateForInitState;
391401
std::vector<ConditionalDestroy> ConditionalDestroys;
392402

393-
llvm::SmallDenseMap<SILBasicBlock*, LiveOutBlockState, 32> PerBlockInfo;
403+
BlockStates &blockStates;
404+
BasicBlockFlag blockStateInitialized;
394405

395406
/// This is a map of uses that are not loads (i.e., they are Stores,
396407
/// InOutUses, and Escapes), to their entry in Uses.
@@ -427,7 +438,8 @@ namespace {
427438

428439
public:
429440
LifetimeChecker(const DIMemoryObjectInfo &TheMemory,
430-
DIElementUseInfo &UseInfo);
441+
DIElementUseInfo &UseInfo,
442+
BlockStates &blockStates);
431443

432444
void doIt();
433445

@@ -436,9 +448,10 @@ namespace {
436448
void emitSelfConsumedDiagnostic(SILInstruction *Inst);
437449

438450
LiveOutBlockState &getBlockInfo(SILBasicBlock *BB) {
439-
return PerBlockInfo
440-
.insert({BB, LiveOutBlockState(TheMemory.getNumElements())})
441-
.first->second;
451+
auto &state = blockStates.get(BB, []() { return LiveOutBlockState(); });
452+
if (!blockStateInitialized.testAndSet(BB))
453+
state.init(TheMemory.getNumElements());
454+
return state;
442455
}
443456

444457
AvailabilitySet getLivenessAtInst(SILInstruction *Inst, unsigned FirstElt,
@@ -514,10 +527,12 @@ namespace {
514527
} // end anonymous namespace
515528

516529
LifetimeChecker::LifetimeChecker(const DIMemoryObjectInfo &TheMemory,
517-
DIElementUseInfo &UseInfo)
530+
DIElementUseInfo &UseInfo,
531+
BlockStates &blockStates)
518532
: F(TheMemory.getFunction()), Module(TheMemory.getModule()),
519533
TheMemory(TheMemory), Uses(UseInfo.Uses),
520-
StoresToSelf(UseInfo.StoresToSelf), Destroys(UseInfo.Releases) {
534+
StoresToSelf(UseInfo.StoresToSelf), Destroys(UseInfo.Releases),
535+
blockStates(blockStates), blockStateInitialized(&F) {
521536

522537
// The first step of processing an element is to collect information about the
523538
// element into data structures we use later.
@@ -3087,7 +3102,8 @@ bool LifetimeChecker::isInitializedAtUse(const DIMemoryUse &Use,
30873102
// Top Level Driver
30883103
//===----------------------------------------------------------------------===//
30893104

3090-
static void processMemoryObject(MarkUninitializedInst *I) {
3105+
static void processMemoryObject(MarkUninitializedInst *I,
3106+
BlockStates &blockStates) {
30913107
LLVM_DEBUG(llvm::dbgs() << "*** Definite Init looking at: " << *I << "\n");
30923108
DIMemoryObjectInfo MemInfo(I);
30933109

@@ -3097,7 +3113,7 @@ static void processMemoryObject(MarkUninitializedInst *I) {
30973113
// Walk the use list of the pointer, collecting them into the Uses array.
30983114
collectDIElementUsesFrom(MemInfo, UseInfo);
30993115

3100-
LifetimeChecker(MemInfo, UseInfo).doIt();
3116+
LifetimeChecker(MemInfo, UseInfo, blockStates).doIt();
31013117
}
31023118

31033119
/// Check that all memory objects that require initialization before use are
@@ -3108,6 +3124,8 @@ static bool checkDefiniteInitialization(SILFunction &Fn) {
31083124
<< Fn.getName() << "\n");
31093125
bool Changed = false;
31103126

3127+
BlockStates blockStates(&Fn);
3128+
31113129
for (auto &BB : Fn) {
31123130
for (auto I = BB.begin(), E = BB.end(); I != E;) {
31133131
SILInstruction *Inst = &*I;
@@ -3119,7 +3137,7 @@ static bool checkDefiniteInitialization(SILFunction &Fn) {
31193137
}
31203138

31213139
// Then process the memory object.
3122-
processMemoryObject(MUI);
3140+
processMemoryObject(MUI, blockStates);
31233141

31243142
// Move off of the MUI only after we have processed memory objects. The
31253143
// lifetime checker may rewrite instructions, so it is important to not

0 commit comments

Comments
 (0)