authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-28 17:46:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-28 17:46:50-07:00
log52056b156b8e8ed848c909e527f0c89435e24deb
tree723e3dba7c22d4f4db2f70cc736c1904b868a903
parent87c6341b61aa54301aa98fea1a449fff40ba25af

stage2: C backend: pointer cast decl refs if necessary


1 files changed, 32 insertions(+), 19 deletions(-)

src/codegen/c.zig+32-19
......@@ -11,6 +11,7 @@ const Type = @import("../type.zig").Type;
1111const C = link.File.C;
1212const Decl = Module.Decl;
1313const mem = std.mem;
14const log = std.log.scoped(.c);
1415
1516const Writer = std.ArrayList(u8).Writer;
1617
......@@ -22,7 +23,6 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
2223
2324fn renderType(
2425 ctx: *Context,
25 header: *C.Header,
2626 writer: Writer,
2727 t: Type,
2828) error{ OutOfMemory, AnalysisFail }!void {
......@@ -80,12 +80,12 @@ fn renderType(
8080 if (t.isVolatilePtr()) {
8181 try writer.writeAll("volatile ");
8282 }
83 try renderType(ctx, header, writer, t.elemType());
83 try renderType(ctx, writer, t.elemType());
8484 try writer.writeAll(" *");
8585 }
8686 },
8787 .Array => {
88 try renderType(ctx, header, writer, t.elemType());
88 try renderType(ctx, writer, t.elemType());
8989 const sentinel_bit = @boolToInt(t.sentinel() != null);
9090 const c_len = t.arrayLen() + sentinel_bit;
9191 try writer.print("[{d}]", .{c_len});
......@@ -113,7 +113,16 @@ fn renderValue(
113113 .one => try writer.writeAll("1"),
114114 .decl_ref => {
115115 const decl_ref_payload = val.cast(Value.Payload.DeclRef).?;
116 try writer.print("&{s}", .{decl_ref_payload.decl.name});
116
117 // Determine if we must pointer cast.
118 const decl_tv = decl_ref_payload.decl.typed_value.most_recent.typed_value;
119 if (t.eql(decl_tv.ty)) {
120 try writer.print("&{s}", .{decl_ref_payload.decl.name});
121 } else {
122 try writer.writeAll("(");
123 try renderType(ctx, writer, t);
124 try writer.print(")&{s}", .{decl_ref_payload.decl.name});
125 }
117126 },
118127 .function => {
119128 const payload = val.cast(Value.Payload.Function).?;
......@@ -155,12 +164,11 @@ fn renderValue(
155164
156165fn renderFunctionSignature(
157166 ctx: *Context,
158 header: *C.Header,
159167 writer: Writer,
160168 decl: *Decl,
161169) !void {
162170 const tv = decl.typed_value.most_recent.typed_value;
163 try renderType(ctx, header, writer, tv.ty.fnReturnType());
171 try renderType(ctx, writer, tv.ty.fnReturnType());
164172 // Use the child allocator directly, as we know the name can be freed before
165173 // the rest of the arena.
166174 const name = try map(ctx.arena.child_allocator, mem.spanZ(decl.name));
......@@ -175,7 +183,7 @@ fn renderFunctionSignature(
175183 if (index > 0) {
176184 try writer.writeAll(", ");
177185 }
178 try renderType(ctx, header, writer, tv.ty.fnParamType(index));
186 try renderType(ctx, writer, tv.ty.fnParamType(index));
179187 try writer.print(" arg{}", .{index});
180188 }
181189 }
......@@ -194,6 +202,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
194202 .arena = &arena,
195203 .inst_map = &inst_map,
196204 .target = file.base.options.target,
205 .header = &file.header,
197206 };
198207 defer {
199208 file.error_msg = ctx.error_msg;
......@@ -202,7 +211,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
202211
203212 if (tv.val.cast(Value.Payload.Function)) |func_payload| {
204213 const writer = file.main.writer();
205 try renderFunctionSignature(&ctx, &file.header, writer, decl);
214 try renderFunctionSignature(&ctx, writer, decl);
206215
207216 try writer.writeAll(" {");
208217
......@@ -211,9 +220,11 @@ pub fn generate(file: *C, decl: *Decl) !void {
211220 if (instructions.len > 0) {
212221 try writer.writeAll("\n");
213222 for (instructions) |inst| {
214 const indent_size = 4;
215 const indent_level = 1;
216 try writer.writeByteNTimes(' ', indent_size * indent_level);
223 if (inst.tag != .dbg_stmt) {
224 const indent_size = 4;
225 const indent_level = 1;
226 try writer.writeByteNTimes(' ', indent_size * indent_level);
227 }
217228 if (switch (inst.tag) {
218229 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
219230 .call => try genCall(&ctx, file, inst.castTag(.call).?),
......@@ -226,7 +237,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
226237 .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?),
227238 .unreach => try genUnreach(file, inst.castTag(.unreach).?),
228239 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
229 else => |e| return ctx.fail(decl.src(), "TODO implement C codegen for {}", .{e}),
240 else => |e| return ctx.fail(decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
230241 }) |name| {
231242 try ctx.inst_map.putNoClobber(inst, name);
232243 }
......@@ -243,7 +254,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
243254 // TODO ask the Decl if it is const
244255 // https://github.com/ziglang/zig/issues/7582
245256
246 try renderType(&ctx, &file.header, writer, tv.ty);
257 try renderType(&ctx, writer, tv.ty);
247258 try writer.print(" {s} = ", .{decl.name});
248259 try renderValue(&ctx, writer, tv.ty, tv.val);
249260 try writer.writeAll(";\n");
......@@ -269,9 +280,10 @@ pub fn generateHeader(
269280 .arena = &arena,
270281 .inst_map = &inst_map,
271282 .target = comp.getTarget(),
283 .header = header,
272284 };
273285 const writer = header.buf.writer();
274 renderFunctionSignature(&ctx, header, writer, decl) catch |err| {
286 renderFunctionSignature(&ctx, writer, decl) catch |err| {
275287 if (err == error.AnalysisFail) {
276288 try module.failed_decls.put(module.gpa, decl, ctx.error_msg);
277289 }
......@@ -291,6 +303,7 @@ const Context = struct {
291303 unnamed_index: usize = 0,
292304 error_msg: *Compilation.ErrorMsg = undefined,
293305 target: std.Target,
306 header: *C.Header,
294307
295308 fn resolveInst(self: *Context, inst: *Inst) ![]u8 {
296309 if (inst.cast(Inst.Constant)) |const_inst| {
......@@ -355,9 +368,9 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
355368 const name = try ctx.name();
356369 const from = try ctx.resolveInst(inst.operand);
357370 try writer.writeAll("const ");
358 try renderType(ctx, &file.header, writer, inst.base.ty);
371 try renderType(ctx, writer, inst.base.ty);
359372 try writer.print(" {} = (", .{name});
360 try renderType(ctx, &file.header, writer, inst.base.ty);
373 try renderType(ctx, writer, inst.base.ty);
361374 try writer.print("){};\n", .{from});
362375 return name;
363376}
......@@ -370,7 +383,7 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, comptime operator: []con
370383 const writer = file.main.writer();
371384 const name = try ctx.name();
372385 try writer.writeAll("const ");
373 try renderType(ctx, &file.header, writer, inst.base.ty);
386 try renderType(ctx, writer, inst.base.ty);
374387 try writer.print(" {} = {} " ++ operator ++ " {};\n", .{ name, lhs, rhs });
375388 return name;
376389}
......@@ -394,7 +407,7 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
394407 const fn_name = mem.spanZ(fn_decl.name);
395408 if (file.called.get(fn_name) == null) {
396409 try file.called.put(fn_name, void{});
397 try renderFunctionSignature(ctx, &file.header, header, fn_decl);
410 try renderFunctionSignature(ctx, header, fn_decl);
398411 try header.writeAll(";\n");
399412 }
400413 try writer.print("{s}(", .{fn_name});
......@@ -440,7 +453,7 @@ fn genAsm(ctx: *Context, file: *C, as: *Inst.Assembly) !?[]u8 {
440453 const reg = i[1 .. i.len - 1];
441454 const arg = as.args[index];
442455 try writer.writeAll("register ");
443 try renderType(ctx, &file.header, writer, arg.ty);
456 try renderType(ctx, writer, arg.ty);
444457 try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg });
445458 // TODO merge constant handling into inst_map as well
446459 if (arg.castTag(.constant)) |c| {