diff --git a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -546,19 +546,27 @@ // Traverse all instructions, collect loads/stores/returns, check for calls. for (auto &BB : F) { for (auto &Inst : BB) { - if (isAtomic(&Inst)) + bool Barrier = false; + + if (isAtomic(&Inst)) { AtomicAccesses.push_back(&Inst); - else if (isa(Inst) || isa(Inst)) + Barrier = true; + } else if (isa(Inst) || isa(Inst)) { LocalLoadsAndStores.push_back(&Inst); - else if (isa(Inst) || isa(Inst)) { + } else if (isa(Inst) || isa(Inst)) { if (CallInst *CI = dyn_cast(&Inst)) maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); if (isa(Inst)) MemIntrinCalls.push_back(&Inst); HasCalls = true; + Barrier = true; + } + + if (Barrier) + // Flush instructions found so far, avoiding compounding instrumentation + // with any instructions that follow. chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL); - } } chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL); } diff --git a/llvm/test/Instrumentation/ThreadSanitizer/read_before_write.ll b/llvm/test/Instrumentation/ThreadSanitizer/read_before_write.ll --- a/llvm/test/Instrumentation/ThreadSanitizer/read_before_write.ll +++ b/llvm/test/Instrumentation/ThreadSanitizer/read_before_write.ll @@ -37,6 +37,50 @@ declare void @foo() +define void @IncrementWithFence(i32* nocapture %ptr) nounwind uwtable sanitize_thread { +entry: + %0 = load i32, i32* %ptr, align 4 + %inc = add nsw i32 %0, 1 + fence seq_cst + store i32 %inc, i32* %ptr, align 4 + ret void +} + +; CHECK-LABEL: define void @IncrementWithFence +; CHECK: __tsan_read4 +; CHECK: __tsan_atomic_thread_fence +; CHECK: __tsan_write4 +; CHECK: ret void + +define void @IncrementWithAtomic(i32* nocapture %ptr) nounwind uwtable sanitize_thread { +entry: + %0 = load i32, i32* %ptr, align 4 + %inc = add nsw i32 %0, 1 + %1 = load atomic i32, i32* %ptr acquire, align 4 + store i32 %inc, i32* %ptr, align 4 + ret void +} + +; CHECK-LABEL: define void @IncrementWithAtomic +; CHECK: __tsan_read4 +; CHECK: __tsan_atomic32_load +; CHECK: __tsan_write4 +; CHECK: ret void + +define void @IncrementWithAsm(i32* nocapture %ptr) nounwind uwtable sanitize_thread { +entry: + %0 = load i32, i32* %ptr, align 4 + %inc = add nsw i32 %0, 1 + call void asm sideeffect "", ""() + store i32 %inc, i32* %ptr, align 4 + ret void +} + +; CHECK-LABEL: define void @IncrementWithAsm +; CHECK: __tsan_read4 +; CHECK: __tsan_write4 +; CHECK: ret void + define void @VolatileLoad(i32* nocapture %ptr) nounwind uwtable sanitize_thread { entry: %0 = load volatile i32, i32* %ptr, align 4