mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
add C ABI tests for exotic float types
This commit is contained in:
parent
474848ac0b
commit
5572c67e73
4 changed files with 215 additions and 24 deletions
|
|
@ -112,7 +112,16 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
.Float => switch (ty.floatBits(target)) {
|
.Float => switch (ty.floatBits(target)) {
|
||||||
16, 32, 64 => {
|
16 => {
|
||||||
|
if (ctx == .other) {
|
||||||
|
result[0] = .memory;
|
||||||
|
} else {
|
||||||
|
// TODO clang doesn't allow __fp16 as .ret or .arg
|
||||||
|
result[0] = .sse;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
32, 64 => {
|
||||||
result[0] = .sse;
|
result[0] = .sse;
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
@ -120,11 +129,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
|
||||||
// "Arguments of types__float128, _Decimal128 and__m128 are
|
// "Arguments of types__float128, _Decimal128 and__m128 are
|
||||||
// split into two halves. The least significant ones belong
|
// split into two halves. The least significant ones belong
|
||||||
// to class SSE, the most significant one to class SSEUP."
|
// to class SSE, the most significant one to class SSEUP."
|
||||||
|
if (ctx == .other) {
|
||||||
|
result[0] = .memory;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
result[0] = .sse;
|
result[0] = .sse;
|
||||||
result[1] = .sseup;
|
result[1] = .sseup;
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
else => {
|
80 => {
|
||||||
// "The 64-bit mantissa of arguments of type long double
|
// "The 64-bit mantissa of arguments of type long double
|
||||||
// belongs to classX87, the 16-bit exponent plus 6 bytes
|
// belongs to classX87, the 16-bit exponent plus 6 bytes
|
||||||
// of padding belongs to class X87UP."
|
// of padding belongs to class X87UP."
|
||||||
|
|
@ -132,6 +145,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
|
||||||
result[1] = .x87up;
|
result[1] = .x87up;
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.Vector => {
|
.Vector => {
|
||||||
const elem_ty = ty.childType();
|
const elem_ty = ty.childType();
|
||||||
|
|
|
||||||
|
|
@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
|
||||||
.mips, .mipsel => return false,
|
.mips, .mipsel => return false,
|
||||||
.x86_64 => switch (target.os.tag) {
|
.x86_64 => switch (target.os.tag) {
|
||||||
.windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,
|
.windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,
|
||||||
else => return x86_64_abi.classifySystemV(fn_info.return_type, target, .ret)[0] == .memory,
|
else => {
|
||||||
|
const class = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret);
|
||||||
|
if (class[0] == .memory) return true;
|
||||||
|
if (class[0] == .x87 and class[2] != .none) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
|
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
|
||||||
.aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory,
|
.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 {
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
|
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
|
||||||
llvm_types_index += 1;
|
llvm_types_index += 1;
|
||||||
},
|
},
|
||||||
.sse => {
|
.sse, .sseup => {
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
|
||||||
llvm_types_index += 1;
|
|
||||||
},
|
|
||||||
.sseup => {
|
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
||||||
llvm_types_index += 1;
|
llvm_types_index += 1;
|
||||||
},
|
},
|
||||||
.x87 => {
|
.x87 => {
|
||||||
|
if (llvm_types_index != 0 or classes[2] != .none) {
|
||||||
|
return dg.context.voidType();
|
||||||
|
}
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
|
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
|
||||||
llvm_types_index += 1;
|
llvm_types_index += 1;
|
||||||
},
|
},
|
||||||
.x87up => {
|
.x87up => continue,
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
|
|
||||||
llvm_types_index += 1;
|
|
||||||
},
|
|
||||||
.complex_x87 => {
|
.complex_x87 => {
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
},
|
},
|
||||||
|
|
@ -10689,22 +10690,17 @@ const ParamTypeIterator = struct {
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
|
llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
|
||||||
llvm_types_index += 1;
|
llvm_types_index += 1;
|
||||||
},
|
},
|
||||||
.sse => {
|
.sse, .sseup => {
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
|
||||||
llvm_types_index += 1;
|
|
||||||
},
|
|
||||||
.sseup => {
|
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
|
||||||
llvm_types_index += 1;
|
llvm_types_index += 1;
|
||||||
},
|
},
|
||||||
.x87 => {
|
.x87 => {
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
|
it.zig_index += 1;
|
||||||
llvm_types_index += 1;
|
it.llvm_index += 1;
|
||||||
},
|
it.byval_attr = true;
|
||||||
.x87up => {
|
return .byref;
|
||||||
llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
|
|
||||||
llvm_types_index += 1;
|
|
||||||
},
|
},
|
||||||
|
.x87up => unreachable,
|
||||||
.complex_x87 => {
|
.complex_x87 => {
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void zig_panic();
|
void zig_panic(void);
|
||||||
|
|
||||||
static void assert_or_panic(bool ok) {
|
static void assert_or_panic(bool ok) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
|
@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) {
|
||||||
# define ZIG_NO_COMPLEX
|
# define ZIG_NO_COMPLEX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mips__
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __riscv
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __wasm__
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
#define ZIG_NO_RAW_F16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __mips__
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __riscv
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define ZIG_NO_F128
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ZIG_NO_I128
|
#ifndef ZIG_NO_I128
|
||||||
struct i128 {
|
struct i128 {
|
||||||
__int128 value;
|
__int128 value;
|
||||||
|
|
@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *
|
||||||
assert_or_panic((intptr_t)d == 4);
|
assert_or_panic((intptr_t)d == 4);
|
||||||
assert_or_panic(e == 5);
|
assert_or_panic(e == 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ZIG_NO_RAW_F16
|
||||||
|
__fp16 c_f16(__fp16 a) {
|
||||||
|
assert_or_panic(a == 12);
|
||||||
|
return 34;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__fp16 a;
|
||||||
|
} f16_struct;
|
||||||
|
f16_struct c_f16_struct(f16_struct a) {
|
||||||
|
assert_or_panic(a.a == 12);
|
||||||
|
return (f16_struct){34};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined __x86_64__ || defined __i386__
|
||||||
|
typedef long double f80;
|
||||||
|
f80 c_f80(f80 a) {
|
||||||
|
assert_or_panic((double)a == 12.34);
|
||||||
|
return 56.78;
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
f80 a;
|
||||||
|
} f80_struct;
|
||||||
|
f80_struct c_f80_struct(f80_struct a) {
|
||||||
|
assert_or_panic((double)a.a == 12.34);
|
||||||
|
return (f80_struct){56.78};
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
f80 a;
|
||||||
|
int b;
|
||||||
|
} f80_extra_struct;
|
||||||
|
f80_extra_struct c_f80_extra_struct(f80_extra_struct a) {
|
||||||
|
assert_or_panic((double)a.a == 12.34);
|
||||||
|
assert_or_panic(a.b == 42);
|
||||||
|
return (f80_extra_struct){56.78, 24};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZIG_NO_F128
|
||||||
|
__float128 c_f128(__float128 a) {
|
||||||
|
assert_or_panic((double)a == 12.34);
|
||||||
|
return 56.78;
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
__float128 a;
|
||||||
|
} f128_struct;
|
||||||
|
f128_struct c_f128_struct(f128_struct a) {
|
||||||
|
assert_or_panic((double)a.a == 12.34);
|
||||||
|
return (f128_struct){56.78};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ const expectEqual = std.testing.expectEqual;
|
||||||
const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and
|
const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and
|
||||||
!builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
|
!builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
|
||||||
|
|
||||||
|
const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin();
|
||||||
|
const has_f80 = builtin.cpu.arch.isX86();
|
||||||
|
|
||||||
extern fn run_c_tests() void;
|
extern fn run_c_tests() void;
|
||||||
|
|
||||||
export fn zig_panic() noreturn {
|
export fn zig_panic() noreturn {
|
||||||
|
|
@ -1069,3 +1072,80 @@ test "C function that takes byval struct called via function pointer" {
|
||||||
@as(c_ulong, 5),
|
@as(c_ulong, 5),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn c_f16(f16) f16;
|
||||||
|
test "f16 bare" {
|
||||||
|
if (!comptime builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f16(12);
|
||||||
|
try expect(a == 34);
|
||||||
|
}
|
||||||
|
|
||||||
|
const f16_struct = extern struct {
|
||||||
|
a: f16,
|
||||||
|
};
|
||||||
|
extern fn c_f16_struct(f16_struct) f16_struct;
|
||||||
|
test "f16 struct" {
|
||||||
|
if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
|
||||||
|
if (comptime builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest;
|
||||||
|
if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
|
if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
|
if (comptime builtin.cpu.arch.isARM() and builtin.mode != .Debug) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f16_struct(.{ .a = 12 });
|
||||||
|
try expect(a.a == 34);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn c_f80(f80) f80;
|
||||||
|
test "f80 bare" {
|
||||||
|
if (!has_f80) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f80(12.34);
|
||||||
|
try expect(@floatCast(f64, a) == 56.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
const f80_struct = extern struct {
|
||||||
|
a: f80,
|
||||||
|
};
|
||||||
|
extern fn c_f80_struct(f80_struct) f80_struct;
|
||||||
|
test "f80 struct" {
|
||||||
|
if (!has_f80) return error.SkipZigTest;
|
||||||
|
if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
|
||||||
|
if (builtin.mode != .Debug) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f80_struct(.{ .a = 12.34 });
|
||||||
|
try expect(@floatCast(f64, a.a) == 56.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
const f80_extra_struct = extern struct {
|
||||||
|
a: f80,
|
||||||
|
b: c_int,
|
||||||
|
};
|
||||||
|
extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct;
|
||||||
|
test "f80 extra struct" {
|
||||||
|
if (!has_f80) return error.SkipZigTest;
|
||||||
|
if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f80_extra_struct(.{ .a = 12.34, .b = 42 });
|
||||||
|
try expect(@floatCast(f64, a.a) == 56.78);
|
||||||
|
try expect(a.b == 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn c_f128(f128) f128;
|
||||||
|
test "f128 bare" {
|
||||||
|
if (!has_f128) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f128(12.34);
|
||||||
|
try expect(@floatCast(f64, a) == 56.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
const f128_struct = extern struct {
|
||||||
|
a: f128,
|
||||||
|
};
|
||||||
|
extern fn c_f128_struct(f128_struct) f128_struct;
|
||||||
|
test "f128 struct" {
|
||||||
|
if (!has_f128) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const a = c_f128_struct(.{ .a = 12.34 });
|
||||||
|
try expect(@floatCast(f64, a.a) == 56.78);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue