| author | |
| committer | |
| log | cf09b335d8b7ad5b43ceefd169b4c2e6be8ed249 |
| tree | 9a0a75d48eb34dc75d75972bfc8362a9a7a83197 |
| parent | cf86aa8772f266cb475711aeee7b0c1b2083e6aa |
| signature |
3 files changed, 95 insertions(+), 25 deletions(-)
src-self-hosted/cgen.zig+53-18| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | const link = @import("link.zig"); |
| 2 | 2 | const Module = @import("Module.zig"); |
| 3 | const std = @import("std"); | |
| 3 | const ir = @import("ir.zig"); | |
| 4 | 4 | const Value = @import("value.zig").Value; |
| 5 | const Type = @import("type.zig").Type; | |
| 6 | const std = @import("std"); | |
| 5 | 7 | |
| 6 | 8 | const C = link.File.C; |
| 7 | 9 | const Decl = Module.Decl; |
| ... | ... | @@ -14,36 +16,69 @@ fn map(name: []const u8) ![]const u8 { |
| 14 | 16 | return name; |
| 15 | 17 | } |
| 16 | 18 | |
| 19 | fn renderFunctionSignature(writer: std.ArrayList(u8).Writer, decl: *Decl) !void { | |
| 20 | const tv = decl.typed_value.most_recent.typed_value; | |
| 21 | switch (tv.ty.fnReturnType().zigTypeTag()) { | |
| 22 | .NoReturn => { | |
| 23 | try writer.writeAll("_Noreturn void "); | |
| 24 | }, | |
| 25 | else => return error.Unimplemented, | |
| 26 | } | |
| 27 | const name = try map(mem.spanZ(decl.name)); | |
| 28 | try writer.print("{}(", .{name}); | |
| 29 | if (tv.ty.fnParamLen() == 0) { | |
| 30 | try writer.writeAll("void)"); | |
| 31 | } else { | |
| 32 | return error.Unimplemented; | |
| 33 | } | |
| 34 | } | |
| 35 | ||
| 17 | 36 | pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { |
| 18 | const writer = file.file.?.writer(); | |
| 37 | const writer = file.main.writer(); | |
| 38 | const header = file.header.writer(); | |
| 19 | 39 | const tv = decl.typed_value.most_recent.typed_value; |
| 20 | 40 | switch (tv.ty.zigTypeTag()) { |
| 21 | 41 | .Fn => { |
| 22 | const return_type = tv.ty.fnReturnType(); | |
| 23 | switch (return_type.zigTypeTag()) { | |
| 24 | .NoReturn => try writer.writeAll("_Noreturn void "), | |
| 25 | else => return error.Unimplemented, | |
| 26 | } | |
| 27 | ||
| 28 | const name = try map(mem.spanZ(decl.name)); | |
| 29 | try writer.print("{} (", .{name}); | |
| 30 | if (tv.ty.fnParamLen() == 0) { | |
| 31 | try writer.writeAll("void){"); | |
| 32 | } else { | |
| 33 | return error.Unimplemented; | |
| 34 | } | |
| 42 | try renderFunctionSignature(writer, decl); | |
| 43 | try writer.writeAll(" {"); | |
| 35 | 44 | |
| 36 | 45 | const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func; |
| 37 | 46 | const instructions = func.analysis.success.instructions; |
| 38 | 47 | if (instructions.len > 0) { |
| 39 | try writer.writeAll("\n\t"); | |
| 40 | 48 | for (instructions) |inst| { |
| 41 | std.debug.warn("\nTranslating {}\n", .{inst.*}); | |
| 49 | try writer.writeAll("\n\t"); | |
| 50 | switch (inst.tag) { | |
| 51 | .call => { | |
| 52 | const call = inst.cast(ir.Inst.Call).?.args; | |
| 53 | if (call.func.cast(ir.Inst.Constant)) |func_inst| { | |
| 54 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | |
| 55 | const target = func_val.func.owner_decl; | |
| 56 | const tname = mem.spanZ(target.name); | |
| 57 | if (file.called.get(tname) == null) { | |
| 58 | try file.called.put(tname, void{}); | |
| 59 | try renderFunctionSignature(header, target); | |
| 60 | try header.writeAll(";\n"); | |
| 61 | } | |
| 62 | try writer.print("{}();", .{tname}); | |
| 63 | } else { | |
| 64 | return error.Unimplemented; | |
| 65 | } | |
| 66 | if (call.args.len != 0) { | |
| 67 | return error.Unimplemented; | |
| 68 | } | |
| 69 | } else { | |
| 70 | return error.Unimplemented; | |
| 71 | } | |
| 72 | }, | |
| 73 | else => { | |
| 74 | std.debug.warn("\nTranslating {}\n", .{inst.*}); | |
| 75 | }, | |
| 76 | } | |
| 42 | 77 | } |
| 43 | 78 | try writer.writeAll("\n"); |
| 44 | 79 | } |
| 45 | 80 | |
| 46 | try writer.writeAll("}\n"); | |
| 81 | try writer.writeAll("}\n\n"); | |
| 47 | 82 | }, |
| 48 | 83 | else => return error.Unimplemented, |
| 49 | 84 | } |
src-self-hosted/link.zig+25-3| ... | ... | @@ -93,6 +93,9 @@ pub fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C |
| 93 | 93 | .file = file, |
| 94 | 94 | .options = options, |
| 95 | 95 | .owns_file_handle = false, |
| 96 | .main = std.ArrayList(u8).init(allocator), | |
| 97 | .header = std.ArrayList(u8).init(allocator), | |
| 98 | .called = std.StringHashMap(void).init(allocator), | |
| 96 | 99 | }; |
| 97 | 100 | errdefer self.deinit(); |
| 98 | 101 | return self; |
| ... | ... | @@ -165,9 +168,7 @@ pub const File = struct { |
| 165 | 168 | pub fn flush(base: *File) !void { |
| 166 | 169 | try switch (base.tag) { |
| 167 | 170 | .Elf => @fieldParentPtr(Elf, "base", base).flush(), |
| 168 | .C => { | |
| 169 | //TODO | |
| 170 | }, | |
| 171 | .C => @fieldParentPtr(C, "base", base).flush(), | |
| 171 | 172 | else => unreachable, |
| 172 | 173 | }; |
| 173 | 174 | } |
| ... | ... | @@ -208,9 +209,12 @@ pub const File = struct { |
| 208 | 209 | base: File = File{ .tag = base_tag }, |
| 209 | 210 | |
| 210 | 211 | allocator: *Allocator, |
| 212 | header: std.ArrayList(u8), | |
| 213 | main: std.ArrayList(u8), | |
| 211 | 214 | file: ?fs.File, |
| 212 | 215 | owns_file_handle: bool, |
| 213 | 216 | options: Options, |
| 217 | called: std.StringHashMap(void), | |
| 214 | 218 | |
| 215 | 219 | pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { |
| 216 | 220 | assert(self.owns_file_handle); |
| ... | ... | @@ -223,6 +227,9 @@ pub const File = struct { |
| 223 | 227 | } |
| 224 | 228 | |
| 225 | 229 | pub fn deinit(self: *File.C) void { |
| 230 | self.main.deinit(); | |
| 231 | self.header.deinit(); | |
| 232 | self.called.deinit(); | |
| 226 | 233 | if (self.owns_file_handle) { |
| 227 | 234 | if (self.file) |f| |
| 228 | 235 | f.close(); |
| ... | ... | @@ -232,6 +239,21 @@ pub const File = struct { |
| 232 | 239 | pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { |
| 233 | 240 | try cgen.generate(self, decl, self.options.c_standard.?); |
| 234 | 241 | } |
| 242 | ||
| 243 | pub fn flush(self: *File.C) !void { | |
| 244 | const writer = self.file.?.writer(); | |
| 245 | if (self.header.items.len > 0) { | |
| 246 | try self.header.append('\n'); | |
| 247 | } | |
| 248 | try writer.writeAll(self.header.items); | |
| 249 | if (self.main.items.len > 1) { | |
| 250 | const last_two = self.main.items[self.main.items.len - 2 ..]; | |
| 251 | if (std.mem.eql(u8, last_two, "\n\n")) { | |
| 252 | self.main.items.len -= 1; | |
| 253 | } | |
| 254 | } | |
| 255 | try writer.writeAll(self.main.items); | |
| 256 | } | |
| 235 | 257 | }; |
| 236 | 258 | |
| 237 | 259 | pub const Elf = struct { |
test/stage2/cbe.zig+17-4| ... | ... | @@ -9,13 +9,26 @@ const linux_x64 = std.zig.CrossTarget{ |
| 9 | 9 | }; |
| 10 | 10 | |
| 11 | 11 | pub fn addCases(ctx: *TestContext) !void { |
| 12 | // These tests should work on every platform | |
| 13 | 12 | ctx.c11("empty start function", linux_x64, |
| 14 | 13 | \\export fn _start() noreturn {} |
| 15 | 14 | , |
| 16 | // A newline is always generated after every function; this ensures, among | |
| 17 | // other things, that there is always a newline at the end of the file | |
| 18 | \\_Noreturn void _start(void) {} | |
| 15 | \\_Noreturn void _start(void) {} | |
| 16 | \\ | |
| 17 | ); | |
| 18 | ctx.c11("less empty start function", linux_x64, | |
| 19 | \\fn main() noreturn {} | |
| 20 | \\ | |
| 21 | \\export fn _start() noreturn { | |
| 22 | \\	main(); | |
| 23 | \\} | |
| 24 | , | |
| 25 | \\_Noreturn void main(void); | |
| 26 | \\ | |
| 27 | \\_Noreturn void _start(void) { | |
| 28 | \\	main(); | |
| 29 | \\} | |
| 30 | \\ | |
| 31 | \\_Noreturn void main(void) {} | |
| 19 | 32 | \\ |
| 20 | 33 | ); |
| 21 | 34 | } |