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
9 // FREEBSD: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
10 // WIN64: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
12 void __attribute__((ms_abi
)) f1(void);
13 void __attribute__((sysv_abi
)) f2(void);
15 // FREEBSD-LABEL: define{{.*}} void @f3()
16 // WIN64-LABEL: define dso_local void @f3()
18 // FREEBSD: call win64cc void @f1()
19 // WIN64: call void @f1()
21 // FREEBSD: call void @f2()
22 // WIN64: call x86_64_sysvcc void @f2()
24 // FREEBSD: declare win64cc void @f1()
25 // FREEBSD: declare void @f2()
26 // WIN64: declare dso_local void @f1()
27 // WIN64: declare dso_local x86_64_sysvcc void @f2()
30 void __attribute__((ms_abi
)) f4(int a
, ...) {
31 // FREEBSD-LABEL: define{{.*}} win64cc void @f4
32 // WIN64-LABEL: define dso_local void @f4
33 __builtin_ms_va_list ap
;
34 __builtin_ms_va_start(ap
, a
);
35 // FREEBSD: %[[AP:.*]] = alloca ptr
36 // FREEBSD: call void @llvm.va_start
37 // WIN64: %[[AP:.*]] = alloca ptr
38 // WIN64: call void @llvm.va_start
39 int b
= __builtin_va_arg(ap
, int);
40 // FREEBSD: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]
41 // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8
42 // FREEBSD-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]
43 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]
44 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8
45 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]
46 double _Complex c
= __builtin_va_arg(ap
, double _Complex
);
47 // FREEBSD: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]
48 // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8
49 // FREEBSD-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]
50 // FREEBSD-NEXT: load ptr, ptr %[[AP_CUR2]]
51 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]
52 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8
53 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]
54 // WIN64-NEXT: load ptr, ptr %[[AP_CUR2]]
55 struct foo d
= __builtin_va_arg(ap
, struct foo
);
56 // FREEBSD: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]
57 // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8
58 // FREEBSD-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]
59 // FREEBSD-NEXT: load ptr, ptr %[[AP_CUR3]]
60 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]
61 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8
62 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]
63 // WIN64-NEXT: load ptr, ptr %[[AP_CUR3]]
64 __builtin_ms_va_list ap2
;
65 __builtin_ms_va_copy(ap2
, ap
);
66 // FREEBSD: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]
67 // FREEBSD-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]
68 // WIN64: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]
69 // WIN64-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]
70 __builtin_ms_va_end(ap
);
71 // FREEBSD: call void @llvm.va_end
72 // WIN64: call void @llvm.va_end
75 // Let's verify that normal va_lists work right on Win64, too.
77 // WIN64-LABEL: define dso_local void @f5
79 __builtin_va_start(ap
, a
);
80 // WIN64: %[[AP:.*]] = alloca ptr
81 // WIN64: call void @llvm.va_start
82 int b
= __builtin_va_arg(ap
, int);
83 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]
84 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8
85 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]
86 double _Complex c
= __builtin_va_arg(ap
, double _Complex
);
87 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]
88 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8
89 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]
90 struct foo d
= __builtin_va_arg(ap
, struct foo
);
91 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]
92 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8
93 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]
94 __builtin_va_list ap2
;
95 __builtin_va_copy(ap2
, ap
);
96 // WIN64: call void @llvm.va_copy
98 // WIN64: call void @llvm.va_end
101 // Verify that using a Win64 va_list from a System V function works.
102 void __attribute__((sysv_abi
)) f6(__builtin_ms_va_list ap
) {
103 // FREEBSD-LABEL: define{{.*}} void @f6
104 // FREEBSD: store ptr %ap, ptr %[[AP:.*]]
105 // WIN64-LABEL: define dso_local x86_64_sysvcc void @f6
106 // WIN64: store ptr %ap, ptr %[[AP:.*]]
107 int b
= __builtin_va_arg(ap
, int);
108 // FREEBSD: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]
109 // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8
110 // FREEBSD-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]
111 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]
112 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8
113 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]
114 double _Complex c
= __builtin_va_arg(ap
, double _Complex
);
115 // FREEBSD: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]
116 // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8
117 // FREEBSD-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]
118 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]
119 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8
120 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]
121 struct foo d
= __builtin_va_arg(ap
, struct foo
);
122 // FREEBSD: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]
123 // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8
124 // FREEBSD-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]
125 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]
126 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8
127 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]
128 __builtin_ms_va_list ap2
;
129 __builtin_ms_va_copy(ap2
, ap
);
130 // FREEBSD: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]
131 // FREEBSD-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]
132 // WIN64: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]
133 // WIN64-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]
136 // This test checks if structs are passed according to Win64 calling convention
137 // when it's enforced by __attribute((ms_abi)).
139 unsigned long long a
;
140 unsigned long long b
;
143 __attribute__((ms_abi
)) struct i128
f7(struct i128 a
) {
144 // WIN64: define dso_local void @f7(ptr noalias sret(%struct.i128) align 8 %agg.result, ptr noundef %a)
145 // FREEBSD: define{{.*}} win64cc void @f7(ptr noalias sret(%struct.i128) align 8 %agg.result, ptr noundef %a)