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
|
//===--- AccessPathVerification.cpp - verify access paths and storage -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
///
/// Verify AccessPath computation. For the address of every memory operation in
/// the module, compute the access path, compute all the users of that path,
/// then verify that all users have the same access path.
///
/// This is potentially expensive, so there is a fast mode that limits the
/// number of uses visited per path.
///
/// During full verification, also check that all addresses that share an
/// AccessPath are covered when computed the use list of that AccessPath. This
/// is important because optimizations may assume that the use list is
/// complete.
///
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "access-path-verification"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/Support/Debug.h"
using namespace swift;
namespace {
/// Verify access path and uses of each access.
class AccessPathVerification : public SILModuleTransform {
llvm::DenseMap<Operand *, AccessPath> useToPathMap;
// Transient uses
llvm::SmallVector<Operand *, 64> uses;
public:
void verifyAccessPath(Operand *operand) {
auto accessPath = AccessPath::compute(operand->get());
if (!accessPath.isValid())
return;
auto iterAndInserted = useToPathMap.try_emplace(operand, accessPath);
// If this use was already computed from a previously visited path, make
// sure the path we just computed matches.
if (!iterAndInserted.second) {
auto collectedFromPath = iterAndInserted.first->second;
if (collectedFromPath != accessPath) {
llvm::errs() << "Address use: " << *operand->getUser()
<< " collected from path\n ";
collectedFromPath.print(llvm::errs());
llvm::errs() << " has different path\n ";
accessPath.print(llvm::errs());
operand->getUser()->getFunction()->print(llvm::errs());
assert(false && "computed path does not match collected path");
}
return;
}
// This is a new path, so map all its uses.
assert(uses.empty());
accessPath.collectUses(uses, AccessUseType::Exact,
operand->getParentFunction());
bool foundOperandUse = false;
for (Operand *use : uses) {
if (use == operand) {
foundOperandUse = true;
continue;
}
auto iterAndInserted = useToPathMap.try_emplace(use, accessPath);
if (!iterAndInserted.second) {
llvm::errs() << "Address use: " << *operand->getUser()
<< " with path...\n";
accessPath.print(llvm::errs());
llvm::errs() << " was not collected for: " << *use->getUser();
llvm::errs() << " with path...\n";
auto computedPath = iterAndInserted.first->second;
computedPath.print(llvm::errs());
use->getUser()->getFunction()->print(llvm::errs());
assert(false && "missing collected use");
}
}
if (!foundOperandUse && !accessPath.hasUnknownOffset()) {
llvm::errs() << "Address use: " << *operand->getUser()
<< " is not a use of path\n ";
accessPath.print(llvm::errs());
assert(false && "not a user of its own computed path ");
}
uses.clear();
}
void run() override {
for (auto &fn : *getModule()) {
if (fn.empty())
continue;
PrettyStackTraceSILFunction functionDumper("...", &fn);
for (auto &bb : fn) {
for (auto &inst : bb) {
if (inst.mayReadOrWriteMemory())
visitAccessedAddress(&inst, [this](Operand *operand) {
return verifyAccessPath(operand);
});
}
}
useToPathMap.clear();
}
}
};
} // end anonymous namespace
SILTransform *swift::createAccessPathVerification() {
return new AccessPathVerification();
}
|