diff options
| -rw-r--r-- | src-self-hosted/cgen.zig | 71 | ||||
| -rw-r--r-- | src-self-hosted/link.zig | 28 | ||||
| -rw-r--r-- | test/stage2/cbe.zig | 21 |
3 files changed, 95 insertions, 25 deletions
diff --git a/src-self-hosted/cgen.zig b/src-self-hosted/cgen.zig index 48b725c988..99828ee362 100644 --- a/src-self-hosted/cgen.zig +++ b/src-self-hosted/cgen.zig @@ -1,7 +1,9 @@ const link = @import("link.zig"); const Module = @import("Module.zig"); -const std = @import("std"); +const ir = @import("ir.zig"); const Value = @import("value.zig").Value; +const Type = @import("type.zig").Type; +const std = @import("std"); const C = link.File.C; const Decl = Module.Decl; @@ -14,36 +16,69 @@ fn map(name: []const u8) ![]const u8 { return name; } +fn renderFunctionSignature(writer: std.ArrayList(u8).Writer, decl: *Decl) !void { + const tv = decl.typed_value.most_recent.typed_value; + switch (tv.ty.fnReturnType().zigTypeTag()) { + .NoReturn => { + try writer.writeAll("_Noreturn void "); + }, + else => return error.Unimplemented, + } + const name = try map(mem.spanZ(decl.name)); + try writer.print("{}(", .{name}); + if (tv.ty.fnParamLen() == 0) { + try writer.writeAll("void)"); + } else { + return error.Unimplemented; + } +} + pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { - const writer = file.file.?.writer(); + const writer = file.main.writer(); + const header = file.header.writer(); const tv = decl.typed_value.most_recent.typed_value; switch (tv.ty.zigTypeTag()) { .Fn => { - const return_type = tv.ty.fnReturnType(); - switch (return_type.zigTypeTag()) { - .NoReturn => try writer.writeAll("_Noreturn void "), - else => return error.Unimplemented, - } - - const name = try map(mem.spanZ(decl.name)); - try writer.print("{} (", .{name}); - if (tv.ty.fnParamLen() == 0) { - try writer.writeAll("void){"); - } else { - return error.Unimplemented; - } + try renderFunctionSignature(writer, decl); + try writer.writeAll(" {"); const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func; const instructions = func.analysis.success.instructions; if (instructions.len > 0) { - try writer.writeAll("\n\t"); for (instructions) |inst| { - std.debug.warn("\nTranslating {}\n", .{inst.*}); + try writer.writeAll("\n\t"); + switch (inst.tag) { + .call => { + const call = inst.cast(ir.Inst.Call).?.args; + if (call.func.cast(ir.Inst.Constant)) |func_inst| { + if (func_inst.val.cast(Value.Payload.Function)) |func_val| { + const target = func_val.func.owner_decl; + const tname = mem.spanZ(target.name); + if (file.called.get(tname) == null) { + try file.called.put(tname, void{}); + try renderFunctionSignature(header, target); + try header.writeAll(";\n"); + } + try writer.print("{}();", .{tname}); + } else { + return error.Unimplemented; + } + if (call.args.len != 0) { + return error.Unimplemented; + } + } else { + return error.Unimplemented; + } + }, + else => { + std.debug.warn("\nTranslating {}\n", .{inst.*}); + }, + } } try writer.writeAll("\n"); } - try writer.writeAll("}\n"); + try writer.writeAll("}\n\n"); }, else => return error.Unimplemented, } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 98133a4f42..c47e1597c6 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -93,6 +93,9 @@ pub fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C .file = file, .options = options, .owns_file_handle = false, + .main = std.ArrayList(u8).init(allocator), + .header = std.ArrayList(u8).init(allocator), + .called = std.StringHashMap(void).init(allocator), }; errdefer self.deinit(); return self; @@ -165,9 +168,7 @@ pub const File = struct { pub fn flush(base: *File) !void { try switch (base.tag) { .Elf => @fieldParentPtr(Elf, "base", base).flush(), - .C => { - //TODO - }, + .C => @fieldParentPtr(C, "base", base).flush(), else => unreachable, }; } @@ -208,9 +209,12 @@ pub const File = struct { base: File = File{ .tag = base_tag }, allocator: *Allocator, + header: std.ArrayList(u8), + main: std.ArrayList(u8), file: ?fs.File, owns_file_handle: bool, options: Options, + called: std.StringHashMap(void), pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { assert(self.owns_file_handle); @@ -223,6 +227,9 @@ pub const File = struct { } pub fn deinit(self: *File.C) void { + self.main.deinit(); + self.header.deinit(); + self.called.deinit(); if (self.owns_file_handle) { if (self.file) |f| f.close(); @@ -232,6 +239,21 @@ pub const File = struct { pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { try cgen.generate(self, decl, self.options.c_standard.?); } + + pub fn flush(self: *File.C) !void { + const writer = self.file.?.writer(); + if (self.header.items.len > 0) { + try self.header.append('\n'); + } + try writer.writeAll(self.header.items); + if (self.main.items.len > 1) { + const last_two = self.main.items[self.main.items.len - 2 ..]; + if (std.mem.eql(u8, last_two, "\n\n")) { + self.main.items.len -= 1; + } + } + try writer.writeAll(self.main.items); + } }; pub const Elf = struct { diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index 86f966af82..88eb6c5953 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -9,13 +9,26 @@ const linux_x64 = std.zig.CrossTarget{ }; pub fn addCases(ctx: *TestContext) !void { - // These tests should work on every platform ctx.c11("empty start function", linux_x64, \\export fn _start() noreturn {} , - // A newline is always generated after every function; this ensures, among - // other things, that there is always a newline at the end of the file - \\_Noreturn void _start(void) {} + \\_Noreturn void _start(void) {} + \\ + ); + ctx.c11("less empty start function", linux_x64, + \\fn main() noreturn {} + \\ + \\export fn _start() noreturn { + \\ main(); + \\} + , + \\_Noreturn void main(void); + \\ + \\_Noreturn void _start(void) { + \\ main(); + \\} + \\ + \\_Noreturn void main(void) {} \\ ); } |
