From 8baf976ea89110a1e0e5ed27b91605c1ed499244 Mon Sep 17 00:00:00 2001 From: Jean Dao Date: Wed, 2 Feb 2022 18:53:12 +0100 Subject: [PATCH] C backend: better f16 support --- src/codegen/c.zig | 11 +++++------ src/link/C/zig.h | 21 +++++++++++++++++++++ test/behavior/floatop.zig | 11 +++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 763b15366fbd..03eef276a22a 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -525,7 +525,6 @@ pub const DeclGen = struct { } fn renderSmallFloat( - dg: *DeclGen, comptime T: type, writer: anytype, val: Value, @@ -534,7 +533,7 @@ pub const DeclGen = struct { if (std.math.isNan(v) or std.math.isInf(v)) { // just generate a bit cast (exactly like we do in airBitcast) switch (T) { - f16 => return dg.fail("TODO: C backend: implement 16-bit float lowering", .{}), + f16 => return writer.print("zig_bitcast_f16_u16(0x{x})", .{v}), f32 => return writer.print("zig_bitcast_f32_u32(0x{x})", .{v}), f64 => return writer.print("zig_bitcast_f64_u64(0x{x})", .{v}), else => unreachable, @@ -607,9 +606,9 @@ pub const DeclGen = struct { }, .Float => { switch (ty.tag()) { - .f16 => return dg.renderSmallFloat(f16, writer, val), - .f32 => return dg.renderSmallFloat(f32, writer, val), - .f64 => return dg.renderSmallFloat(f64, writer, val), + .f16 => return renderSmallFloat(f16, writer, val), + .f32 => return renderSmallFloat(f32, writer, val), + .f64 => return renderSmallFloat(f64, writer, val), .f128 => return renderFloat128(writer, val.toFloat(f128)), else => unreachable, } @@ -1241,7 +1240,7 @@ pub const DeclGen = struct { .f32 => try w.writeAll("float"), .f64 => try w.writeAll("double"), .c_longdouble => try w.writeAll("long double"), - .f16 => return dg.fail("TODO: C backend: implement float type f16", .{}), + .f16 => try w.writeAll("float16_t"), .f128 => try w.writeAll("float128_t"), else => unreachable, } diff --git a/src/link/C/zig.h b/src/link/C/zig.h index 93f710a43331..83ba40d8c7f8 100644 --- a/src/link/C/zig.h +++ b/src/link/C/zig.h @@ -174,6 +174,19 @@ #define float128_t __float128 #endif +#if defined(__clang__) +#define ZIG_HAS_FLOAT16 +#define float16_t __fp16 +#elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__)) +#define ZIG_HAS_FLOAT16 +#define float16_t __fp16 +#elif defined(__GNUC__) && defined(__i386__) && defined(__SSE2__) +#define ZIG_HAS_FLOAT16 +#define float16_t _Float16 +#else +#define float16_t float16_t_is_not_supported_on_this_target +#endif + ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t); ZIG_EXTERN_C void *memset (void *, int, size_t); @@ -405,6 +418,14 @@ static inline long long zig_subw_longlong(long long lhs, long long rhs, long lon return (long long)(((unsigned long long)lhs) - ((unsigned long long)rhs)); } +#if defined(ZIG_HAS_FLOAT16) +static inline float zig_bitcast_f16_u16(uint16_t arg) { + float16_t dest; + memcpy(&dest, &arg, sizeof dest); + return dest; +} +#endif + static inline float zig_bitcast_f32_u32(uint32_t arg) { float dest; memcpy(&dest, &arg, sizeof dest); diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 63ed28277747..9135dfb13630 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -698,6 +698,17 @@ test "f128 at compile time is lossy" { try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); } +test "f16 literals" { + var buf: f16 = math.f16_min; + try expect(math.f16_min == buf); + + buf = math.f16_max; + try expect(math.f16_max == buf); + + buf = 0; + try expect(@as(f16, 0) == buf); +} + test "f128 tests" { if (builtin.zig_backend != .stage2_c) return error.SkipZigTest; // TODO