151 lines · c
1// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 -emit-llvm < %s | FileCheck -check-prefix=FREEBSD %s2// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s3// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s4// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s5// RUN: %clang_cc1 -triple x86_64-uefi -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s6 7struct foo {8 int x;9 float y;10 char z;11};12// FREEBSD: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }13// WIN64: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }14 15void __attribute__((ms_abi)) f1(void);16void __attribute__((sysv_abi)) f2(void);17void f3(void) {18 // FREEBSD-LABEL: define{{.*}} void @f3()19 // WIN64-LABEL: define dso_local void @f3()20 f1();21 // FREEBSD: call win64cc void @f1()22 // WIN64: call void @f1()23 f2();24 // FREEBSD: call void @f2()25 // WIN64: call x86_64_sysvcc void @f2()26}27// FREEBSD: declare win64cc void @f1()28// FREEBSD: declare void @f2()29// WIN64: declare dso_local void @f1()30// WIN64: declare dso_local x86_64_sysvcc void @f2()31 32// Win64 ABI varargs33void __attribute__((ms_abi)) f4(int a, ...) {34 // FREEBSD-LABEL: define{{.*}} win64cc void @f435 // WIN64-LABEL: define dso_local void @f436 __builtin_ms_va_list ap;37 __builtin_ms_va_start(ap, a);38 // FREEBSD: %[[AP:.*]] = alloca ptr39 // FREEBSD: call void @llvm.va_start40 // WIN64: %[[AP:.*]] = alloca ptr41 // WIN64: call void @llvm.va_start42 int b = __builtin_va_arg(ap, int);43 // FREEBSD: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]44 // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 845 // FREEBSD-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]46 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]47 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 848 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]49 double _Complex c = __builtin_va_arg(ap, double _Complex);50 // FREEBSD: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]51 // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 852 // FREEBSD-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]53 // FREEBSD-NEXT: load ptr, ptr %[[AP_CUR2]]54 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]55 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 856 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]57 // WIN64-NEXT: load ptr, ptr %[[AP_CUR2]]58 struct foo d = __builtin_va_arg(ap, struct foo);59 // FREEBSD: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]60 // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 861 // FREEBSD-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]62 // FREEBSD-NEXT: load ptr, ptr %[[AP_CUR3]]63 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]64 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 865 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]66 // WIN64-NEXT: load ptr, ptr %[[AP_CUR3]]67 __builtin_ms_va_list ap2;68 __builtin_ms_va_copy(ap2, ap);69 // FREEBSD: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]70 // FREEBSD-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]71 // WIN64: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]72 // WIN64-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]73 __builtin_ms_va_end(ap);74 // FREEBSD: call void @llvm.va_end75 // WIN64: call void @llvm.va_end76}77 78// Let's verify that normal va_lists work right on Win64, too.79void f5(int a, ...) {80 // WIN64-LABEL: define dso_local void @f581 __builtin_va_list ap;82 __builtin_va_start(ap, a);83 // WIN64: %[[AP:.*]] = alloca ptr84 // WIN64: call void @llvm.va_start85 int b = __builtin_va_arg(ap, int);86 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]87 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 888 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]89 double _Complex c = __builtin_va_arg(ap, double _Complex);90 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]91 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 892 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]93 struct foo d = __builtin_va_arg(ap, struct foo);94 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]95 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 896 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]97 __builtin_va_list ap2;98 __builtin_va_copy(ap2, ap);99 // WIN64: call void @llvm.va_copy100 __builtin_va_end(ap);101 // WIN64: call void @llvm.va_end102}103 104// Verify that using a Win64 va_list from a System V function works.105void __attribute__((sysv_abi)) f6(__builtin_ms_va_list ap) {106 // FREEBSD-LABEL: define{{.*}} void @f6107 // FREEBSD: store ptr %ap, ptr %[[AP:.*]]108 // WIN64-LABEL: define dso_local x86_64_sysvcc void @f6109 // WIN64: store ptr %ap, ptr %[[AP:.*]]110 int b = __builtin_va_arg(ap, int);111 // FREEBSD: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]112 // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8113 // FREEBSD-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]114 // WIN64: %[[AP_CUR:.*]] = load ptr, ptr %[[AP]]115 // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR]], i64 8116 // WIN64-NEXT: store ptr %[[AP_NEXT]], ptr %[[AP]]117 double _Complex c = __builtin_va_arg(ap, double _Complex);118 // FREEBSD: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]119 // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8120 // FREEBSD-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]121 // WIN64: %[[AP_CUR2:.*]] = load ptr, ptr %[[AP]]122 // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR2]], i64 8123 // WIN64-NEXT: store ptr %[[AP_NEXT2]], ptr %[[AP]]124 struct foo d = __builtin_va_arg(ap, struct foo);125 // FREEBSD: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]126 // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8127 // FREEBSD-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]128 // WIN64: %[[AP_CUR3:.*]] = load ptr, ptr %[[AP]]129 // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, ptr %[[AP_CUR3]], i64 8130 // WIN64-NEXT: store ptr %[[AP_NEXT3]], ptr %[[AP]]131 __builtin_ms_va_list ap2;132 __builtin_ms_va_copy(ap2, ap);133 // FREEBSD: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]134 // FREEBSD-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]135 // WIN64: %[[AP_VAL:.*]] = load ptr, ptr %[[AP]]136 // WIN64-NEXT: store ptr %[[AP_VAL]], ptr %[[AP2:.*]]137}138 139// This test checks if structs are passed according to Win64 calling convention140// when it's enforced by __attribute((ms_abi)).141struct i128 {142 unsigned long long a;143 unsigned long long b;144};145 146__attribute__((ms_abi)) struct i128 f7(struct i128 a) {147 // WIN64: define dso_local void @f7(ptr dead_on_unwind noalias writable sret(%struct.i128) align 8 %agg.result, ptr dead_on_return noundef %a)148 // FREEBSD: define{{.*}} win64cc void @f7(ptr dead_on_unwind noalias writable sret(%struct.i128) align 8 %agg.result, ptr dead_on_return noundef %a)149 return a;150}151