Skip to content

Commit bb15e40

Browse files
authored
Merge pull request #14271 from Vexu/c-abi
float related C ABI fixes
2 parents 18191b8 + 0013042 commit bb15e40

File tree

6 files changed

+273
-25
lines changed

6 files changed

+273
-25
lines changed

build.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ pub fn build(b: *Builder) !void {
440440
b.enable_wine,
441441
enable_symlinks_windows,
442442
));
443-
test_step.dependOn(tests.addCAbiTests(b, skip_non_native));
443+
test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release));
444444
test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows));
445445
test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
446446
test_step.dependOn(tests.addCliTests(b, test_filter, modes));

src/arch/x86_64/abi.zig

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,19 @@ const assert = std.debug.assert;
55
const Register = @import("bits.zig").Register;
66
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
77

8-
pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 };
8+
pub const Class = enum {
9+
integer,
10+
sse,
11+
sseup,
12+
x87,
13+
x87up,
14+
complex_x87,
15+
memory,
16+
none,
17+
win_i128,
18+
float,
19+
float_combine,
20+
};
921

1022
pub fn classifyWindows(ty: Type, target: Target) Class {
1123
// https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
@@ -112,26 +124,44 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
112124
return result;
113125
},
114126
.Float => switch (ty.floatBits(target)) {
115-
16, 32, 64 => {
127+
16 => {
128+
if (ctx == .other) {
129+
result[0] = .memory;
130+
} else {
131+
// TODO clang doesn't allow __fp16 as .ret or .arg
132+
result[0] = .sse;
133+
}
134+
return result;
135+
},
136+
32 => {
137+
result[0] = .float;
138+
return result;
139+
},
140+
64 => {
116141
result[0] = .sse;
117142
return result;
118143
},
119144
128 => {
120145
// "Arguments of types__float128, _Decimal128 and__m128 are
121146
// split into two halves. The least significant ones belong
122147
// to class SSE, the most significant one to class SSEUP."
148+
if (ctx == .other) {
149+
result[0] = .memory;
150+
return result;
151+
}
123152
result[0] = .sse;
124153
result[1] = .sseup;
125154
return result;
126155
},
127-
else => {
156+
80 => {
128157
// "The 64-bit mantissa of arguments of type long double
129158
// belongs to classX87, the 16-bit exponent plus 6 bytes
130159
// of padding belongs to class X87UP."
131160
result[0] = .x87;
132161
result[1] = .x87up;
133162
return result;
134163
},
164+
else => unreachable,
135165
},
136166
.Vector => {
137167
const elem_ty = ty.childType();
@@ -238,6 +268,9 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
238268
combine: {
239269
// "If both classes are equal, this is the resulting class."
240270
if (result[result_i] == field_class[0]) {
271+
if (result[result_i] == .float) {
272+
result[result_i] = .float_combine;
273+
}
241274
break :combine;
242275
}
243276

src/codegen/llvm.zig

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
1039510395
.mips, .mipsel => return false,
1039610396
.x86_64 => switch (target.os.tag) {
1039710397
.windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,
10398-
else => return x86_64_abi.classifySystemV(fn_info.return_type, target, .ret)[0] == .memory,
10398+
else => {
10399+
const class = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret);
10400+
if (class[0] == .memory) return true;
10401+
if (class[0] == .x87 and class[2] != .none) return true;
10402+
return false;
10403+
},
1039910404
},
1040010405
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
1040110406
.aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory,
@@ -10469,22 +10474,26 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1046910474
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
1047010475
llvm_types_index += 1;
1047110476
},
10472-
.sse => {
10477+
.sse, .sseup => {
1047310478
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
1047410479
llvm_types_index += 1;
1047510480
},
10476-
.sseup => {
10477-
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
10481+
.float => {
10482+
llvm_types_buffer[llvm_types_index] = dg.context.floatType();
1047810483
llvm_types_index += 1;
1047910484
},
10480-
.x87 => {
10481-
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
10485+
.float_combine => {
10486+
llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2);
1048210487
llvm_types_index += 1;
1048310488
},
10484-
.x87up => {
10489+
.x87 => {
10490+
if (llvm_types_index != 0 or classes[2] != .none) {
10491+
return dg.context.voidType();
10492+
}
1048510493
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
1048610494
llvm_types_index += 1;
1048710495
},
10496+
.x87up => continue,
1048810497
.complex_x87 => {
1048910498
@panic("TODO");
1049010499
},
@@ -10689,22 +10698,25 @@ const ParamTypeIterator = struct {
1068910698
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
1069010699
llvm_types_index += 1;
1069110700
},
10692-
.sse => {
10701+
.sse, .sseup => {
1069310702
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
1069410703
llvm_types_index += 1;
1069510704
},
10696-
.sseup => {
10697-
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
10705+
.float => {
10706+
llvm_types_buffer[llvm_types_index] = dg.context.floatType();
1069810707
llvm_types_index += 1;
1069910708
},
10700-
.x87 => {
10701-
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
10709+
.float_combine => {
10710+
llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2);
1070210711
llvm_types_index += 1;
1070310712
},
10704-
.x87up => {
10705-
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
10706-
llvm_types_index += 1;
10713+
.x87 => {
10714+
it.zig_index += 1;
10715+
it.llvm_index += 1;
10716+
it.byval_attr = true;
10717+
return .byref;
1070710718
},
10719+
.x87up => unreachable,
1070810720
.complex_x87 => {
1070910721
@panic("TODO");
1071010722
},

test/c_abi/cfuncs.c

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <stdlib.h>
55
#include <string.h>
66

7-
void zig_panic();
7+
void zig_panic(void);
88

99
static void assert_or_panic(bool ok) {
1010
if (!ok) {
@@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) {
6060
# define ZIG_NO_COMPLEX
6161
#endif
6262

63+
#ifdef __x86_64__
64+
#define ZIG_NO_RAW_F16
65+
#endif
66+
67+
#ifdef __i386__
68+
#define ZIG_NO_RAW_F16
69+
#endif
70+
71+
#ifdef __mips__
72+
#define ZIG_NO_RAW_F16
73+
#endif
74+
75+
#ifdef __riscv
76+
#define ZIG_NO_RAW_F16
77+
#endif
78+
79+
#ifdef __wasm__
80+
#define ZIG_NO_RAW_F16
81+
#endif
82+
83+
#ifdef __powerpc__
84+
#define ZIG_NO_RAW_F16
85+
#endif
86+
87+
#ifdef __aarch64__
88+
#define ZIG_NO_F128
89+
#endif
90+
91+
#ifdef __arm__
92+
#define ZIG_NO_F128
93+
#endif
94+
95+
#ifdef __mips__
96+
#define ZIG_NO_F128
97+
#endif
98+
99+
#ifdef __riscv
100+
#define ZIG_NO_F128
101+
#endif
102+
103+
#ifdef __powerpc__
104+
#define ZIG_NO_F128
105+
#endif
106+
107+
#ifdef __APPLE__
108+
#define ZIG_NO_F128
109+
#endif
110+
63111
#ifndef ZIG_NO_I128
64112
struct i128 {
65113
__int128 value;
@@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *
884932
assert_or_panic((intptr_t)d == 4);
885933
assert_or_panic(e == 5);
886934
}
935+
936+
#ifndef ZIG_NO_RAW_F16
937+
__fp16 c_f16(__fp16 a) {
938+
assert_or_panic(a == 12);
939+
return 34;
940+
}
941+
#endif
942+
943+
typedef struct {
944+
__fp16 a;
945+
} f16_struct;
946+
f16_struct c_f16_struct(f16_struct a) {
947+
assert_or_panic(a.a == 12);
948+
return (f16_struct){34};
949+
}
950+
951+
#if defined __x86_64__ || defined __i386__
952+
typedef long double f80;
953+
f80 c_f80(f80 a) {
954+
assert_or_panic((double)a == 12.34);
955+
return 56.78;
956+
}
957+
typedef struct {
958+
f80 a;
959+
} f80_struct;
960+
f80_struct c_f80_struct(f80_struct a) {
961+
assert_or_panic((double)a.a == 12.34);
962+
return (f80_struct){56.78};
963+
}
964+
typedef struct {
965+
f80 a;
966+
int b;
967+
} f80_extra_struct;
968+
f80_extra_struct c_f80_extra_struct(f80_extra_struct a) {
969+
assert_or_panic((double)a.a == 12.34);
970+
assert_or_panic(a.b == 42);
971+
return (f80_extra_struct){56.78, 24};
972+
}
973+
#endif
974+
975+
#ifndef ZIG_NO_F128
976+
__float128 c_f128(__float128 a) {
977+
assert_or_panic((double)a == 12.34);
978+
return 56.78;
979+
}
980+
typedef struct {
981+
__float128 a;
982+
} f128_struct;
983+
f128_struct c_f128_struct(f128_struct a) {
984+
assert_or_panic((double)a.a == 12.34);
985+
return (f128_struct){56.78};
986+
}
987+
#endif

0 commit comments

Comments
 (0)