Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / test / Instrumentation / DataFlowSanitizer / struct.ll
blob8069d28e557db4e583994f4875113d79ae0faacb
1 ; RUN: opt < %s -passes=dfsan -dfsan-event-callbacks=true -S | FileCheck %s --check-prefixes=CHECK,EVENT_CALLBACKS
2 ; RUN: opt < %s -passes=dfsan -S | FileCheck %s --check-prefixes=CHECK,FAST
3 ; RUN: opt < %s -passes=dfsan -dfsan-combine-pointer-labels-on-load=false -S | FileCheck %s --check-prefixes=CHECK,NO_COMBINE_LOAD_PTR
4 ; RUN: opt < %s -passes=dfsan -dfsan-combine-pointer-labels-on-store=true -S | FileCheck %s --check-prefixes=CHECK,COMBINE_STORE_PTR
5 ; RUN: opt < %s -passes=dfsan -dfsan-track-select-control-flow=false -S | FileCheck %s --check-prefixes=CHECK,NO_SELECT_CONTROL
6 ; RUN: opt < %s -passes=dfsan -dfsan-debug-nonzero-labels -S | FileCheck %s --check-prefixes=CHECK,DEBUG_NONZERO_LABELS
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"
8 target triple = "x86_64-unknown-linux-gnu"
10 ; CHECK: @__dfsan_arg_tls = external thread_local(initialexec) global [[TLS_ARR:\[100 x i64\]]]
11 ; CHECK: @__dfsan_retval_tls = external thread_local(initialexec) global [[TLS_ARR]]
12 define {ptr, i32} @pass_struct({ptr, i32} %s) {
13   ; NO_COMBINE_LOAD_PTR: @pass_struct.dfsan
14   ; NO_COMBINE_LOAD_PTR: [[L:%.*]] = load { i8, i8 }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
15   ; NO_COMBINE_LOAD_PTR: store { i8, i8 } [[L]], ptr @__dfsan_retval_tls, align [[ALIGN]]
17   ; DEBUG_NONZERO_LABELS: @pass_struct.dfsan
18   ; DEBUG_NONZERO_LABELS: [[L:%.*]] = load { i8, i8 }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
19   ; DEBUG_NONZERO_LABELS: [[L0:%.*]] = extractvalue { i8, i8 } [[L]], 0
20   ; DEBUG_NONZERO_LABELS: [[L1:%.*]] = extractvalue { i8, i8 } [[L]], 1
21   ; DEBUG_NONZERO_LABELS: [[L01:%.*]] = or i8 [[L0]], [[L1]]
22   ; DEBUG_NONZERO_LABELS: {{.*}} = icmp ne i8 [[L01]], 0
23   ; DEBUG_NONZERO_LABELS: call void @__dfsan_nonzero_label()
24   ; DEBUG_NONZERO_LABELS: store { i8, i8 } [[L]], ptr @__dfsan_retval_tls, align [[ALIGN]]
26   ret {ptr, i32} %s
29 %StructOfAggr = type {ptr, [4 x i2], <4 x i3>, {i1, i1}}
31 define %StructOfAggr @pass_struct_of_aggregate(%StructOfAggr %s) {
32   ; NO_COMBINE_LOAD_PTR: @pass_struct_of_aggregate.dfsan
33   ; NO_COMBINE_LOAD_PTR: %1 = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
34   ; NO_COMBINE_LOAD_PTR: store { i8, [4 x i8], i8, { i8, i8 } } %1, ptr @__dfsan_retval_tls, align [[ALIGN]]
36   ret %StructOfAggr %s
39 define {} @load_empty_struct(ptr %p) {
40   ; NO_COMBINE_LOAD_PTR: @load_empty_struct.dfsan
41   ; NO_COMBINE_LOAD_PTR: store {} zeroinitializer, ptr @__dfsan_retval_tls, align 2
43   %a = load {}, ptr %p
44   ret {} %a
47 @Y = constant {i1, i32} {i1 1, i32 1}
49 define {i1, i32} @load_global_struct() {
50   ; NO_COMBINE_LOAD_PTR: @load_global_struct.dfsan
51   ; NO_COMBINE_LOAD_PTR: store { i8, i8 } zeroinitializer, ptr @__dfsan_retval_tls, align 2
53   %a = load {i1, i32}, ptr @Y
54   ret {i1, i32} %a
57 define {i1, i32} @select_struct(i1 %c, {i1, i32} %a, {i1, i32} %b) {
58   ; NO_SELECT_CONTROL: @select_struct.dfsan
59   ; NO_SELECT_CONTROL: [[B:%.*]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 4) to ptr), align [[ALIGN:2]]
60   ; NO_SELECT_CONTROL: [[A:%.*]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
61   ; NO_SELECT_CONTROL: [[C:%.*]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN]]
62   ; NO_SELECT_CONTROL: [[S:%.*]] = select i1 %c, { i8, i8 } [[A]], { i8, i8 } [[B]]
63   ; NO_SELECT_CONTROL: store { i8, i8 } [[S]], ptr @__dfsan_retval_tls, align [[ALIGN]]
65   ; FAST: @select_struct.dfsan
66   ; FAST: %[[#R:]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 4) to ptr), align [[ALIGN:2]]
67   ; FAST: %[[#R+1]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
68   ; FAST: %[[#R+2]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN]]
69   ; FAST: %[[#R+3]] = select i1 %c, { i8, i8 } %[[#R+1]], { i8, i8 } %[[#R]]
70   ; FAST: %[[#R+4]] = extractvalue { i8, i8 } %[[#R+3]], 0
71   ; FAST: %[[#R+5]] = extractvalue { i8, i8 } %[[#R+3]], 1
72   ; FAST: %[[#R+6]] = or i8 %[[#R+4]], %[[#R+5]]
73   ; FAST: %[[#R+7]] = or i8 %[[#R+2]], %[[#R+6]]
74   ; FAST: %[[#R+8]] = insertvalue { i8, i8 } undef, i8 %[[#R+7]], 0
75   ; FAST: %[[#R+9]] = insertvalue { i8, i8 } %[[#R+8]], i8 %[[#R+7]], 1
76   ; FAST: store { i8, i8 } %[[#R+9]], ptr @__dfsan_retval_tls, align [[ALIGN]]
78   %s = select i1 %c, {i1, i32} %a, {i1, i32} %b
79   ret {i1, i32} %s
82 define { i32, i32 } @asm_struct(i32 %0, i32 %1) {
83   ; FAST: @asm_struct.dfsan
84   ; FAST: [[E1:%.*]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN:2]]
85   ; FAST: [[E0:%.*]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN]]
86   ; FAST: [[E01:%.*]] = or i8 [[E0]], [[E1]]
87   ; FAST: [[S0:%.*]] = insertvalue { i8, i8 } undef, i8 [[E01]], 0
88   ; FAST: [[S1:%.*]] = insertvalue { i8, i8 } [[S0]], i8 [[E01]], 1
89   ; FAST: store { i8, i8 } [[S1]], ptr @__dfsan_retval_tls, align [[ALIGN]]
91 entry:
92   %a = call { i32, i32 } asm "", "=r,=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1)
93   ret { i32, i32 } %a
96 define {i32, i32} @const_struct() {
97   ; FAST: @const_struct.dfsan
98   ; FAST: store { i8, i8 } zeroinitializer, ptr @__dfsan_retval_tls, align 2
99   ret {i32, i32} { i32 42, i32 11 }
102 define i1 @extract_struct({i1, i5} %s) {
103   ; FAST: @extract_struct.dfsan
104   ; FAST: [[SM:%.*]] = load { i8, i8 }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
105   ; FAST: [[EM:%.*]] = extractvalue { i8, i8 } [[SM]], 0
106   ; FAST: store i8 [[EM]], ptr @__dfsan_retval_tls, align [[ALIGN]]
108   %e2 = extractvalue {i1, i5} %s, 0
109   ret i1 %e2
112 define {i1, i5} @insert_struct({i1, i5} %s, i5 %e1) {
113   ; FAST: @insert_struct.dfsan
114   ; FAST: [[EM:%.*]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN:2]]
115   ; FAST: [[SM:%.*]] = load { i8, i8 }, ptr @__dfsan_arg_tls, align [[ALIGN]]
116   ; FAST: [[SM1:%.*]] = insertvalue { i8, i8 } [[SM]], i8 [[EM]], 1
117   ; FAST: store { i8, i8 } [[SM1]], ptr @__dfsan_retval_tls, align [[ALIGN]]
118   %s1 = insertvalue {i1, i5} %s, i5 %e1, 1
119   ret {i1, i5} %s1
122 define {i1, i1} @load_struct(ptr %p) {
123   ; NO_COMBINE_LOAD_PTR: @load_struct.dfsan
124   ; NO_COMBINE_LOAD_PTR: [[OL:%.*]] = or i8
125   ; NO_COMBINE_LOAD_PTR: [[S0:%.*]] = insertvalue { i8, i8 } undef, i8 [[OL]], 0
126   ; NO_COMBINE_LOAD_PTR: [[S1:%.*]] = insertvalue { i8, i8 } [[S0]], i8 [[OL]], 1
127   ; NO_COMBINE_LOAD_PTR: store { i8, i8 } [[S1]], ptr @__dfsan_retval_tls, align 2
129   ; EVENT_CALLBACKS: @load_struct.dfsan
130   ; EVENT_CALLBACKS: [[OL0:%.*]] = or i8
131   ; EVENT_CALLBACKS: [[OL1:%.*]] = or i8 [[OL0]],
132   ; EVENT_CALLBACKS: [[S0:%.*]] = insertvalue { i8, i8 } undef, i8 [[OL1]], 0
133   ; EVENT_CALLBACKS: call void @__dfsan_load_callback(i8 zeroext [[OL1]]
135   %s = load {i1, i1}, ptr %p
136   ret {i1, i1} %s
139 define void @store_struct(ptr %p, {i1, i1} %s) {
140   ; FAST: @store_struct.dfsan
141   ; FAST: [[S:%.*]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN:2]]
142   ; FAST: [[E0:%.*]] = extractvalue { i8, i8 } [[S]], 0
143   ; FAST: [[E1:%.*]] = extractvalue { i8, i8 } [[S]], 1
144   ; FAST: [[E:%.*]] = or i8 [[E0]], [[E1]]
145   ; FAST: [[P0:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 0
146   ; FAST: store i8 [[E]], ptr [[P0]], align 1
147   ; FAST: [[P1:%.*]] = getelementptr i8, ptr [[P]], i32 1
148   ; FAST: store i8 [[E]], ptr [[P1]], align 1
150   ; EVENT_CALLBACKS: @store_struct.dfsan
151   ; EVENT_CALLBACKS: [[OL:%.*]] = or i8
152   ; EVENT_CALLBACKS: call void @__dfsan_store_callback(i8 zeroext [[OL]]
154   ; COMBINE_STORE_PTR: @store_struct.dfsan
155   ; COMBINE_STORE_PTR: [[PL:%.*]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
156   ; COMBINE_STORE_PTR: [[SL:%.*]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
157   ; COMBINE_STORE_PTR: [[SL0:%.*]] = extractvalue { i8, i8 } [[SL]], 0
158   ; COMBINE_STORE_PTR: [[SL1:%.*]] = extractvalue { i8, i8 } [[SL]], 1
159   ; COMBINE_STORE_PTR: [[SL01:%.*]] = or i8 [[SL0]], [[SL1]]
160   ; COMBINE_STORE_PTR: [[E:%.*]] = or i8 [[SL01]], [[PL]]
161   ; COMBINE_STORE_PTR: [[P0:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 0
162   ; COMBINE_STORE_PTR: store i8 [[E]], ptr [[P0]], align 1
163   ; COMBINE_STORE_PTR: [[P1:%.*]] = getelementptr i8, ptr [[P]], i32 1
164   ; COMBINE_STORE_PTR: store i8 [[E]], ptr [[P1]], align 1
166   store {i1, i1} %s, ptr %p
167   ret void
170 define i2 @extract_struct_of_aggregate11(%StructOfAggr %s) {
171   ; FAST: @extract_struct_of_aggregate11.dfsan
172   ; FAST: [[E:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
173   ; FAST: [[E11:%.*]] = extractvalue { i8, [4 x i8], i8, { i8, i8 } } [[E]], 1, 1
174   ; FAST: store i8 [[E11]], ptr @__dfsan_retval_tls, align [[ALIGN]]
176   %e11 = extractvalue %StructOfAggr %s, 1, 1
177   ret i2 %e11
180 define [4 x i2] @extract_struct_of_aggregate1(%StructOfAggr %s) {
181   ; FAST: @extract_struct_of_aggregate1.dfsan
182   ; FAST: [[E:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
183   ; FAST: [[E1:%.*]] = extractvalue { i8, [4 x i8], i8, { i8, i8 } } [[E]], 1
184   ; FAST: store [4 x i8] [[E1]], ptr @__dfsan_retval_tls, align [[ALIGN]]
185   %e1 = extractvalue %StructOfAggr %s, 1
186   ret [4 x i2] %e1
189 define <4 x i3> @extract_struct_of_aggregate2(%StructOfAggr %s) {
190   ; FAST: @extract_struct_of_aggregate2.dfsan
191   ; FAST: [[E:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
192   ; FAST: [[E2:%.*]] = extractvalue { i8, [4 x i8], i8, { i8, i8 } } [[E]], 2
193   ; FAST: store i8 [[E2]], ptr @__dfsan_retval_tls, align [[ALIGN]]
194   %e2 = extractvalue %StructOfAggr %s, 2
195   ret <4 x i3> %e2
198 define { i1, i1 } @extract_struct_of_aggregate3(%StructOfAggr %s) {
199   ; FAST: @extract_struct_of_aggregate3.dfsan
200   ; FAST: [[E:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
201   ; FAST: [[E3:%.*]] = extractvalue { i8, [4 x i8], i8, { i8, i8 } } [[E]], 3
202   ; FAST: store { i8, i8 } [[E3]], ptr @__dfsan_retval_tls, align [[ALIGN]]
203   %e3 = extractvalue %StructOfAggr %s, 3
204   ret { i1, i1 } %e3
207 define i1 @extract_struct_of_aggregate31(%StructOfAggr %s) {
208   ; FAST: @extract_struct_of_aggregate31.dfsan
209   ; FAST: [[E:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
210   ; FAST: [[E31:%.*]] = extractvalue { i8, [4 x i8], i8, { i8, i8 } } [[E]], 3, 1
211   ; FAST: store i8 [[E31]], ptr @__dfsan_retval_tls, align [[ALIGN]]
212   %e31 = extractvalue %StructOfAggr %s, 3, 1
213   ret i1 %e31
216 define %StructOfAggr @insert_struct_of_aggregate11(%StructOfAggr %s, i2 %e11) {
217   ; FAST: @insert_struct_of_aggregate11.dfsan
218   ; FAST: [[E11:%.*]]  = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 8) to ptr), align [[ALIGN:2]]
219   ; FAST: [[S:%.*]] = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_arg_tls, align [[ALIGN]]
220   ; FAST: [[S1:%.*]] = insertvalue { i8, [4 x i8], i8, { i8, i8 } } [[S]], i8 [[E11]], 1, 1
221   ; FAST: store { i8, [4 x i8], i8, { i8, i8 } } [[S1]], ptr @__dfsan_retval_tls, align [[ALIGN]]
223   %s1 = insertvalue %StructOfAggr %s, i2 %e11, 1, 1
224   ret %StructOfAggr %s1
227 define {ptr, i32} @call_struct({ptr, i32} %s) {
228   ; FAST: @call_struct.dfsan
229   ; FAST: [[S:%.*]] = load { i8, i8 }, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
230   ; FAST: store { i8, i8 } [[S]], ptr @__dfsan_arg_tls, align [[ALIGN]]
231   ; FAST: %_dfsret = load { i8, i8 }, ptr @__dfsan_retval_tls, align [[ALIGN]]
232   ; FAST: store { i8, i8 } %_dfsret, ptr @__dfsan_retval_tls, align [[ALIGN]]
234   %r = call {ptr, i32} @pass_struct({ptr, i32} %s)
235   ret {ptr, i32} %r
238 declare %StructOfAggr @fun_with_many_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s)
240 define %StructOfAggr @call_many_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s) {
241   ; FAST: @call_many_aggr_args.dfsan
242   ; FAST: [[S:%.*]] = load { i8, i8 }, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 4) to ptr), align [[ALIGN:2]]
243   ; FAST: [[A:%.*]] = load [2 x i8], ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
244   ; FAST: [[V:%.*]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN]]
245   ; FAST: store i8 [[V]], ptr @__dfsan_arg_tls, align [[ALIGN]]
246   ; FAST: store [2 x i8] [[A]], ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
247   ; FAST: store { i8, i8 } [[S]], ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 4) to ptr), align [[ALIGN]]
248   ; FAST: %_dfsret = load { i8, [4 x i8], i8, { i8, i8 } }, ptr @__dfsan_retval_tls, align [[ALIGN]]
249   ; FAST: store { i8, [4 x i8], i8, { i8, i8 } } %_dfsret, ptr @__dfsan_retval_tls, align [[ALIGN]]
251   %r = call %StructOfAggr @fun_with_many_aggr_args(<2 x i7> %v, [2 x i5] %a, {i3, i3} %s)
252   ret %StructOfAggr %r