mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Although I don't plan to bring over new assertions wholesale into the current qualification branch, it's entirely possible that various minor changes in main will use the new assertions; having this basic support in the release branch will simplify that. (This is why I'm adding the includes as a separate pass from rewriting the individual assertions)
135 lines
4.8 KiB
C++
135 lines
4.8 KiB
C++
//===--- PassManagerVerifierAnalysis.cpp ----------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "sil-passmanager-verifier-analysis"
|
|
#include "swift/SILOptimizer/Analysis/PassManagerVerifierAnalysis.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
static llvm::cl::opt<bool>
|
|
EnableVerifier("enable-sil-passmanager-verifier-analysis",
|
|
llvm::cl::desc("Enable verification of the passmanagers "
|
|
"function notification infrastructure"),
|
|
llvm::cl::init(true));
|
|
|
|
using namespace swift;
|
|
|
|
PassManagerVerifierAnalysis::PassManagerVerifierAnalysis(SILModule *mod)
|
|
: SILAnalysis(SILAnalysisKind::PassManagerVerifier), mod(*mod) {
|
|
#ifndef NDEBUG
|
|
if (!EnableVerifier)
|
|
return;
|
|
for (auto &fn : *mod) {
|
|
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add: " << fn.getName()
|
|
<< '\n');
|
|
liveFunctionNames.insert(fn.getName());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// Validate that the analysis is able to look up all functions and that those
|
|
/// functions are live.
|
|
void PassManagerVerifierAnalysis::invalidate() {}
|
|
|
|
/// Validate that the analysis is able to look up the given function.
|
|
void PassManagerVerifierAnalysis::invalidate(SILFunction *f,
|
|
InvalidationKind k) {}
|
|
|
|
/// If a function has not yet been seen start tracking it.
|
|
void PassManagerVerifierAnalysis::notifyAddedOrModifiedFunction(
|
|
SILFunction *f) {
|
|
#ifndef NDEBUG
|
|
if (!EnableVerifier)
|
|
return;
|
|
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Add|Mod: " << f->getName()
|
|
<< '\n');
|
|
liveFunctionNames.insert(f->getName());
|
|
#endif
|
|
}
|
|
|
|
/// Stop tracking a function.
|
|
void PassManagerVerifierAnalysis::notifyWillDeleteFunction(SILFunction *f) {
|
|
#ifndef NDEBUG
|
|
if (!EnableVerifier)
|
|
return;
|
|
LLVM_DEBUG(llvm::dbgs() << "PMVerifierAnalysis. Delete: " << f->getName()
|
|
<< '\n');
|
|
if (liveFunctionNames.erase(f->getName()))
|
|
return;
|
|
|
|
llvm::errs()
|
|
<< "Error! Tried to delete function that analysis was not aware of: "
|
|
<< f->getName() << '\n';
|
|
llvm_unreachable("triggering standard assertion failure routine");
|
|
#endif
|
|
}
|
|
|
|
/// Make sure that when we invalidate a function table, make sure we can find
|
|
/// all functions for all witness tables.
|
|
void PassManagerVerifierAnalysis::invalidateFunctionTables() {}
|
|
|
|
/// Run the entire verification.
|
|
void PassManagerVerifierAnalysis::verifyFull() const {
|
|
#ifndef NDEBUG
|
|
if (!EnableVerifier)
|
|
return;
|
|
|
|
// We check that liveFunctionNames is in sync with the module's function list
|
|
// by going through the module's function list and attempting to remove all
|
|
// functions in the module. If we fail to remove fn, then we know that a
|
|
// function was added to the module without an appropriate message being sent
|
|
// by the pass manager.
|
|
bool foundError = false;
|
|
|
|
unsigned count = 0;
|
|
for (auto &fn : mod) {
|
|
if (liveFunctionNames.count(fn.getName())) {
|
|
++count;
|
|
continue;
|
|
}
|
|
llvm::errs() << "Found function in module that was not added to verifier: "
|
|
<< fn.getName() << '\n';
|
|
foundError = true;
|
|
}
|
|
|
|
// Ok, so now we know that function(mod) is a subset of
|
|
// liveFunctionNames. Relying on the uniqueness provided by the module's
|
|
// function list, we know that liveFunction should be exactly count in
|
|
// size. Otherwise, we must have an error. If and only if we detect this
|
|
// error, do the expensive work of finding the missing deletes. This is an
|
|
// important performance optimization to avoid a large copy on the hot path.
|
|
if (liveFunctionNames.size() != count) {
|
|
auto liveFunctionNamesCopy = llvm::StringSet<>(liveFunctionNames);
|
|
for (auto &fn : mod) {
|
|
liveFunctionNamesCopy.erase(fn.getName());
|
|
}
|
|
for (auto &iter : liveFunctionNamesCopy) {
|
|
llvm::errs() << "Missing delete message for function: " << iter.first()
|
|
<< '\n';
|
|
foundError = true;
|
|
}
|
|
}
|
|
|
|
// We assert here so we emit /all/ errors before asserting.
|
|
assert(!foundError && "triggering standard assertion failure routine");
|
|
#endif
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Main Entry Point
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SILAnalysis *swift::createPassManagerVerifierAnalysis(SILModule *m) {
|
|
return new PassManagerVerifierAnalysis(m);
|
|
}
|