Skip to content

Commit c4cfcc7

Browse files
authored
Merge pull request swiftlang#35583 from eeckstein/use-basicblockflag
2 parents e3ade39 + f481919 commit c4cfcc7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+565
-525
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_SIL_BASICBLOCKUTILS_H
1515

1616
#include "swift/SIL/SILValue.h"
17+
#include "swift/SIL/SILBitfield.h"
1718
#include "llvm/ADT/SetVector.h"
1819
#include "llvm/ADT/SmallPtrSet.h"
1920
#include "llvm/ADT/SmallVector.h"
@@ -98,13 +99,6 @@ struct JointPostDominanceSetComputer {
9899
/// The worklist that drives the algorithm.
99100
SmallVector<SILBasicBlock *, 32> worklist;
100101

101-
/// A set that guards our worklist. Any block before it is added to worklist
102-
/// should be checked against visitedBlocks.
103-
SmallPtrSet<SILBasicBlock *, 32> visitedBlocks;
104-
105-
/// The set of blocks where we begin our walk.
106-
SmallPtrSet<SILBasicBlock *, 8> initialBlocks;
107-
108102
/// A subset of our initial blocks that we found as a predecessor of another
109103
/// block along our walk.
110104
SmallVector<SILBasicBlock *, 8> reachableInputBlocks;
@@ -113,7 +107,7 @@ struct JointPostDominanceSetComputer {
113107
/// visited yet are placed in here. At the end of our worklist, any blocks
114108
/// that remain here are "leaking blocks" that together with our initial set
115109
/// would provide a jointly-postdominating set of our dominating value.
116-
SmallSetVector<SILBasicBlock *, 8> blocksThatLeakIfNeverVisited;
110+
SmallVector<SILBasicBlock *, 32> blocksThatLeakIfNeverVisited;
117111

118112
DeadEndBlocks &deadEndBlocks;
119113

@@ -122,8 +116,6 @@ struct JointPostDominanceSetComputer {
122116

123117
void clear() {
124118
worklist.clear();
125-
visitedBlocks.clear();
126-
initialBlocks.clear();
127119
reachableInputBlocks.clear();
128120
blocksThatLeakIfNeverVisited.clear();
129121
}

include/swift/SIL/LinearLifetimeChecker.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "swift/SIL/SILBasicBlock.h"
2121
#include "swift/SIL/SILFunction.h"
2222
#include "swift/SIL/SILValue.h"
23+
#include "swift/SIL/BasicBlockUtils.h"
24+
#include "swift/SIL/SILBitfield.h"
2325
#include "llvm/ADT/SmallPtrSet.h"
2426

2527
namespace swift {
@@ -28,7 +30,6 @@ class SILBasicBlock;
2830
class SILInstruction;
2931
class SILModule;
3032
class SILValue;
31-
class DeadEndBlocks;
3233
class SILOwnershipVerifier;
3334
class SILValueOwnershipChecker;
3435

@@ -56,13 +57,11 @@ class LinearLifetimeChecker {
5657
friend class SILOwnershipVerifier;
5758
friend class SILValueOwnershipChecker;
5859

59-
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
6060
DeadEndBlocks &deadEndBlocks;
6161

6262
public:
63-
LinearLifetimeChecker(SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
64-
DeadEndBlocks &deadEndBlocks)
65-
: visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {}
63+
LinearLifetimeChecker(DeadEndBlocks &deadEndBlocks)
64+
: deadEndBlocks(deadEndBlocks) {}
6665

6766
/// Returns true that \p value forms a linear lifetime with consuming uses \p
6867
/// consumingUses, non consuming uses \p nonConsumingUses. Returns false

include/swift/SIL/OwnershipUtils.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,6 @@ struct BorrowedValue {
448448
/// borrow scopes if needed.
449449
bool areUsesWithinScope(ArrayRef<Operand *> uses,
450450
SmallVectorImpl<Operand *> &scratchSpace,
451-
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
452451
DeadEndBlocks &deadEndBlocks) const;
453452

454453
/// Given a local borrow scope introducer, visit all non-forwarding consuming

include/swift/SIL/SILBitfield.h

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,29 @@
1818
#define SWIFT_SIL_SILBITFIELD_H
1919

2020
#include "swift/SIL/SILFunction.h"
21+
#include "llvm/ADT/SmallVector.h"
2122

2223
namespace swift {
2324

2425
/// Utility to add a custom bitfield to a function's basic blocks.
2526
///
2627
/// This can be used by transforms to store temporary flags or tiny values per
2728
/// basic block.
28-
/// It is very efficient: no memory allocation is needed, no hash set or map is
29-
/// needed for lookup and there is no initialization cost (in contrast to
30-
/// BasicBlockData which needs to iterate over all blocks at initialization).
29+
/// The memory managed is a 32 bit field within each basic block (\see
30+
/// BasicBlock::customBits) and thus is very efficient: no memory allocation is
31+
/// needed, no hash set or map is needed for lookup and there is no
32+
/// initialization cost (in contrast to BasicBlockData which needs to iterate
33+
/// over all blocks at initialization).
3134
///
32-
/// Restrictions:
35+
/// Invariants:
3336
/// * BasicBlockBitfield instances must be allocated and deallocated
34-
/// following a strict stack discipline. This means, it's fine to use them as
35-
/// (or in) local variables in transformations. But it's e.g. not possible to
36-
/// store a BasicBlockBitfield in an Analysis.
37+
/// following a strict stack discipline, because bit-positions in
38+
/// BasicBlock::customBits are "allocated" and "freed" with a stack-allocation
39+
/// algorithm. This means, it's fine to use a BasicBlockBitfield as (or in)
40+
/// local variables, e.g. in transformations. But it's not possible to store
41+
/// a BasicBlockBitfield in an Analysis.
3742
/// * The total number of bits which are alive at the same time must not exceed
38-
/// 32.
43+
/// 32 (the size of BasicBlock::customBits).
3944
class BasicBlockBitfield {
4045
/// The bitfield is "added" to the blocks of this function.
4146
SILFunction *function;
@@ -89,6 +94,7 @@ class BasicBlockBitfield {
8994
SILFunction *getFunction() const { return function; }
9095

9196
unsigned get(SILBasicBlock *block) const {
97+
assert(block->getParent() == function);
9298
if (bitfieldID > block->lastInitializedBitfieldID) {
9399
// The bitfield is not initialized yet in this block.
94100
return 0;
@@ -97,6 +103,7 @@ class BasicBlockBitfield {
97103
}
98104

99105
void set(SILBasicBlock *block, unsigned value) {
106+
assert(block->getParent() == function);
100107
assert(((value << startBit) & ~mask) == 0 &&
101108
"value too large for BasicBlockBitfield");
102109
unsigned clearMask = mask;
@@ -136,7 +143,9 @@ class BasicBlockFlag {
136143

137144
bool get(SILBasicBlock *block) const { return (bool)bit.get(block); }
138145

139-
void set(SILBasicBlock *block) { bit.set(block, 1); }
146+
void set(SILBasicBlock *block, bool value = true) {
147+
bit.set(block, (unsigned)value);
148+
}
140149
void reset(SILBasicBlock *block) { bit.set(block, 0); }
141150

142151
/// Sets the flag and returns the old value.
@@ -161,7 +170,45 @@ class BasicBlockSet {
161170
/// Returns true if \p block was not contained in the set before inserting.
162171
bool insert(SILBasicBlock *block) { return !flag.testAndSet(block); }
163172

164-
void remove(SILBasicBlock *block) { flag.reset(block); }
173+
void erase(SILBasicBlock *block) { flag.reset(block); }
174+
};
175+
176+
/// An implementation of `llvm::SetVector<SILBasicBlock *,
177+
/// SmallVector<SILBasicBlock *, N>,
178+
/// BasicBlockSet>`.
179+
///
180+
/// Unfortunately it's not possible to use `llvm::SetVector` directly because
181+
/// the BasicBlockSet constructor needs a `SILFunction` argument.
182+
///
183+
/// Note: This class does not provide a `remove` method intentinally, because
184+
/// it would have a O(n) complexity.
185+
template <unsigned N> class BasicBlockSetVector {
186+
using Vector = llvm::SmallVector<SILBasicBlock *, N>;
187+
188+
Vector vector;
189+
BasicBlockSet set;
190+
191+
public:
192+
using iterator = typename Vector::const_iterator;
193+
194+
BasicBlockSetVector(SILFunction *function) : set(function) {}
195+
196+
iterator begin() const { return vector.begin(); }
197+
iterator end() const { return vector.end(); }
198+
199+
unsigned size() const { return vector.size(); }
200+
bool empty() const { return vector.empty(); }
201+
202+
bool contains(SILBasicBlock *block) const { return set.contains(block); }
203+
204+
/// Returns true if \p block was not contained in the set before inserting.
205+
bool insert(SILBasicBlock *block) {
206+
if (set.insert(block)) {
207+
vector.push_back(block);
208+
return true;
209+
}
210+
return false;
211+
}
165212
};
166213

167214
} // namespace swift

include/swift/SIL/SILCloner.h

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,6 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
6767
// convenient way to iterate over the cloned region.
6868
SmallVector<SILBasicBlock *, 8> preorderBlocks;
6969

70-
/// Set of basic blocks where unreachable was inserted.
71-
SmallPtrSet<SILBasicBlock *, 32> BlocksWithUnreachables;
72-
7370
// Keep track of the last cloned block in function order. For single block
7471
// regions, this will be the start block.
7572
SILBasicBlock *lastClonedBB = nullptr;
@@ -97,7 +94,6 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
9794
ValueMap.clear();
9895
BBMap.clear();
9996
preorderBlocks.clear();
100-
BlocksWithUnreachables.clear();
10197
}
10298

10399
/// Clients of SILCloner who want to know about any newly created
@@ -170,12 +166,6 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
170166
asImpl().mapValue(origValue, mappedValue);
171167
}
172168

173-
/// Mark a block containing an unreachable instruction for use in the `fixUp`
174-
/// callback.
175-
void addBlockWithUnreachable(SILBasicBlock *BB) {
176-
BlocksWithUnreachables.insert(BB);
177-
}
178-
179169
/// Register a re-mapping for opened existentials.
180170
void registerOpenedExistentialRemapping(ArchetypeType *From,
181171
ArchetypeType *To) {
@@ -787,32 +777,6 @@ SILCloner<ImplClass>::doFixUp(SILFunction *F) {
787777
}
788778
}
789779

790-
// Remove any code after unreachable instructions.
791-
792-
// NOTE: It is unfortunate that it essentially duplicates the code from
793-
// sil-combine, but doing so allows for avoiding any cross-layer invocations
794-
// between SIL and SILOptimizer layers.
795-
796-
for (auto *BB : BlocksWithUnreachables) {
797-
for (auto &I : *BB) {
798-
if (!isa<UnreachableInst>(&I))
799-
continue;
800-
801-
// Collect together all the instructions after this point
802-
llvm::SmallVector<SILInstruction *, 32> ToRemove;
803-
for (auto Inst = BB->rbegin(); &*Inst != &I; ++Inst)
804-
ToRemove.push_back(&*Inst);
805-
806-
for (auto *Inst : ToRemove) {
807-
// Replace any non-dead results with SILUndef values
808-
Inst->replaceAllUsesOfAllResultsWithUndef();
809-
Inst->eraseFromParent();
810-
}
811-
}
812-
}
813-
814-
BlocksWithUnreachables.clear();
815-
816780
// Call any cleanup specific to the CRTP extensions.
817781
asImpl().fixUp(F);
818782
}

include/swift/SIL/SILFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class SILFunction
199199

200200
/// A monotonically increasing ID which is incremented whenever a
201201
/// BasicBlockBitfield is constructed.
202-
/// Usually this stays below 1000, so a 32-bit unsigned is more than
202+
/// Usually this stays below 100000, so a 32-bit unsigned is more than
203203
/// sufficient.
204204
/// For details see BasicBlockBitfield::bitfieldID;
205205
unsigned currentBitfieldID = 1;

include/swift/SIL/TypeSubstCloner.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
137137
using SILClonerWithScopes<ImplClass>::getOpBasicBlock;
138138
using SILClonerWithScopes<ImplClass>::recordClonedInstruction;
139139
using SILClonerWithScopes<ImplClass>::recordFoldedValue;
140-
using SILClonerWithScopes<ImplClass>::addBlockWithUnreachable;
141140
using SILClonerWithScopes<ImplClass>::OpenedArchetypesTracker;
142141

143142
TypeSubstCloner(SILFunction &To,

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/SIL/InstructionUtils.h"
3232
#include "swift/SIL/MemAccessUtils.h"
3333
#include "swift/SIL/PrettyStackTrace.h"
34+
#include "swift/SIL/SILBitfield.h"
3435
#include "swift/SIL/SILDebugScope.h"
3536
#include "swift/SIL/SILDeclRef.h"
3637
#include "swift/SIL/SILLinkage.h"
@@ -2007,7 +2008,7 @@ void IRGenSILFunction::emitSILFunction() {
20072008

20082009
// Invariant: for every block in the work queue, we have visited all
20092010
// of its dominators.
2010-
llvm::SmallPtrSet<SILBasicBlock*, 8> visitedBlocks;
2011+
BasicBlockSet visitedBlocks(CurSILFn);
20112012
SmallVector<SILBasicBlock*, 8> workQueue; // really a stack
20122013

20132014
// Queue up the entry block, for which the invariant trivially holds.
@@ -2042,15 +2043,15 @@ void IRGenSILFunction::emitSILFunction() {
20422043
// Therefore the invariant holds of all the successors, and we can
20432044
// queue them up if we haven't already visited them.
20442045
for (auto *succBB : bb->getSuccessorBlocks()) {
2045-
if (visitedBlocks.insert(succBB).second)
2046+
if (visitedBlocks.insert(succBB))
20462047
workQueue.push_back(succBB);
20472048
}
20482049
}
20492050

20502051
// If there are dead blocks in the SIL function, we might have left
20512052
// invalid blocks in the IR. Do another pass and kill them off.
20522053
for (SILBasicBlock &bb : *CurSILFn)
2053-
if (!visitedBlocks.count(&bb))
2054+
if (!visitedBlocks.contains(&bb))
20542055
LoweredBBs[&bb].bb->eraseFromParent();
20552056

20562057
}

lib/SIL/IR/SILFunction.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#define DEBUG_TYPE "sil-function"
14+
1315
#include "swift/SIL/SILArgument.h"
1416
#include "swift/SIL/SILBasicBlock.h"
1517
#include "swift/SIL/SILFunction.h"
@@ -24,13 +26,16 @@
2426
#include "swift/Basic/OptimizationMode.h"
2527
#include "swift/Basic/Statistic.h"
2628
#include "llvm/ADT/Optional.h"
29+
#include "llvm/ADT/Statistic.h"
2730
#include "llvm/Support/CommandLine.h"
2831
#include "llvm/Support/GraphWriter.h"
2932
#include "clang/AST/Decl.h"
3033

3134
using namespace swift;
3235
using namespace Lowering;
3336

37+
STATISTIC(MaxBitfieldID, "Max value of SILFunction::currentBitfieldID");
38+
3439
SILSpecializeAttr::SILSpecializeAttr(bool exported, SpecializationKind kind,
3540
GenericSignature specializedSig,
3641
SILFunction *target, Identifier spiGroup,
@@ -212,6 +217,8 @@ SILFunction::~SILFunction() {
212217
"Function cannot be deleted while function_ref's still exist");
213218
assert(!newestAliveBitfield &&
214219
"Not all BasicBlockBitfields deleted at function destruction");
220+
if (currentBitfieldID > MaxBitfieldID)
221+
MaxBitfieldID = currentBitfieldID;
215222
}
216223

217224
void SILFunction::createProfiler(ASTNode Root, SILDeclRef forDecl,

0 commit comments

Comments
 (0)