[llvm] [TSan] Add dominance-based redundant instrumentation elimination (PR #169897)
Dmitry Vyukov via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 7 07:06:48 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 {
+entry:
+ %v1 = load i32, ptr @g1, align 4
+ %v2 = load i32, ptr @g1, align 4
+ ret void
+}
+; CHECK-LABEL: define void @intra_block_read_read
+; CHECK: call void @__tsan_read4(ptr @g1)
+; CHECK-NOT: call void @__tsan_read4(ptr @g1)
+; CHECK: ret void
+
+; A dominating read does NOT eliminate a write on a dominated path.
+; The read-before-write elimination in chooseInstructionsToInstrument only
+; applies within the same basic block, so this uses an inter-block scenario.
----------------
dvyukov wrote:
but "a dominating read subsumes only a subsequent read", so would this be eliminated even w/o basic blocks?
perhaps we need to use 2 writes here?
https://github.com/llvm/llvm-project/pull/169897
More information about the llvm-commits
mailing list