1; Test for handling of asm constraints in MSan instrumentation.
2; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0                    \
3; RUN: -msan-handle-asm-conservative=0 -S -passes=msan 2>&1 | FileCheck        \
4; RUN: "-check-prefixes=CHECK,CHECK-NONCONS" %s
5; RUN: opt < %s -msan -msan-kernel=1 -msan-check-access-address=0 -msan-handle-asm-conservative=0 -S | FileCheck -check-prefixes=CHECK,CHECK-NONCONS %s
6; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0                    \
7; RUN: -msan-handle-asm-conservative=1 -S -passes=msan 2>&1 | FileCheck        \
8; RUN: "-check-prefixes=CHECK,CHECK-CONS" %s
9; RUN: opt < %s -msan -msan-kernel=1 -msan-check-access-address=0 -msan-handle-asm-conservative=1 -S | FileCheck -check-prefixes=CHECK,CHECK-CONS %s
10
11target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
12target triple = "x86_64-unknown-linux-gnu"
13
14%struct.pair = type { i32, i32 }
15
16@id1 = common dso_local global i32 0, align 4
17@is1 = common dso_local global i32 0, align 4
18@id2 = common dso_local global i32 0, align 4
19@is2 = common dso_local global i32 0, align 4
20@id3 = common dso_local global i32 0, align 4
21@pair2 = common dso_local global %struct.pair zeroinitializer, align 4
22@pair1 = common dso_local global %struct.pair zeroinitializer, align 4
23@c2 = common dso_local global i8 0, align 1
24@c1 = common dso_local global i8 0, align 1
25@memcpy_d1 = common dso_local global i8* (i8*, i8*, i32)* null, align 8
26@memcpy_d2 = common dso_local global i8* (i8*, i8*, i32)* null, align 8
27@memcpy_s1 = common dso_local global i8* (i8*, i8*, i32)* null, align 8
28@memcpy_s2 = common dso_local global i8* (i8*, i8*, i32)* null, align 8
29
30; The functions below were generated from a C source that contains declarations like follows:
31;   void f1() {
32;     asm("" : "=r" (id1) : "r" (is1));
33;   }
34; with corresponding input/output constraints.
35; Note that the assembly statement is always empty, as MSan doesn't look at it anyway.
36
37; One input register, one output register:
38;   asm("" : "=r" (id1) : "r" (is1));
39define dso_local void @f_1i_1o_reg() sanitize_memory {
40entry:
41  %0 = load i32, i32* @is1, align 4
42  %1 = call i32 asm "", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0)
43  store i32 %1, i32* @id1, align 4
44  ret void
45}
46
47; CHECK-LABEL: @f_1i_1o_reg
48; CHECK: [[IS1_F1:%.*]] = load i32, i32* @is1, align 4
49; CHECK: call void @__msan_warning
50; CHECK: call i32 asm "",{{.*}}(i32 [[IS1_F1]])
51; CHECK: [[PACK1_F1:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id1{{.*}})
52; CHECK: [[EXT1_F1:%.*]] = extractvalue { i8*, i32* } [[PACK1_F1]], 0
53; CHECK: [[CAST1_F1:%.*]] = bitcast i8* [[EXT1_F1]] to i32*
54; CHECK: store i32 0, i32* [[CAST1_F1]]
55
56
57; Two input registers, two output registers:
58;   asm("" : "=r" (id1), "=r" (id2) : "r" (is1), "r"(is2));
59define dso_local void @f_2i_2o_reg() sanitize_memory {
60entry:
61  %0 = load i32, i32* @is1, align 4
62  %1 = load i32, i32* @is2, align 4
63  %2 = call { i32, i32 } asm "", "=r,=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1)
64  %asmresult = extractvalue { i32, i32 } %2, 0
65  %asmresult1 = extractvalue { i32, i32 } %2, 1
66  store i32 %asmresult, i32* @id1, align 4
67  store i32 %asmresult1, i32* @id2, align 4
68  ret void
69}
70
71; CHECK-LABEL: @f_2i_2o_reg
72; CHECK: [[IS1_F2:%.*]] = load i32, i32* @is1, align 4
73; CHECK: [[IS2_F2:%.*]] = load i32, i32* @is2, align 4
74; CHECK: call void @__msan_warning
75; CHECK: call void @__msan_warning
76; CHECK: call { i32, i32 } asm "",{{.*}}(i32 [[IS1_F2]], i32 [[IS2_F2]])
77; CHECK: [[PACK1_F2:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id1{{.*}})
78; CHECK: [[EXT1_F2:%.*]] = extractvalue { i8*, i32* } [[PACK1_F2]], 0
79; CHECK: [[CAST1_F2:%.*]] = bitcast i8* [[EXT1_F2]] to i32*
80; CHECK: store i32 0, i32* [[CAST1_F2]]
81; CHECK: [[PACK2_F2:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id2{{.*}})
82; CHECK: [[EXT2_F2:%.*]] = extractvalue { i8*, i32* } [[PACK2_F2]], 0
83; CHECK: [[CAST2_F2:%.*]] = bitcast i8* [[EXT2_F2]] to i32*
84; CHECK: store i32 0, i32* [[CAST2_F2]]
85
86; Input same as output, used twice:
87;   asm("" : "=r" (id1), "=r" (id2) : "r" (id1), "r" (id2));
88define dso_local void @f_2i_2o_reuse2_reg() sanitize_memory {
89entry:
90  %0 = load i32, i32* @id1, align 4
91  %1 = load i32, i32* @id2, align 4
92  %2 = call { i32, i32 } asm "", "=r,=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1)
93  %asmresult = extractvalue { i32, i32 } %2, 0
94  %asmresult1 = extractvalue { i32, i32 } %2, 1
95  store i32 %asmresult, i32* @id1, align 4
96  store i32 %asmresult1, i32* @id2, align 4
97  ret void
98}
99
100; CHECK-LABEL: @f_2i_2o_reuse2_reg
101; CHECK: [[ID1_F3:%.*]] = load i32, i32* @id1, align 4
102; CHECK: [[ID2_F3:%.*]] = load i32, i32* @id2, align 4
103; CHECK: call void @__msan_warning
104; CHECK: call void @__msan_warning
105; CHECK: call { i32, i32 } asm "",{{.*}}(i32 [[ID1_F3]], i32 [[ID2_F3]])
106; CHECK: [[PACK1_F3:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id1{{.*}})
107; CHECK: [[EXT1_F3:%.*]] = extractvalue { i8*, i32* } [[PACK1_F3]], 0
108; CHECK: [[CAST1_F3:%.*]] = bitcast i8* [[EXT1_F3]] to i32*
109; CHECK: store i32 0, i32* [[CAST1_F3]]
110; CHECK: [[PACK2_F3:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id2{{.*}})
111; CHECK: [[EXT2_F3:%.*]] = extractvalue { i8*, i32* } [[PACK2_F3]], 0
112; CHECK: [[CAST2_F3:%.*]] = bitcast i8* [[EXT2_F3]] to i32*
113; CHECK: store i32 0, i32* [[CAST2_F3]]
114
115
116; One of the input registers is also an output:
117;   asm("" : "=r" (id1), "=r" (id2) : "r" (id1), "r"(is1));
118define dso_local void @f_2i_2o_reuse1_reg() sanitize_memory {
119entry:
120  %0 = load i32, i32* @id1, align 4
121  %1 = load i32, i32* @is1, align 4
122  %2 = call { i32, i32 } asm "", "=r,=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %1)
123  %asmresult = extractvalue { i32, i32 } %2, 0
124  %asmresult1 = extractvalue { i32, i32 } %2, 1
125  store i32 %asmresult, i32* @id1, align 4
126  store i32 %asmresult1, i32* @id2, align 4
127  ret void
128}
129
130; CHECK-LABEL: @f_2i_2o_reuse1_reg
131; CHECK: [[ID1_F4:%.*]] = load i32, i32* @id1, align 4
132; CHECK: [[IS1_F4:%.*]] = load i32, i32* @is1, align 4
133; CHECK: call void @__msan_warning
134; CHECK: call void @__msan_warning
135; CHECK: call { i32, i32 } asm "",{{.*}}(i32 [[ID1_F4]], i32 [[IS1_F4]])
136; CHECK: [[PACK1_F4:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id1{{.*}})
137; CHECK: [[EXT1_F4:%.*]] = extractvalue { i8*, i32* } [[PACK1_F4]], 0
138; CHECK: [[CAST1_F4:%.*]] = bitcast i8* [[EXT1_F4]] to i32*
139; CHECK: store i32 0, i32* [[CAST1_F4]]
140; CHECK: [[PACK2_F4:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id2{{.*}})
141; CHECK: [[EXT2_F4:%.*]] = extractvalue { i8*, i32* } [[PACK2_F4]], 0
142; CHECK: [[CAST2_F4:%.*]] = bitcast i8* [[EXT2_F4]] to i32*
143; CHECK: store i32 0, i32* [[CAST2_F4]]
144
145
146; One input register, three output registers:
147;   asm("" : "=r" (id1), "=r" (id2), "=r" (id3) : "r" (is1));
148define dso_local void @f_1i_3o_reg() sanitize_memory {
149entry:
150  %0 = load i32, i32* @is1, align 4
151  %1 = call { i32, i32, i32 } asm "", "=r,=r,=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0)
152  %asmresult = extractvalue { i32, i32, i32 } %1, 0
153  %asmresult1 = extractvalue { i32, i32, i32 } %1, 1
154  %asmresult2 = extractvalue { i32, i32, i32 } %1, 2
155  store i32 %asmresult, i32* @id1, align 4
156  store i32 %asmresult1, i32* @id2, align 4
157  store i32 %asmresult2, i32* @id3, align 4
158  ret void
159}
160
161; CHECK-LABEL: @f_1i_3o_reg
162; CHECK: [[IS1_F5:%.*]] = load i32, i32* @is1, align 4
163; CHECK: call void @__msan_warning
164; CHECK: call { i32, i32, i32 } asm "",{{.*}}(i32 [[IS1_F5]])
165; CHECK: [[PACK1_F5:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id1{{.*}})
166; CHECK: [[EXT1_F5:%.*]] = extractvalue { i8*, i32* } [[PACK1_F5]], 0
167; CHECK: [[CAST1_F5:%.*]] = bitcast i8* [[EXT1_F5]] to i32*
168; CHECK: store i32 0, i32* [[CAST1_F5]]
169; CHECK: [[PACK2_F5:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id2{{.*}})
170; CHECK: [[EXT2_F5:%.*]] = extractvalue { i8*, i32* } [[PACK2_F5]], 0
171; CHECK: [[CAST2_F5:%.*]] = bitcast i8* [[EXT2_F5]] to i32*
172; CHECK: store i32 0, i32* [[CAST2_F5]]
173; CHECK: [[PACK3_F5:%.*]] = call {{.*}} @__msan_metadata_ptr_for_store_4({{.*}}@id3{{.*}})
174; CHECK: [[EXT3_F5:%.*]] = extractvalue { i8*, i32* } [[PACK3_F5]], 0
175; CHECK: [[CAST3_F5:%.*]] = bitcast i8* [[EXT3_F5]] to i32*
176; CHECK: store i32 0, i32* [[CAST3_F5]]
177
178
179; 2 input memory args, 2 output memory args:
180;  asm("" : "=m" (id1), "=m" (id2) : "m" (is1), "m"(is2))
181define dso_local void @f_2i_2o_mem() sanitize_memory {
182entry:
183  call void asm "", "=*m,=*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(i32* @id1, i32* @id2, i32* @is1, i32* @is2)
184  ret void
185}
186
187; CHECK-LABEL: @f_2i_2o_mem
188; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@id1{{.*}}, i64 4)
189; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@id2{{.*}}, i64 4)
190; CHECK: call void asm "", "=*m,=*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(i32* @id1, i32* @id2, i32* @is1, i32* @is2)
191
192
193; Same input and output passed as both memory and register:
194;  asm("" : "=r" (id1), "=m"(id1) : "r"(is1), "m"(is1));
195define dso_local void @f_1i_1o_memreg() sanitize_memory {
196entry:
197  %0 = load i32, i32* @is1, align 4
198  %1 = call i32 asm "", "=r,=*m,r,*m,~{dirflag},~{fpsr},~{flags}"(i32* @id1, i32 %0, i32* @is1)
199  store i32 %1, i32* @id1, align 4
200  ret void
201}
202
203; CHECK-LABEL: @f_1i_1o_memreg
204; CHECK: [[IS1_F7:%.*]] = load i32, i32* @is1, align 4
205; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@id1{{.*}}, i64 4)
206; CHECK: call void @__msan_warning
207; CHECK: call i32 asm "", "=r,=*m,r,*m,~{dirflag},~{fpsr},~{flags}"(i32* @id1, i32 [[IS1_F7]], i32* @is1)
208
209
210; Three outputs, first and last returned via regs, second via mem:
211;  asm("" : "=r" (id1), "=m"(id2), "=r" (id3):);
212define dso_local void @f_3o_reg_mem_reg() sanitize_memory {
213entry:
214  %0 = call { i32, i32 } asm "", "=r,=*m,=r,~{dirflag},~{fpsr},~{flags}"(i32* @id2)
215  %asmresult = extractvalue { i32, i32 } %0, 0
216  %asmresult1 = extractvalue { i32, i32 } %0, 1
217  store i32 %asmresult, i32* @id1, align 4
218  store i32 %asmresult1, i32* @id3, align 4
219  ret void
220}
221
222; CHECK-LABEL: @f_3o_reg_mem_reg
223; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@id2{{.*}}), i64 4)
224; CHECK: call { i32, i32 } asm "", "=r,=*m,=r,~{dirflag},~{fpsr},~{flags}"(i32* @id2)
225
226
227; Three inputs and three outputs of different types: a pair, a char, a function pointer.
228; Everything is meant to be passed in registers, but LLVM chooses to return the integer pair by pointer:
229;  asm("" : "=r" (pair2), "=r" (c2), "=r" (memcpy_d1) : "r"(pair1), "r"(c1), "r"(memcpy_s1));
230define dso_local void @f_3i_3o_complex_reg() sanitize_memory {
231entry:
232  %0 = load i64, i64* bitcast (%struct.pair* @pair1 to i64*), align 4
233  %1 = load i8, i8* @c1, align 1
234  %2 = load i8* (i8*, i8*, i32)*, i8* (i8*, i8*, i32)** @memcpy_s1, align 8
235  %3 = call { i8, i8* (i8*, i8*, i32)* } asm "", "=*r,=r,=r,r,r,r,~{dirflag},~{fpsr},~{flags}"(%struct.pair* @pair2, i64 %0, i8 %1, i8* (i8*, i8*, i32)* %2)
236  %asmresult = extractvalue { i8, i8* (i8*, i8*, i32)* } %3, 0
237  %asmresult1 = extractvalue { i8, i8* (i8*, i8*, i32)* } %3, 1
238  store i8 %asmresult, i8* @c2, align 1
239  store i8* (i8*, i8*, i32)* %asmresult1, i8* (i8*, i8*, i32)** @memcpy_d1, align 8
240  ret void
241}
242
243; CHECK-LABEL: @f_3i_3o_complex_reg
244; CHECK: [[PAIR1_F9:%.*]] = load {{.*}} @pair1
245; CHECK: [[C1_F9:%.*]] = load {{.*}} @c1
246; CHECK: [[MEMCPY_S1_F9:%.*]] = load {{.*}} @memcpy_s1
247; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@pair2{{.*}}, i64 8)
248; CHECK: call void @__msan_warning
249; CHECK: call void @__msan_warning
250; CHECK: call void @__msan_warning
251; CHECK: call { i8, i8* (i8*, i8*, i32)* } asm "", "=*r,=r,=r,r,r,r,~{dirflag},~{fpsr},~{flags}"(%struct.pair* @pair2, {{.*}}[[PAIR1_F9]], i8 [[C1_F9]], {{.*}} [[MEMCPY_S1_F9]])
252
253; Three inputs and three outputs of different types: a pair, a char, a function pointer.
254; Everything is passed in memory:
255;  asm("" : "=m" (pair2), "=m" (c2), "=m" (memcpy_d1) : "m"(pair1), "m"(c1), "m"(memcpy_s1));
256define dso_local void @f_3i_3o_complex_mem() sanitize_memory {
257entry:
258  call void asm "", "=*m,=*m,=*m,*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(%struct.pair* @pair2, i8* @c2, i8* (i8*, i8*, i32)** @memcpy_d1, %struct.pair* @pair1, i8* @c1, i8* (i8*, i8*, i32)** @memcpy_s1)
259  ret void
260}
261
262; CHECK-LABEL: @f_3i_3o_complex_mem
263; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@pair2{{.*}}, i64 8)
264; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@c2{{.*}}, i64 1)
265; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@memcpy_d1{{.*}}, i64 8)
266; CHECK: call void asm "", "=*m,=*m,=*m,*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(%struct.pair* @pair2, i8* @c2, i8* (i8*, i8*, i32)** @memcpy_d1, %struct.pair* @pair1, i8* @c1, i8* (i8*, i8*, i32)** @memcpy_s1)
267
268
269; A simple asm goto construct to check that callbr is handled correctly:
270;  int asm_goto(int n) {
271;    int v = 1;
272;    asm goto("cmp %0, %1; jnz %l2;" :: "r"(n), "r"(v)::skip_label);
273;    return 0;
274;  skip_label:
275;    return 1;
276;  }
277; asm goto statements can't have outputs, so just make sure we check the input
278; and the compiler doesn't crash.
279define dso_local i32 @asm_goto(i32 %n) sanitize_memory {
280entry:
281  callbr void asm sideeffect "cmp $0, $1; jnz ${2:l}", "r,r,X,~{dirflag},~{fpsr},~{flags}"(i32 %n, i32 1, i8* blockaddress(@asm_goto, %skip_label))
282          to label %cleanup [label %skip_label]
283
284skip_label:                                       ; preds = %entry
285  br label %cleanup
286
287cleanup:                                          ; preds = %entry, %skip_label
288  %retval.0 = phi i32 [ 2, %skip_label ], [ 1, %entry ]
289  ret i32 %retval.0
290}
291
292; CHECK-LABEL: @asm_goto
293; CHECK: [[LOAD_ARG:%.*]] = load {{.*}} %_msarg
294; CHECK: [[CMP:%.*]] = icmp ne {{.*}} [[LOAD_ARG]], 0
295; CHECK: br {{.*}} [[CMP]], label %[[LABEL:.*]], label
296; CHECK: [[LABEL]]:
297; CHECK-NEXT: call void @__msan_warning
298