Skip to content

Commit 3bac57d

Browse files
authored
Merge pull request #62907 from gottesmm/pruned-liveness-fixes
[pruned-liveness] Make some small fixes that only are exposed when working with multi-bit code
2 parents 68ceda4 + 5dceb82 commit 3bac57d

File tree

5 files changed

+123
-72
lines changed

5 files changed

+123
-72
lines changed

include/swift/Basic/FrozenMultiMap.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,19 @@ class FrozenMultiMap {
246246
auto optRange = makeOptionalTransformRange(baseRange, ToNonErasedValues());
247247
return makeTransformRange(optRange, PairWithTypeErasedOptionalSecondElt());
248248
}
249+
250+
/// Returns true if all values for all keys have been deleted.
251+
///
252+
/// This is intended to be used in use cases where a frozen multi map is
253+
/// filled up with a multi-map and then as we process keys, we delete values
254+
/// we have handled. In certain cases, one wishes to validate after processing
255+
/// that all values for all keys were properly handled. One cannot perform
256+
/// this operation with getRange() in a nice way.
257+
bool allValuesHaveBeenDeleted() const {
258+
return llvm::all_of(storage, [](const std::pair<Key, Optional<Value>> &pair) {
259+
return !pair.second.hasValue();
260+
});
261+
}
249262
};
250263

251264
template <typename Key, typename Value, typename Storage>

include/swift/Basic/SmallBitVector.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===--- SmallBitVector.h -------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_BASIC_SMALLBITVECTOR_H
14+
#define SWIFT_BASIC_SMALLBITVECTOR_H
15+
16+
#include "llvm/ADT/SmallBitVector.h"
17+
#include "llvm/Support/raw_ostream.h"
18+
19+
namespace llvm {
20+
21+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
22+
const SmallBitVector &bv) {
23+
for (unsigned i = 0, e = bv.size(); i != e; ++i)
24+
os << (bv[i] ? '1' : '0');
25+
return os;
26+
}
27+
28+
} // namespace llvm
29+
30+
#endif

