• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt < %s -msan -S | FileCheck %s
2
3target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
4target triple = "aarch64-unknown-linux-gnu"
5
6%struct.__va_list = type { i8*, i8*, i8*, i32, i32 }
7
8define i32 @foo(i32 %guard, ...) {
9  %vl = alloca %struct.__va_list, align 8
10  %1 = bitcast %struct.__va_list* %vl to i8*
11  call void @llvm.lifetime.start(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(i64 32, i8* %1)
15  ret i32 0
16}
17
18; First check if the variadic shadow values are saved in stack with correct
19; size (192 is total of general purpose registers size, 64, plus total of
20; floating-point registers size, 128).
21
22; CHECK-LABEL: @foo
23; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls
24; CHECK: [[B:%.*]] = add i64 192, [[A]]
25; CHECK: alloca {{.*}} [[B]]
26
27; We expect three memcpy operations: one for the general purpose registers,
28; one for floating-point/SIMD ones, and one for thre remaining arguments.
29
30; Propagate the GR shadow values on for the va_list::__gp_top, adjust the
31; offset in the __msan_va_arg_tls based on va_list:__gp_off, and finally
32; issue the memcpy.
33; CHECK: [[GRP:%.*]] = getelementptr inbounds i8, i8* {{%.*}}, i64 {{%.*}}
34; CHECK: [[GRSIZE:%.*]] = sub i64 64, {{%.*}}
35; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{%.*}}, i8* [[GRP]], i64 [[GRSIZE]], i32 8, i1 false)
36
37; Propagate the VR shadow values on for the va_list::__vr_top, adjust the
38; offset in the __msan_va_arg_tls based on va_list:__vr_off, and finally
39; issue the memcpy.
40; CHECK: [[VRP:%.*]] = getelementptr inbounds i8, i8* {{%.*}}, i64 {{%.*}}
41; CHECK: [[VRSIZE:%.*]] = sub i64 128, {{%.*}}
42; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{%.*}}, i8* [[VRP]], i64 [[VRSIZE]], i32 8, i1 false)
43
44; Copy the remaining shadow values on the va_list::__stack position (it is
45; on the constant offset of 192 from __msan_va_arg_tls).
46; CHECK: [[STACK:%.*]] = getelementptr inbounds i8, i8* {{%.*}}, i32 192
47; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{%.*}}, i8* [[STACK]], i64 {{%.*}}, i32 16, i1 false)
48
49declare void @llvm.lifetime.start(i64, i8* nocapture) #1
50declare void @llvm.va_start(i8*) #2
51declare void @llvm.va_end(i8*) #2
52declare void @llvm.lifetime.end(i64, i8* nocapture) #1
53
54define i32 @bar() {
55  %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i32 2, double 3.000000e+00,
56                                double 4.000000e+00, i32 5, i32 6,
57                                double 7.000000e+00, i32 8, i32 9, i32 10, i32 11)
58  ret i32 %1
59}
60
61; Save the incoming shadow value from the arguments in the __msan_va_arg_tls
62; array.  General purpose registers are saved at positions from 0 to 64, Floating
63; point and SIMD are saved from 64 to 192, and the remaining from 192.
64; CHECK-LABEL: @bar
65; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 8
66; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 16
67; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 64
68; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 80
69; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24
70; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32
71; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 96
72; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 40
73; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 48
74; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 56
75; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 192
76; CHECK: store {{.*}} 8, {{.*}} @__msan_va_arg_overflow_size_tls
77