Home | History | Annotate | Download | only in CodeGen
      1 // RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 -emit-llvm < %s | FileCheck -check-prefix=FREEBSD %s
      2 // RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s
      3 
      4 struct foo {
      5   int x;
      6   float y;
      7   char z;
      8 };
      9 // FREEBSD: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
     10 // WIN64: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
     11 
     12 void __attribute__((ms_abi)) f1(void);
     13 void __attribute__((sysv_abi)) f2(void);
     14 void f3(void) {
     15   // FREEBSD-LABEL: define void @f3()
     16   // WIN64-LABEL: define void @f3()
     17   f1();
     18   // FREEBSD: call x86_64_win64cc void @f1()
     19   // WIN64: call void @f1()
     20   f2();
     21   // FREEBSD: call void @f2()
     22   // WIN64: call x86_64_sysvcc void @f2()
     23 }
     24 // FREEBSD: declare x86_64_win64cc void @f1()
     25 // FREEBSD: declare void @f2()
     26 // WIN64: declare void @f1()
     27 // WIN64: declare x86_64_sysvcc void @f2()
     28 
     29 // Win64 ABI varargs
     30 void __attribute__((ms_abi)) f4(int a, ...) {
     31   // FREEBSD-LABEL: define x86_64_win64cc void @f4
     32   // WIN64-LABEL: define void @f4
     33   __builtin_ms_va_list ap;
     34   __builtin_ms_va_start(ap, a);
     35   // FREEBSD: %[[AP:.*]] = alloca i8*
     36   // FREEBSD: call void @llvm.va_start
     37   // WIN64: %[[AP:.*]] = alloca i8*
     38   // WIN64: call void @llvm.va_start
     39   int b = __builtin_va_arg(ap, int);
     40   // FREEBSD: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
     41   // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
     42   // FREEBSD-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
     43   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR]] to i32*
     44   // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
     45   // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
     46   // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
     47   // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
     48   double _Complex c = __builtin_va_arg(ap, double _Complex);
     49   // FREEBSD: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
     50   // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
     51   // FREEBSD-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
     52   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
     53   // WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
     54   // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
     55   // WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
     56   // WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
     57   struct foo d = __builtin_va_arg(ap, struct foo);
     58   // FREEBSD: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
     59   // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
     60   // FREEBSD-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
     61   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
     62   // WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
     63   // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
     64   // WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
     65   // WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
     66   __builtin_ms_va_list ap2;
     67   __builtin_ms_va_copy(ap2, ap);
     68   // FREEBSD: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
     69   // FREEBSD-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
     70   // WIN64: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
     71   // WIN64-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
     72   __builtin_ms_va_end(ap);
     73   // FREEBSD: call void @llvm.va_end
     74   // WIN64: call void @llvm.va_end
     75 }
     76 
     77 // Let's verify that normal va_lists work right on Win64, too.
     78 void f5(int a, ...) {
     79   // WIN64-LABEL: define void @f5
     80   __builtin_va_list ap;
     81   __builtin_va_start(ap, a);
     82   // WIN64: %[[AP:.*]] = alloca i8*
     83   // WIN64: call void @llvm.va_start
     84   int b = __builtin_va_arg(ap, int);
     85   // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
     86   // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
     87   // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
     88   // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
     89   double _Complex c = __builtin_va_arg(ap, double _Complex);
     90   // WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
     91   // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
     92   // WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
     93   // WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
     94   struct foo d = __builtin_va_arg(ap, struct foo);
     95   // WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
     96   // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
     97   // WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
     98   // WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
     99   __builtin_va_list ap2;
    100   __builtin_va_copy(ap2, ap);
    101   // WIN64: call void @llvm.va_copy
    102   __builtin_va_end(ap);
    103   // WIN64: call void @llvm.va_end
    104 }
    105 
    106 // Verify that using a Win64 va_list from a System V function works.
    107 void __attribute__((sysv_abi)) f6(__builtin_ms_va_list ap) {
    108   // FREEBSD-LABEL: define void @f6
    109   // FREEBSD: store i8* %ap, i8** %[[AP:.*]]
    110   // WIN64-LABEL: define x86_64_sysvcc void @f6
    111   // WIN64: store i8* %ap, i8** %[[AP:.*]]
    112   int b = __builtin_va_arg(ap, int);
    113   // FREEBSD: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
    114   // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
    115   // FREEBSD-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
    116   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR]] to i32*
    117   // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
    118   // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
    119   // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
    120   // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
    121   double _Complex c = __builtin_va_arg(ap, double _Complex);
    122   // FREEBSD: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
    123   // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
    124   // FREEBSD-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
    125   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
    126   // WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
    127   // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
    128   // WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
    129   // WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
    130   struct foo d = __builtin_va_arg(ap, struct foo);
    131   // FREEBSD: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
    132   // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
    133   // FREEBSD-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
    134   // FREEBSD-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
    135   // WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
    136   // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
    137   // WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
    138   // WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
    139   __builtin_ms_va_list ap2;
    140   __builtin_ms_va_copy(ap2, ap);
    141   // FREEBSD: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
    142   // FREEBSD-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
    143   // WIN64: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
    144   // WIN64-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
    145 }
    146