1; RUN: opt < %s -S -mcpu=z13 -passes=msan 2>&1 | FileCheck %s
2
3target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"
4target triple = "s390x-unknown-linux-gnu"
5
6%struct.__va_list = type { i64, i64, i8*, i8* }
7
8define i64 @foo(i64 %guard, ...) {
9  %vl = alloca %struct.__va_list, align 8
10  %1 = bitcast %struct.__va_list* %vl to i8*
11  call void @llvm.lifetime.start.p0i8(i64 32, i8* %1)
12  call void @llvm.va_start(i8* %1)
13  call void @llvm.va_end(i8* %1)
14  call void @llvm.lifetime.end.p0i8(i64 32, i8* %1)
15  ret i64 0
16}
17
18; First check if the variadic shadow values are saved in stack with correct
19; size (which is 160 - size of the register save area).
20
21; CHECK-LABEL: @foo
22; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls
23; CHECK: [[B:%.*]] = add i64 160, [[A]]
24; CHECK: alloca {{.*}} [[B]]
25
26; We expect two memcpy operations: one for the register save area, and one for
27; the overflow arg area.
28
29; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 {{%.*}}, i8* align 8 {{%.*}}, i64 160, i1 false)
30; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 {{%.*}}, i8* align 8 {{%.*}}, i64 [[A]], i1 false)
31
32declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
33declare void @llvm.va_start(i8*) #2
34declare void @llvm.va_end(i8*) #2
35declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
36
37declare i32 @random_i32()
38declare i64 @random_i64()
39declare float @random_float()
40declare double @random_double()
41
42define i64 @bar() {
43  %arg2 = call i32 () @random_i32()
44  %arg3 = call float () @random_float()
45  %arg4 = call i32 () @random_i32()
46  %arg5 = call double () @random_double()
47  %arg6 = call i64 () @random_i64()
48  %arg9 = call i32 () @random_i32()
49  %arg11 = call float () @random_float()
50  %arg12 = call i32 () @random_i32()
51  %arg13 = call double () @random_double()
52  %arg14 = call i64 () @random_i64()
53  %1 = call i64 (i64, ...) @foo(i64 1, i32 zeroext %arg2, float %arg3,
54                                i32 signext %arg4, double %arg5, i64 %arg6,
55                                i64 7, double 8.0, i32 zeroext %arg9,
56                                double 10.0, float %arg11, i32 signext %arg12,
57                                double %arg13, i64 %arg14)
58  ret i64 %1
59}
60
61; Save the incoming shadow values from the varargs in the __msan_va_arg_tls
62; array at the offsets equal to those defined by the ABI for the corresponding
63; registers in the register save area, and for the corresponding overflow args
64; in the overflow arg area:
65; - r2@16              == i64 1            - skipped, because it's fixed
66; - r3@24              == i32 zext %arg2   - shadow is zero-extended
67; - f0@128             == float %arg3      - left-justified, shadow is 32-bit
68; - r4@32              == i32 sext %arg4   - shadow is sign-extended
69; - f2@136             == double %arg5     - straightforward
70; - r5@40              == i64 %arg6        - straightforward
71; - r6@48              == 7                - filler
72; - f4@144             == 8.0              - filler
73; - overflow@160       == i32 zext %arg9   - shadow is zero-extended
74; - f6@152             == 10.0             - filler
75; - overflow@(168 + 4) == float %arg11     - right-justified, shadow is 32-bit
76; - overflow@176       == i32 sext %arg12  - shadow is sign-extended
77; - overflow@184       == double %arg13    - straightforward
78; - overflow@192       == i64 %arg14       - straightforward
79; Overflow arg area size is 40.
80
81; CHECK-LABEL: @bar
82
83; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24
84; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 128
85; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32
86; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 136
87; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 40
88; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 48
89; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 144
90; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160
91; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 152
92; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 172
93; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 176
94; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 184
95; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 192
96; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls
97
98; Test that MSan doesn't generate code overflowing __msan_va_arg_tls when too many arguments are
99; passed to a variadic function.
100
101define dso_local i64 @many_args() {
102entry:
103  %ret = call i64 (i64, ...) @sum(i64 120,
104    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
105    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
106    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
107    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
108    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
109    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
110    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
111    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
112    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
113    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
114    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1,
115    i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1
116  )
117  ret i64 %ret
118}
119
120; If the size of __msan_va_arg_tls changes the second argument of `add` must also be changed.
121; CHECK-LABEL: @many_args
122; CHECK: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 792)
123; CHECK-NOT: i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 800)
124
125declare i64 @sum(i64 %n, ...)
126
127; Test offset calculation for vector arguments.
128; Regardless of whether or not fixed args overflow, we should copy a shadow
129; for a single vector vararg to offset 160.
130
131declare void @vr_no_overflow(<4 x float> %v24, <4 x float> %v26,
132                             <4 x float> %v28, <4 x float> %v30,
133                             <4 x float> %v25, <4 x float> %v27,
134                             <4 x float> %v29, ...)
135
136declare <4 x float> @vr_value()
137
138define void @vr_no_overflow_caller() {
139  %1 = call <4 x float> () @vr_value()
140  call void (<4 x float>, <4 x float>, <4 x float>,
141             <4 x float>, <4 x float>, <4 x float>,
142             <4 x float>, ...) @vr_no_overflow(
143    <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1,
144    <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1)
145  ret void
146}
147
148; CHECK-LABEL: @vr_no_overflow_caller
149; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160
150; CHECK-NOT: store {{.*}} @__msan_va_arg_tls {{.*}}
151; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
152
153declare void @vr_overflow(<4 x float> %v24, <4 x float> %v26,
154                          <4 x float> %v28, <4 x float> %v30,
155                          <4 x float> %v25, <4 x float> %v27,
156                          <4 x float> %v29, <4 x float> %v31,
157                          <4 x float> %overflow, ...)
158
159define void @vr_overflow_caller() {
160  %1 = call <4 x float> @vr_value()
161  call void (<4 x float>, <4 x float>, <4 x float>,
162             <4 x float>, <4 x float>, <4 x float>,
163             <4 x float>, <4 x float>, <4 x float>,
164             ...) @vr_overflow(
165    <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1,
166    <4 x float> %1, <4 x float> %1, <4 x float> %1, <4 x float> %1,
167    <4 x float> %1, <4 x float> %1)
168  ret void
169}
170
171; CHECK-LABEL: @vr_overflow_caller
172; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 160
173; CHECK-NOT: store {{.*}} @__msan_va_arg_tls {{.*}}
174; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
175
176; Test that i128 and fp128 are passed by reference.
177
178declare i128 @random_i128()
179declare fp128 @random_fp128()
180
181define i64 @bar_128() {
182  %iarg = call i128 @random_i128()
183  %fparg = call fp128 @random_fp128()
184  %1 = call i64 (i64, ...) @foo(i64 1, i128 %iarg, fp128 %fparg)
185  ret i64 %1
186}
187
188; CHECK-LABEL: @bar_128
189; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24
190; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32
191; CHECK: store {{.*}} 0, {{.*}} @__msan_va_arg_overflow_size_tls
192