| author | |
| committer | |
| log | 5572c67e73222716372762d30453cc44ca4339c0 |
| tree | b3da065281add01a271a7142297e0423ae1c4610 |
| parent | 474848ac0b6cd026502d85f0f77f0474516e887b |
4 files changed, 215 insertions(+), 24 deletions(-)
src/arch/x86_64/abi.zig+16-2| ... | ... | @@ -112,7 +112,16 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 112 | 112 | return result; |
| 113 | 113 | }, |
| 114 | 114 | .Float => switch (ty.floatBits(target)) { |
| 115 | 16, 32, 64 => { | |
| 115 | 16 => { | |
| 116 | if (ctx == .other) { | |
| 117 | result[0] = .memory; | |
| 118 | } else { | |
| 119 | // TODO clang doesn't allow __fp16 as .ret or .arg | |
| 120 | result[0] = .sse; | |
| 121 | } | |
| 122 | return result; | |
| 123 | }, | |
| 124 | 32, 64 => { | |
| 116 | 125 | result[0] = .sse; |
| 117 | 126 | return result; |
| 118 | 127 | }, |
| ... | ... | @@ -120,11 +129,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 120 | 129 | // "Arguments of types__float128, _Decimal128 and__m128 are |
| 121 | 130 | // split into two halves. The least significant ones belong |
| 122 | 131 | // to class SSE, the most significant one to class SSEUP." |
| 132 | if (ctx == .other) { | |
| 133 | result[0] = .memory; | |
| 134 | return result; | |
| 135 | } | |
| 123 | 136 | result[0] = .sse; |
| 124 | 137 | result[1] = .sseup; |
| 125 | 138 | return result; |
| 126 | 139 | }, |
| 127 | else => { | |
| 140 | 80 => { | |
| 128 | 141 | // "The 64-bit mantissa of arguments of type long double |
| 129 | 142 | // belongs to classX87, the 16-bit exponent plus 6 bytes |
| 130 | 143 | // of padding belongs to class X87UP." |
| ... | ... | @@ -132,6 +145,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 132 | 145 | result[1] = .x87up; |
| 133 | 146 | return result; |
| 134 | 147 | }, |
| 148 | else => unreachable, | |
| 135 | 149 | }, |
| 136 | 150 | .Vector => { |
| 137 | 151 | const elem_ty = ty.childType(); |
src/codegen/llvm.zig+17-21| ... | ... | @@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 10395 | 10395 | .mips, .mipsel => return false, |
| 10396 | 10396 | .x86_64 => switch (target.os.tag) { |
| 10397 | 10397 | .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 | }, | |
| 10399 | 10404 | }, |
| 10400 | 10405 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect, |
| 10401 | 10406 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory, |
| ... | ... | @@ -10469,22 +10474,18 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10469 | 10474 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10470 | 10475 | llvm_types_index += 1; |
| 10471 | 10476 | }, |
| 10472 | .sse => { | |
| 10473 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); | |
| 10474 | llvm_types_index += 1; | |
| 10475 | }, | |
| 10476 | .sseup => { | |
| 10477 | .sse, .sseup => { | |
| 10477 | 10478 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10478 | 10479 | llvm_types_index += 1; |
| 10479 | 10480 | }, |
| 10480 | 10481 | .x87 => { |
| 10482 | if (llvm_types_index != 0 or classes[2] != .none) { | |
| 10483 | return dg.context.voidType(); | |
| 10484 | } | |
| 10481 | 10485 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 10482 | 10486 | llvm_types_index += 1; |
| 10483 | 10487 | }, |
| 10484 | .x87up => { | |
| 10485 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10486 | llvm_types_index += 1; | |
| 10487 | }, | |
| 10488 | .x87up => continue, | |
| 10488 | 10489 | .complex_x87 => { |
| 10489 | 10490 | @panic("TODO"); |
| 10490 | 10491 | }, |
| ... | ... | @@ -10689,22 +10690,17 @@ const ParamTypeIterator = struct { |
| 10689 | 10690 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10690 | 10691 | llvm_types_index += 1; |
| 10691 | 10692 | }, |
| 10692 | .sse => { | |
| 10693 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); | |
| 10694 | llvm_types_index += 1; | |
| 10695 | }, | |
| 10696 | .sseup => { | |
| 10693 | .sse, .sseup => { | |
| 10697 | 10694 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10698 | 10695 | llvm_types_index += 1; |
| 10699 | 10696 | }, |
| 10700 | 10697 | .x87 => { |
| 10701 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10702 | llvm_types_index += 1; | |
| 10703 | }, | |
| 10704 | .x87up => { | |
| 10705 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10706 | llvm_types_index += 1; | |
| 10698 | it.zig_index += 1; | |
| 10699 | it.llvm_index += 1; | |
| 10700 | it.byval_attr = true; | |
| 10701 | return .byref; | |
| 10707 | 10702 | }, |
| 10703 | .x87up => unreachable, | |
| 10708 | 10704 | .complex_x87 => { |
| 10709 | 10705 | @panic("TODO"); |
| 10710 | 10706 | }, |
test/c_abi/cfuncs.c+102-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | #include <stdlib.h> |
| 5 | 5 | #include <string.h> |
| 6 | 6 | |
| 7 | void zig_panic(); | |
| 7 | void zig_panic(void); | |
| 8 | 8 | |
| 9 | 9 | static void assert_or_panic(bool ok) { |
| 10 | 10 | if (!ok) { |
| ... | ... | @@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) { |
| 60 | 60 | # define ZIG_NO_COMPLEX |
| 61 | 61 | #endif |
| 62 | 62 | |
| 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 | ||
| 63 | 111 | #ifndef ZIG_NO_I128 |
| 64 | 112 | struct i128 { |
| 65 | 113 | __int128 value; |
| ... | ... | @@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void * |
| 884 | 932 | assert_or_panic((intptr_t)d == 4); |
| 885 | 933 | assert_or_panic(e == 5); |
| 886 | 934 | } |
| 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 |
test/c_abi/main.zig+80| ... | ... | @@ -13,6 +13,9 @@ const expectEqual = std.testing.expectEqual; |
| 13 | 13 | const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and |
| 14 | 14 | !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC(); |
| 15 | 15 | |
| 16 | const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin(); | |
| 17 | const has_f80 = builtin.cpu.arch.isX86(); | |
| 18 | ||
| 16 | 19 | extern fn run_c_tests() void; |
| 17 | 20 | |
| 18 | 21 | export fn zig_panic() noreturn { |
| ... | ... | @@ -1069,3 +1072,80 @@ test "C function that takes byval struct called via function pointer" { |
| 1069 | 1072 | @as(c_ulong, 5), |
| 1070 | 1073 | ); |
| 1071 | 1074 | } |
| 1075 | ||
| 1076 | extern fn c_f16(f16) f16; | |
| 1077 | test "f16 bare" { | |
| 1078 | if (!comptime builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; | |
| 1079 | ||
| 1080 | const a = c_f16(12); | |
| 1081 | try expect(a == 34); | |
| 1082 | } | |
| 1083 | ||
| 1084 | const f16_struct = extern struct { | |
| 1085 | a: f16, | |
| 1086 | }; | |
| 1087 | extern fn c_f16_struct(f16_struct) f16_struct; | |
| 1088 | test "f16 struct" { | |
| 1089 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1090 | if (comptime builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest; | |
| 1091 | if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest; | |
| 1092 | if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest; | |
| 1093 | if (comptime builtin.cpu.arch.isARM() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 1094 | ||
| 1095 | const a = c_f16_struct(.{ .a = 12 }); | |
| 1096 | try expect(a.a == 34); | |
| 1097 | } | |
| 1098 | ||
| 1099 | extern fn c_f80(f80) f80; | |
| 1100 | test "f80 bare" { | |
| 1101 | if (!has_f80) return error.SkipZigTest; | |
| 1102 | ||
| 1103 | const a = c_f80(12.34); | |
| 1104 | try expect(@floatCast(f64, a) == 56.78); | |
| 1105 | } | |
| 1106 | ||
| 1107 | const f80_struct = extern struct { | |
| 1108 | a: f80, | |
| 1109 | }; | |
| 1110 | extern fn c_f80_struct(f80_struct) f80_struct; | |
| 1111 | test "f80 struct" { | |
| 1112 | if (!has_f80) return error.SkipZigTest; | |
| 1113 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1114 | if (builtin.mode != .Debug) return error.SkipZigTest; | |
| 1115 | ||
| 1116 | const a = c_f80_struct(.{ .a = 12.34 }); | |
| 1117 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1118 | } | |
| 1119 | ||
| 1120 | const f80_extra_struct = extern struct { | |
| 1121 | a: f80, | |
| 1122 | b: c_int, | |
| 1123 | }; | |
| 1124 | extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct; | |
| 1125 | test "f80 extra struct" { | |
| 1126 | if (!has_f80) return error.SkipZigTest; | |
| 1127 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1128 | ||
| 1129 | const a = c_f80_extra_struct(.{ .a = 12.34, .b = 42 }); | |
| 1130 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1131 | try expect(a.b == 24); | |
| 1132 | } | |
| 1133 | ||
| 1134 | extern fn c_f128(f128) f128; | |
| 1135 | test "f128 bare" { | |
| 1136 | if (!has_f128) return error.SkipZigTest; | |
| 1137 | ||
| 1138 | const a = c_f128(12.34); | |
| 1139 | try expect(@floatCast(f64, a) == 56.78); | |
| 1140 | } | |
| 1141 | ||
| 1142 | const f128_struct = extern struct { | |
| 1143 | a: f128, | |
| 1144 | }; | |
| 1145 | extern fn c_f128_struct(f128_struct) f128_struct; | |
| 1146 | test "f128 struct" { | |
| 1147 | if (!has_f128) return error.SkipZigTest; | |
| 1148 | ||
| 1149 | const a = c_f128_struct(.{ .a = 12.34 }); | |
| 1150 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1151 | } |