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;...@@ -11,6 +11,7 @@ const Type = @import("../type.zig").Type;
11const C = link.File.C;11const C = link.File.C;
12const Decl = Module.Decl;12const Decl = Module.Decl;
13const mem = std.mem;13const mem = std.mem;
14const log = std.log.scoped(.c);
1415
15const Writer = std.ArrayList(u8).Writer;16const Writer = std.ArrayList(u8).Writer;
1617
...@@ -22,7 +23,6 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {...@@ -22,7 +23,6 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
2223
23fn renderType(24fn renderType(
24 ctx: *Context,25 ctx: *Context,
25 header: *C.Header,
26 writer: Writer,26 writer: Writer,
27 t: Type,27 t: Type,
28) error{ OutOfMemory, AnalysisFail }!void {28) error{ OutOfMemory, AnalysisFail }!void {
...@@ -80,12 +80,12 @@ fn renderType(...@@ -80,12 +80,12 @@ fn renderType(
80 if (t.isVolatilePtr()) {80 if (t.isVolatilePtr()) {
81 try writer.writeAll("volatile ");81 try writer.writeAll("volatile ");
82 }82 }
83 try renderType(ctx, header, writer, t.elemType());83 try renderType(ctx, writer, t.elemType());
84 try writer.writeAll(" *");84 try writer.writeAll(" *");
85 }85 }
86 },86 },
87 .Array => {87 .Array => {
88 try renderType(ctx, header, writer, t.elemType());88 try renderType(ctx, writer, t.elemType());
89 const sentinel_bit = @boolToInt(t.sentinel() != null);89 const sentinel_bit = @boolToInt(t.sentinel() != null);
90 const c_len = t.arrayLen() + sentinel_bit;90 const c_len = t.arrayLen() + sentinel_bit;
91 try writer.print("[{d}]", .{c_len});91 try writer.print("[{d}]", .{c_len});
...@@ -113,7 +113,16 @@ fn renderValue(...@@ -113,7 +113,16 @@ fn renderValue(
113 .one => try writer.writeAll("1"),113 .one => try writer.writeAll("1"),
114 .decl_ref => {114 .decl_ref => {
115 const decl_ref_payload = val.cast(Value.Payload.DeclRef).?;115 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 }
117 },126 },
118 .function => {127 .function => {
119 const payload = val.cast(Value.Payload.Function).?;128 const payload = val.cast(Value.Payload.Function).?;
...@@ -155,12 +164,11 @@ fn renderValue(...@@ -155,12 +164,11 @@ fn renderValue(
155164
156fn renderFunctionSignature(165fn renderFunctionSignature(
157 ctx: *Context,166 ctx: *Context,
158 header: *C.Header,
159 writer: Writer,167 writer: Writer,
160 decl: *Decl,168 decl: *Decl,
161) !void {169) !void {
162 const tv = decl.typed_value.most_recent.typed_value;170 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());
164 // Use the child allocator directly, as we know the name can be freed before172 // Use the child allocator directly, as we know the name can be freed before
165 // the rest of the arena.173 // the rest of the arena.
166 const name = try map(ctx.arena.child_allocator, mem.spanZ(decl.name));174 const name = try map(ctx.arena.child_allocator, mem.spanZ(decl.name));
...@@ -175,7 +183,7 @@ fn renderFunctionSignature(...@@ -175,7 +183,7 @@ fn renderFunctionSignature(
175 if (index > 0) {183 if (index > 0) {
176 try writer.writeAll(", ");184 try writer.writeAll(", ");
177 }185 }
178 try renderType(ctx, header, writer, tv.ty.fnParamType(index));186 try renderType(ctx, writer, tv.ty.fnParamType(index));
179 try writer.print(" arg{}", .{index});187 try writer.print(" arg{}", .{index});
180 }188 }
181 }189 }
...@@ -194,6 +202,7 @@ pub fn generate(file: *C, decl: *Decl) !void {...@@ -194,6 +202,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
194 .arena = &arena,202 .arena = &arena,
195 .inst_map = &inst_map,203 .inst_map = &inst_map,
196 .target = file.base.options.target,204 .target = file.base.options.target,
205 .header = &file.header,
197 };206 };
198 defer {207 defer {
199 file.error_msg = ctx.error_msg;208 file.error_msg = ctx.error_msg;
...@@ -202,7 +211,7 @@ pub fn generate(file: *C, decl: *Decl) !void {...@@ -202,7 +211,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
202211
203 if (tv.val.cast(Value.Payload.Function)) |func_payload| {212 if (tv.val.cast(Value.Payload.Function)) |func_payload| {
204 const writer = file.main.writer();213 const writer = file.main.writer();
205 try renderFunctionSignature(&ctx, &file.header, writer, decl);214 try renderFunctionSignature(&ctx, writer, decl);
206215
207 try writer.writeAll(" {");216 try writer.writeAll(" {");
208217
...@@ -211,9 +220,11 @@ pub fn generate(file: *C, decl: *Decl) !void {...@@ -211,9 +220,11 @@ pub fn generate(file: *C, decl: *Decl) !void {
211 if (instructions.len > 0) {220 if (instructions.len > 0) {
212 try writer.writeAll("\n");221 try writer.writeAll("\n");
213 for (instructions) |inst| {222 for (instructions) |inst| {
214 const indent_size = 4;223 if (inst.tag != .dbg_stmt) {
215 const indent_level = 1;224 const indent_size = 4;
216 try writer.writeByteNTimes(' ', indent_size * indent_level);225 const indent_level = 1;
226 try writer.writeByteNTimes(' ', indent_size * indent_level);
227 }
217 if (switch (inst.tag) {228 if (switch (inst.tag) {
218 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),229 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
219 .call => try genCall(&ctx, file, inst.castTag(.call).?),230 .call => try genCall(&ctx, file, inst.castTag(.call).?),
...@@ -226,7 +237,7 @@ pub fn generate(file: *C, decl: *Decl) !void {...@@ -226,7 +237,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
226 .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?),237 .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?),
227 .unreach => try genUnreach(file, inst.castTag(.unreach).?),238 .unreach => try genUnreach(file, inst.castTag(.unreach).?),
228 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),239 .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}),
230 }) |name| {241 }) |name| {
231 try ctx.inst_map.putNoClobber(inst, name);242 try ctx.inst_map.putNoClobber(inst, name);
232 }243 }
...@@ -243,7 +254,7 @@ pub fn generate(file: *C, decl: *Decl) !void {...@@ -243,7 +254,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
243 // TODO ask the Decl if it is const254 // TODO ask the Decl if it is const
244 // https://github.com/ziglang/zig/issues/7582255 // https://github.com/ziglang/zig/issues/7582
245256
246 try renderType(&ctx, &file.header, writer, tv.ty);257 try renderType(&ctx, writer, tv.ty);
247 try writer.print(" {s} = ", .{decl.name});258 try writer.print(" {s} = ", .{decl.name});
248 try renderValue(&ctx, writer, tv.ty, tv.val);259 try renderValue(&ctx, writer, tv.ty, tv.val);
249 try writer.writeAll(";\n");260 try writer.writeAll(";\n");
...@@ -269,9 +280,10 @@ pub fn generateHeader(...@@ -269,9 +280,10 @@ pub fn generateHeader(
269 .arena = &arena,280 .arena = &arena,
270 .inst_map = &inst_map,281 .inst_map = &inst_map,
271 .target = comp.getTarget(),282 .target = comp.getTarget(),
283 .header = header,
272 };284 };
273 const writer = header.buf.writer();285 const writer = header.buf.writer();
274 renderFunctionSignature(&ctx, header, writer, decl) catch |err| {286 renderFunctionSignature(&ctx, writer, decl) catch |err| {
275 if (err == error.AnalysisFail) {287 if (err == error.AnalysisFail) {
276 try module.failed_decls.put(module.gpa, decl, ctx.error_msg);288 try module.failed_decls.put(module.gpa, decl, ctx.error_msg);
277 }289 }
...@@ -291,6 +303,7 @@ const Context = struct {...@@ -291,6 +303,7 @@ const Context = struct {
291 unnamed_index: usize = 0,303 unnamed_index: usize = 0,
292 error_msg: *Compilation.ErrorMsg = undefined,304 error_msg: *Compilation.ErrorMsg = undefined,
293 target: std.Target,305 target: std.Target,
306 header: *C.Header,
294307
295 fn resolveInst(self: *Context, inst: *Inst) ![]u8 {308 fn resolveInst(self: *Context, inst: *Inst) ![]u8 {
296 if (inst.cast(Inst.Constant)) |const_inst| {309 if (inst.cast(Inst.Constant)) |const_inst| {
...@@ -355,9 +368,9 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {...@@ -355,9 +368,9 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
355 const name = try ctx.name();368 const name = try ctx.name();
356 const from = try ctx.resolveInst(inst.operand);369 const from = try ctx.resolveInst(inst.operand);
357 try writer.writeAll("const ");370 try writer.writeAll("const ");
358 try renderType(ctx, &file.header, writer, inst.base.ty);371 try renderType(ctx, writer, inst.base.ty);
359 try writer.print(" {} = (", .{name});372 try writer.print(" {} = (", .{name});
360 try renderType(ctx, &file.header, writer, inst.base.ty);373 try renderType(ctx, writer, inst.base.ty);
361 try writer.print("){};\n", .{from});374 try writer.print("){};\n", .{from});
362 return name;375 return name;
363}376}
...@@ -370,7 +383,7 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, comptime operator: []con...@@ -370,7 +383,7 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, comptime operator: []con
370 const writer = file.main.writer();383 const writer = file.main.writer();
371 const name = try ctx.name();384 const name = try ctx.name();
372 try writer.writeAll("const ");385 try writer.writeAll("const ");
373 try renderType(ctx, &file.header, writer, inst.base.ty);386 try renderType(ctx, writer, inst.base.ty);
374 try writer.print(" {} = {} " ++ operator ++ " {};\n", .{ name, lhs, rhs });387 try writer.print(" {} = {} " ++ operator ++ " {};\n", .{ name, lhs, rhs });
375 return name;388 return name;
376}389}
...@@ -394,7 +407,7 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {...@@ -394,7 +407,7 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
394 const fn_name = mem.spanZ(fn_decl.name);407 const fn_name = mem.spanZ(fn_decl.name);
395 if (file.called.get(fn_name) == null) {408 if (file.called.get(fn_name) == null) {
396 try file.called.put(fn_name, void{});409 try file.called.put(fn_name, void{});
397 try renderFunctionSignature(ctx, &file.header, header, fn_decl);410 try renderFunctionSignature(ctx, header, fn_decl);
398 try header.writeAll(";\n");411 try header.writeAll(";\n");
399 }412 }
400 try writer.print("{s}(", .{fn_name});413 try writer.print("{s}(", .{fn_name});
...@@ -440,7 +453,7 @@ fn genAsm(ctx: *Context, file: *C, as: *Inst.Assembly) !?[]u8 {...@@ -440,7 +453,7 @@ fn genAsm(ctx: *Context, file: *C, as: *Inst.Assembly) !?[]u8 {
440 const reg = i[1 .. i.len - 1];453 const reg = i[1 .. i.len - 1];
441 const arg = as.args[index];454 const arg = as.args[index];
442 try writer.writeAll("register ");455 try writer.writeAll("register ");
443 try renderType(ctx, &file.header, writer, arg.ty);456 try renderType(ctx, writer, arg.ty);
444 try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg });457 try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg });
445 // TODO merge constant handling into inst_map as well458 // TODO merge constant handling into inst_map as well
446 if (arg.castTag(.constant)) |c| {459 if (arg.castTag(.constant)) |c| {