
Verify that the arguments of a naked function are not used. They can only be referenced via registers/stack in inline asm, not as IR values. Doing so will result in assertion failures in the backend. There's probably more that we should verify, though I'm not completely sure what the constraints are (would it be correct to require that naked functions are exactly an inline asm call + unreachable, or is more allowed?) Fixes https://github.com/llvm/llvm-project/issues/104718.
127 lines
4.0 KiB
LLVM
127 lines
4.0 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(ptr %a) sanitize_thread {
|
|
entry:
|
|
%tmp1 = load i32, ptr %a, align 4
|
|
ret i32 %tmp1
|
|
}
|
|
|
|
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tsan.module_ctor]
|
|
; CHECK: @llvm.global_ctors = {{.*}}@tsan.module_ctor
|
|
|
|
; CHECK: define i32 @read_4_bytes(ptr %a)
|
|
; CHECK: call void @__tsan_func_entry(ptr %0)
|
|
; CHECK-NEXT: call void @__tsan_read4(ptr %a)
|
|
; CHECK-NEXT: %tmp1 = load i32, ptr %a, align 4
|
|
; CHECK-NEXT: call void @__tsan_func_exit()
|
|
; CHECK: ret i32
|
|
|
|
|
|
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
|
|
declare void @llvm.memcpy.inline.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
|
|
declare void @llvm.memmove.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
|
|
declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1)
|
|
declare void @llvm.memset.inline.p0.i64(ptr nocapture, i8, i64, i1)
|
|
|
|
|
|
; Check that tsan converts mem intrinsics back to function calls.
|
|
|
|
define void @MemCpyTest(ptr nocapture %x, ptr nocapture %y) sanitize_thread {
|
|
entry:
|
|
tail call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 16, i1 false)
|
|
ret void
|
|
; CHECK: define void @MemCpyTest
|
|
; CHECK: call ptr @__tsan_memcpy
|
|
; CHECK: ret void
|
|
}
|
|
|
|
define void @MemCpyInlineTest(ptr nocapture %x, ptr nocapture %y) sanitize_thread {
|
|
entry:
|
|
tail call void @llvm.memcpy.inline.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 16, i1 false)
|
|
ret void
|
|
; CHECK: define void @MemCpyInlineTest
|
|
; CHECK: call ptr @__tsan_memcpy
|
|
; CHECK: ret void
|
|
}
|
|
|
|
define void @MemMoveTest(ptr nocapture %x, ptr nocapture %y) sanitize_thread {
|
|
entry:
|
|
tail call void @llvm.memmove.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 16, i1 false)
|
|
ret void
|
|
; CHECK: define void @MemMoveTest
|
|
; CHECK: call ptr @__tsan_memmove
|
|
; CHECK: ret void
|
|
}
|
|
|
|
define void @MemSetTest(ptr nocapture %x) sanitize_thread {
|
|
entry:
|
|
tail call void @llvm.memset.p0.i64(ptr align 4 %x, i8 77, i64 16, i1 false)
|
|
ret void
|
|
; CHECK: define void @MemSetTest
|
|
; CHECK: call ptr @__tsan_memset
|
|
; CHECK: ret void
|
|
}
|
|
|
|
define void @MemSetInlineTest(ptr nocapture %x) sanitize_thread {
|
|
entry:
|
|
tail call void @llvm.memset.inline.p0.i64(ptr align 4 %x, i8 77, i64 16, i1 false)
|
|
ret void
|
|
; CHECK: define void @MemSetInlineTest
|
|
; CHECK: call ptr @__tsan_memset
|
|
; CHECK: ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @SwiftError
|
|
; CHECK-NOT: __tsan_read
|
|
; CHECK-NOT: __tsan_write
|
|
; CHECK: ret
|
|
define void @SwiftError(ptr swifterror) sanitize_thread {
|
|
%swifterror_ptr_value = load ptr, ptr %0
|
|
store ptr null, ptr %0
|
|
%swifterror_addr = alloca swifterror ptr
|
|
%swifterror_ptr_value_2 = load ptr, ptr %swifterror_addr
|
|
store ptr null, ptr %swifterror_addr
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @SwiftErrorCall
|
|
; CHECK-NOT: __tsan_read
|
|
; CHECK-NOT: __tsan_write
|
|
; CHECK: ret
|
|
define void @SwiftErrorCall(ptr swifterror) sanitize_thread {
|
|
%swifterror_addr = alloca swifterror ptr
|
|
store ptr null, ptr %0
|
|
call void @SwiftError(ptr %0)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: @NakedTest()
|
|
; CHECK-NEXT: %a = call ptr @foo()
|
|
; CHECK-NEXT: %tmp1 = load i32, ptr %a, align 4
|
|
; CHECK-NEXT: ret i32 %tmp1
|
|
define i32 @NakedTest() naked sanitize_thread {
|
|
%a = call ptr @foo()
|
|
%tmp1 = load i32, ptr %a, align 4
|
|
ret i32 %tmp1
|
|
}
|
|
|
|
; vscale is unsupported, just don't crash here.
|
|
define void @test_load_store_i32(ptr %a, ptr %b) sanitize_thread {
|
|
; CHECK-LABEL: define void @test_load_store_i32(
|
|
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 4 x i32>, ptr [[A]], align 16
|
|
; CHECK-NEXT: store <vscale x 4 x i32> [[TMP1]], ptr [[B]], align 16
|
|
; CHECK-NEXT: ret void
|
|
%1 = load <vscale x 4 x i32>, ptr %a
|
|
store <vscale x 4 x i32> %1, ptr %b
|
|
ret void
|
|
}
|
|
|
|
declare void @foo() nounwind
|
|
|
|
; CHECK: define internal void @tsan.module_ctor()
|
|
; CHECK: call void @__tsan_init()
|