Skip to content

[pmo] Simplify/cleanup some code in preparation for available value c… #21908

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 72 additions & 45 deletions lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1017,9 +1017,8 @@ class AllocOptimize {
bool promoteLoad(SILInstruction *Inst);
void promoteDestroyAddr(DestroyAddrInst *DAI,
MutableArrayRef<AvailableValue> Values);
bool
canPromoteDestroyAddr(DestroyAddrInst *DAI,
llvm::SmallVectorImpl<AvailableValue> &AvailableValues);
bool canPromoteDestroyAddr(DestroyAddrInst *DAI,
SmallVectorImpl<AvailableValue> &AvailableValues);

bool tryToRemoveDeadAllocation();
};
Expand Down Expand Up @@ -1149,8 +1148,7 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {

/// Return true if we can promote the given destroy.
bool AllocOptimize::canPromoteDestroyAddr(
DestroyAddrInst *DAI,
llvm::SmallVectorImpl<AvailableValue> &AvailableValues) {
DestroyAddrInst *DAI, SmallVectorImpl<AvailableValue> &AvailableValues) {
SILValue Address = DAI->getOperand();

// We cannot promote destroys of address-only types, because we can't expose
Expand Down Expand Up @@ -1224,8 +1222,49 @@ void AllocOptimize::promoteDestroyAddr(
DAI->eraseFromParent();
}

/// tryToRemoveDeadAllocation - If the allocation is an autogenerated allocation
/// that is only stored to (after load promotion) then remove it completely.
namespace {

struct DestroyAddrPromotionState {
ArrayRef<SILInstruction *> destroys;
SmallVector<unsigned, 8> destroyAddrIndices;
SmallVector<AvailableValue, 32> availableValueList;
SmallVector<unsigned, 8> availableValueStartOffsets;

DestroyAddrPromotionState(ArrayRef<SILInstruction *> destroys)
: destroys(destroys) {}

unsigned size() const {
return destroyAddrIndices.size();
}

void initializeForDestroyAddr(unsigned destroyAddrIndex) {
availableValueStartOffsets.push_back(availableValueList.size());
destroyAddrIndices.push_back(destroyAddrIndex);
}

std::pair<DestroyAddrInst *, MutableArrayRef<AvailableValue>>
getData(unsigned index) {
unsigned destroyAddrIndex = destroyAddrIndices[index];
unsigned startOffset = availableValueStartOffsets[index];
unsigned count;

if ((availableValueStartOffsets.size() - 1) != index) {
count = availableValueStartOffsets[index + 1] - startOffset;
} else {
count = availableValueList.size() - startOffset;
}

MutableArrayRef<AvailableValue> values(&availableValueList[startOffset],
count);
auto *dai = cast<DestroyAddrInst>(destroys[destroyAddrIndex]);
return {dai, values};
}
};

} // end anonymous namespace

/// If the allocation is an autogenerated allocation that is only stored to
/// (after load promotion) then remove it completely.
bool AllocOptimize::tryToRemoveDeadAllocation() {
assert((isa<AllocBoxInst>(TheMemory) || isa<AllocStackInst>(TheMemory)) &&
"Unhandled allocation case");
Expand All @@ -1236,29 +1275,30 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {
// 1. They are in a transparent function.
// 2. They are in a normal function, but didn't come from a VarDecl, or came
// from one that was autogenerated or inlined from a transparent function.
SILLocation Loc = TheMemory->getLoc();
SILLocation loc = TheMemory->getLoc();
if (!TheMemory->getFunction()->isTransparent() &&
Loc.getAsASTNode<VarDecl>() && !Loc.isAutoGenerated() &&
!Loc.is<MandatoryInlinedLocation>())
loc.getAsASTNode<VarDecl>() && !loc.isAutoGenerated() &&
!loc.is<MandatoryInlinedLocation>())
return false;

// Check the uses list to see if there are any non-store uses left over after
// load promotion and other things PMO does.
for (auto &U : Uses) {
for (auto &u : Uses) {
// Ignore removed instructions.
if (U.Inst == nullptr) continue;
if (u.Inst == nullptr)
continue;

switch (U.Kind) {
switch (u.Kind) {
case PMOUseKind::Assign:
case PMOUseKind::PartialStore:
case PMOUseKind::InitOrAssign:
break; // These don't prevent removal.
case PMOUseKind::Initialization:
if (!isa<ApplyInst>(U.Inst) &&
if (!isa<ApplyInst>(u.Inst) &&
// A copy_addr that is not a take affects the retain count
// of the source.
(!isa<CopyAddrInst>(U.Inst) ||
cast<CopyAddrInst>(U.Inst)->isTakeOfSrc()))
(!isa<CopyAddrInst>(u.Inst) ||
cast<CopyAddrInst>(u.Inst)->isTakeOfSrc()))
break;
// FALL THROUGH.
LLVM_FALLTHROUGH;
Expand All @@ -1267,7 +1307,8 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {
case PMOUseKind::InOutUse:
case PMOUseKind::Escape:
LLVM_DEBUG(llvm::dbgs() << "*** Failed to remove autogenerated alloc: "
"kept alive by: " << *U.Inst);
"kept alive by: "
<< *u.Inst);
return false; // These do prevent removal.
}
}
Expand All @@ -1289,53 +1330,39 @@ bool AllocOptimize::tryToRemoveDeadAllocation() {

// Otherwise removing the deallocation will drop any releases. Check that
// there is nothing preventing removal.
llvm::SmallVector<unsigned, 8> DestroyAddrIndices;
llvm::SmallVector<AvailableValue, 32> AvailableValueList;
llvm::SmallVector<unsigned, 8> AvailableValueStartOffsets;
DestroyAddrPromotionState state(Releases);

for (auto P : llvm::enumerate(Releases)) {
auto *R = P.value();
if (R == nullptr)
for (auto p : llvm::enumerate(Releases)) {
auto *r = p.value();
if (r == nullptr)
continue;

// We stash all of the destroy_addr that we see.
if (auto *DAI = dyn_cast<DestroyAddrInst>(R)) {
AvailableValueStartOffsets.push_back(AvailableValueList.size());
if (auto *dai = dyn_cast<DestroyAddrInst>(r)) {
state.initializeForDestroyAddr(p.index() /*destroyAddrIndex*/);
// Make sure we can actually promote this destroy addr. If we can not,
// then we must bail. In order to not gather available values twice, we
// gather the available values here that we will use to promote the
// values.
if (!canPromoteDestroyAddr(DAI, AvailableValueList))
if (!canPromoteDestroyAddr(dai, state.availableValueList))
return false;
DestroyAddrIndices.push_back(P.index());
continue;
}

LLVM_DEBUG(llvm::dbgs()
<< "*** Failed to remove autogenerated non-trivial alloc: "
"kept alive by release: "
<< *R);
<< *r);
return false;
}

// If we reached this point, we can promote all of our destroy_addr.
for (auto P : llvm::enumerate(DestroyAddrIndices)) {
unsigned DestroyAddrIndex = P.value();
unsigned AvailableValueIndex = P.index();
unsigned StartOffset = AvailableValueStartOffsets[AvailableValueIndex];
unsigned Count;

if ((AvailableValueStartOffsets.size() - 1) != AvailableValueIndex) {
Count = AvailableValueStartOffsets[AvailableValueIndex + 1] - StartOffset;
} else {
Count = AvailableValueList.size() - StartOffset;
}

MutableArrayRef<AvailableValue> Values(&AvailableValueList[StartOffset],
Count);
auto *DAI = cast<DestroyAddrInst>(Releases[DestroyAddrIndex]);
promoteDestroyAddr(DAI, Values);
Releases[DestroyAddrIndex] = nullptr;
for (unsigned i : range(state.size())) {
DestroyAddrInst *dai;
MutableArrayRef<AvailableValue> values;
std::tie(dai, values) = state.getData(i);
promoteDestroyAddr(dai, values);
// We do not need to unset releases, since we are going to exit here.
}

LLVM_DEBUG(llvm::dbgs() << "*** Removing autogenerated non-trivial alloc: "
Expand Down