include/swift/SIL/PrunedLiveness.h

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -196,26 +196,19 @@ class PrunedLiveBlocks {
196196

197197
unsigned size() const { return bits.size() / 2; }
198198

199-
// FIXME: specialize this for scalar liveness, which is the critical path
200-
// for all OSSA utilities.
201199
IsLive getLiveness(unsigned bitNo) const {
202-
SmallVector<IsLive, 1> foundLiveness;
203-
getLiveness(bitNo, bitNo + 1, foundLiveness);
204-
return foundLiveness[0];
200+
if (!bits[bitNo * 2])
201+
return IsLive::Dead;
202+
return bits[bitNo * 2 + 1] ? LiveOut : LiveWithin;
205203
}
206204

205+
/// Returns the liveness in \p resultingFoundLiveness. We only return the
206+
/// bits for endBitNo - startBitNo.
207207
void getLiveness(unsigned startBitNo, unsigned endBitNo,
208208
SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
209209
unsigned actualStartBitNo = startBitNo * 2;
210210
unsigned actualEndBitNo = endBitNo * 2;
211211

212-
// NOTE: We pad both before/after with Dead to ensure that we are
213-
// returning an array that acts as a bit mask and thus can be directly
214-
// compared against other such bitmasks. This invariant is used when
215-
// computing boundaries.
216-
for (unsigned i = 0; i != startBitNo; ++i) {
217-
resultingFoundLiveness.push_back(Dead);
218-
}
219212
for (unsigned i = actualStartBitNo, e = actualEndBitNo; i != e; i += 2) {
220213
if (!bits[i]) {
221214
resultingFoundLiveness.push_back(Dead);
@@ -224,9 +217,6 @@ class PrunedLiveBlocks {
224217

225218
resultingFoundLiveness.push_back(bits[i + 1] ? LiveOut : LiveWithin);
226219
}
227-
for (unsigned i = endBitNo, e = size(); i != e; ++i) {
228-
resultingFoundLiveness.push_back(Dead);
229-
}
230220
}
231221

232222
void setLiveness(unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
@@ -291,9 +281,12 @@ class PrunedLiveBlocks {
291281

292282
/// Update this liveness result for a single use.
293283
IsLive updateForUse(SILInstruction *user, unsigned bitNo) {
294-
SmallVector<IsLive, 1> resultingLiveness;
295-
updateForUse(user, bitNo, bitNo + 1, resultingLiveness);
296-
return resultingLiveness[0];
284+
auto *block = user->getParent();
285+
auto liveness = getBlockLiveness(block, bitNo);
286+
if (liveness != Dead)
287+
return liveness;
288+
computeScalarUseBlockLiveness(block, bitNo);
289+
return getBlockLiveness(block, bitNo);
297290
}
298291

299292
/// Update this range of liveness results for a single use.
@@ -302,19 +295,22 @@ class PrunedLiveBlocks {
302295
SmallVectorImpl<IsLive> &resultingLiveness);
303296

304297
IsLive getBlockLiveness(SILBasicBlock *bb, unsigned bitNo) const {
305-
SmallVector<IsLive, 1> isLive;
306-
getBlockLiveness(bb, bitNo, bitNo + 1, isLive);
307-
return isLive[0];
298+
auto liveBlockIter = liveBlocks.find(bb);
299+
if (liveBlockIter == liveBlocks.end()) {
300+
return Dead;
301+
}
302+
303+
return liveBlockIter->second.getLiveness(bitNo);
308304
}
309305

310-
// FIXME: This API should directly return the live bitset. The live bitset
311-
// type should have an api for querying and iterating over the live fields.
306+
/// FIXME: This API should directly return the live bitset. The live bitset
307+
/// type should have an api for querying and iterating over the live fields.
312308
void getBlockLiveness(SILBasicBlock *bb, unsigned startBitNo,
313309
unsigned endBitNo,
314310
SmallVectorImpl<IsLive> &foundLivenessInfo) const {
315311
auto liveBlockIter = liveBlocks.find(bb);
316312
if (liveBlockIter == liveBlocks.end()) {
317-
for (unsigned i : range(numBitsToTrack)) {
313+
for (unsigned i : range(endBitNo - startBitNo)) {
318314
(void)i;
319315
foundLivenessInfo.push_back(Dead);
320316
}
@@ -330,11 +326,6 @@ class PrunedLiveBlocks {
330326

331327
protected:
332328
void markBlockLive(SILBasicBlock *bb, unsigned bitNo, IsLive isLive) {
333-
markBlockLive(bb, bitNo, bitNo + 1, isLive);
334-
}
335-
336-
void markBlockLive(SILBasicBlock *bb, unsigned startBitNo, unsigned endBitNo,
337-
IsLive isLive) {
338329
assert(isLive != Dead && "erasing live blocks isn't implemented.");
339330
auto iterAndInserted =
340331
liveBlocks.insert(std::make_pair(bb, LivenessSmallBitVector()));
@@ -344,18 +335,44 @@ class PrunedLiveBlocks {
344335
// we have more than SmallBitVector's small size number of bits.
345336
auto &insertedBV = iterAndInserted.first->getSecond();
346337
insertedBV.init(numBitsToTrack);
347-
insertedBV.setLiveness(startBitNo, endBitNo, isLive);
338+
insertedBV.setLiveness(bitNo, bitNo + 1, isLive);
348339
if (discoveredBlocks)
349340
discoveredBlocks->push_back(bb);
350-
} else if (isLive == LiveOut) {
351-
// Update the existing entry to be live-out.
352-
iterAndInserted.first->getSecond().setLiveness(startBitNo, endBitNo,
353-
LiveOut);
341+
} else {
342+
// If we are dead, always update to the new liveness.
343+
switch (iterAndInserted.first->getSecond().getLiveness(bitNo)) {
344+
case Dead:
345+
iterAndInserted.first->getSecond().setLiveness(bitNo, bitNo + 1,
346+
isLive);
347+
break;
348+
case LiveWithin:
349+
if (isLive == LiveOut) {
350+
// Update the existing entry to be live-out.
351+
iterAndInserted.first->getSecond().setLiveness(bitNo, bitNo + 1,
352+
LiveOut);
353+
}
354+
break;
355+
case LiveOut:
356+
break;
357+
}
354358
}
355359
}
356360

357-
void computeUseBlockLiveness(SILBasicBlock *userBB, unsigned startBitNo,
358-
unsigned endBitNo);
361+
void markBlockLive(SILBasicBlock *bb, unsigned startBitNo, unsigned endBitNo,
362+
IsLive isLive) {
363+
for (unsigned index : range(startBitNo, endBitNo)) {
364+
markBlockLive(bb, index, isLive);
365+
}
366+
}
367+
368+
private:
369+
/// A helper routine that as a fast path handles the scalar case. We do not
370+
/// handle the mult-bit case today since the way the code is written today
371+
/// assumes we process a bit at a time.
372+
///
373+
/// TODO: Make a multi-bit query for efficiency reasons.
374+
void computeScalarUseBlockLiveness(SILBasicBlock *userBB,
375+
unsigned startBitNo);
359376
};
360377

361378
/// If inner borrows are 'Contained', then liveness is fully described by the

lib/SIL/Utils/PrunedLiveness.cpp

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@
2121

2222
using namespace swift;
2323

24-
/// Mark blocks live during a reverse CFG traversal from one specific block
25-
/// containing a user.
26-
void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB,
27-
unsigned startBitNo,
28-
unsigned endBitNo) {
24+
void PrunedLiveBlocks::computeScalarUseBlockLiveness(SILBasicBlock *userBB,
25+
unsigned bitNo) {
2926
// If, we are visiting this block, then it is not already LiveOut. Mark it
3027
// LiveWithin to indicate a liveness boundary within the block.
31-
markBlockLive(userBB, startBitNo, endBitNo, LiveWithin);
28+
markBlockLive(userBB, bitNo, LiveWithin);
3229

33-
SmallVector<IsLive, 8> predLivenessInfo;
3430
BasicBlockWorklist worklist(userBB->getFunction());
3531
worklist.push(userBB);
3632

@@ -40,19 +36,15 @@ void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB,
4036
// Traversal terminates at any previously visited block, including the
4137
// blocks initialized as definition blocks.
4238
for (auto *predBlock : block->getPredecessorBlocks()) {
43-
SWIFT_DEFER { predLivenessInfo.clear(); };
44-
getBlockLiveness(predBlock, startBitNo, endBitNo, predLivenessInfo);
45-
for (unsigned i : indices(predLivenessInfo)) {
46-
switch (predLivenessInfo[i]) {
47-
case Dead:
48-
worklist.pushIfNotVisited(predBlock);
49-
LLVM_FALLTHROUGH;
50-
case LiveWithin:
51-
markBlockLive(predBlock, startBitNo, endBitNo, LiveOut);
52-
break;
53-
case LiveOut:
54-
break;
55-
}
39+
switch (getBlockLiveness(predBlock, bitNo)) {
40+
case Dead:
41+
worklist.pushIfNotVisited(predBlock);
42+
LLVM_FALLTHROUGH;
43+
case LiveWithin:
44+
markBlockLive(predBlock, bitNo, LiveOut);
45+
break;
46+
case LiveOut:
47+
break;
5648
}
5749
}
5850
}
@@ -66,22 +58,26 @@ void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB,
6658
void PrunedLiveBlocks::updateForUse(
6759
SILInstruction *user, unsigned startBitNo, unsigned endBitNo,
6860
SmallVectorImpl<IsLive> &resultingLivenessInfo) {
61+
resultingLivenessInfo.clear();
62+
6963
SWIFT_ASSERT_ONLY(seenUse = true);
7064

7165
auto *bb = user->getParent();
7266
getBlockLiveness(bb, startBitNo, endBitNo, resultingLivenessInfo);
7367

74-
for (auto isLive : resultingLivenessInfo) {
75-
switch (isLive) {
68+
for (auto pair : llvm::enumerate(resultingLivenessInfo)) {
69+
unsigned index = pair.index();
70+
unsigned specificBitNo = startBitNo + index;
71+
switch (pair.value()) {
7672
case LiveOut:
7773
case LiveWithin:
7874
continue;
7975
case Dead: {
8076
// This use block has not yet been marked live. Mark it and its
8177
// predecessor blocks live.
82-
computeUseBlockLiveness(bb, startBitNo, endBitNo);
83-
resultingLivenessInfo.clear();
84-
return getBlockLiveness(bb, startBitNo, endBitNo, resultingLivenessInfo);
78+
computeScalarUseBlockLiveness(bb, specificBitNo);
79+
resultingLivenessInfo.push_back(getBlockLiveness(bb, specificBitNo));
80+
continue;
8581
}
8682
}
8783
llvm_unreachable("covered switch");
@@ -179,10 +175,13 @@ void PrunedLiveBlocks::print(llvm::raw_ostream &OS) const {
179175
if (!discoveredBlocks) {
180176
OS << "No deterministic live block list\n";
181177
}
178+
SmallVector<IsLive, 8> isLive;
182179
for (auto *block : *discoveredBlocks) {
183180
block->printAsOperand(OS);
184-
OS
185-
<< ": " << getStringRef(this->getBlockLiveness(block, 0)) << "\n";
181+
OS << ": ";
182+
for (unsigned i : range(getNumBitsToTrack()))
183+
OS << getStringRef(this->getBlockLiveness(block, i)) << ", ";
184+
OS << "\n";
186185
}
187186
}
188187

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
#include "swift/Basic/Defer.h"
142142
#include "swift/Basic/FrozenMultiMap.h"
143143
#include "swift/Basic/GraphNodeWorklist.h"
144+
#include "swift/Basic/SmallBitVector.h"
144145
#include "swift/SIL/BasicBlockBits.h"
145146
#include "swift/SIL/BasicBlockDatastructures.h"
146147
#include "swift/SIL/Consumption.h"
@@ -183,15 +184,6 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
183184
Context.Diags.diagnose(loc, diag, std::forward<U>(args)...);
184185
}
185186

186-
namespace llvm {
187-
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SmallBitVector &bv) {
188-
for (unsigned index : range(bv.size())) {
189-
os << (bv[index] ? 1 : 0);
190-
}
191-
return os;
192-
}
193-
} // namespace llvm
194-
195187
static SourceLoc getSourceLocFromValue(SILValue value) {
196188
if (auto *defInst = value->getDefiningInstruction())
197189
return defInst->getLoc().getSourceLoc();

0 commit comments

Comments
 (0)