const DataLayout &DL);
bool addrPointsToConstantData(Value *Addr);
int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
+ void InsertRuntimeIgnores(Function &F, SmallVector<Instruction*, 8> &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];
"__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;
return false;
}
+void ThreadSanitizer::InsertRuntimeIgnores(Function &F,
+ SmallVector<Instruction*, 8> &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.
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());
--- /dev/null
+; 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