Home | History | Annotate | Download | only in AArch64
      1 ; RUN: opt < %s -msan -S | FileCheck %s
      2 
      3 target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
      4 target triple = "aarch64-unknown-linux-gnu"
      5 
      6 %struct.__va_list = type { i8*, i8*, i8*, i32, i32 }
      7 
      8 define 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, 56, rounded to 16
     20 ; plus total of 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 56, {{%.*}}
     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 
     49 declare void @llvm.lifetime.start(i64, i8* nocapture) #1
     50 declare void @llvm.va_start(i8*) #2
     51 declare void @llvm.va_end(i8*) #2
     52 declare void @llvm.lifetime.end(i64, i8* nocapture) #1
     53 
     54 define 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 56, 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 {{.*}} 64
     67 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 80
     68 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 16
     69 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 24
     70 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 96
     71 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 32
     72 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 40
     73 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 48
     74 ; CHECK: store {{.*}} @__msan_va_arg_tls {{.*}} 192
     75 ; CHECK: store {{.*}} 8, {{.*}} @__msan_va_arg_overflow_size_tls
     76