[llvm] [TSan] Add dominance-based redundant instrumentation elimination (PR #169897)

Alexey Paznikov via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 04:49:09 PDT 2026


================
@@ -0,0 +1,884 @@
+; RUN: opt < %s -passes=tsan -S | FileCheck %s
+; RUN: opt < %s -passes=tsan -tsan-use-dominance-analysis=false -S | FileCheck %s --check-prefix=NODOM
+; RUN: opt < %s -passes=tsan -tsan-distinguish-volatile -S | FileCheck %s --check-prefix=VOLATILE
+
+; Tests for TSan dominance-based redundant instrumentation elimination.
+; Redundant instrumentation is removed when one access dominates another to
+; the same location with no synchronization on any path between them.
+;
+; Check prefixes:
+;   CHECK   - default run (optimization enabled)
+;   NODOM   - optimization disabled; all accesses must remain instrumented
+;   VOLATILE - -tsan-distinguish-volatile enabled; volatile and non-volatile
+;              accesses emit different runtime calls and must not be merged
+
+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-S128"
+
+ at g1 = global i32 0, align 4
+ at g2 = global i32 0, align 4
+ at arr = global [5 x i32] zeroinitializer, align 4
+
+; Unsafe call (no nosync): blocks dominance-based elimination.
+declare void @ext_call()
+; nosync call: safe to cross for dominance-based elimination.
+declare void @nosync_func() #0
+; Unsafe function returning i32, used in loop tests.
+declare i32 @ext_check(...)
+
+; ===========================================================================
+; Intra-block dominance
+; ===========================================================================
+
+; First write dominates second write to the same location.
+define void @intra_block_write_write() nounwind uwtable sanitize_thread {
+entry:
+  store i32 1, ptr @g1, align 4
+  store i32 2, ptr @g1, align 4
+  ret void
+}
+; CHECK-LABEL: define void @intra_block_write_write
+; CHECK:       call void @__tsan_write4(ptr @g1)
+; CHECK-NOT:   call void @__tsan_write4(ptr @g1)
+; CHECK:       ret void
+;
+; NODOM-LABEL: define void @intra_block_write_write
+; NODOM:       call void @__tsan_write4(ptr @g1)
+; NODOM:       call void @__tsan_write4(ptr @g1)
+; NODOM:       ret void
+
+; Write dominates following read: write covers read, so read is removed.
+define void @intra_block_write_read() nounwind uwtable sanitize_thread {
+entry:
+  store i32 1, ptr @g1, align 4
+  %val = load i32, ptr @g1, align 4
+  ret void
+}
+; CHECK-LABEL: define void @intra_block_write_read
+; CHECK:       call void @__tsan_write4(ptr @g1)
+; CHECK-NOT:   call void @__tsan_read4(ptr @g1)
+; CHECK:       ret void
+
+; First read dominates second read to the same location.
+define void @intra_block_read_read() nounwind uwtable sanitize_thread {
----------------
apaznikov wrote:

Added `@intra_block_read_write`. Note that with default flags the existing read-before-write elimination in `chooseInstructionsToInstrument` drops the read before this analysis runs, so the test also runs under `-tsan-instrument-read-before-write` (RBW prefix) to check that the pair actually reaches `DominanceBasedElimination` and both accesses are kept.

https://github.com/llvm/llvm-project/pull/169897


More information about the llvm-commits mailing list