Skip to content

Commit

Permalink
[NewPM] Port tsan
Browse files Browse the repository at this point in the history
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
  • Loading branch information
pfaffe committed Jan 8, 2019
1 parent 6a18c53 commit 82f995d
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 49 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/InitializePasses.h
Expand Up @@ -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&);
Expand Down
3 changes: 0 additions & 3 deletions llvm/include/llvm/Transforms/Instrumentation.h
Expand Up @@ -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>(),
Expand Down
19 changes: 19 additions & 0 deletions llvm/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<ThreadSanitizerPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
}
#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H */
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassRegistry.def
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
Expand Up @@ -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);
Expand Down
97 changes: 57 additions & 40 deletions llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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.

private:
///
/// 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:
void initializeCallbacks(Module &M);
bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
bool instrumentAtomic(Instruction *I, const DataLayout &DL);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
6 changes: 2 additions & 4 deletions llvm/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"
Expand All @@ -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)
Expand Down Expand Up @@ -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()

0 comments on commit 82f995d

Please sign in to comment.