Index: llvm/trunk/include/llvm/InitializePasses.h =================================================================== --- llvm/trunk/include/llvm/InitializePasses.h +++ llvm/trunk/include/llvm/InitializePasses.h @@ -391,7 +391,7 @@ void initializeTargetLibraryInfoWrapperPassPass(PassRegistry&); void initializeTargetPassConfigPass(PassRegistry&); void initializeTargetTransformInfoWrapperPassPass(PassRegistry&); -void initializeThreadSanitizerPass(PassRegistry&); +void initializeThreadSanitizerLegacyPassPass(PassRegistry&); void initializeTwoAddressInstructionPassPass(PassRegistry&); void initializeTypeBasedAAWrapperPassPass(PassRegistry&); void initializeUnifyFunctionExitNodesPass(PassRegistry&); Index: llvm/trunk/include/llvm/Transforms/Instrumentation.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Instrumentation.h +++ llvm/trunk/include/llvm/Transforms/Instrumentation.h @@ -155,9 +155,6 @@ 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 &ABIListFiles = std::vector(), Index: llvm/trunk/include/llvm/Transforms/Instrumentation/ThreadSanitizer.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Instrumentation/ThreadSanitizer.h +++ llvm/trunk/include/llvm/Transforms/Instrumentation/ThreadSanitizer.h @@ -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 { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} +#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H */ Index: llvm/trunk/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/trunk/lib/Passes/PassBuilder.cpp +++ llvm/trunk/lib/Passes/PassBuilder.cpp @@ -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" Index: llvm/trunk/lib/Passes/PassRegistry.def =================================================================== --- llvm/trunk/lib/Passes/PassRegistry.def +++ llvm/trunk/lib/Passes/PassRegistry.def @@ -234,6 +234,7 @@ 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 Index: llvm/trunk/lib/Transforms/Instrumentation/Instrumentation.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/Instrumentation.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -113,7 +113,7 @@ initializeInstrProfilingLegacyPassPass(Registry); initializeMemorySanitizerLegacyPassPass(Registry); initializeHWAddressSanitizerPass(Registry); - initializeThreadSanitizerPass(Registry); + initializeThreadSanitizerLegacyPassPass(Registry); initializeSanitizerCoverageModulePass(Registry); initializeDataFlowSanitizerPass(Registry); initializeEfficiencySanitizerPass(Registry); Index: llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -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(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 @@ 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 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(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(); } -FunctionPass *llvm::createThreadSanitizerPass() { - return new ThreadSanitizer(); +bool ThreadSanitizerLegacyPass::doInitialization(Module &M) { + TSan.emplace(M); + return true; +} + +bool ThreadSanitizerLegacyPass::runOnFunction(Function &F) { + auto &TLI = getAnalysis().getTLI(); + TSan->sanitizeFunction(F, TLI); + return true; +} + +FunctionPass *llvm::createThreadSanitizerLegacyPassPass() { + return new ThreadSanitizerLegacyPass(); } void ThreadSanitizer::initializeCallbacks(Module &M) { @@ -252,16 +280,10 @@ 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 @@ } } -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 AllLoadsAndStores; SmallVector LocalLoadsAndStores; @@ -416,8 +435,6 @@ bool HasCalls = false; bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread); const DataLayout &DL = F.getParent()->getDataLayout(); - const TargetLibraryInfo *TLI = - &getAnalysis().getTLI(); // Traverse all instructions, collect loads/stores/returns, check for calls. for (auto &BB : F) { @@ -428,7 +445,7 @@ LocalLoadsAndStores.push_back(&Inst); else if (isa(Inst) || isa(Inst)) { if (CallInst *CI = dyn_cast(&Inst)) - maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI); + maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); if (isa(Inst)) MemIntrinCalls.push_back(&Inst); HasCalls = true; Index: llvm/trunk/test/Instrumentation/ThreadSanitizer/tsan_basic.ll =================================================================== --- llvm/trunk/test/Instrumentation/ThreadSanitizer/tsan_basic.ll +++ llvm/trunk/test/Instrumentation/ThreadSanitizer/tsan_basic.ll @@ -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 @@ 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 @@ call void @SwiftError(i8** %0) ret void } - -; CHECK: define internal void @tsan.module_ctor() -; CHECK: call void @__tsan_init()