Skip to content

Commit a72fcef

Browse files
authored
Merge pull request swiftlang#35552 from eeckstein/blockdata-in-DI
DefiniteInitialization: use BasicBlockData instead of a map.
2 parents 2c083ca + c9c7619 commit a72fcef

File tree

4 files changed

+56
-25
lines changed

4 files changed

+56
-25
lines changed

include/swift/SIL/BasicBlockData.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ namespace swift {
4141
/// long as the invalidation mechanism ensures that the analysis data is not
4242
/// retrieved after the function's block list changed.
4343
///
44-
/// The Vector template argument specifies how the data is stored. By default
45-
/// it's a SmallVector with an inline-size of 4. This avoids memory allocation
46-
/// for about 70% of all functions.
47-
template <typename Data, typename Vector = llvm::SmallVector<Data, 4>>
44+
/// The template argument \p N specifies how many Data elements can be stored
45+
/// inline in the data vector. The default value of 32 avoids malloc for about
46+
/// 90% of all functions.
47+
template <typename Data, unsigned N = 32>
4848
class BasicBlockData {
4949
SILFunction *function;
50-
Vector data;
50+
llvm::SmallVector<Data, N> data;
5151

5252
/// The data is valid if validForBlockOrder matches the function's
5353
/// BlockListChangeIdx.
@@ -200,6 +200,19 @@ class BasicBlockData {
200200
const Data &operator[] (SILBasicBlock *block) const {
201201
return data[getIndex(block)];
202202
}
203+
204+
/// If \p block is a new block, i.e. created after this BasicBlockData was
205+
/// constructed, creates a new Data with \p init and returns it.
206+
Data &get(SILBasicBlock *block, llvm::function_ref<Data()> init) {
207+
if (block->index < 0) {
208+
assert(validForBlockOrder == function->BlockListChangeIdx &&
209+
"BasicBlockData invalid because the function's block list changed");
210+
validForBlockOrder = ++function->BlockListChangeIdx;
211+
block->index = data.size();
212+
data.push_back(init());
213+
}
214+
return data[getIndex(block)];
215+
}
203216
};
204217

205218
} // end swift namespace

include/swift/SIL/SILBasicBlock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
3535
friend class SILSuccessor;
3636
friend class SILFunction;
3737
friend class SILGlobalVariable;
38-
template <typename Data, typename Vector> friend class BasicBlockData;
38+
template <typename, unsigned> friend class BasicBlockData;
3939
friend class BasicBlockBitfield;
4040

4141
public:

include/swift/SIL/SILFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class SILFunction
148148
friend class SILBasicBlock;
149149
friend class SILModule;
150150
friend class SILFunctionBuilder;
151-
template <typename Data, typename Vector> friend class BasicBlockData;
151+
template <typename, unsigned> friend class BasicBlockData;
152152
friend class BasicBlockBitfield;
153153

154154
/// Module - The SIL module that the function belongs to.

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)