Files
swift-mirror/lib/SILOptimizer/Mandatory/DiagnosticDeadFunctionElimination.cpp
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00

98 lines
3.5 KiB
C++

//===--- DiagnosticDeadFunctionElimination.cpp ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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
//
//===----------------------------------------------------------------------===//
///
/// Delete functions that early diagnostic specialization passes mark as being
/// able to be DCE-ed if there are no further uses. This prevents later
/// diagnostic passes from emitting diagnostics both on the original function
/// and the diagnostic function.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-diagnostic-dead-function-eliminator"
#include "swift/AST/SemanticAttrs.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/Support/Debug.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// MARK: Top Level Entrypoint
//===----------------------------------------------------------------------===//
namespace {
struct DiagnosticDeadFunctionEliminator : SILFunctionTransform {
void run() override {
auto *fn = getFunction();
auto &mod = fn->getModule();
// If an earlier pass asked us to eliminate the function body if it's
// unused, and the function is in fact unused, do that now.
if (!fn->hasSemanticsAttr(semantics::DELETE_IF_UNUSED) ||
fn->getRefCount() != 0 ||
isPossiblyUsedExternally(fn->getLinkage(),
fn->getModule().isWholeModule())) {
return;
}
LLVM_DEBUG(llvm::dbgs()
<< "===> Stubbifying unused function " << fn->getName()
<< "'s body that was marked for deletion\n");
// Remove all non-entry blocks.
auto entryBB = fn->begin();
auto nextBB = std::next(entryBB);
while (nextBB != fn->end()) {
auto thisBB = nextBB;
++nextBB;
thisBB->eraseFromParent();
}
// Rewrite the entry block to only contain an unreachable.
auto loc = entryBB->begin()->getLoc();
entryBB->eraseAllInstructions(fn->getModule());
{
SILBuilder b(&*entryBB);
b.createUnreachable(loc);
}
// Drop differentiability witnesses, if any
if (!mod.lookUpDifferentiabilityWitnessesForFunction(fn->getName()).empty())
mod.eraseAllDifferentiabilityWitnesses(fn);
// If the function has shared linkage, reduce this version to private
// linkage, because we don't want the deleted-body form to win in any
// ODR shootouts.
if (fn->getLinkage() == SILLinkage::Shared) {
fn->setLinkage(SILLinkage::Private);
fn->setSerializedKind(IsNotSerialized);
}
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
// We know that this pass does not create infinite loops even if it
// deletes basic blocks.
fn->setNeedBreakInfiniteLoops(false);
// Replacing the whole function with an `unreachable` does not create
// incomplete lifetimes.
fn->setNeedCompleteLifetimes(false);
}
};
} // namespace
SILTransform *swift::createDiagnosticDeadFunctionElimination() {
return new DiagnosticDeadFunctionEliminator();
}