Skip to content

Commit a6dddbd

Browse files
committed
[NFC] OSSACanonicalizeOwned: Record def kinds.
Add a type which distinguishes among the types of defs that are pushed onto the "def-use worklist". Note that it's not possible to rely on the kind of value because the root may itself be a copy_value. For now, the distinction is discarded as soon as the def is visited.
1 parent 03319e5 commit a6dddbd

File tree

2 files changed

+168
-9
lines changed

2 files changed

+168
-9
lines changed

include/swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898

9999
#include "swift/Basic/GraphNodeWorklist.h"
100100
#include "swift/Basic/SmallPtrSetVector.h"
101+
#include "swift/Basic/TaggedUnion.h"
101102
#include "swift/SIL/PrunedLiveness.h"
102103
#include "swift/SIL/SILInstruction.h"
103104
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
@@ -279,8 +280,74 @@ class CanonicalizeOSSALifetime final {
279280
/// outside the pruned liveness at the time it is discovered.
280281
llvm::SmallPtrSet<DebugValueInst *, 8> debugValues;
281282

283+
class Def {
284+
struct Root {
285+
SILValue value;
286+
};
287+
struct Copy {
288+
CopyValueInst *cvi;
289+
};
290+
struct BorrowedFrom {
291+
BorrowedFromInst *bfi;
292+
};
293+
struct Reborrow {
294+
SILArgument *argument;
295+
};
296+
using Payload = TaggedUnion<Root, Copy, BorrowedFrom, Reborrow>;
297+
Payload payload;
298+
Def(Payload payload) : payload(payload) {}
299+
300+
public:
301+
enum class Kind {
302+
Root,
303+
Copy,
304+
BorrowedFrom,
305+
Reborrow,
306+
};
307+
Kind getKind() const {
308+
if (payload.isa<Root>()) {
309+
return Kind::Root;
310+
}
311+
if (payload.isa<Copy>()) {
312+
return Kind::Copy;
313+
}
314+
if (payload.isa<BorrowedFrom>()) {
315+
return Kind::BorrowedFrom;
316+
}
317+
assert(payload.isa<Reborrow>());
318+
return Kind::Reborrow;
319+
}
320+
operator Kind() const { return getKind(); }
321+
bool operator==(Def rhs) const {
322+
return getKind() == rhs.getKind() && getValue() == rhs.getValue();
323+
}
324+
static Def root(SILValue value) { return {Root{value}}; }
325+
static Def copy(CopyValueInst *cvi) { return {Copy{cvi}}; }
326+
static Def borrowedFrom(BorrowedFromInst *bfi) {
327+
return {BorrowedFrom{bfi}};
328+
}
329+
static Def reborrow(SILArgument *argument) { return {Reborrow{argument}}; }
330+
SILValue getValue() const {
331+
switch (*this) {
332+
case Kind::Root:
333+
return payload.get<Root>().value;
334+
case Kind::Copy:
335+
return payload.get<Copy>().cvi;
336+
case Kind::BorrowedFrom:
337+
return payload.get<BorrowedFrom>().bfi;
338+
case Kind::Reborrow:
339+
return payload.get<Reborrow>().argument;
340+
}
341+
llvm_unreachable("covered switch");
342+
}
343+
};
344+
friend llvm::DenseMapInfo<Def>;
345+
friend llvm::PointerLikeTypeTraits<Def>;
346+
friend llvm::PointerLikeTypeTraits<
347+
std::optional<swift::CanonicalizeOSSALifetime::Def>>;
348+
282349
/// Visited set for general def-use traversal that prevents revisiting values.
283-
GraphNodeWorklist<SILValue, 8> defUseWorklist;
350+
GraphNodeWorklist<std::optional<Def>, 8> defUseWorklist;
284351

285352
/// The blocks that were discovered by PrunedLiveness.
286353
SmallVector<SILBasicBlock *, 32> discoveredBlocks;
@@ -496,4 +563,94 @@ class CanonicalizeOSSALifetime final {
496563

497564
} // end namespace swift
498565

566+
namespace llvm {
567+
template <>
568+
struct DenseMapInfo<swift::CanonicalizeOSSALifetime::Def> {
569+
static swift::CanonicalizeOSSALifetime::Def getEmptyKey() {
570+
return swift::CanonicalizeOSSALifetime::Def::root(
571+
DenseMapInfo<swift::SILValue>::getEmptyKey());
572+
}
573+
static swift::CanonicalizeOSSALifetime::Def getTombstoneKey() {
574+
return swift::CanonicalizeOSSALifetime::Def::root(
575+
DenseMapInfo<swift::SILValue>::getTombstoneKey());
576+
}
577+
static unsigned getHashValue(swift::CanonicalizeOSSALifetime::Def def) {
578+
return detail::combineHashValue(
579+
DenseMapInfo<swift::CanonicalizeOSSALifetime::Def::Kind>::getHashValue(
580+
def.getKind()),
581+
DenseMapInfo<swift::SILValue>::getHashValue(def.getValue()));
582+
}
583+
static bool isEqual(swift::CanonicalizeOSSALifetime::Def LHS,
584+
swift::CanonicalizeOSSALifetime::Def RHS) {
585+
return LHS == RHS;
586+
}
587+
};
588+
template <>
589+
struct PointerLikeTypeTraits<swift::CanonicalizeOSSALifetime::Def> {
590+
private:
591+
using Def = swift::CanonicalizeOSSALifetime::Def;
592+
593+
public:
594+
static void *getAsVoidPointer(Def def) {
595+
return reinterpret_cast<void *>(
596+
reinterpret_cast<uintptr_t>(def.getValue().getOpaqueValue()) |
597+
((uintptr_t)def.getKind()) << NumLowBitsAvailable);
598+
}
599+
static Def getFromVoidPointer(void *p) {
600+
auto kind = (Def::Kind)((reinterpret_cast<uintptr_t>(p) & 0b110) >>
601+
NumLowBitsAvailable);
602+
auto opaque =
603+
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) & ~0b111);
604+
auto value = swift::SILValue::getFromOpaqueValue(opaque);
605+
switch (kind) {
606+
case Def::Kind::Root:
607+
return Def::root(value);
608+
case Def::Kind::Copy:
609+
return Def::copy(cast<swift::CopyValueInst>(value));
610+
case Def::Kind::Reborrow:
611+
return Def::reborrow(cast<swift::SILArgument>(value));
612+
case Def::Kind::BorrowedFrom:
613+
return Def::borrowedFrom(cast<swift::BorrowedFromInst>(value));
614+
}
615+
}
616+
617+
enum {
618+
NumLowBitsAvailable =
619+
llvm::PointerLikeTypeTraits<swift::SILValue>::NumLowBitsAvailable - 2
620+
};
621+
};
622+
template <>
623+
struct PointerLikeTypeTraits<
624+
std::optional<swift::CanonicalizeOSSALifetime::Def>> {
625+
private:
626+
using Def = swift::CanonicalizeOSSALifetime::Def;
627+
using Payload = std::optional<Def>;
628+
629+
public:
630+
static void *getAsVoidPointer(Payload payload) {
631+
if (!payload)
632+
return 0x0;
633+
return reinterpret_cast<void *>(
634+
reinterpret_cast<uintptr_t>(
635+
PointerLikeTypeTraits<swift::CanonicalizeOSSALifetime::Def>::
636+
getAsVoidPointer(*payload)) |
637+
0b1);
638+
}
639+
static Payload getFromVoidPointer(void *p) {
640+
auto none = reinterpret_cast<uintptr_t>(p) & 0b1;
641+
if (none)
642+
return std::nullopt;
643+
auto opaque =
644+
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) & ~0b1);
645+
return {PointerLikeTypeTraits<
646+
swift::CanonicalizeOSSALifetime::Def>::getFromVoidPointer(opaque)};
647+
}
648+
649+
enum {
650+
NumLowBitsAvailable =
651+
llvm::PointerLikeTypeTraits<Def>::NumLowBitsAvailable - 1
652+
};
653+
};
654+
} // end namespace llvm
655+
499656
#endif

lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,18 @@ static bool isDestroyOfCopyOf(SILInstruction *instruction, SILValue def) {
132132
bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
133133
LLVM_DEBUG(llvm::dbgs() << "Computing canonical liveness from:\n";
134134
getCurrentDef()->print(llvm::dbgs()));
135-
defUseWorklist.initialize(getCurrentDef());
135+
defUseWorklist.initialize(Def::root(getCurrentDef()));
136136
// Only the first level of reborrows need to be consider. All nested inner
137137
// adjacent reborrows and phis are encapsulated within their lifetimes.
138138
SILPhiArgument *arg;
139139
if ((arg = dyn_cast<SILPhiArgument>(getCurrentDef())) && arg->isPhi()) {
140140
visitInnerAdjacentPhis(arg, [&](SILArgument *reborrow) {
141-
defUseWorklist.insert(reborrow);
141+
defUseWorklist.insert(Def::reborrow(reborrow));
142142
return true;
143143
});
144144
}
145-
while (SILValue value = defUseWorklist.pop()) {
145+
while (auto def = defUseWorklist.pop()) {
146+
auto value = def->getValue();
146147
LLVM_DEBUG(llvm::dbgs() << " Uses of value:\n";
147148
value->print(llvm::dbgs()));
148149

@@ -153,11 +154,11 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
153154
auto *user = use->getUser();
154155
// Recurse through copies.
155156
if (auto *copy = dyn_cast<CopyValueInst>(user)) {
156-
defUseWorklist.insert(copy);
157+
defUseWorklist.insert(Def::copy(copy));
157158
continue;
158159
}
159160
if (auto *bfi = dyn_cast<BorrowedFromInst>(user)) {
160-
defUseWorklist.insert(bfi);
161+
defUseWorklist.insert(Def::borrowedFrom(bfi));
161162
continue;
162163
}
163164
// Handle debug_value instructions separately.
@@ -244,7 +245,7 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
244245
// This branch reborrows a guaranteed phi whose lifetime is dependent on
245246
// currentDef. Uses of the reborrowing phi extend liveness.
246247
auto *reborrow = PhiOperand(use).getValue();
247-
defUseWorklist.insert(reborrow);
248+
defUseWorklist.insert(Def::reborrow(reborrow));
248249
break;
249250
}
250251
}
@@ -1159,7 +1160,7 @@ void CanonicalizeOSSALifetime::rewriteCopies(
11591160
auto *user = use->getUser();
11601161
// Recurse through copies.
11611162
if (auto *copy = dyn_cast<CopyValueInst>(user)) {
1162-
defUseWorklist.insert(copy);
1163+
defUseWorklist.insert(Def::copy(copy));
11631164
return true;
11641165
}
11651166
if (destroys.contains(user)) {
@@ -1202,7 +1203,8 @@ void CanonicalizeOSSALifetime::rewriteCopies(
12021203
copyLiveUse(use, getCallbacks());
12031204
}
12041205
}
1205-
while (SILValue value = defUseWorklist.pop()) {
1206+
while (auto def = defUseWorklist.pop()) {
1207+
SILValue value = def->getValue();
12061208
CopyValueInst *srcCopy = cast<CopyValueInst>(value);
12071209
// Recurse through copies while replacing their uses.
12081210
Operand *reusedCopyOp = nullptr;

0 commit comments

Comments
 (0)