summaryrefslogtreecommitdiff
path: root/test/Instrumentation
diff options
context:
space:
mode:
Diffstat (limited to 'test/Instrumentation')
-rw-r--r--test/Instrumentation/AddressSanitizer/X86/bug_11395.ll4
-rw-r--r--test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll57
-rw-r--r--test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll6
-rw-r--r--test/Instrumentation/AddressSanitizer/basic.ll61
-rw-r--r--test/Instrumentation/AddressSanitizer/debug_info.ll61
-rw-r--r--test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll41
-rw-r--r--test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll7
-rw-r--r--test/Instrumentation/AddressSanitizer/instrument-no-return.ll38
-rw-r--r--test/Instrumentation/AddressSanitizer/instrument_global.ll2
-rw-r--r--test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll49
-rw-r--r--test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll2
-rw-r--r--test/Instrumentation/AddressSanitizer/lifetime.ll84
-rw-r--r--test/Instrumentation/AddressSanitizer/test64.ll10
-rw-r--r--test/Instrumentation/MemorySanitizer/lit.local.cfg1
-rw-r--r--test/Instrumentation/MemorySanitizer/msan_basic.ll625
-rw-r--r--test/Instrumentation/MemorySanitizer/unreachable.ll39
-rw-r--r--test/Instrumentation/ThreadSanitizer/atomic.ll250
-rw-r--r--test/Instrumentation/ThreadSanitizer/read_from_global.ll2
-rw-r--r--test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll26
-rw-r--r--test/Instrumentation/ThreadSanitizer/tsan_basic.ll33
-rw-r--r--test/Instrumentation/ThreadSanitizer/vptr_read.ll13
21 files changed, 1358 insertions, 53 deletions
diff --git a/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll b/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll
index 35c5c4a0bba4e..38168fc2d68da 100644
--- a/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll
+++ b/test/Instrumentation/AddressSanitizer/X86/bug_11395.ll
@@ -36,14 +36,14 @@ target triple = "i386-unknown-linux-gnu"
@ff_mlp_firorder_7 = external global i8
@ff_mlp_firorder_8 = external global i8
-define void @ff_mlp_init_x86(%struct.DSPContext* nocapture %c, %struct.AVCodecContext* nocapture %avctx) nounwind address_safety {
+define void @ff_mlp_init_x86(%struct.DSPContext* nocapture %c, %struct.AVCodecContext* nocapture %avctx) nounwind sanitize_address {
entry:
%mlp_filter_channel = getelementptr inbounds %struct.DSPContext* %c, i32 0, i32 131
store void (i32*, i32*, i32, i32, i32, i32, i32, i32*)* @mlp_filter_channel_x86, void (i32*, i32*, i32, i32, i32, i32, i32, i32*)** %mlp_filter_channel, align 4, !tbaa !0
ret void
}
-define internal void @mlp_filter_channel_x86(i32* %state, i32* %coeff, i32 %firorder, i32 %iirorder, i32 %filter_shift, i32 %mask, i32 %blocksize, i32* %sample_buffer) nounwind address_safety {
+define internal void @mlp_filter_channel_x86(i32* %state, i32* %coeff, i32 %firorder, i32 %iirorder, i32 %filter_shift, i32 %mask, i32 %blocksize, i32* %sample_buffer) nounwind sanitize_address {
entry:
%filter_shift.addr = alloca i32, align 4
%mask.addr = alloca i32, align 4
diff --git a/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll b/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
new file mode 100644
index 0000000000000..6a60d1c29f564
--- /dev/null
+++ b/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
@@ -0,0 +1,57 @@
+; RUN: opt < %s -asan -asan-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"
+
+; Here we check that the global redzone sizes grow with the object size.
+
+@G10 = global [10 x i8] zeroinitializer, align 1
+; CHECK: @G10 = global { [10 x i8], [54 x i8] }
+
+@G31 = global [31 x i8] zeroinitializer, align 1
+@G32 = global [32 x i8] zeroinitializer, align 1
+@G33 = global [33 x i8] zeroinitializer, align 1
+; CHECK: @G31 = global { [31 x i8], [33 x i8] }
+; CHECK: @G32 = global { [32 x i8], [32 x i8] }
+; CHECK: @G33 = global { [33 x i8], [63 x i8] }
+
+@G63 = global [63 x i8] zeroinitializer, align 1
+@G64 = global [64 x i8] zeroinitializer, align 1
+@G65 = global [65 x i8] zeroinitializer, align 1
+; CHECK: @G63 = global { [63 x i8], [33 x i8] }
+; CHECK: @G64 = global { [64 x i8], [32 x i8] }
+; CHECK: @G65 = global { [65 x i8], [63 x i8] }
+
+@G127 = global [127 x i8] zeroinitializer, align 1
+@G128 = global [128 x i8] zeroinitializer, align 1
+@G129 = global [129 x i8] zeroinitializer, align 1
+; CHECK: @G127 = global { [127 x i8], [33 x i8] }
+; CHECK: @G128 = global { [128 x i8], [32 x i8] }
+; CHECK: @G129 = global { [129 x i8], [63 x i8] }
+
+@G255 = global [255 x i8] zeroinitializer, align 1
+@G256 = global [256 x i8] zeroinitializer, align 1
+@G257 = global [257 x i8] zeroinitializer, align 1
+; CHECK: @G255 = global { [255 x i8], [33 x i8] }
+; CHECK: @G256 = global { [256 x i8], [64 x i8] }
+; CHECK: @G257 = global { [257 x i8], [95 x i8] }
+
+@G511 = global [511 x i8] zeroinitializer, align 1
+@G512 = global [512 x i8] zeroinitializer, align 1
+@G513 = global [513 x i8] zeroinitializer, align 1
+; CHECK: @G511 = global { [511 x i8], [97 x i8] }
+; CHECK: @G512 = global { [512 x i8], [128 x i8] }
+; CHECK: @G513 = global { [513 x i8], [159 x i8] }
+
+@G1023 = global [1023 x i8] zeroinitializer, align 1
+@G1024 = global [1024 x i8] zeroinitializer, align 1
+@G1025 = global [1025 x i8] zeroinitializer, align 1
+; CHECK: @G1023 = global { [1023 x i8], [225 x i8] }
+; CHECK: @G1024 = global { [1024 x i8], [256 x i8] }
+; CHECK: @G1025 = global { [1025 x i8], [287 x i8] }
+
+@G1000000 = global [1000000 x i8] zeroinitializer, align 1
+@G10000000 = global [10000000 x i8] zeroinitializer, align 1
+@G100000000 = global [100000000 x i8] zeroinitializer, align 1
+; CHECK: @G1000000 = global { [1000000 x i8], [249984 x i8] }
+; CHECK: @G10000000 = global { [10000000 x i8], [262144 x i8] }
+; CHECK: @G100000000 = global { [100000000 x i8], [262144 x i8] }
diff --git a/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll b/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll
index c0fe15e9fcecb..da8f54137598e 100644
--- a/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll
+++ b/test/Instrumentation/AddressSanitizer/asan-vs-gvn.ll
@@ -11,9 +11,9 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
@f = global %struct_of_7_bytes_4_aligned zeroinitializer, align 4
-; Accessing bytes 4 and 6, not ok to widen to i32 if address_safety is set.
+; Accessing bytes 4 and 6, not ok to widen to i32 if sanitize_address is set.
-define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone address_safety {
+define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone sanitize_address {
entry:
%tmp = load i8* getelementptr inbounds (%struct_of_7_bytes_4_aligned* @f, i64 0, i32 1), align 4
%conv = zext i8 %tmp to i32
@@ -36,7 +36,7 @@ define void @end_test_widening_bad() {
;; Accessing bytes 4 and 5. Ok to widen to i16.
-define i32 @test_widening_ok(i8* %P) nounwind ssp noredzone address_safety {
+define i32 @test_widening_ok(i8* %P) nounwind ssp noredzone sanitize_address {
entry:
%tmp = load i8* getelementptr inbounds (%struct_of_7_bytes_4_aligned* @f, i64 0, i32 1), align 4
%conv = zext i8 %tmp to i32
diff --git a/test/Instrumentation/AddressSanitizer/basic.ll b/test/Instrumentation/AddressSanitizer/basic.ll
index 655f69c16fdf3..fb32e704af86c 100644
--- a/test/Instrumentation/AddressSanitizer/basic.ll
+++ b/test/Instrumentation/AddressSanitizer/basic.ll
@@ -5,12 +5,12 @@
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 @test_load(i32* %a) address_safety {
+define i32 @test_load(i32* %a) sanitize_address {
; CHECK: @test_load
; CHECK-NOT: load
; CHECK: %[[LOAD_ADDR:[^ ]*]] = ptrtoint i32* %a to i64
; CHECK: lshr i64 %[[LOAD_ADDR]], 3
-; CHECK: or i64
+; CHECK: {{or|add}}
; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr
; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8* %[[LOAD_SHADOW_PTR]]
; CHECK: icmp ne i8
@@ -38,12 +38,12 @@ entry:
ret i32 %tmp1
}
-define void @test_store(i32* %a) address_safety {
+define void @test_store(i32* %a) sanitize_address {
; CHECK: @test_store
; CHECK-NOT: store
; CHECK: %[[STORE_ADDR:[^ ]*]] = ptrtoint i32* %a to i64
; CHECK: lshr i64 %[[STORE_ADDR]], 3
-; CHECK: or i64
+; CHECK: {{or|add}}
; CHECK: %[[STORE_SHADOW_PTR:[^ ]*]] = inttoptr
; CHECK: %[[STORE_SHADOW:[^ ]*]] = load i8* %[[STORE_SHADOW_PTR]]
; CHECK: icmp ne i8
@@ -73,7 +73,7 @@ entry:
; Check that asan leaves just one alloca.
declare void @alloca_test_use([10 x i8]*)
-define void @alloca_test() address_safety {
+define void @alloca_test() sanitize_address {
entry:
%x = alloca [10 x i8], align 1
%y = alloca [10 x i8], align 1
@@ -89,3 +89,54 @@ entry:
; CHECK-NOT: = alloca
; CHECK: ret void
+define void @LongDoubleTest(x86_fp80* nocapture %a) nounwind uwtable sanitize_address {
+entry:
+ store x86_fp80 0xK3FFF8000000000000000, x86_fp80* %a, align 16
+ ret void
+}
+
+; CHECK: LongDoubleTest
+; CHECK: __asan_report_store_n
+; CHECK: __asan_report_store_n
+; CHECK: ret void
+
+
+define void @i40test(i40* %a, i40* %b) nounwind uwtable sanitize_address {
+ entry:
+ %t = load i40* %a
+ store i40 %t, i40* %b, align 8
+ ret void
+}
+
+; CHECK: i40test
+; CHECK: __asan_report_load_n{{.*}}, i64 5)
+; CHECK: __asan_report_load_n{{.*}}, i64 5)
+; CHECK: __asan_report_store_n{{.*}}, i64 5)
+; CHECK: __asan_report_store_n{{.*}}, i64 5)
+; CHECK: ret void
+
+define void @i80test(i80* %a, i80* %b) nounwind uwtable sanitize_address {
+ entry:
+ %t = load i80* %a
+ store i80 %t, i80* %b, align 8
+ ret void
+}
+
+; CHECK: i80test
+; CHECK: __asan_report_load_n{{.*}}, i64 10)
+; CHECK: __asan_report_load_n{{.*}}, i64 10)
+; CHECK: __asan_report_store_n{{.*}}, i64 10)
+; CHECK: __asan_report_store_n{{.*}}, i64 10)
+; CHECK: ret void
+
+; asan should not instrument functions with available_externally linkage.
+define available_externally i32 @f_available_externally(i32* %a) sanitize_address {
+entry:
+ %tmp1 = load i32* %a
+ ret i32 %tmp1
+}
+; CHECK: @f_available_externally
+; CHECK-NOT: __asan_report
+; CHECK: ret i32
+
+
diff --git a/test/Instrumentation/AddressSanitizer/debug_info.ll b/test/Instrumentation/AddressSanitizer/debug_info.ll
new file mode 100644
index 0000000000000..ec51caeb58687
--- /dev/null
+++ b/test/Instrumentation/AddressSanitizer/debug_info.ll
@@ -0,0 +1,61 @@
+; RUN: opt < %s -asan -asan-module -S | FileCheck %s
+
+; Checks that llvm.dbg.declare instructions are updated
+; accordingly as we merge allocas.
+
+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"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @_Z3zzzi(i32 %p) nounwind uwtable sanitize_address {
+entry:
+ %p.addr = alloca i32, align 4
+ %r = alloca i32, align 4
+ store i32 %p, i32* %p.addr, align 4
+ call void @llvm.dbg.declare(metadata !{i32* %p.addr}, metadata !10), !dbg !11
+ call void @llvm.dbg.declare(metadata !{i32* %r}, metadata !12), !dbg !14
+ %0 = load i32* %p.addr, align 4, !dbg !14
+ %add = add nsw i32 %0, 1, !dbg !14
+ store i32 %add, i32* %r, align 4, !dbg !14
+ %1 = load i32* %r, align 4, !dbg !15
+ ret i32 %1, !dbg !15
+}
+
+; CHECK: define i32 @_Z3zzzi
+; CHECK: entry:
+; Verify that llvm.dbg.declare calls are in the entry basic block.
+; CHECK-NOT: %entry
+; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ARG_ID:[0-9]+]])
+; CHECK-NOT: %entry
+; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[VAR_ID:[0-9]+]])
+
+declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone
+
+!llvm.dbg.cu = !{!0}
+
+!0 = metadata !{i32 786449, i32 0, i32 4, metadata !"a.cc", metadata !"/usr/local/google/llvm_cmake_clang/tmp/debuginfo", metadata !"clang version 3.3 (trunk 169314)", i1 true, i1 false, metadata !"", i32 0, metadata !1, metadata !1, metadata !3, metadata !1} ; [ DW_TAG_compile_unit ] [/usr/local/google/llvm_cmake_clang/tmp/debuginfo/a.cc] [DW_LANG_C_plus_plus]
+!1 = metadata !{metadata !2}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{metadata !5}
+!5 = metadata !{i32 786478, metadata !6, metadata !"zzz", metadata !"zzz", metadata !"_Z3zzzi", metadata !6, i32 1, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z3zzzi, null, null, metadata !1, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [zzz]
+!6 = metadata !{i32 786473, metadata !16} ; [ DW_TAG_file_type ]
+!7 = metadata !{i32 786453, i32 0, metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{metadata !9, metadata !9}
+!9 = metadata !{i32 786468, null, metadata !"int", null, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!10 = metadata !{i32 786689, metadata !5, metadata !"p", metadata !6, i32 16777217, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [p] [line 1]
+!11 = metadata !{i32 1, i32 0, metadata !5, null}
+!12 = metadata !{i32 786688, metadata !13, metadata !"r", metadata !6, i32 2, metadata !9, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [r] [line 2]
+
+; Verify that debug descriptors for argument and local variable will be replaced
+; with descriptors that end with OpDeref (encoded as 2).
+; CHECK: ![[ARG_ID]] = metadata {{.*}} i64 2} ; [ DW_TAG_arg_variable ] [p] [line 1]
+; CHECK: ![[VAR_ID]] = metadata {{.*}} i64 2} ; [ DW_TAG_auto_variable ] [r] [line 2]
+; Verify that there are no more variable descriptors.
+; CHECK-NOT: DW_TAG_arg_variable
+; CHECK-NOT: DW_TAG_auto_variable
+
+
+!13 = metadata !{i32 786443, metadata !5, i32 1, i32 0, metadata !6, i32 0} ; [ DW_TAG_lexical_block ] [/usr/local/google/llvm_cmake_clang/tmp/debuginfo/a.cc]
+!14 = metadata !{i32 2, i32 0, metadata !13, null}
+!15 = metadata !{i32 3, i32 0, metadata !13, null}
+!16 = metadata !{metadata !"a.cc", metadata !"/usr/local/google/llvm_cmake_clang/tmp/debuginfo"}
diff --git a/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll b/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll
new file mode 100644
index 0000000000000..b0371769be05a
--- /dev/null
+++ b/test/Instrumentation/AddressSanitizer/different_scale_and_offset.ll
@@ -0,0 +1,41 @@
+; Test non-default shadow mapping scale and offset.
+;
+; RUN: opt < %s -asan -asan-mapping-scale=2 -asan-mapping-offset-log=0 -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"
+
+; Test that ASan tells scale and offset to runtime.
+; CHECK: @__asan_mapping_offset = linkonce_odr constant i64 0
+; CHECK: @__asan_mapping_scale = linkonce_odr constant i64 2
+
+define i32 @test_load(i32* %a) sanitize_address {
+; CHECK: @test_load
+; CHECK-NOT: load
+; CHECK: %[[LOAD_ADDR:[^ ]*]] = ptrtoint i32* %a to i64
+; CHECK: lshr i64 %[[LOAD_ADDR]], 2
+
+; No need in shift for zero offset.
+; CHECK-NOT: or i64
+
+; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr
+; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8* %[[LOAD_SHADOW_PTR]]
+; CHECK: icmp ne i8
+; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+
+; No need in slow path for i32 and mapping scale equal to 2.
+; CHECK-NOT: and i64 %[[LOAD_ADDR]]
+;
+; The crash block reports the error.
+; CHECK: call void @__asan_report_load4(i64 %[[LOAD_ADDR]])
+; CHECK: unreachable
+;
+; The actual load.
+; CHECK: %tmp1 = load i32* %a
+; CHECK: ret i32 %tmp1
+
+entry:
+ %tmp1 = load i32* %a
+ ret i32 %tmp1
+}
+
diff --git a/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll b/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll
index 28d4ac0c0f589..0928c494154ef 100644
--- a/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll
+++ b/test/Instrumentation/AddressSanitizer/do-not-instrument-internal-globals.ll
@@ -5,7 +5,7 @@
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"
target triple = "x86_64-unknown-linux-gnu"
-define void @_Z3barv() uwtable address_safety {
+define void @_Z3barv() uwtable sanitize_address {
entry:
%a = alloca i32, align 4
call void @_Z3fooPi(i32* %a)
@@ -14,6 +14,7 @@ entry:
declare void @_Z3fooPi(i32*)
; We create one global string constant for the stack frame above.
+; It should have unnamed_addr and align 1.
; Make sure we don't create any other global constants.
-; CHECK: = private constant
-; CHECK-NOT: = private constant
+; CHECK: = private unnamed_addr constant{{.*}}align 1
+; CHECK-NOT: = private unnamed_addr constant
diff --git a/test/Instrumentation/AddressSanitizer/instrument-no-return.ll b/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
index 80f1b1c74cd11..2d835a34080a1 100644
--- a/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
+++ b/test/Instrumentation/AddressSanitizer/instrument-no-return.ll
@@ -1,17 +1,49 @@
; RUN: opt < %s -asan -S | FileCheck %s
; AddressSanitizer must insert __asan_handle_no_return
-; before every noreturn call.
+; before every noreturn call or invoke.
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"
declare void @MyNoReturnFunc(i32) noreturn
-define i32 @_Z5ChildPv(i8* nocapture %arg) uwtable address_safety {
+define i32 @Call1(i8* nocapture %arg) uwtable sanitize_address {
entry:
- call void @MyNoReturnFunc(i32 1) noreturn
+ call void @MyNoReturnFunc(i32 1) noreturn ; The call insn has noreturn attr.
+; CHECK: @Call1
+; CHECK: call void @__asan_handle_no_return
+; CHECK-NEXT: call void @MyNoReturnFunc
+; CHECK-NEXT: unreachable
unreachable
}
+define i32 @Call2(i8* nocapture %arg) uwtable sanitize_address {
+entry:
+ call void @MyNoReturnFunc(i32 1) ; No noreturn attribure on the call.
+; CHECK: @Call2
; CHECK: call void @__asan_handle_no_return
; CHECK-NEXT: call void @MyNoReturnFunc
+; CHECK-NEXT: unreachable
+ unreachable
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+define i64 @Invoke1(i8** %esc) nounwind uwtable ssp sanitize_address {
+entry:
+ invoke void @MyNoReturnFunc(i32 1)
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+ ret i64 0
+
+lpad:
+ %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ filter [0 x i8*] zeroinitializer
+ ret i64 1
+}
+; CHECK: @Invoke1
+; CHECK: call void @__asan_handle_no_return
+; CHECK-NEXT: invoke void @MyNoReturnFunc
+; CHECK: ret i64 0
+; CHECK: ret i64 1
diff --git a/test/Instrumentation/AddressSanitizer/instrument_global.ll b/test/Instrumentation/AddressSanitizer/instrument_global.ll
index 3d92946087ecf..2c183f523feb2 100644
--- a/test/Instrumentation/AddressSanitizer/instrument_global.ll
+++ b/test/Instrumentation/AddressSanitizer/instrument_global.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -asan -S | FileCheck %s
+; RUN: opt < %s -asan -asan-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"
@xxx = global i32 0, align 4
diff --git a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
index 472551654e539..1d00cfacafe4a 100644
--- a/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
+++ b/test/Instrumentation/AddressSanitizer/instrument_initializer_metadata.ll
@@ -1,11 +1,15 @@
-; RUN: opt < %s -asan -asan-initialization-order -S | FileCheck %s
+; RUN: opt < %s -asan -asan-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"
-@xxx = global i32 0, align 4
+@xxx = internal global i32 0, align 4 ; With dynamic initializer.
+@XXX = global i32 0, align 4 ; With dynamic initializer.
+@yyy = internal global i32 0, align 4 ; W/o dynamic initializer.
+@YYY = global i32 0, align 4 ; W/o dynamic initializer.
; Clang will emit the following metadata identifying @xxx as dynamically
; initialized.
!0 = metadata !{i32* @xxx}
-!llvm.asan.dynamically_initialized_globals = !{!0}
+!1 = metadata !{i32* @XXX}
+!llvm.asan.dynamically_initialized_globals = !{!0, !1}
define i32 @initializer() uwtable {
entry:
@@ -19,7 +23,7 @@ entry:
ret void
}
-define internal void @_GLOBAL__I_a() address_safety section ".text.startup" {
+define internal void @_GLOBAL__I_a() sanitize_address section ".text.startup" {
entry:
call void @__cxx_global_var_init()
ret void
@@ -34,3 +38,40 @@ entry:
; CHECK: call void @__cxx_global_var_init
; CHECK: call void @__asan_after_dynamic_init
; CHECK: ret
+
+; Check that xxx is instrumented.
+define void @touch_xxx() sanitize_address {
+ store i32 0, i32 *@xxx, align 4
+ ret void
+; CHECK: define void @touch_xxx
+; CHECK: call void @__asan_report_store4
+; CHECK: ret void
+}
+
+; Check that XXX is instrumented.
+define void @touch_XXX() sanitize_address {
+ store i32 0, i32 *@XXX, align 4
+ ret void
+; CHECK: define void @touch_XXX
+; CHECK: call void @__asan_report_store4
+; CHECK: ret void
+}
+
+
+; Check that yyy is NOT instrumented (as it does not have dynamic initializer).
+define void @touch_yyy() sanitize_address {
+ store i32 0, i32 *@yyy, align 4
+ ret void
+; CHECK: define void @touch_yyy
+; CHECK-NOT: call void @__asan_report_store4
+; CHECK: ret void
+}
+
+; Check that YYY is NOT instrumented (as it does not have dynamic initializer).
+define void @touch_YYY() sanitize_address {
+ store i32 0, i32 *@YYY, align 4
+ ret void
+; CHECK: define void @touch_YYY
+; CHECK-NOT: call void @__asan_report_store4
+; CHECK: ret void
+}
diff --git a/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll b/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll
index 633bf9ae78c02..23cf6d28ec6cd 100644
--- a/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll
+++ b/test/Instrumentation/AddressSanitizer/instrument_load_then_store.ll
@@ -4,7 +4,7 @@
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 void @IncrementMe(i32* %a) address_safety {
+define void @IncrementMe(i32* %a) sanitize_address {
entry:
%tmp1 = load i32* %a, align 4
%tmp2 = add i32 %tmp1, 1
diff --git a/test/Instrumentation/AddressSanitizer/lifetime.ll b/test/Instrumentation/AddressSanitizer/lifetime.ll
new file mode 100644
index 0000000000000..334872865f1a0
--- /dev/null
+++ b/test/Instrumentation/AddressSanitizer/lifetime.ll
@@ -0,0 +1,84 @@
+; Test hanlding of llvm.lifetime intrinsics.
+; RUN: opt < %s -asan -asan-check-lifetime -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-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind
+
+define void @lifetime_no_size() sanitize_address {
+entry:
+ %i = alloca i32, align 4
+ %i.ptr = bitcast i32* %i to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %i.ptr)
+ call void @llvm.lifetime.end(i64 -1, i8* %i.ptr)
+
+; Check that lifetime with no size are ignored.
+; CHECK: @lifetime_no_size
+; CHECK-NOT: @__asan_poison_stack_memory
+; CHECK-NOT: @__asan_unpoison_stack_memory
+; CHECK: ret void
+ ret void
+}
+
+; Generic case of lifetime analysis.
+define void @lifetime() sanitize_address {
+ ; CHECK: @lifetime
+
+ ; Regular variable lifetime intrinsics.
+ %i = alloca i32, align 4
+ %i.ptr = bitcast i32* %i to i8*
+ call void @llvm.lifetime.start(i64 3, i8* %i.ptr)
+ ; Memory is unpoisoned at llvm.lifetime.start
+ ; CHECK: %[[VAR:[^ ]*]] = ptrtoint i32* %{{[^ ]+}} to i64
+ ; CHECK-NEXT: call void @__asan_unpoison_stack_memory(i64 %[[VAR]], i64 3)
+ call void @llvm.lifetime.end(i64 4, i8* %i.ptr)
+ call void @llvm.lifetime.end(i64 2, i8* %i.ptr)
+ ; Memory is poisoned at every call to llvm.lifetime.end
+ ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4)
+ ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 2)
+
+ ; Lifetime intrinsics for array.
+ %arr = alloca [10 x i32], align 16
+ %arr.ptr = bitcast [10 x i32]* %arr to i8*
+ call void @llvm.lifetime.start(i64 40, i8* %arr.ptr)
+ ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 40)
+ call void @llvm.lifetime.end(i64 40, i8* %arr.ptr)
+ ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 40)
+
+ ; One more lifetime start/end for the same variable %i.
+ call void @llvm.lifetime.start(i64 4, i8* %i.ptr)
+ ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 4)
+ call void @llvm.lifetime.end(i64 4, i8* %i.ptr)
+ ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4)
+
+ ; Memory is unpoisoned at function exit (only once).
+ ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 {{.*}})
+ ; CHECK-NOT: @__asan_unpoison_stack_memory
+ ; CHECK: ret void
+ ret void
+}
+
+; Check that arguments of lifetime may come from phi nodes.
+define void @phi_args(i1 %x) sanitize_address {
+ ; CHECK: @phi_args
+
+entry:
+ %i = alloca i64, align 4
+ %i.ptr = bitcast i64* %i to i8*
+ call void @llvm.lifetime.start(i64 8, i8* %i.ptr)
+ ; CHECK: __asan_unpoison_stack_memory
+ br i1 %x, label %bb0, label %bb1
+
+bb0:
+ %i.ptr2 = bitcast i64* %i to i8*
+ br label %bb1
+
+bb1:
+ %i.phi = phi i8* [ %i.ptr, %entry ], [ %i.ptr2, %bb0 ]
+ call void @llvm.lifetime.end(i64 8, i8* %i.phi)
+ ; CHECK: __asan_poison_stack_memory
+ ; CHECK: ret void
+ ret void
+}
diff --git a/test/Instrumentation/AddressSanitizer/test64.ll b/test/Instrumentation/AddressSanitizer/test64.ll
index d544d77b93db9..6aa5c28850994 100644
--- a/test/Instrumentation/AddressSanitizer/test64.ll
+++ b/test/Instrumentation/AddressSanitizer/test64.ll
@@ -1,7 +1,7 @@
; RUN: opt < %s -asan -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) address_safety {
+define i32 @read_4_bytes(i32* %a) sanitize_address {
entry:
%tmp1 = load i32* %a, align 4
ret i32 %tmp1
@@ -9,11 +9,11 @@ entry:
; CHECK: @read_4_bytes
; CHECK-NOT: ret
; CHECK: lshr {{.*}} 3
-; Check for ASAN's Offset for 64-bit (2^44)
-; CHECK-NEXT: 17592186044416
+; Check for ASAN's Offset for 64-bit (2^44 or 7fff8000)
+; CHECK-NEXT: {{17592186044416|2147450880}}
; CHECK: ret
-define void @example_atomicrmw(i64* %ptr) nounwind uwtable address_safety {
+define void @example_atomicrmw(i64* %ptr) nounwind uwtable sanitize_address {
entry:
%0 = atomicrmw add i64* %ptr, i64 1 seq_cst
ret void
@@ -24,7 +24,7 @@ entry:
; CHECK: atomicrmw
; CHECK: ret
-define void @example_cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) nounwind uwtable address_safety {
+define void @example_cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) nounwind uwtable sanitize_address {
entry:
%0 = cmpxchg i64* %ptr, i64 %compare_to, i64 %new_value seq_cst
ret void
diff --git a/test/Instrumentation/MemorySanitizer/lit.local.cfg b/test/Instrumentation/MemorySanitizer/lit.local.cfg
new file mode 100644
index 0000000000000..19eebc0ac7ac3
--- /dev/null
+++ b/test/Instrumentation/MemorySanitizer/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.ll', '.c', '.cpp']
diff --git a/test/Instrumentation/MemorySanitizer/msan_basic.ll b/test/Instrumentation/MemorySanitizer/msan_basic.ll
new file mode 100644
index 0000000000000..1e7a31793deae
--- /dev/null
+++ b/test/Instrumentation/MemorySanitizer/msan_basic.ll
@@ -0,0 +1,625 @@
+; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck %s
+; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck -check-prefix=CHECK-ORIGINS %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-S128"
+
+; Check the presence of __msan_init
+; CHECK: @llvm.global_ctors {{.*}} @__msan_init
+
+; Check the presence and the linkage type of __msan_track_origins
+; CHECK: @__msan_track_origins = weak_odr constant i32 0
+
+
+; Check instrumentation of stores
+
+define void @Store(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i32 %x, i32* %p, align 4
+ ret void
+}
+
+; CHECK: @Store
+; CHECK: load {{.*}} @__msan_param_tls
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+; CHECK-ORIGINS: @Store
+; CHECK-ORIGINS: load {{.*}} @__msan_param_tls
+; CHECK-ORIGINS: store
+; CHECK-ORIGINS: icmp
+; CHECK-ORIGINS: br i1
+; CHECK-ORIGINS: <label>
+; CHECK-ORIGINS: store
+; CHECK-ORIGINS: br label
+; CHECK-ORIGINS: <label>
+; CHECK-ORIGINS: store
+; CHECK-ORIGINS: ret void
+
+
+; Check instrumentation of aligned stores
+; Shadow store has the same alignment as the original store; origin store
+; does not specify explicit alignment.
+
+define void @AlignedStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
+entry:
+ store i32 %x, i32* %p, align 32
+ ret void
+}
+
+; CHECK: @AlignedStore
+; CHECK: load {{.*}} @__msan_param_tls
+; CHECK: store {{.*}} align 32
+; CHECK: store {{.*}} align 32
+; CHECK: ret void
+; CHECK-ORIGINS: @AlignedStore
+; CHECK-ORIGINS: load {{.*}} @__msan_param_tls
+; CHECK-ORIGINS: store {{.*}} align 32
+; CHECK-ORIGINS: icmp
+; CHECK-ORIGINS: br i1
+; CHECK-ORIGINS: <label>
+; CHECK-ORIGINS: store {{.*}} align 32
+; CHECK-ORIGINS: br label
+; CHECK-ORIGINS: <label>
+; CHECK-ORIGINS: store {{.*}} align 32
+; CHECK-ORIGINS: ret void
+
+
+; load followed by cmp: check that we load the shadow and call __msan_warning.
+define void @LoadAndCmp(i32* nocapture %a) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i32* %a, align 4
+ %tobool = icmp eq i32 %0, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then: ; preds = %entry
+ tail call void (...)* @foo() nounwind
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ ret void
+}
+
+declare void @foo(...)
+
+; CHECK: @LoadAndCmp
+; CHECK: = load
+; CHECK: = load
+; CHECK: call void @__msan_warning_noreturn()
+; CHECK-NEXT: call void asm sideeffect
+; CHECK-NEXT: unreachable
+; CHECK: ret void
+
+; Check that we store the shadow for the retval.
+define i32 @ReturnInt() nounwind uwtable readnone sanitize_memory {
+entry:
+ ret i32 123
+}
+
+; CHECK: @ReturnInt
+; CHECK: store i32 0,{{.*}}__msan_retval_tls
+; CHECK: ret i32
+
+; Check that we get the shadow for the retval.
+define void @CopyRetVal(i32* nocapture %a) nounwind uwtable sanitize_memory {
+entry:
+ %call = tail call i32 @ReturnInt() nounwind
+ store i32 %call, i32* %a, align 4
+ ret void
+}
+
+; CHECK: @CopyRetVal
+; CHECK: load{{.*}}__msan_retval_tls
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+
+
+; Check that we generate PHIs for shadow.
+define void @FuncWithPhi(i32* nocapture %a, i32* %b, i32* nocapture %c) nounwind uwtable sanitize_memory {
+entry:
+ %tobool = icmp eq i32* %b, null
+ br i1 %tobool, label %if.else, label %if.then
+
+ if.then: ; preds = %entry
+ %0 = load i32* %b, align 4
+ br label %if.end
+
+ if.else: ; preds = %entry
+ %1 = load i32* %c, align 4
+ br label %if.end
+
+ if.end: ; preds = %if.else, %if.then
+ %t.0 = phi i32 [ %0, %if.then ], [ %1, %if.else ]
+ store i32 %t.0, i32* %a, align 4
+ ret void
+}
+
+; CHECK: @FuncWithPhi
+; CHECK: = phi
+; CHECK-NEXT: = phi
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+
+; Compute shadow for "x << 10"
+define void @ShlConst(i32* nocapture %x) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i32* %x, align 4
+ %1 = shl i32 %0, 10
+ store i32 %1, i32* %x, align 4
+ ret void
+}
+
+; CHECK: @ShlConst
+; CHECK: = load
+; CHECK: = load
+; CHECK: shl
+; CHECK: shl
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+
+; Compute shadow for "10 << x": it should have 'sext i1'.
+define void @ShlNonConst(i32* nocapture %x) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i32* %x, align 4
+ %1 = shl i32 10, %0
+ store i32 %1, i32* %x, align 4
+ ret void
+}
+
+; CHECK: @ShlNonConst
+; CHECK: = load
+; CHECK: = load
+; CHECK: = sext i1
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+
+; SExt
+define void @SExt(i32* nocapture %a, i16* nocapture %b) nounwind uwtable sanitize_memory {
+entry:
+ %0 = load i16* %b, align 2
+ %1 = sext i16 %0 to i32
+ store i32 %1, i32* %a, align 4
+ ret void
+}
+
+; CHECK: @SExt
+; CHECK: = load
+; CHECK: = load
+; CHECK: = sext
+; CHECK: = sext
+; CHECK: store
+; CHECK: store
+; CHECK: ret void
+
+
+; memset
+define void @MemSet(i8* nocapture %x) nounwind uwtable sanitize_memory {
+entry:
+ call void @llvm.memset.p0i8.i64(i8* %x, i8 42, i64 10, i32 1, i1 false)
+ ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: @MemSet
+; CHECK: call i8* @__msan_memset
+; CHECK: ret void
+
+
+; memcpy
+define void @MemCpy(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory {
+entry:
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false)
+ ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
+
+; CHECK: @MemCpy
+; CHECK: call i8* @__msan_memcpy
+; CHECK: ret void
+
+
+; memmove is lowered to a call
+define void @MemMove(i8* nocapture %x, i8* nocapture %y) nounwind uwtable sanitize_memory {
+entry:
+ call void @llvm.memmove.p0i8.p0i8.i64(i8* %x, i8* %y, i64 10, i32 1, i1 false)
+ ret void
+}
+
+declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
+
+; CHECK: @MemMove
+; CHECK: call i8* @__msan_memmove
+; CHECK: ret void
+
+
+; Check that we propagate shadow for "select"
+
+define i32 @Select(i32 %a, i32 %b, i32 %c) nounwind uwtable readnone sanitize_memory {
+entry:
+ %tobool = icmp ne i32 %c, 0
+ %cond = select i1 %tobool, i32 %a, i32 %b
+ ret i32 %cond
+}
+
+; CHECK: @Select
+; CHECK: select
+; CHECK-NEXT: select
+; CHECK: ret i32
+
+
+; Check that we propagate origin for "select" with vector condition.
+; Select condition is flattened to i1, which is then used to select one of the
+; argument origins.
+
+define <8 x i16> @SelectVector(<8 x i16> %a, <8 x i16> %b, <8 x i1> %c) nounwind uwtable readnone sanitize_memory {
+entry:
+ %cond = select <8 x i1> %c, <8 x i16> %a, <8 x i16> %b
+ ret <8 x i16> %cond
+}
+
+; CHECK-ORIGINS: @SelectVector
+; CHECK-ORIGINS: bitcast <8 x i1> {{.*}} to i8
+; CHECK-ORIGINS: icmp ne i8
+; CHECK-ORIGINS: select i1
+; CHECK-ORIGINS: ret <8 x i16>
+
+
+define i8* @IntToPtr(i64 %x) nounwind uwtable readnone sanitize_memory {
+entry:
+ %0 = inttoptr i64 %x to i8*
+ ret i8* %0
+}
+
+; CHECK: @IntToPtr
+; CHECK: load i64*{{.*}}__msan_param_tls
+; CHECK-NEXT: inttoptr
+; CHECK-NEXT: store i64{{.*}}__msan_retval_tls
+; CHECK: ret i8
+
+
+define i8* @IntToPtr_ZExt(i16 %x) nounwind uwtable readnone sanitize_memory {
+entry:
+ %0 = inttoptr i16 %x to i8*
+ ret i8* %0
+}
+
+; CHECK: @IntToPtr_ZExt
+; CHECK: zext
+; CHECK-NEXT: inttoptr
+; CHECK: ret i8
+
+
+; Check that we insert exactly one check on udiv
+; (2nd arg shadow is checked, 1st arg shadow is propagated)
+
+define i32 @Div(i32 %a, i32 %b) nounwind uwtable readnone sanitize_memory {
+entry:
+ %div = udiv i32 %a, %b
+ ret i32 %div
+}
+
+; CHECK: @Div
+; CHECK: icmp
+; CHECK: call void @__msan_warning
+; CHECK-NOT: icmp
+; CHECK: udiv
+; CHECK-NOT: icmp
+; CHECK: ret i32
+
+
+; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
+
+define zeroext i1 @ICmpSLT(i32 %x) nounwind uwtable readnone sanitize_memory {
+ %1 = icmp slt i32 %x, 0
+ ret i1 %1
+}
+
+; CHECK: @ICmpSLT
+; CHECK: icmp slt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp slt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i1
+
+define zeroext i1 @ICmpSGE(i32 %x) nounwind uwtable readnone sanitize_memory {
+ %1 = icmp sge i32 %x, 0
+ ret i1 %1
+}
+
+; CHECK: @ICmpSGE
+; CHECK: icmp slt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp sge
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i1
+
+define zeroext i1 @ICmpSGT(i32 %x) nounwind uwtable readnone sanitize_memory {
+ %1 = icmp sgt i32 0, %x
+ ret i1 %1
+}
+
+; CHECK: @ICmpSGT
+; CHECK: icmp slt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp sgt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i1
+
+define zeroext i1 @ICmpSLE(i32 %x) nounwind uwtable readnone sanitize_memory {
+ %1 = icmp sle i32 0, %x
+ ret i1 %1
+}
+
+; CHECK: @ICmpSLE
+; CHECK: icmp slt
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp sle
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i1
+
+
+; Check that we propagate shadow for x<0, x>=0, etc (i.e. sign bit tests)
+; of the vector arguments.
+
+define <2 x i1> @ICmpSLT_vector(<2 x i32*> %x) nounwind uwtable readnone sanitize_memory {
+ %1 = icmp slt <2 x i32*> %x, zeroinitializer
+ ret <2 x i1> %1
+}
+
+; CHECK: @ICmpSLT_vector
+; CHECK: icmp slt <2 x i64>
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp slt <2 x i32*>
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret <2 x i1>
+
+
+; Check that we propagate shadow for unsigned relational comparisons with
+; constants
+
+define zeroext i1 @ICmpUGTConst(i32 %x) nounwind uwtable readnone sanitize_memory {
+entry:
+ %cmp = icmp ugt i32 %x, 7
+ ret i1 %cmp
+}
+
+; CHECK: @ICmpUGTConst
+; CHECK: icmp ugt i32
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp ugt i32
+; CHECK-NOT: call void @__msan_warning
+; CHECK: icmp ugt i32
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i1
+
+
+; Check that loads of shadow have the same aligment as the original loads.
+; Check that loads of origin have the aligment of max(4, original alignment).
+
+define i32 @ShadowLoadAlignmentLarge() nounwind uwtable sanitize_memory {
+ %y = alloca i32, align 64
+ %1 = load volatile i32* %y, align 64
+ ret i32 %1
+}
+
+; CHECK: @ShadowLoadAlignmentLarge
+; CHECK: load i32* {{.*}} align 64
+; CHECK: load volatile i32* {{.*}} align 64
+; CHECK: ret i32
+
+define i32 @ShadowLoadAlignmentSmall() nounwind uwtable sanitize_memory {
+ %y = alloca i32, align 2
+ %1 = load volatile i32* %y, align 2
+ ret i32 %1
+}
+
+; CHECK: @ShadowLoadAlignmentSmall
+; CHECK: load i32* {{.*}} align 2
+; CHECK: load volatile i32* {{.*}} align 2
+; CHECK: ret i32
+
+; CHECK-ORIGINS: @ShadowLoadAlignmentSmall
+; CHECK-ORIGINS: load i32* {{.*}} align 2
+; CHECK-ORIGINS: load i32* {{.*}} align 4
+; CHECK-ORIGINS: load volatile i32* {{.*}} align 2
+; CHECK-ORIGINS: ret i32
+
+
+; Test vector manipulation instructions.
+; Check that the same bit manipulation is applied to the shadow values.
+; Check that there is a zero test of the shadow of %idx argument, where present.
+
+define i32 @ExtractElement(<4 x i32> %vec, i32 %idx) sanitize_memory {
+ %x = extractelement <4 x i32> %vec, i32 %idx
+ ret i32 %x
+}
+
+; CHECK: @ExtractElement
+; CHECK: extractelement
+; CHECK: call void @__msan_warning
+; CHECK: extractelement
+; CHECK: ret i32
+
+define <4 x i32> @InsertElement(<4 x i32> %vec, i32 %idx, i32 %x) sanitize_memory {
+ %vec1 = insertelement <4 x i32> %vec, i32 %x, i32 %idx
+ ret <4 x i32> %vec1
+}
+
+; CHECK: @InsertElement
+; CHECK: insertelement
+; CHECK: call void @__msan_warning
+; CHECK: insertelement
+; CHECK: ret <4 x i32>
+
+define <4 x i32> @ShuffleVector(<4 x i32> %vec, <4 x i32> %vec1) sanitize_memory {
+ %vec2 = shufflevector <4 x i32> %vec, <4 x i32> %vec1,
+ <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+ ret <4 x i32> %vec2
+}
+
+; CHECK: @ShuffleVector
+; CHECK: shufflevector
+; CHECK-NOT: call void @__msan_warning
+; CHECK: shufflevector
+; CHECK: ret <4 x i32>
+
+
+; Test bswap intrinsic instrumentation
+define i32 @BSwap(i32 %x) nounwind uwtable readnone sanitize_memory {
+ %y = tail call i32 @llvm.bswap.i32(i32 %x)
+ ret i32 %y
+}
+
+declare i32 @llvm.bswap.i32(i32) nounwind readnone
+
+; CHECK: @BSwap
+; CHECK-NOT: call void @__msan_warning
+; CHECK: @llvm.bswap.i32
+; CHECK-NOT: call void @__msan_warning
+; CHECK: @llvm.bswap.i32
+; CHECK-NOT: call void @__msan_warning
+; CHECK: ret i32
+
+
+; Store intrinsic.
+
+define void @StoreIntrinsic(i8* %p, <4 x float> %x) nounwind uwtable sanitize_memory {
+ call void @llvm.x86.sse.storeu.ps(i8* %p, <4 x float> %x)
+ ret void
+}
+
+declare void @llvm.x86.sse.storeu.ps(i8*, <4 x float>) nounwind
+
+; CHECK: @StoreIntrinsic
+; CHECK-NOT: br
+; CHECK-NOT: = or
+; CHECK: store <4 x i32> {{.*}} align 1
+; CHECK: call void @llvm.x86.sse.storeu.ps
+; CHECK: ret void
+
+
+; Load intrinsic.
+
+define <16 x i8> @LoadIntrinsic(i8* %p) nounwind uwtable sanitize_memory {
+ %call = call <16 x i8> @llvm.x86.sse3.ldu.dq(i8* %p)
+ ret <16 x i8> %call
+}
+
+declare <16 x i8> @llvm.x86.sse3.ldu.dq(i8* %p) nounwind
+
+; CHECK: @LoadIntrinsic
+; CHECK: load <16 x i8>* {{.*}} align 1
+; CHECK-NOT: br
+; CHECK-NOT: = or
+; CHECK: call <16 x i8> @llvm.x86.sse3.ldu.dq
+; CHECK: store <16 x i8> {{.*}} @__msan_retval_tls
+; CHECK: ret <16 x i8>
+
+; CHECK-ORIGINS: @LoadIntrinsic
+; CHECK-ORIGINS: [[ORIGIN:%[01-9a-z]+]] = load i32* {{.*}}
+; CHECK-ORIGINS: call <16 x i8> @llvm.x86.sse3.ldu.dq
+; CHECK-ORIGINS: store i32 {{.*}}[[ORIGIN]], i32* @__msan_retval_origin_tls
+; CHECK-ORIGINS: ret <16 x i8>
+
+
+; Simple NoMem intrinsic
+; Check that shadow is OR'ed, and origin is Select'ed
+; And no shadow checks!
+
+define <8 x i16> @Paddsw128(<8 x i16> %a, <8 x i16> %b) nounwind uwtable sanitize_memory {
+ %call = call <8 x i16> @llvm.x86.sse2.padds.w(<8 x i16> %a, <8 x i16> %b)
+ ret <8 x i16> %call
+}
+
+declare <8 x i16> @llvm.x86.sse2.padds.w(<8 x i16> %a, <8 x i16> %b) nounwind
+
+; CHECK: @Paddsw128
+; CHECK-NEXT: load <8 x i16>* {{.*}} @__msan_param_tls
+; CHECK-NEXT: load <8 x i16>* {{.*}} @__msan_param_tls
+; CHECK-NEXT: = or <8 x i16>
+; CHECK-NEXT: call <8 x i16> @llvm.x86.sse2.padds.w
+; CHECK-NEXT: store <8 x i16> {{.*}} @__msan_retval_tls
+; CHECK-NEXT: ret <8 x i16>
+
+; CHECK-ORIGINS: @Paddsw128
+; CHECK-ORIGINS: load i32* {{.*}} @__msan_param_origin_tls
+; CHECK-ORIGINS: load i32* {{.*}} @__msan_param_origin_tls
+; CHECK-ORIGINS: = bitcast <8 x i16> {{.*}} to i128
+; CHECK-ORIGINS-NEXT: = icmp ne i128 {{.*}}, 0
+; CHECK-ORIGINS-NEXT: = select i1 {{.*}}, i32 {{.*}}, i32
+; CHECK-ORIGINS: call <8 x i16> @llvm.x86.sse2.padds.w
+; CHECK-ORIGINS: store i32 {{.*}} @__msan_retval_origin_tls
+; CHECK-ORIGINS: ret <8 x i16>
+
+
+; Test handling of vectors of pointers.
+; Check that shadow of such vector is a vector of integers.
+
+define <8 x i8*> @VectorOfPointers(<8 x i8*>* %p) nounwind uwtable sanitize_memory {
+ %x = load <8 x i8*>* %p
+ ret <8 x i8*> %x
+}
+
+; CHECK: @VectorOfPointers
+; CHECK: load <8 x i64>*
+; CHECK: load <8 x i8*>*
+; CHECK: store <8 x i64> {{.*}} @__msan_retval_tls
+; CHECK: ret <8 x i8*>
+
+; Test handling of va_copy.
+
+declare void @llvm.va_copy(i8*, i8*) nounwind
+
+define void @VACopy(i8* %p1, i8* %p2) nounwind uwtable sanitize_memory {
+ call void @llvm.va_copy(i8* %p1, i8* %p2) nounwind
+ ret void
+}
+
+; CHECK: @VACopy
+; CHECK: call void @llvm.memset.p0i8.i64({{.*}}, i8 0, i64 24, i32 8, i1 false)
+; CHECK: ret void
+
+
+; Test handling of volatile stores.
+; Check that MemorySanitizer does not add a check of the value being stored.
+
+define void @VolatileStore(i32* nocapture %p, i32 %x) nounwind uwtable sanitize_memory {
+entry:
+ store volatile i32 %x, i32* %p, align 4
+ ret void
+}
+
+; CHECK: @VolatileStore
+; CHECK-NOT: @__msan_warning
+; CHECK: ret void
+
+
+; Test that checks are omitted but shadow propagation is kept if
+; sanitize_memory attribute is missing.
+
+define i32 @NoSanitizeMemory(i32 %x) uwtable {
+entry:
+ %tobool = icmp eq i32 %x, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then: ; preds = %entry
+ tail call void @bar()
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ ret i32 %x
+}
+
+declare void @bar()
+
+; CHECK: @NoSanitizeMemory
+; CHECK-NOT: @__msan_warning
+; CHECK: load i32* {{.*}} @__msan_param_tls
+; CHECK-NOT: @__msan_warning
+; CHECK: store {{.*}} @__msan_retval_tls
+; CHECK-NOT: @__msan_warning
+; CHECK: ret i32
diff --git a/test/Instrumentation/MemorySanitizer/unreachable.ll b/test/Instrumentation/MemorySanitizer/unreachable.ll
new file mode 100644
index 0000000000000..c8130717c7daa
--- /dev/null
+++ b/test/Instrumentation/MemorySanitizer/unreachable.ll
@@ -0,0 +1,39 @@
+; RUN: opt < %s -msan -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-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+; Test that MemorySanitizer correctly handles unreachable blocks.
+
+define i32 @Func(i32* %p) nounwind uwtable {
+entry:
+ br label %exit
+
+unreachable:
+ %x = load i32* %p
+ br label %exit
+
+exit:
+ %z = phi i32 [ 42, %entry ], [ %x, %unreachable ]
+ ret i32 %z
+}
+
+; CHECK: @Func
+; CHECK: store i32 0, {{.*}} @__msan_retval_tls
+; CHECK: ret i32 42
+
+
+define i32 @UnreachableLoop() nounwind uwtable {
+entry:
+ ret i32 0
+
+zzz:
+ br label %xxx
+
+xxx:
+ br label %zzz
+}
+
+; CHECK: @UnreachableLoop
+; CHECK: store i32 0, {{.*}} @__msan_retval_tls
+; CHECK: ret i32 0
diff --git a/test/Instrumentation/ThreadSanitizer/atomic.ll b/test/Instrumentation/ThreadSanitizer/atomic.ll
index 107dbdc0f227b..70b6cbbf31050 100644
--- a/test/Instrumentation/ThreadSanitizer/atomic.ll
+++ b/test/Instrumentation/ThreadSanitizer/atomic.ll
@@ -114,6 +114,14 @@ entry:
; CHECK: atomic8_xor_monotonic
; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 0)
+define void @atomic8_nand_monotonic(i8* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i8* %a, i8 0 monotonic
+ ret void
+}
+; CHECK: atomic8_nand_monotonic
+; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 0)
+
define void @atomic8_xchg_acquire(i8* %a) nounwind uwtable {
entry:
atomicrmw xchg i8* %a, i8 0 acquire
@@ -162,6 +170,14 @@ entry:
; CHECK: atomic8_xor_acquire
; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 2)
+define void @atomic8_nand_acquire(i8* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i8* %a, i8 0 acquire
+ ret void
+}
+; CHECK: atomic8_nand_acquire
+; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 2)
+
define void @atomic8_xchg_release(i8* %a) nounwind uwtable {
entry:
atomicrmw xchg i8* %a, i8 0 release
@@ -210,6 +226,14 @@ entry:
; CHECK: atomic8_xor_release
; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 3)
+define void @atomic8_nand_release(i8* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i8* %a, i8 0 release
+ ret void
+}
+; CHECK: atomic8_nand_release
+; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 3)
+
define void @atomic8_xchg_acq_rel(i8* %a) nounwind uwtable {
entry:
atomicrmw xchg i8* %a, i8 0 acq_rel
@@ -258,6 +282,14 @@ entry:
; CHECK: atomic8_xor_acq_rel
; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 4)
+define void @atomic8_nand_acq_rel(i8* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i8* %a, i8 0 acq_rel
+ ret void
+}
+; CHECK: atomic8_nand_acq_rel
+; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 4)
+
define void @atomic8_xchg_seq_cst(i8* %a) nounwind uwtable {
entry:
atomicrmw xchg i8* %a, i8 0 seq_cst
@@ -306,13 +338,21 @@ entry:
; CHECK: atomic8_xor_seq_cst
; CHECK: call i8 @__tsan_atomic8_fetch_xor(i8* %a, i8 0, i32 5)
+define void @atomic8_nand_seq_cst(i8* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i8* %a, i8 0 seq_cst
+ ret void
+}
+; CHECK: atomic8_nand_seq_cst
+; CHECK: call i8 @__tsan_atomic8_fetch_nand(i8* %a, i8 0, i32 5)
+
define void @atomic8_cas_monotonic(i8* %a) nounwind uwtable {
entry:
cmpxchg i8* %a, i8 0, i8 1 monotonic
ret void
}
; CHECK: atomic8_cas_monotonic
-; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0)
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0, i32 0)
define void @atomic8_cas_acquire(i8* %a) nounwind uwtable {
entry:
@@ -320,7 +360,7 @@ entry:
ret void
}
; CHECK: atomic8_cas_acquire
-; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2)
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2, i32 2)
define void @atomic8_cas_release(i8* %a) nounwind uwtable {
entry:
@@ -328,7 +368,7 @@ entry:
ret void
}
; CHECK: atomic8_cas_release
-; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3)
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3, i32 0)
define void @atomic8_cas_acq_rel(i8* %a) nounwind uwtable {
entry:
@@ -336,7 +376,7 @@ entry:
ret void
}
; CHECK: atomic8_cas_acq_rel
-; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4)
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4, i32 2)
define void @atomic8_cas_seq_cst(i8* %a) nounwind uwtable {
entry:
@@ -344,7 +384,7 @@ entry:
ret void
}
; CHECK: atomic8_cas_seq_cst
-; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5)
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5, i32 5)
define i16 @atomic16_load_unordered(i16* %a) nounwind uwtable {
entry:
@@ -458,6 +498,14 @@ entry:
; CHECK: atomic16_xor_monotonic
; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 0)
+define void @atomic16_nand_monotonic(i16* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i16* %a, i16 0 monotonic
+ ret void
+}
+; CHECK: atomic16_nand_monotonic
+; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 0)
+
define void @atomic16_xchg_acquire(i16* %a) nounwind uwtable {
entry:
atomicrmw xchg i16* %a, i16 0 acquire
@@ -506,6 +554,14 @@ entry:
; CHECK: atomic16_xor_acquire
; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 2)
+define void @atomic16_nand_acquire(i16* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i16* %a, i16 0 acquire
+ ret void
+}
+; CHECK: atomic16_nand_acquire
+; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 2)
+
define void @atomic16_xchg_release(i16* %a) nounwind uwtable {
entry:
atomicrmw xchg i16* %a, i16 0 release
@@ -554,6 +610,14 @@ entry:
; CHECK: atomic16_xor_release
; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 3)
+define void @atomic16_nand_release(i16* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i16* %a, i16 0 release
+ ret void
+}
+; CHECK: atomic16_nand_release
+; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 3)
+
define void @atomic16_xchg_acq_rel(i16* %a) nounwind uwtable {
entry:
atomicrmw xchg i16* %a, i16 0 acq_rel
@@ -602,6 +666,14 @@ entry:
; CHECK: atomic16_xor_acq_rel
; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 4)
+define void @atomic16_nand_acq_rel(i16* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i16* %a, i16 0 acq_rel
+ ret void
+}
+; CHECK: atomic16_nand_acq_rel
+; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 4)
+
define void @atomic16_xchg_seq_cst(i16* %a) nounwind uwtable {
entry:
atomicrmw xchg i16* %a, i16 0 seq_cst
@@ -650,13 +722,21 @@ entry:
; CHECK: atomic16_xor_seq_cst
; CHECK: call i16 @__tsan_atomic16_fetch_xor(i16* %a, i16 0, i32 5)
+define void @atomic16_nand_seq_cst(i16* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i16* %a, i16 0 seq_cst
+ ret void
+}
+; CHECK: atomic16_nand_seq_cst
+; CHECK: call i16 @__tsan_atomic16_fetch_nand(i16* %a, i16 0, i32 5)
+
define void @atomic16_cas_monotonic(i16* %a) nounwind uwtable {
entry:
cmpxchg i16* %a, i16 0, i16 1 monotonic
ret void
}
; CHECK: atomic16_cas_monotonic
-; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0)
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0, i32 0)
define void @atomic16_cas_acquire(i16* %a) nounwind uwtable {
entry:
@@ -664,7 +744,7 @@ entry:
ret void
}
; CHECK: atomic16_cas_acquire
-; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2)
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2, i32 2)
define void @atomic16_cas_release(i16* %a) nounwind uwtable {
entry:
@@ -672,7 +752,7 @@ entry:
ret void
}
; CHECK: atomic16_cas_release
-; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3)
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3, i32 0)
define void @atomic16_cas_acq_rel(i16* %a) nounwind uwtable {
entry:
@@ -680,7 +760,7 @@ entry:
ret void
}
; CHECK: atomic16_cas_acq_rel
-; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4)
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4, i32 2)
define void @atomic16_cas_seq_cst(i16* %a) nounwind uwtable {
entry:
@@ -688,7 +768,7 @@ entry:
ret void
}
; CHECK: atomic16_cas_seq_cst
-; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5)
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5, i32 5)
define i32 @atomic32_load_unordered(i32* %a) nounwind uwtable {
entry:
@@ -802,6 +882,14 @@ entry:
; CHECK: atomic32_xor_monotonic
; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 0)
+define void @atomic32_nand_monotonic(i32* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i32* %a, i32 0 monotonic
+ ret void
+}
+; CHECK: atomic32_nand_monotonic
+; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 0)
+
define void @atomic32_xchg_acquire(i32* %a) nounwind uwtable {
entry:
atomicrmw xchg i32* %a, i32 0 acquire
@@ -850,6 +938,14 @@ entry:
; CHECK: atomic32_xor_acquire
; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 2)
+define void @atomic32_nand_acquire(i32* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i32* %a, i32 0 acquire
+ ret void
+}
+; CHECK: atomic32_nand_acquire
+; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 2)
+
define void @atomic32_xchg_release(i32* %a) nounwind uwtable {
entry:
atomicrmw xchg i32* %a, i32 0 release
@@ -898,6 +994,14 @@ entry:
; CHECK: atomic32_xor_release
; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 3)
+define void @atomic32_nand_release(i32* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i32* %a, i32 0 release
+ ret void
+}
+; CHECK: atomic32_nand_release
+; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 3)
+
define void @atomic32_xchg_acq_rel(i32* %a) nounwind uwtable {
entry:
atomicrmw xchg i32* %a, i32 0 acq_rel
@@ -946,6 +1050,14 @@ entry:
; CHECK: atomic32_xor_acq_rel
; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 4)
+define void @atomic32_nand_acq_rel(i32* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i32* %a, i32 0 acq_rel
+ ret void
+}
+; CHECK: atomic32_nand_acq_rel
+; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 4)
+
define void @atomic32_xchg_seq_cst(i32* %a) nounwind uwtable {
entry:
atomicrmw xchg i32* %a, i32 0 seq_cst
@@ -994,13 +1106,21 @@ entry:
; CHECK: atomic32_xor_seq_cst
; CHECK: call i32 @__tsan_atomic32_fetch_xor(i32* %a, i32 0, i32 5)
+define void @atomic32_nand_seq_cst(i32* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i32* %a, i32 0 seq_cst
+ ret void
+}
+; CHECK: atomic32_nand_seq_cst
+; CHECK: call i32 @__tsan_atomic32_fetch_nand(i32* %a, i32 0, i32 5)
+
define void @atomic32_cas_monotonic(i32* %a) nounwind uwtable {
entry:
cmpxchg i32* %a, i32 0, i32 1 monotonic
ret void
}
; CHECK: atomic32_cas_monotonic
-; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0)
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0, i32 0)
define void @atomic32_cas_acquire(i32* %a) nounwind uwtable {
entry:
@@ -1008,7 +1128,7 @@ entry:
ret void
}
; CHECK: atomic32_cas_acquire
-; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2)
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2, i32 2)
define void @atomic32_cas_release(i32* %a) nounwind uwtable {
entry:
@@ -1016,7 +1136,7 @@ entry:
ret void
}
; CHECK: atomic32_cas_release
-; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3)
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3, i32 0)
define void @atomic32_cas_acq_rel(i32* %a) nounwind uwtable {
entry:
@@ -1024,7 +1144,7 @@ entry:
ret void
}
; CHECK: atomic32_cas_acq_rel
-; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4)
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4, i32 2)
define void @atomic32_cas_seq_cst(i32* %a) nounwind uwtable {
entry:
@@ -1032,7 +1152,7 @@ entry:
ret void
}
; CHECK: atomic32_cas_seq_cst
-; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5)
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5, i32 5)
define i64 @atomic64_load_unordered(i64* %a) nounwind uwtable {
entry:
@@ -1146,6 +1266,14 @@ entry:
; CHECK: atomic64_xor_monotonic
; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 0)
+define void @atomic64_nand_monotonic(i64* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i64* %a, i64 0 monotonic
+ ret void
+}
+; CHECK: atomic64_nand_monotonic
+; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 0)
+
define void @atomic64_xchg_acquire(i64* %a) nounwind uwtable {
entry:
atomicrmw xchg i64* %a, i64 0 acquire
@@ -1194,6 +1322,14 @@ entry:
; CHECK: atomic64_xor_acquire
; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 2)
+define void @atomic64_nand_acquire(i64* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i64* %a, i64 0 acquire
+ ret void
+}
+; CHECK: atomic64_nand_acquire
+; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 2)
+
define void @atomic64_xchg_release(i64* %a) nounwind uwtable {
entry:
atomicrmw xchg i64* %a, i64 0 release
@@ -1242,6 +1378,14 @@ entry:
; CHECK: atomic64_xor_release
; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 3)
+define void @atomic64_nand_release(i64* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i64* %a, i64 0 release
+ ret void
+}
+; CHECK: atomic64_nand_release
+; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 3)
+
define void @atomic64_xchg_acq_rel(i64* %a) nounwind uwtable {
entry:
atomicrmw xchg i64* %a, i64 0 acq_rel
@@ -1290,6 +1434,14 @@ entry:
; CHECK: atomic64_xor_acq_rel
; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 4)
+define void @atomic64_nand_acq_rel(i64* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i64* %a, i64 0 acq_rel
+ ret void
+}
+; CHECK: atomic64_nand_acq_rel
+; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 4)
+
define void @atomic64_xchg_seq_cst(i64* %a) nounwind uwtable {
entry:
atomicrmw xchg i64* %a, i64 0 seq_cst
@@ -1338,13 +1490,21 @@ entry:
; CHECK: atomic64_xor_seq_cst
; CHECK: call i64 @__tsan_atomic64_fetch_xor(i64* %a, i64 0, i32 5)
+define void @atomic64_nand_seq_cst(i64* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i64* %a, i64 0 seq_cst
+ ret void
+}
+; CHECK: atomic64_nand_seq_cst
+; CHECK: call i64 @__tsan_atomic64_fetch_nand(i64* %a, i64 0, i32 5)
+
define void @atomic64_cas_monotonic(i64* %a) nounwind uwtable {
entry:
cmpxchg i64* %a, i64 0, i64 1 monotonic
ret void
}
; CHECK: atomic64_cas_monotonic
-; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0)
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0, i32 0)
define void @atomic64_cas_acquire(i64* %a) nounwind uwtable {
entry:
@@ -1352,7 +1512,7 @@ entry:
ret void
}
; CHECK: atomic64_cas_acquire
-; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2)
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2, i32 2)
define void @atomic64_cas_release(i64* %a) nounwind uwtable {
entry:
@@ -1360,7 +1520,7 @@ entry:
ret void
}
; CHECK: atomic64_cas_release
-; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3)
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3, i32 0)
define void @atomic64_cas_acq_rel(i64* %a) nounwind uwtable {
entry:
@@ -1368,7 +1528,7 @@ entry:
ret void
}
; CHECK: atomic64_cas_acq_rel
-; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4)
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4, i32 2)
define void @atomic64_cas_seq_cst(i64* %a) nounwind uwtable {
entry:
@@ -1376,7 +1536,7 @@ entry:
ret void
}
; CHECK: atomic64_cas_seq_cst
-; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5)
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 5)
define i128 @atomic128_load_unordered(i128* %a) nounwind uwtable {
entry:
@@ -1490,6 +1650,14 @@ entry:
; CHECK: atomic128_xor_monotonic
; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 0)
+define void @atomic128_nand_monotonic(i128* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i128* %a, i128 0 monotonic
+ ret void
+}
+; CHECK: atomic128_nand_monotonic
+; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 0)
+
define void @atomic128_xchg_acquire(i128* %a) nounwind uwtable {
entry:
atomicrmw xchg i128* %a, i128 0 acquire
@@ -1538,6 +1706,14 @@ entry:
; CHECK: atomic128_xor_acquire
; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 2)
+define void @atomic128_nand_acquire(i128* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i128* %a, i128 0 acquire
+ ret void
+}
+; CHECK: atomic128_nand_acquire
+; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 2)
+
define void @atomic128_xchg_release(i128* %a) nounwind uwtable {
entry:
atomicrmw xchg i128* %a, i128 0 release
@@ -1586,6 +1762,14 @@ entry:
; CHECK: atomic128_xor_release
; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 3)
+define void @atomic128_nand_release(i128* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i128* %a, i128 0 release
+ ret void
+}
+; CHECK: atomic128_nand_release
+; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 3)
+
define void @atomic128_xchg_acq_rel(i128* %a) nounwind uwtable {
entry:
atomicrmw xchg i128* %a, i128 0 acq_rel
@@ -1634,6 +1818,14 @@ entry:
; CHECK: atomic128_xor_acq_rel
; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 4)
+define void @atomic128_nand_acq_rel(i128* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i128* %a, i128 0 acq_rel
+ ret void
+}
+; CHECK: atomic128_nand_acq_rel
+; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 4)
+
define void @atomic128_xchg_seq_cst(i128* %a) nounwind uwtable {
entry:
atomicrmw xchg i128* %a, i128 0 seq_cst
@@ -1682,13 +1874,21 @@ entry:
; CHECK: atomic128_xor_seq_cst
; CHECK: call i128 @__tsan_atomic128_fetch_xor(i128* %a, i128 0, i32 5)
+define void @atomic128_nand_seq_cst(i128* %a) nounwind uwtable {
+entry:
+ atomicrmw nand i128* %a, i128 0 seq_cst
+ ret void
+}
+; CHECK: atomic128_nand_seq_cst
+; CHECK: call i128 @__tsan_atomic128_fetch_nand(i128* %a, i128 0, i32 5)
+
define void @atomic128_cas_monotonic(i128* %a) nounwind uwtable {
entry:
cmpxchg i128* %a, i128 0, i128 1 monotonic
ret void
}
; CHECK: atomic128_cas_monotonic
-; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 0)
+; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 0, i32 0)
define void @atomic128_cas_acquire(i128* %a) nounwind uwtable {
entry:
@@ -1696,7 +1896,7 @@ entry:
ret void
}
; CHECK: atomic128_cas_acquire
-; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 2)
+; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 2, i32 2)
define void @atomic128_cas_release(i128* %a) nounwind uwtable {
entry:
@@ -1704,7 +1904,7 @@ entry:
ret void
}
; CHECK: atomic128_cas_release
-; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 3)
+; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 3, i32 0)
define void @atomic128_cas_acq_rel(i128* %a) nounwind uwtable {
entry:
@@ -1712,7 +1912,7 @@ entry:
ret void
}
; CHECK: atomic128_cas_acq_rel
-; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 4)
+; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 4, i32 2)
define void @atomic128_cas_seq_cst(i128* %a) nounwind uwtable {
entry:
@@ -1720,7 +1920,7 @@ entry:
ret void
}
; CHECK: atomic128_cas_seq_cst
-; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 5)
+; CHECK: call i128 @__tsan_atomic128_compare_exchange_val(i128* %a, i128 0, i128 1, i32 5, i32 5)
define void @atomic_signal_fence_acquire() nounwind uwtable {
entry:
diff --git a/test/Instrumentation/ThreadSanitizer/read_from_global.ll b/test/Instrumentation/ThreadSanitizer/read_from_global.ll
index a08453ac4a94a..7b6b94edf1b1c 100644
--- a/test/Instrumentation/ThreadSanitizer/read_from_global.ll
+++ b/test/Instrumentation/ThreadSanitizer/read_from_global.ll
@@ -48,7 +48,7 @@ entry:
}
; CHECK: define void @call_virtual_func
-; CHECK: __tsan_read
+; CHECK: __tsan_vptr_read
; CHECK: = load
; CHECK-NOT: __tsan_read
; CHECK: = load
diff --git a/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll b/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll
new file mode 100644
index 0000000000000..a83a274bcf6e3
--- /dev/null
+++ b/test/Instrumentation/ThreadSanitizer/tsan-vs-gvn.ll
@@ -0,0 +1,26 @@
+; RUN: opt < %s -basicaa -gvn -tsan -S | FileCheck %s
+; TSAN conflicts with load widening. Make sure the load widening is off with -tsan.
+
+; 32-bit little endian target.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
+
+%struct_of_8_bytes_4_aligned = type { i32, i8, i8, i8, i8}
+
+@f = global %struct_of_8_bytes_4_aligned zeroinitializer, align 4
+
+; Accessing bytes 4 and 6, not ok to widen to i32 if sanitize_thread is set.
+
+define i32 @test_widening_bad(i8* %P) nounwind ssp noredzone sanitize_thread {
+entry:
+ %tmp = load i8* getelementptr inbounds (%struct_of_8_bytes_4_aligned* @f, i64 0, i32 1), align 4
+ %conv = zext i8 %tmp to i32
+ %tmp1 = load i8* getelementptr inbounds (%struct_of_8_bytes_4_aligned* @f, i64 0, i32 3), align 1
+ %conv2 = zext i8 %tmp1 to i32
+ %add = add nsw i32 %conv, %conv2
+ ret i32 %add
+; CHECK: @test_widening_bad
+; CHECK: call void @__tsan_read1
+; CHECK: call void @__tsan_read1
+; CHECK-NOT: call void @__tsan_read4
+; CHECK: ret i32
+}
diff --git a/test/Instrumentation/ThreadSanitizer/tsan_basic.ll b/test/Instrumentation/ThreadSanitizer/tsan_basic.ll
index 33c703b4c9bd8..0ecff40493a24 100644
--- a/test/Instrumentation/ThreadSanitizer/tsan_basic.ll
+++ b/test/Instrumentation/ThreadSanitizer/tsan_basic.ll
@@ -20,3 +20,36 @@ entry:
; CHECK: ret i32
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1)
+declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1)
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1)
+
+
+; Check that tsan converts mem intrinsics back to function calls.
+
+define void @MemCpyTest(i8* nocapture %x, i8* nocapture %y) {
+entry:
+ tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %x, i8* %y, i64 16, i32 4, i1 false)
+ ret void
+; CHECK: define void @MemCpyTest
+; CHECK: call i8* @memcpy
+; CHECK: ret void
+}
+
+define void @MemMoveTest(i8* nocapture %x, i8* nocapture %y) {
+entry:
+ tail call void @llvm.memmove.p0i8.p0i8.i64(i8* %x, i8* %y, i64 16, i32 4, i1 false)
+ ret void
+; CHECK: define void @MemMoveTest
+; CHECK: call i8* @memmove
+; CHECK: ret void
+}
+
+define void @MemSetTest(i8* nocapture %x) {
+entry:
+ tail call void @llvm.memset.p0i8.i64(i8* %x, i8 77, i64 16, i32 4, i1 false)
+ ret void
+; CHECK define void @MemSetTest
+; CHECK: call i8* @memset
+; CHECK: ret void
+}
diff --git a/test/Instrumentation/ThreadSanitizer/vptr_read.ll b/test/Instrumentation/ThreadSanitizer/vptr_read.ll
new file mode 100644
index 0000000000000..404ca3ffe50f9
--- /dev/null
+++ b/test/Instrumentation/ThreadSanitizer/vptr_read.ll
@@ -0,0 +1,13 @@
+; RUN: opt < %s -tsan -S | FileCheck %s
+; Check that vptr reads are treated in a special way.
+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"
+
+define i8 @Foo(i8* %a) nounwind uwtable {
+entry:
+; CHECK: call void @__tsan_vptr_read
+ %0 = load i8* %a, align 8, !tbaa !0
+ ret i8 %0
+}
+!0 = metadata !{metadata !"vtable pointer", metadata !1}
+!1 = metadata !{metadata !"Simple C/C++ TBAA", null}
+