Skip to content

Commit 387806b

Browse files
committed
[ownership] Add a simple helper wrapper called canonicalizeOSSALifetimes around CanonicalizeOSSALifetime that clean up extra copies inserted when RAUWing or promoting loads.
Based on code in CopyPropagation. It is assumed that the passed in set of defs is unique and that all such defs were found by using CanonicalizeOSSALifetime::getCanonicalCopiedDef(copy).
1 parent 3ab207c commit 387806b

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

include/swift/SILOptimizer/Utils/CanonicalOSSALifetime.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ class CanonicalizeOSSALifetime {
398398
/// lifetime, call this API again on the value defined by the new copy.
399399
bool canonicalizeValueLifetime(SILValue def);
400400

401+
/// Return the inst mod callbacks struct used by this CanonicalizeOSSALifetime
402+
/// to pass to other APIs that need to compose with CanonicalizeOSSALifetime.
403+
InstModCallbacks getInstModCallbacks() const { return instModCallbacks; }
404+
401405
protected:
402406
void recordDebugValue(DebugValueInst *dvi) {
403407
debugValues.insert(dvi);
@@ -438,6 +442,29 @@ class CanonicalizeOSSALifetime {
438442
void injectPoison();
439443
};
440444

445+
/// Canonicalize the passed in set of defs, eliminating in one batch any that
446+
/// are not needed given the canonical lifetime of the various underlying owned
447+
/// value introducers.
448+
///
449+
/// On success, returns the invalidation kind that the caller must use to
450+
/// invalidate analyses. Currently it will only ever return
451+
/// SILAnalysis::InvalidationKind::Instructions or None.
452+
///
453+
/// NOTE: This routine is guaranteed to not invalidate
454+
/// NonLocalAccessBlockAnalysis, so callers should lock it before invalidating
455+
/// instructions. E.x.:
456+
///
457+
/// accessBlockAnalysis->lockInvalidation();
458+
/// pass->invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
459+
/// accessBlockAnalysis->unlockInvalidation();
460+
///
461+
/// NOTE: We assume that all \p inputDefs is a set (that is it has no duplicate
462+
/// elements) and that all values have been generated by running a copy through
463+
/// CanonicalizeOSSALifetime::getCanonicalCopiedDef(copy)).
464+
SILAnalysis::InvalidationKind
465+
canonicalizeOSSALifetimes(CanonicalizeOSSALifetime &canonicalizeLifetime,
466+
ArrayRef<SILValue> inputDefs);
467+
441468
} // end namespace swift
442469

443470
#endif

lib/SILOptimizer/Utils/CanonicalOSSALifetime.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,3 +1221,64 @@ SWIFT_ASSERT_ONLY_DECL(
12211221
llvm::dbgs() << " " << *blockAndInst.getSecond();
12221222
}
12231223
})
1224+
1225+
//===----------------------------------------------------------------------===//
1226+
// MARK: Canonicalize Lifetimes Utility
1227+
//===----------------------------------------------------------------------===//
1228+
1229+
SILAnalysis::InvalidationKind
1230+
swift::canonicalizeOSSALifetimes(CanonicalizeOSSALifetime &canonicalizer,
1231+
ArrayRef<SILValue> copiedDefs) {
1232+
auto isCopyDead = [](CopyValueInst *copy, bool pruneDebug) -> bool {
1233+
for (Operand *use : copy->getUses()) {
1234+
auto *user = use->getUser();
1235+
if (isa<DestroyValueInst>(user)) {
1236+
continue;
1237+
}
1238+
if (pruneDebug && isa<DebugValueInst>(user)) {
1239+
continue;
1240+
}
1241+
return false;
1242+
}
1243+
return true;
1244+
};
1245+
1246+
// Cleanup dead copies. If getCanonicalCopiedDef returns a copy (because the
1247+
// copy's source operand is unrecgonized), then the copy is itself treated
1248+
// like a def and may be dead after canonicalization.
1249+
SmallVector<SILInstruction *, 4> deadCopies;
1250+
for (auto def : copiedDefs) {
1251+
// Canonicalized this def. If we did not perform any canonicalization, just
1252+
// continue.
1253+
if (!canonicalizer.canonicalizeValueLifetime(def))
1254+
continue;
1255+
1256+
// Otherwise, see if we have a dead copy.
1257+
if (auto *copy = dyn_cast<CopyValueInst>(def)) {
1258+
if (isCopyDead(copy, false /*prune debug*/)) {
1259+
deadCopies.push_back(copy);
1260+
}
1261+
}
1262+
1263+
// Canonicalize any new outer copy.
1264+
if (SILValue outerCopy = canonicalizer.createdOuterCopy()) {
1265+
SILValue outerDef = canonicalizer.getCanonicalCopiedDef(outerCopy);
1266+
canonicalizer.canonicalizeValueLifetime(outerDef);
1267+
}
1268+
1269+
// TODO: also canonicalize any lifetime.persistentCopies like separate owned
1270+
// live ranges.
1271+
}
1272+
1273+
if (!canonicalizer.hasChanged() && deadCopies.empty()) {
1274+
return SILAnalysis::InvalidationKind::Nothing;
1275+
}
1276+
1277+
// We use our canonicalizers inst mod callbacks.
1278+
InstructionDeleter deleter(canonicalizer.getInstModCallbacks());
1279+
for (auto *copy : deadCopies) {
1280+
deleter.recursivelyDeleteUsersIfDead(copy);
1281+
}
1282+
1283+
return SILAnalysis::InvalidationKind::Instructions;
1284+
}

0 commit comments

Comments
 (0)