Skip to content

Commit 2f890dc

Browse files
committedJan 27, 2021
SIL: some improvements to the BasicBlockBitfield utilities
* add a BasicBlockSetVector class * add a second argument to BasicBlockFlag::set, for the set value. * rename BasicBlockSet::remove -> BasicBlockSet::erase. * add a MaxBitfieldID statistics value in SILFunction.cpp
1 parent ddd0f4d commit 2f890dc

File tree

4 files changed

+72
-13
lines changed

4 files changed

+72
-13
lines changed
 

‎include/swift/SIL/SILBitfield.h

+57-10
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/SILFunction.h

+1-1
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;

‎lib/SIL/IR/SILFunction.cpp

+7
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,

‎unittests/SIL/SILBitfieldTest.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -25,8 +25,13 @@ struct SILFunction {
2525
};
2626

2727
struct SILBasicBlock {
28+
SILFunction *function;
2829
uint32_t customBits = 0;
2930
uint64_t lastInitializedBitfieldID = 0;
31+
32+
SILBasicBlock(SILFunction *function): function(function) {}
33+
34+
SILFunction *getParent() const { return function; }
3035
};
3136

3237
}
@@ -41,7 +46,7 @@ namespace {
4146

4247
TEST(SILBitfieldTest, Basic) {
4348
SILFunction f;
44-
SILBasicBlock b;
49+
SILBasicBlock b(&f);
4550

4651
{
4752
BasicBlockFlag A(&f);

0 commit comments

Comments
 (0)