Index: llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -99,12 +99,15 @@ const DataLayout &DL); bool addrPointsToConstantData(Value *Addr); int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL); + void InsertRuntimeIgnores(Function &F, SmallVector &RetVec); Type *IntptrTy; IntegerType *OrdTy; // Callbacks to run-time library are computed in doInitialization. Function *TsanFuncEntry; Function *TsanFuncExit; + Function *TsanIgnoreBegin; + Function *TsanIgnoreEnd; // Accesses sizes are powers of two: 1, 2, 4, 8, 16. static const size_t kNumberOfAccessSizes = 5; Function *TsanRead[kNumberOfAccessSizes]; @@ -152,6 +155,10 @@ "__tsan_func_entry", IRB.getVoidTy(), IRB.getInt8PtrTy(), nullptr)); TsanFuncExit = checkSanitizerInterfaceFunction( M.getOrInsertFunction("__tsan_func_exit", IRB.getVoidTy(), nullptr)); + TsanIgnoreBegin = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + "__tsan_ignore_thread_begin", IRB.getVoidTy(), nullptr)); + TsanIgnoreEnd = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + "__tsan_ignore_thread_end", IRB.getVoidTy(), nullptr)); OrdTy = IRB.getInt32Ty(); for (size_t i = 0; i < kNumberOfAccessSizes; ++i) { const unsigned ByteSize = 1U << i; @@ -376,6 +383,16 @@ return false; } +void ThreadSanitizer::InsertRuntimeIgnores(Function &F, + SmallVector &RetVec) { + IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + IRB.CreateCall(TsanIgnoreBegin); + for (auto RetInst : RetVec) { + IRBuilder<> IRB(RetInst); + IRB.CreateCall(TsanIgnoreEnd); + } +} + bool ThreadSanitizer::runOnFunction(Function &F) { // This is required to prevent instrumenting call to __tsan_init from within // the module constructor. @@ -438,6 +455,12 @@ Res |= instrumentMemIntrinsic(Inst); } + if (F.hasFnAttribute("sanitize_thread_no_checking_at_run_time")) { + assert(!F.hasFnAttribute(Attribute::SanitizeThread)); + if (HasCalls) + InsertRuntimeIgnores(F, RetVec); + } + // Instrument function entry/exit points if there were instrumented accesses. if ((Res || HasCalls) && ClInstrumentFuncEntryExit) { IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); Index: llvm/trunk/test/Instrumentation/ThreadSanitizer/sanitize-thread-no-checking.ll =================================================================== --- llvm/trunk/test/Instrumentation/ThreadSanitizer/sanitize-thread-no-checking.ll +++ llvm/trunk/test/Instrumentation/ThreadSanitizer/sanitize-thread-no-checking.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -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" + +define i32 @"\01-[NoCalls dealloc]"(i32* %a) "sanitize_thread_no_checking_at_run_time" { +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +} + +; CHECK: define i32 @"\01-[NoCalls dealloc]"(i32* %a) +; CHECK-NEXT: entry: +; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4 +; CHECK-NEXT: ret i32 %tmp1 + +declare void @"foo"() + +define i32 @"\01-[WithCalls dealloc]"(i32* %a) "sanitize_thread_no_checking_at_run_time" { +entry: + %tmp1 = load i32, i32* %a, align 4 + call void @foo() + ret i32 %tmp1 +} + +; CHECK: define i32 @"\01-[WithCalls dealloc]"(i32* %a) +; CHECK-NEXT: entry: +; CHECK-NEXT: %0 = call i8* @llvm.returnaddress(i32 0) +; CHECK-NEXT: call void @__tsan_func_entry(i8* %0) +; CHECK-NEXT: call void @__tsan_ignore_thread_begin() +; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4 +; CHECK-NEXT: call void @foo() +; CHECK-NEXT: call void @__tsan_ignore_thread_end() +; CHECK-NEXT: call void @__tsan_func_exit() +; CHECK-NEXT: ret i32 %tmp1