1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
//===--- SILGenCleanup.cpp ------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// Perform peephole-style "cleanup" to aid SIL diagnostic passes.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "silgen-cleanup"
#include "swift/Basic/Defer.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/OSSALifetimeCompletion.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/PrunedLiveness.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
using namespace swift;
// Define a CanonicalizeInstruction subclass for use in SILGenCleanup.
struct SILGenCanonicalize final : CanonicalizeInstruction {
bool changed = false;
llvm::SmallPtrSet<SILInstruction *, 16> deadOperands;
SILGenCanonicalize(DeadEndBlocks &deadEndBlocks)
: CanonicalizeInstruction(DEBUG_TYPE, deadEndBlocks) {}
void notifyNewInstruction(SILInstruction *) override { changed = true; }
// Just delete the given 'inst' and record its operands. The callback isn't
// allowed to mutate any other instructions.
void killInstruction(SILInstruction *inst) override {
deadOperands.erase(inst);
for (auto &operand : inst->getAllOperands()) {
if (auto *operInst = operand.get()->getDefiningInstruction())
deadOperands.insert(operInst);
}
inst->eraseFromParent();
changed = true;
}
void notifyHasNewUsers(SILValue) override { changed = true; }
/// Delete trivially dead instructions in non-deterministic order.
///
/// We either have that nextII is endII or if nextII is not endII then endII
/// is nextII->getParent()->end().
SILBasicBlock::iterator deleteDeadOperands(SILBasicBlock::iterator nextII,
SILBasicBlock::iterator endII) {
auto callbacks = InstModCallbacks().onDelete([&](SILInstruction *deadInst) {
LLVM_DEBUG(llvm::dbgs() << "Trivially dead: " << *deadInst);
// If nextII is the instruction we are going to delete, move nextII past
// it.
if (deadInst->getIterator() == nextII)
++nextII;
// Then remove the instruction from the set and delete it.
deadOperands.erase(deadInst);
deadInst->eraseFromParent();
});
while (!deadOperands.empty()) {
SILInstruction *deadOperInst = *deadOperands.begin();
// Make sure at least the first instruction is removed from the set.
deadOperands.erase(deadOperInst);
// Then delete this instruction/everything else that we can.
eliminateDeadInstruction(deadOperInst, callbacks);
}
return nextII;
}
};
//===----------------------------------------------------------------------===//
// SILGenCleanup: Top-Level Module Transform
//===----------------------------------------------------------------------===//
namespace {
// SILGenCleanup must run on all functions that will be seen by any analysis
// used by diagnostics before transforming the function that requires the
// analysis. e.g. Closures need to be cleaned up before the closure's parent can
// be diagnosed.
//
// TODO: This pass can be converted to a function transform if the mandatory
// pipeline runs in bottom-up closure order.
struct SILGenCleanup : SILModuleTransform {
void run() override;
bool completeOSSALifetimes(SILFunction *function);
};
bool SILGenCleanup::completeOSSALifetimes(SILFunction *function) {
if (!getModule()->getOptions().OSSACompleteLifetimes)
return false;
bool changed = false;
// Lifetimes must be completed inside out (bottom-up in the CFG).
PostOrderFunctionInfo *postOrder =
getAnalysis<PostOrderAnalysis>()->get(function);
OSSALifetimeCompletion completion(function, /*DomInfo*/nullptr);
for (auto *block : postOrder->getPostOrder()) {
for (SILInstruction &inst : reverse(*block)) {
for (auto result : inst.getResults()) {
if (completion.completeOSSALifetime(result) ==
LifetimeCompletion::WasCompleted) {
changed = true;
}
}
}
for (SILArgument *arg : block->getArguments()) {
assert(!arg->isReborrow() && "reborrows not legal at this SIL stage");
if (completion.completeOSSALifetime(arg) ==
LifetimeCompletion::WasCompleted) {
changed = true;
}
}
}
function->verifyOwnership(/*deadEndBlocks=*/nullptr);
return changed;
}
void SILGenCleanup::run() {
auto &module = *getModule();
for (auto &function : module) {
if (!function.isDefinition())
continue;
PrettyStackTraceSILFunction stackTrace("silgen cleanup", &function);
LLVM_DEBUG(llvm::dbgs()
<< "\nRunning SILGenCleanup on " << function.getName() << "\n");
bool changed = completeOSSALifetimes(&function);
DeadEndBlocks deadEndBlocks(&function);
SILGenCanonicalize sgCanonicalize(deadEndBlocks);
// Iterate over all blocks even if they aren't reachable. No phi-less
// dataflow cycles should have been created yet, and these transformations
// are simple enough they shouldn't be affected by cycles.
for (auto &bb : function) {
for (auto ii = bb.begin(), ie = bb.end(); ii != ie;) {
ii = sgCanonicalize.canonicalize(&*ii);
ii = sgCanonicalize.deleteDeadOperands(ii, ie);
}
}
changed |= sgCanonicalize.changed;
if (changed) {
auto invalidKind = SILAnalysis::InvalidationKind::Instructions;
invalidateAnalysis(&function, invalidKind);
}
}
}
} // end anonymous namespace
SILTransform *swift::createSILGenCleanup() { return new SILGenCleanup(); }
|