|
| 1 | +//===--- DiagnosticDeadFunctionElimination.cpp ----------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2023 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 | +/// Delete functions that early diagnostic specialization passes mark as being |
| 14 | +/// able to be DCE-ed if there are no further uses. This prevents later |
| 15 | +/// diagnostic passes from emitting diagnostics both on the original function |
| 16 | +/// and the diagnostic function. |
| 17 | +/// |
| 18 | +//===----------------------------------------------------------------------===// |
| 19 | + |
| 20 | +#define DEBUG_TYPE "sil-diagnostic-dead-function-eliminator" |
| 21 | + |
| 22 | +#include "swift/AST/SemanticAttrs.h" |
| 23 | +#include "swift/SIL/SILBuilder.h" |
| 24 | +#include "swift/SILOptimizer/PassManager/Passes.h" |
| 25 | +#include "swift/SILOptimizer/PassManager/Transforms.h" |
| 26 | +#include "llvm/Support/Debug.h" |
| 27 | + |
| 28 | +using namespace swift; |
| 29 | + |
| 30 | +//===----------------------------------------------------------------------===// |
| 31 | +// MARK: Top Level Entrypoint |
| 32 | +//===----------------------------------------------------------------------===// |
| 33 | + |
| 34 | +namespace { |
| 35 | + |
| 36 | +struct DiagnosticDeadFunctionEliminator : SILFunctionTransform { |
| 37 | + void run() override { |
| 38 | + auto *fn = getFunction(); |
| 39 | + |
| 40 | + // If an earlier pass asked us to eliminate the function body if it's |
| 41 | + // unused, and the function is in fact unused, do that now. |
| 42 | + if (!fn->hasSemanticsAttr(semantics::DELETE_IF_UNUSED) || |
| 43 | + fn->getRefCount() != 0 || |
| 44 | + isPossiblyUsedExternally(fn->getLinkage(), |
| 45 | + fn->getModule().isWholeModule())) { |
| 46 | + return; |
| 47 | + } |
| 48 | + |
| 49 | + LLVM_DEBUG(llvm::dbgs() |
| 50 | + << "===> Stubbifying unused function " << fn->getName() |
| 51 | + << "'s body that was marked for deletion\n"); |
| 52 | + // Remove all non-entry blocks. |
| 53 | + auto entryBB = fn->begin(); |
| 54 | + auto nextBB = std::next(entryBB); |
| 55 | + |
| 56 | + while (nextBB != fn->end()) { |
| 57 | + auto thisBB = nextBB; |
| 58 | + ++nextBB; |
| 59 | + thisBB->eraseFromParent(); |
| 60 | + } |
| 61 | + |
| 62 | + // Rewrite the entry block to only contain an unreachable. |
| 63 | + auto loc = entryBB->begin()->getLoc(); |
| 64 | + entryBB->eraseAllInstructions(fn->getModule()); |
| 65 | + { |
| 66 | + SILBuilder b(&*entryBB); |
| 67 | + b.createUnreachable(loc); |
| 68 | + } |
| 69 | + |
| 70 | + // If the function has shared linkage, reduce this version to private |
| 71 | + // linkage, because we don't want the deleted-body form to win in any |
| 72 | + // ODR shootouts. |
| 73 | + if (fn->getLinkage() == SILLinkage::Shared) { |
| 74 | + fn->setLinkage(SILLinkage::Private); |
| 75 | + fn->setSerialized(IsNotSerialized); |
| 76 | + } |
| 77 | + |
| 78 | + invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody); |
| 79 | + } |
| 80 | +}; |
| 81 | + |
| 82 | +} // namespace |
| 83 | + |
| 84 | +SILTransform *swift::createDiagnosticDeadFunctionElimination() { |
| 85 | + return new DiagnosticDeadFunctionEliminator(); |
| 86 | +} |
0 commit comments