Commit c79bf18044

Andrew Kelley <andrew@ziglang.org>
2021-10-03 21:50:34
C backend: fix lowering of struct, float, and slice constants
1 parent 86c265a
Changed files (2)
src
src/codegen/c.zig
@@ -251,10 +251,42 @@ pub const DeclGen = struct {
         return error.AnalysisFail;
     }
 
+    fn renderDeclValue(
+        dg: *DeclGen,
+        writer: anytype,
+        ty: Type,
+        val: Value,
+        decl: *Decl,
+    ) error{ OutOfMemory, AnalysisFail }!void {
+        decl.alive = true;
+
+        if (ty.isSlice()) {
+            try writer.writeByte('(');
+            try dg.renderType(writer, ty);
+            try writer.writeAll("){");
+            var buf: Type.SlicePtrFieldTypeBuffer = undefined;
+            try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val);
+            try writer.writeAll(", ");
+            try writer.print("{d}", .{val.sliceLen()});
+            try writer.writeAll("}");
+            return;
+        }
+
+        // Determine if we must pointer cast.
+        assert(decl.has_tv);
+        if (ty.eql(decl.ty)) {
+            try writer.print("&{s}", .{decl.name});
+        } else {
+            try writer.writeAll("(");
+            try dg.renderType(writer, ty);
+            try writer.print(")&{s}", .{decl.name});
+        }
+    }
+
     fn renderValue(
         dg: *DeclGen,
         writer: anytype,
-        t: Type,
+        ty: Type,
         val: Value,
     ) error{ OutOfMemory, AnalysisFail }!void {
         if (val.isUndef()) {
@@ -264,50 +296,50 @@ pub const DeclGen = struct {
             return writer.writeAll("{}");
             //return dg.fail("TODO: C backend: implement renderValue undef", .{});
         }
-        switch (t.zigTypeTag()) {
+        switch (ty.zigTypeTag()) {
             .Int => {
-                if (t.isSignedInt())
+                if (ty.isSignedInt())
                     return writer.print("{d}", .{val.toSignedInt()});
                 return writer.print("{d}", .{val.toUnsignedInt()});
             },
-            .Pointer => switch (t.ptrSize()) {
-                .Slice => {
+            .Float => {
+                if (ty.floatBits(dg.module.getTarget()) <= 64) {
+                    return writer.print("{x}", .{val.toFloat(f64)});
+                }
+                return dg.fail("TODO: C backend: implement lowering large float values", .{});
+            },
+            .Pointer => switch (val.tag()) {
+                .null_value, .zero => try writer.writeAll("NULL"),
+                .one => try writer.writeAll("1"),
+                .decl_ref => {
+                    const decl = val.castTag(.decl_ref).?.data;
+                    return dg.renderDeclValue(writer, ty, val, decl);
+                },
+                .variable => {
+                    const decl = val.castTag(.variable).?.data.owner_decl;
+                    return dg.renderDeclValue(writer, ty, val, decl);
+                },
+                .slice => {
+                    const slice = val.castTag(.slice).?.data;
+                    var buf: Type.SlicePtrFieldTypeBuffer = undefined;
+
                     try writer.writeByte('(');
-                    try dg.renderType(writer, t);
+                    try dg.renderType(writer, ty);
                     try writer.writeAll("){");
-                    var buf: Type.SlicePtrFieldTypeBuffer = undefined;
-                    try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
+                    try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr);
                     try writer.writeAll(", ");
-                    try writer.print("{d}", .{val.sliceLen()});
+                    try dg.renderValue(writer, Type.usize, slice.len);
                     try writer.writeAll("}");
                 },
-                else => switch (val.tag()) {
-                    .null_value, .zero => try writer.writeAll("NULL"),
-                    .one => try writer.writeAll("1"),
-                    .decl_ref => {
-                        const decl = val.castTag(.decl_ref).?.data;
-                        decl.alive = true;
-
-                        // Determine if we must pointer cast.
-                        assert(decl.has_tv);
-                        if (t.eql(decl.ty)) {
-                            try writer.print("&{s}", .{decl.name});
-                        } else {
-                            try writer.writeAll("(");
-                            try dg.renderType(writer, t);
-                            try writer.print(")&{s}", .{decl.name});
-                        }
-                    },
-                    .function => {
-                        const func = val.castTag(.function).?.data;
-                        try writer.print("{s}", .{func.owner_decl.name});
-                    },
-                    .extern_fn => {
-                        const decl = val.castTag(.extern_fn).?.data;
-                        try writer.print("{s}", .{decl.name});
-                    },
-                    else => unreachable,
+                .function => {
+                    const func = val.castTag(.function).?.data;
+                    try writer.print("{s}", .{func.owner_decl.name});
                 },
+                .extern_fn => {
+                    const decl = val.castTag(.extern_fn).?.data;
+                    try writer.print("{s}", .{decl.name});
+                },
+                else => unreachable,
             },
             .Array => {
                 // First try specific tag representations for more efficiency.
@@ -325,14 +357,14 @@ pub const DeclGen = struct {
 
                         try writer.writeAll("{");
                         var index: usize = 0;
-                        const len = t.arrayLen();
-                        const elem_ty = t.elemType();
+                        const len = ty.arrayLen();
+                        const elem_ty = ty.elemType();
                         while (index < len) : (index += 1) {
                             if (index != 0) try writer.writeAll(",");
                             const elem_val = try val.elemValue(&arena.allocator, index);
                             try dg.renderValue(writer, elem_ty, elem_val);
                         }
-                        if (t.sentinel()) |sentinel_val| {
+                        if (ty.sentinel()) |sentinel_val| {
                             if (index != 0) try writer.writeAll(",");
                             try dg.renderValue(writer, elem_ty, sentinel_val);
                         }
@@ -343,12 +375,12 @@ pub const DeclGen = struct {
             .Bool => return writer.print("{}", .{val.toBool()}),
             .Optional => {
                 var opt_buf: Type.Payload.ElemType = undefined;
-                const payload_type = t.optionalChild(&opt_buf);
-                if (t.isPtrLikeOptional()) {
+                const payload_type = ty.optionalChild(&opt_buf);
+                if (ty.isPtrLikeOptional()) {
                     return dg.renderValue(writer, payload_type, val);
                 }
                 try writer.writeByte('(');
-                try dg.renderType(writer, t);
+                try dg.renderType(writer, ty);
                 try writer.writeAll("){");
                 if (val.castTag(.opt_payload)) |pl| {
                     const payload_val = pl.data;
@@ -374,8 +406,8 @@ pub const DeclGen = struct {
                 }
             },
             .ErrorUnion => {
-                const error_type = t.errorUnionSet();
-                const payload_type = t.errorUnionPayload();
+                const error_type = ty.errorUnionSet();
+                const payload_type = ty.errorUnionPayload();
 
                 if (!payload_type.hasCodeGenBits()) {
                     // We use the error type directly as the type.
@@ -384,7 +416,7 @@ pub const DeclGen = struct {
                 }
 
                 try writer.writeByte('(');
-                try dg.renderType(writer, t);
+                try dg.renderType(writer, ty);
                 try writer.writeAll("){");
                 if (val.castTag(.eu_payload)) |pl| {
                     const payload_val = pl.data;
@@ -401,10 +433,10 @@ pub const DeclGen = struct {
                 switch (val.tag()) {
                     .enum_field_index => {
                         const field_index = val.castTag(.enum_field_index).?.data;
-                        switch (t.tag()) {
+                        switch (ty.tag()) {
                             .enum_simple => return writer.print("{d}", .{field_index}),
                             .enum_full, .enum_nonexhaustive => {
-                                const enum_full = t.cast(Type.Payload.EnumFull).?.data;
+                                const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
                                 if (enum_full.values.count() != 0) {
                                     const tag_val = enum_full.values.keys()[field_index];
                                     return dg.renderValue(writer, enum_full.tag_ty, tag_val);
@@ -417,7 +449,7 @@ pub const DeclGen = struct {
                     },
                     else => {
                         var int_tag_ty_buffer: Type.Payload.Bits = undefined;
-                        const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
+                        const int_tag_ty = ty.intTagType(&int_tag_ty_buffer);
                         return dg.renderValue(writer, int_tag_ty, val);
                     },
                 }
@@ -431,11 +463,11 @@ pub const DeclGen = struct {
 
                     // Determine if we must pointer cast.
                     assert(decl.has_tv);
-                    if (t.eql(decl.ty)) {
+                    if (ty.eql(decl.ty)) {
                         try writer.print("&{s}", .{decl.name});
                     } else {
                         try writer.writeAll("(");
-                        try dg.renderType(writer, t);
+                        try dg.renderType(writer, ty);
                         try writer.print(")&{s}", .{decl.name});
                     }
                 },
@@ -451,8 +483,40 @@ pub const DeclGen = struct {
                 },
                 else => unreachable,
             },
-            else => |e| return dg.fail("TODO: C backend: implement value {s}", .{
-                @tagName(e),
+            .Struct => {
+                const field_vals = val.castTag(.@"struct").?.data;
+
+                try ty.renderFullyQualifiedName(writer);
+                try writer.writeAll("{");
+
+                for (field_vals) |field_val, i| {
+                    const field_ty = ty.structFieldType(i);
+                    if (!field_ty.hasCodeGenBits()) continue;
+
+                    if (i != 0) try writer.writeAll(",");
+                    try dg.renderValue(writer, field_ty, field_val);
+                }
+
+                try writer.writeAll("}");
+            },
+
+            .ComptimeInt => unreachable,
+            .ComptimeFloat => unreachable,
+            .Type => unreachable,
+            .EnumLiteral => unreachable,
+            .Void => unreachable,
+            .NoReturn => unreachable,
+            .Undefined => unreachable,
+            .Null => unreachable,
+            .BoundFn => unreachable,
+            .Opaque => unreachable,
+
+            .Union,
+            .Frame,
+            .AnyFrame,
+            .Vector,
+            => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
+                @tagName(tag),
             }),
         }
     }
src/codegen/llvm.zig
@@ -1010,7 +1010,7 @@ pub const DeclGen = struct {
                             .val = slice.ptr,
                         }),
                         try self.genTypedValue(.{
-                            .ty = Type.initTag(.usize),
+                            .ty = Type.usize,
                             .val = slice.len,
                         }),
                     };