Commit 6869bc9ff8

Zen1th <39484230+zenith391@users.noreply.github.com>
2021-11-10 00:56:01
stage2: Add support for floats in the C backend (#10059)
* Implement float type * Fix int and float undefined value * Handle NaN constants, preserving bit pattern
1 parent 0d7359c
Changed files (2)
src
codegen
link
src/codegen/c.zig
@@ -219,11 +219,36 @@ pub const DeclGen = struct {
         val: Value,
     ) error{ OutOfMemory, AnalysisFail }!void {
         if (val.isUndef()) {
-            // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
-            // lower to leaving variables uninitialized (that might need to be implemented
-            // outside of this function).
-            return writer.writeAll("{}");
-            //return dg.fail("TODO: C backend: implement renderValue undef", .{});
+            switch (ty.zigTypeTag()) {
+                // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang)
+                // with 'error: expected expression' (including when built with 'zig cc')
+                .Int => {
+                    const c_bits = toCIntBits(ty.intInfo(dg.module.getTarget()).bits) orelse
+                        return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
+                    switch (c_bits) {
+                        8 => return writer.writeAll("0xaaU"),
+                        16 => return writer.writeAll("0xaaaaU"),
+                        32 => return writer.writeAll("0xaaaaaaaaU"),
+                        64 => return writer.writeAll("0xaaaaaaaaaaaaaaaaUL"),
+                        128 => return writer.writeAll("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaULL"),
+                        else => unreachable,
+                    }
+                },
+                .Float => {
+                    switch (ty.floatBits(dg.module.getTarget())) {
+                        32 => return writer.writeAll("zig_bitcast_f32_u32(0xaaaaaaaa)"),
+                        64 => return writer.writeAll("zig_bitcast_f64_u64(0xaaaaaaaaaaaaaaaa)"),
+                        else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
+                    }
+                },
+
+                else => {
+                    // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
+                    // lower to leaving variables uninitialized (that might need to be implemented
+                    // outside of this function).
+                    return writer.writeAll("{}");
+                },
+            }
         }
         switch (ty.zigTypeTag()) {
             .Int => {
@@ -233,7 +258,16 @@ pub const DeclGen = struct {
             },
             .Float => {
                 if (ty.floatBits(dg.module.getTarget()) <= 64) {
-                    return writer.print("{x}", .{val.toFloat(f64)});
+                    if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) {
+                        // just generate a bit cast (exactly like we do in airBitcast)
+                        switch (ty.tag()) {
+                            .f32 => return writer.print("zig_bitcast_f32_u32(0x{x})", .{@bitCast(u32, val.toFloat(f32))}),
+                            .f64 => return writer.print("zig_bitcast_f64_u64(0x{x})", .{@bitCast(u64, val.toFloat(f64))}),
+                            else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}),
+                        }
+                    } else {
+                        return writer.print("{x}", .{val.toFloat(f64)});
+                    }
                 }
                 return dg.fail("TODO: C backend: implement lowering large float values", .{});
             },
@@ -521,7 +555,16 @@ pub const DeclGen = struct {
                 }
             },
 
-            .Float => return dg.fail("TODO: C backend: implement type Float", .{}),
+            .Float => {
+                switch (t.tag()) {
+                    .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", .{}),
+                    .f128 => return dg.fail("TODO: C backend: implement float type f128", .{}),
+                    else => unreachable,
+                }
+            },
 
             .Pointer => {
                 if (t.isSlice()) {
src/link/C/zig.h
@@ -123,6 +123,7 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <limits.h>
+
 #define int128_t __int128
 #define uint128_t unsigned __int128
 ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t);
@@ -356,6 +357,18 @@ 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));
 }
 
+static inline float zig_bitcast_f32_u32(uint32_t arg) {
+    float dest;
+    memcpy(&dest, &arg, sizeof dest);
+    return dest;
+}
+
+static inline float zig_bitcast_f64_u64(uint64_t arg) {
+    double dest;
+    memcpy(&dest, &arg, sizeof dest);
+    return dest;
+}
+
 #define zig_add_sat_u(ZT, T) static inline T zig_adds_##ZT(T x, T y, T max) { \
     return (x > max - y) ? max : x + y; \
 }