Vitaly Buka b4257d3bf5 [tsan] Replace mem intrinsics with calls to interceptors
After https://reviews.llvm.org/rG463aa814182a23 tsan replaces llvm
intrinsics with calls to glibc functions. However this approach is
fragile, as slight changes in pipeline can return llvm intrinsics back.
In particular InstCombine can do that.

Msan/Asan already declare own version of these memory
functions for the similar purpose.

KCSAN, or anything that uses something else than compiler-rt, needs to
implement this callbacks.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D133268
2022-09-06 13:09:31 -07:00

116 lines
3.6 KiB
LLVM

; RUN: opt < %s -passes='function(tsan),module(tsan-module)' -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 @read_4_bytes(i32* %a) sanitize_thread {
entry:
%tmp1 = load i32, i32* %a, align 4
ret i32 %tmp1
}
; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @tsan.module_ctor to i8*)]
; CHECK: @llvm.global_ctors = {{.*}}@tsan.module_ctor
; CHECK: define i32 @read_4_bytes(i32* %a)
; CHECK: call void @__tsan_func_entry(i8* %0)
; CHECK-NEXT: %1 = bitcast i32* %a to i8*
; CHECK-NEXT: call void @__tsan_read4(i8* %1)
; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4
; CHECK-NEXT: call void @__tsan_func_exit()
; CHECK: ret i32
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
declare void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1)
declare void @llvm.memset.inline.p0i8.i64(i8* nocapture, i8, i64, i1)
; Check that tsan converts mem intrinsics back to function calls.
define void @MemCpyTest(i8* nocapture %x, i8* nocapture %y) sanitize_thread {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
ret void
; CHECK: define void @MemCpyTest
; CHECK: call i8* @__tsan_memcpy
; CHECK: ret void
}
define void @MemCpyInlineTest(i8* nocapture %x, i8* nocapture %y) sanitize_thread {
entry:
tail call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
ret void
; CHECK: define void @MemCpyInlineTest
; CHECK: call i8* @__tsan_memcpy
; CHECK: ret void
}
define void @MemMoveTest(i8* nocapture %x, i8* nocapture %y) sanitize_thread {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
ret void
; CHECK: define void @MemMoveTest
; CHECK: call i8* @__tsan_memmove
; CHECK: ret void
}
define void @MemSetTest(i8* nocapture %x) sanitize_thread {
entry:
tail call void @llvm.memset.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
ret void
; CHECK: define void @MemSetTest
; CHECK: call i8* @__tsan_memset
; CHECK: ret void
}
define void @MemSetInlineTest(i8* nocapture %x) sanitize_thread {
entry:
tail call void @llvm.memset.inline.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
ret void
; CHECK: define void @MemSetInlineTest
; CHECK: call i8* @__tsan_memset
; CHECK: ret void
}
; CHECK-LABEL: @SwiftError
; CHECK-NOT: __tsan_read
; CHECK-NOT: __tsan_write
; CHECK: ret
define void @SwiftError(i8** swifterror) sanitize_thread {
%swifterror_ptr_value = load i8*, i8** %0
store i8* null, i8** %0
%swifterror_addr = alloca swifterror i8*
%swifterror_ptr_value_2 = load i8*, i8** %swifterror_addr
store i8* null, i8** %swifterror_addr
ret void
}
; CHECK-LABEL: @SwiftErrorCall
; CHECK-NOT: __tsan_read
; CHECK-NOT: __tsan_write
; CHECK: ret
define void @SwiftErrorCall(i8** swifterror) sanitize_thread {
%swifterror_addr = alloca swifterror i8*
store i8* null, i8** %0
call void @SwiftError(i8** %0)
ret void
}
; CHECK-LABEL: @NakedTest(i32* %a)
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4
; CHECK-NEXT: ret i32 %tmp1
define i32 @NakedTest(i32* %a) naked sanitize_thread {
call void @foo()
%tmp1 = load i32, i32* %a, align 4
ret i32 %tmp1
}
declare void @foo() nounwind
; CHECK: define internal void @tsan.module_ctor()
; CHECK: call void @__tsan_init()