authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-03 13:11:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-03 13:28:51-07:00
loga41f812bdba09fbe6962ba0cf33c0d14ca7f839f
tree1b3bb9784433809f9a73f95de6710db59f1748b9
parentc79bf18044e8dadc64ff97fdf01e99b134d5e31b

C backend: fix lowering of struct types

with fields which are function pointers. Before the name was in the wrong place.

2 files changed, 88 insertions(+), 153 deletions(-)

src/codegen/c.zig+88-82
...@@ -32,6 +32,9 @@ pub const CValue = union(enum) {...@@ -32,6 +32,9 @@ pub const CValue = union(enum) {
32 /// By-value32 /// By-value
33 decl: *Decl,33 decl: *Decl,
34 decl_ref: *Decl,34 decl_ref: *Decl,
35 /// Render these bytes literally.
36 /// TODO make this a [*:0]const u8 to save memory
37 bytes: []const u8,
35};38};
3639
37const BlockData = struct {40const BlockData = struct {
...@@ -120,7 +123,7 @@ pub const Function = struct {...@@ -120,7 +123,7 @@ pub const Function = struct {
120123
121 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {124 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
122 const local_value = f.allocLocalValue();125 const local_value = f.allocLocalValue();
123 try f.object.renderTypeAndName(f.object.writer(), ty, local_value, mutability);126 try f.object.dg.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
124 return local_value;127 return local_value;
125 }128 }
126129
...@@ -131,7 +134,7 @@ pub const Function = struct {...@@ -131,7 +134,7 @@ pub const Function = struct {
131 const val = f.air.value(inst).?;134 const val = f.air.value(inst).?;
132 return f.object.dg.renderValue(w, ty, val);135 return f.object.dg.renderValue(w, ty, val);
133 },136 },
134 else => return Object.writeCValue(w, c_value),137 else => return DeclGen.writeCValue(w, c_value),
135 }138 }
136 }139 }
137140
...@@ -154,82 +157,6 @@ pub const Object = struct {...@@ -154,82 +157,6 @@ pub const Object = struct {
154 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {157 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
155 return o.indent_writer.writer();158 return o.indent_writer.writer();
156 }159 }
157
158 fn writeCValue(w: anytype, c_value: CValue) !void {
159 switch (c_value) {
160 .none => unreachable,
161 .local => |i| return w.print("t{d}", .{i}),
162 .local_ref => |i| return w.print("&t{d}", .{i}),
163 .constant => unreachable,
164 .arg => |i| return w.print("a{d}", .{i}),
165 .decl => |decl| return w.writeAll(mem.span(decl.name)),
166 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
167 }
168 }
169
170 fn renderTypeAndName(
171 o: *Object,
172 w: anytype,
173 ty: Type,
174 name: CValue,
175 mutability: Mutability,
176 ) error{ OutOfMemory, AnalysisFail }!void {
177 var suffix = std.ArrayList(u8).init(o.dg.gpa);
178 defer suffix.deinit();
179
180 var render_ty = ty;
181 while (render_ty.zigTypeTag() == .Array) {
182 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
183 const c_len = render_ty.arrayLen() + sentinel_bit;
184 try suffix.writer().print("[{d}]", .{c_len});
185 render_ty = render_ty.elemType();
186 }
187
188 if (render_ty.zigTypeTag() == .Fn) {
189 const ret_ty = render_ty.fnReturnType();
190 if (ret_ty.zigTypeTag() == .NoReturn) {
191 // noreturn attribute is not allowed here.
192 try w.writeAll("void");
193 } else {
194 try o.dg.renderType(w, ret_ty);
195 }
196 try w.writeAll(" (*");
197 switch (mutability) {
198 .Const => try w.writeAll("const "),
199 .Mut => {},
200 }
201 try writeCValue(w, name);
202 try w.writeAll(")(");
203 const param_len = render_ty.fnParamLen();
204 const is_var_args = render_ty.fnIsVarArgs();
205 if (param_len == 0 and !is_var_args)
206 try w.writeAll("void")
207 else {
208 var index: usize = 0;
209 while (index < param_len) : (index += 1) {
210 if (index > 0) {
211 try w.writeAll(", ");
212 }
213 try o.dg.renderType(w, render_ty.fnParamType(index));
214 }
215 }
216 if (is_var_args) {
217 if (param_len != 0) try w.writeAll(", ");
218 try w.writeAll("...");
219 }
220 try w.writeByte(')');
221 } else {
222 try o.dg.renderType(w, render_ty);
223
224 const const_prefix = switch (mutability) {
225 .Const => "const ",
226 .Mut => "",
227 };
228 try w.print(" {s}", .{const_prefix});
229 try writeCValue(w, name);
230 }
231 try w.writeAll(suffix.items);
232 }
233};160};
234161
235/// This data is available both when outputting .c code and when outputting an .h file.162/// This data is available both when outputting .c code and when outputting an .h file.
...@@ -486,7 +413,7 @@ pub const DeclGen = struct {...@@ -486,7 +413,7 @@ pub const DeclGen = struct {
486 .Struct => {413 .Struct => {
487 const field_vals = val.castTag(.@"struct").?.data;414 const field_vals = val.castTag(.@"struct").?.data;
488415
489 try ty.renderFullyQualifiedName(writer);416 try dg.renderType(writer, ty);
490 try writer.writeAll("{");417 try writer.writeAll("{");
491418
492 for (field_vals) |field_val, i| {419 for (field_vals) |field_val, i| {
...@@ -740,9 +667,11 @@ pub const DeclGen = struct {...@@ -740,9 +667,11 @@ pub const DeclGen = struct {
740 {667 {
741 var it = struct_obj.fields.iterator();668 var it = struct_obj.fields.iterator();
742 while (it.next()) |entry| {669 while (it.next()) |entry| {
670 const field_ty = entry.value_ptr.ty;
671 const name: CValue = .{ .bytes = entry.key_ptr.* };
743 try buffer.append(' ');672 try buffer.append(' ');
744 try dg.renderType(buffer.writer(), entry.value_ptr.ty);673 try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut);
745 try buffer.writer().print(" {s};\n", .{fmtIdent(entry.key_ptr.*)});674 try buffer.appendSlice(";\n");
746 }675 }
747 }676 }
748 try buffer.appendSlice("} ");677 try buffer.appendSlice("} ");
...@@ -808,6 +737,70 @@ pub const DeclGen = struct {...@@ -808,6 +737,70 @@ pub const DeclGen = struct {
808 }737 }
809 }738 }
810739
740 fn renderTypeAndName(
741 dg: *DeclGen,
742 w: anytype,
743 ty: Type,
744 name: CValue,
745 mutability: Mutability,
746 ) error{ OutOfMemory, AnalysisFail }!void {
747 var suffix = std.ArrayList(u8).init(dg.gpa);
748 defer suffix.deinit();
749
750 var render_ty = ty;
751 while (render_ty.zigTypeTag() == .Array) {
752 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
753 const c_len = render_ty.arrayLen() + sentinel_bit;
754 try suffix.writer().print("[{d}]", .{c_len});
755 render_ty = render_ty.elemType();
756 }
757
758 if (render_ty.zigTypeTag() == .Fn) {
759 const ret_ty = render_ty.fnReturnType();
760 if (ret_ty.zigTypeTag() == .NoReturn) {
761 // noreturn attribute is not allowed here.
762 try w.writeAll("void");
763 } else {
764 try dg.renderType(w, ret_ty);
765 }
766 try w.writeAll(" (*");
767 switch (mutability) {
768 .Const => try w.writeAll("const "),
769 .Mut => {},
770 }
771 try writeCValue(w, name);
772 try w.writeAll(")(");
773 const param_len = render_ty.fnParamLen();
774 const is_var_args = render_ty.fnIsVarArgs();
775 if (param_len == 0 and !is_var_args)
776 try w.writeAll("void")
777 else {
778 var index: usize = 0;
779 while (index < param_len) : (index += 1) {
780 if (index > 0) {
781 try w.writeAll(", ");
782 }
783 try dg.renderType(w, render_ty.fnParamType(index));
784 }
785 }
786 if (is_var_args) {
787 if (param_len != 0) try w.writeAll(", ");
788 try w.writeAll("...");
789 }
790 try w.writeByte(')');
791 } else {
792 try dg.renderType(w, render_ty);
793
794 const const_prefix = switch (mutability) {
795 .Const => "const ",
796 .Mut => "",
797 };
798 try w.print(" {s}", .{const_prefix});
799 try writeCValue(w, name);
800 }
801 try w.writeAll(suffix.items);
802 }
803
811 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {804 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
812 switch (tv.val.tag()) {805 switch (tv.val.tag()) {
813 .extern_fn => return true,806 .extern_fn => return true,
...@@ -822,6 +815,19 @@ pub const DeclGen = struct {...@@ -822,6 +815,19 @@ pub const DeclGen = struct {
822 else => unreachable,815 else => unreachable,
823 }816 }
824 }817 }
818
819 fn writeCValue(w: anytype, c_value: CValue) !void {
820 switch (c_value) {
821 .none => unreachable,
822 .local => |i| return w.print("t{d}", .{i}),
823 .local_ref => |i| return w.print("&t{d}", .{i}),
824 .constant => unreachable,
825 .arg => |i| return w.print("a{d}", .{i}),
826 .decl => |decl| return w.writeAll(mem.span(decl.name)),
827 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
828 .bytes => |bytes| return w.writeAll(bytes),
829 }
830 }
825};831};
826832
827pub fn genFunc(f: *Function) !void {833pub fn genFunc(f: *Function) !void {
...@@ -891,7 +897,7 @@ pub fn genDecl(o: *Object) !void {...@@ -891,7 +897,7 @@ pub fn genDecl(o: *Object) !void {
891 // https://github.com/ziglang/zig/issues/7582897 // https://github.com/ziglang/zig/issues/7582
892898
893 const decl_c_value: CValue = .{ .decl = o.dg.decl };899 const decl_c_value: CValue = .{ .decl = o.dg.decl };
894 try o.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);900 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);
895901
896 try writer.writeAll(" = ");902 try writer.writeAll(" = ");
897 try o.dg.renderValue(writer, tv.ty, tv.val);903 try o.dg.renderValue(writer, tv.ty, tv.val);
src/type.zig-71
...@@ -896,77 +896,6 @@ pub const Type = extern union {...@@ -896,77 +896,6 @@ pub const Type = extern union {
896 return Type{ .ptr_otherwise = &new_payload.base };896 return Type{ .ptr_otherwise = &new_payload.base };
897 }897 }
898898
899 pub fn renderFullyQualifiedName(ty: Type, writer: anytype) !void {
900 const t = ty.tag();
901 switch (t) {
902 .u1,
903 .u8,
904 .i8,
905 .u16,
906 .i16,
907 .u32,
908 .i32,
909 .u64,
910 .i64,
911 .u128,
912 .i128,
913 .usize,
914 .isize,
915 .c_short,
916 .c_ushort,
917 .c_int,
918 .c_uint,
919 .c_long,
920 .c_ulong,
921 .c_longlong,
922 .c_ulonglong,
923 .c_longdouble,
924 .c_void,
925 .f16,
926 .f32,
927 .f64,
928 .f128,
929 .bool,
930 .void,
931 .type,
932 .anyerror,
933 .@"anyframe",
934 .comptime_int,
935 .comptime_float,
936 .noreturn,
937 .var_args_param,
938 .bound_fn,
939 => return writer.writeAll(@tagName(t)),
940
941 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
942 .@"null" => return writer.writeAll("@Type(.Null)"),
943 .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
944
945 .@"struct" => {
946 const struct_obj = ty.castTag(.@"struct").?.data;
947 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
948 },
949 .@"union", .union_tagged => {
950 const union_obj = ty.cast(Payload.Union).?.data;
951 return union_obj.owner_decl.renderFullyQualifiedName(writer);
952 },
953 .enum_full, .enum_nonexhaustive => {
954 const enum_full = ty.cast(Payload.EnumFull).?.data;
955 return enum_full.owner_decl.renderFullyQualifiedName(writer);
956 },
957 .enum_simple => {
958 const enum_simple = ty.castTag(.enum_simple).?.data;
959 return enum_simple.owner_decl.renderFullyQualifiedName(writer);
960 },
961 .enum_numbered => {
962 const enum_numbered = ty.castTag(.enum_numbered).?.data;
963 return enum_numbered.owner_decl.renderFullyQualifiedName(writer);
964 },
965 .@"opaque" => @panic("TODO"),
966 else => unreachable,
967 }
968 }
969
970 pub fn format(899 pub fn format(
971 start_type: Type,900 start_type: Type,
972 comptime fmt: []const u8,901 comptime fmt: []const u8,