mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-23 14:03:14 +00:00
[NewPM] Port tsan
A straightforward port of tsan to the new PM, following the same path as D55647. Differential Revision: https://reviews.llvm.org/D56433 llvm-svn: 350647
This commit is contained in:
parent
d5b07ff6c9
commit
02a3b0161d
@ -391,7 +391,7 @@ void initializeTailDuplicatePass(PassRegistry&);
|
||||
void initializeTargetLibraryInfoWrapperPassPass(PassRegistry&);
|
||||
void initializeTargetPassConfigPass(PassRegistry&);
|
||||
void initializeTargetTransformInfoWrapperPassPass(PassRegistry&);
|
||||
void initializeThreadSanitizerPass(PassRegistry&);
|
||||
void initializeThreadSanitizerLegacyPassPass(PassRegistry&);
|
||||
void initializeTwoAddressInstructionPassPass(PassRegistry&);
|
||||
void initializeTypeBasedAAWrapperPassPass(PassRegistry&);
|
||||
void initializeUnifyFunctionExitNodesPass(PassRegistry&);
|
||||
|
@ -155,9 +155,6 @@ ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
|
||||
FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false,
|
||||
bool Recover = false);
|
||||
|
||||
// Insert ThreadSanitizer (race detection) instrumentation
|
||||
FunctionPass *createThreadSanitizerPass();
|
||||
|
||||
// Insert DataFlowSanitizer (dynamic data flow analysis) instrumentation
|
||||
ModulePass *createDataFlowSanitizerPass(
|
||||
const std::vector<std::string> &ABIListFiles = std::vector<std::string>(),
|
||||
|
19
include/llvm/Transforms/Instrumentation/ThreadSanitizer.h
Normal file
19
include/llvm/Transforms/Instrumentation/ThreadSanitizer.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H
|
||||
#define LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
// Insert ThreadSanitizer (race detection) instrumentation
|
||||
FunctionPass *createThreadSanitizerLegacyPassPass();
|
||||
|
||||
/// A function pass for tsan instrumentation.
|
||||
///
|
||||
/// Instruments functions to detect race conditions reads. This function pass
|
||||
/// inserts calls to runtime library functions. If the functions aren't declared
|
||||
/// yet, the pass inserts the declarations. Otherwise the existing globals are
|
||||
struct ThreadSanitizerPass : public PassInfoMixin<ThreadSanitizerPass> {
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
|
||||
};
|
||||
}
|
||||
#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H */
|
@ -95,6 +95,7 @@
|
||||
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
|
||||
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
|
||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
|
||||
#include "llvm/Transforms/Scalar/ADCE.h"
|
||||
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
|
||||
|
@ -234,6 +234,7 @@ FUNCTION_PASS("view-cfg", CFGViewerPass())
|
||||
FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass())
|
||||
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
|
||||
FUNCTION_PASS("msan", MemorySanitizerPass())
|
||||
FUNCTION_PASS("tsan", ThreadSanitizerPass())
|
||||
#undef FUNCTION_PASS
|
||||
|
||||
#ifndef LOOP_ANALYSIS
|
||||
|
@ -113,7 +113,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) {
|
||||
initializeInstrProfilingLegacyPassPass(Registry);
|
||||
initializeMemorySanitizerLegacyPassPass(Registry);
|
||||
initializeHWAddressSanitizerPass(Registry);
|
||||
initializeThreadSanitizerPass(Registry);
|
||||
initializeThreadSanitizerLegacyPassPass(Registry);
|
||||
initializeSanitizerCoverageModulePass(Registry);
|
||||
initializeDataFlowSanitizerPass(Registry);
|
||||
initializeEfficiencySanitizerPass(Registry);
|
||||
|
@ -19,6 +19,7 @@
|
||||
// The rest is handled by the run-time library.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -80,21 +81,21 @@ STATISTIC(NumOmittedReadsFromConstantGlobals,
|
||||
STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads");
|
||||
STATISTIC(NumOmittedNonCaptured, "Number of accesses ignored due to capturing");
|
||||
|
||||
static const char *const kTsanModuleCtorName = "tsan.module_ctor";
|
||||
static const char *const kTsanInitName = "__tsan_init";
|
||||
|
||||
namespace {
|
||||
|
||||
/// ThreadSanitizer: instrument the code in module to find races.
|
||||
struct ThreadSanitizer : public FunctionPass {
|
||||
ThreadSanitizer() : FunctionPass(ID) {}
|
||||
StringRef getPassName() const override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
bool doInitialization(Module &M) override;
|
||||
static char ID; // Pass identification, replacement for typeid.
|
||||
///
|
||||
/// Instantiating ThreadSanitizer inserts the msan runtime library API function
|
||||
/// declarations into the module if they don't exist already. Instantiating
|
||||
/// ensures the __tsan_init function is in the list of global constructors for
|
||||
/// the module.
|
||||
struct ThreadSanitizer {
|
||||
ThreadSanitizer(Module &M);
|
||||
bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI);
|
||||
|
||||
private:
|
||||
private:
|
||||
void initializeCallbacks(Module &M);
|
||||
bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
|
||||
bool instrumentAtomic(Instruction *I, const DataLayout &DL);
|
||||
@ -128,29 +129,56 @@ struct ThreadSanitizer : public FunctionPass {
|
||||
Function *TsanVptrUpdate;
|
||||
Function *TsanVptrLoad;
|
||||
Function *MemmoveFn, *MemcpyFn, *MemsetFn;
|
||||
Function *TsanCtorFunction;
|
||||
};
|
||||
|
||||
struct ThreadSanitizerLegacyPass : FunctionPass {
|
||||
ThreadSanitizerLegacyPass() : FunctionPass(ID) {}
|
||||
StringRef getPassName() const override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
bool doInitialization(Module &M) override;
|
||||
static char ID; // Pass identification, replacement for typeid.
|
||||
private:
|
||||
Optional<ThreadSanitizer> TSan;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
char ThreadSanitizer::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(
|
||||
ThreadSanitizer, "tsan",
|
||||
"ThreadSanitizer: detects data races.",
|
||||
false, false)
|
||||
PreservedAnalyses ThreadSanitizerPass::run(Function &F,
|
||||
FunctionAnalysisManager &FAM) {
|
||||
ThreadSanitizer TSan(*F.getParent());
|
||||
if (TSan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F)))
|
||||
return PreservedAnalyses::none();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
char ThreadSanitizerLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(ThreadSanitizerLegacyPass, "tsan",
|
||||
"ThreadSanitizer: detects data races.", false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(
|
||||
ThreadSanitizer, "tsan",
|
||||
"ThreadSanitizer: detects data races.",
|
||||
false, false)
|
||||
INITIALIZE_PASS_END(ThreadSanitizerLegacyPass, "tsan",
|
||||
"ThreadSanitizer: detects data races.", false, false)
|
||||
|
||||
StringRef ThreadSanitizer::getPassName() const { return "ThreadSanitizer"; }
|
||||
StringRef ThreadSanitizerLegacyPass::getPassName() const {
|
||||
return "ThreadSanitizerLegacyPass";
|
||||
}
|
||||
|
||||
void ThreadSanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
void ThreadSanitizerLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createThreadSanitizerPass() {
|
||||
return new ThreadSanitizer();
|
||||
bool ThreadSanitizerLegacyPass::doInitialization(Module &M) {
|
||||
TSan.emplace(M);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadSanitizerLegacyPass::runOnFunction(Function &F) {
|
||||
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
||||
TSan->sanitizeFunction(F, TLI);
|
||||
return true;
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createThreadSanitizerLegacyPassPass() {
|
||||
return new ThreadSanitizerLegacyPass();
|
||||
}
|
||||
|
||||
void ThreadSanitizer::initializeCallbacks(Module &M) {
|
||||
@ -252,16 +280,10 @@ void ThreadSanitizer::initializeCallbacks(Module &M) {
|
||||
IRB.getInt32Ty(), IntptrTy));
|
||||
}
|
||||
|
||||
bool ThreadSanitizer::doInitialization(Module &M) {
|
||||
ThreadSanitizer::ThreadSanitizer(Module &M) {
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
IntptrTy = DL.getIntPtrType(M.getContext());
|
||||
std::tie(TsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
|
||||
M, kTsanModuleCtorName, kTsanInitName, /*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{});
|
||||
|
||||
appendToGlobalCtors(M, TsanCtorFunction, 0);
|
||||
|
||||
return true;
|
||||
getOrCreateInitFunction(M, kTsanInitName);
|
||||
}
|
||||
|
||||
static bool isVtableAccess(Instruction *I) {
|
||||
@ -402,11 +424,8 @@ void ThreadSanitizer::InsertRuntimeIgnores(Function &F) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadSanitizer::runOnFunction(Function &F) {
|
||||
// This is required to prevent instrumenting call to __tsan_init from within
|
||||
// the module constructor.
|
||||
if (&F == TsanCtorFunction)
|
||||
return false;
|
||||
bool ThreadSanitizer::sanitizeFunction(Function &F,
|
||||
const TargetLibraryInfo &TLI) {
|
||||
initializeCallbacks(*F.getParent());
|
||||
SmallVector<Instruction*, 8> AllLoadsAndStores;
|
||||
SmallVector<Instruction*, 8> LocalLoadsAndStores;
|
||||
@ -416,8 +435,6 @@ bool ThreadSanitizer::runOnFunction(Function &F) {
|
||||
bool HasCalls = false;
|
||||
bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread);
|
||||
const DataLayout &DL = F.getParent()->getDataLayout();
|
||||
const TargetLibraryInfo *TLI =
|
||||
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
||||
|
||||
// Traverse all instructions, collect loads/stores/returns, check for calls.
|
||||
for (auto &BB : F) {
|
||||
@ -428,7 +445,7 @@ bool ThreadSanitizer::runOnFunction(Function &F) {
|
||||
LocalLoadsAndStores.push_back(&Inst);
|
||||
else if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
|
||||
if (CallInst *CI = dyn_cast<CallInst>(&Inst))
|
||||
maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
|
||||
maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);
|
||||
if (isa<MemIntrinsic>(Inst))
|
||||
MemIntrinCalls.push_back(&Inst);
|
||||
HasCalls = true;
|
||||
|
@ -1,4 +1,5 @@
|
||||
; RUN: opt < %s -tsan -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=tsan -S | FileCheck %s
|
||||
|
||||
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
@ -9,7 +10,7 @@ entry:
|
||||
ret i32 %tmp1
|
||||
}
|
||||
|
||||
; CHECK: @llvm.global_ctors = {{.*}}@tsan.module_ctor
|
||||
; CHECK: @llvm.global_ctors = {{.*}}@__tsan_init
|
||||
|
||||
; CHECK: define i32 @read_4_bytes(i32* %a)
|
||||
; CHECK: call void @__tsan_func_entry(i8* %0)
|
||||
@ -77,6 +78,3 @@ define void @SwiftErrorCall(i8** swifterror) sanitize_thread {
|
||||
call void @SwiftError(i8** %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define internal void @tsan.module_ctor()
|
||||
; CHECK: call void @__tsan_init()
|
||||
|
Loading…
x
Reference in New Issue
Block a user