| author | |
| committer | |
| log | cf09b335d8b7ad5b43ceefd169b4c2e6be8ed249 |
| tree | 9a0a75d48eb34dc75d75972bfc8362a9a7a83197 |
| parent | cf86aa8772f266cb475711aeee7b0c1b2083e6aa |
| signature | Commit is signed but in an unrecognized format. |
3 files changed, 95 insertions(+), 25 deletions(-)
src-self-hosted/cgen.zig+53-18| ... | @@ -1,7 +1,9 @@ | ... | @@ -1,7 +1,9 @@ |
| 1 | const link = @import("link.zig"); | 1 | const link = @import("link.zig"); |
| 2 | const Module = @import("Module.zig"); | 2 | const Module = @import("Module.zig"); |
| 3 | const std = @import("std"); | 3 | const ir = @import("ir.zig"); |
| 4 | const Value = @import("value.zig").Value; | 4 | const Value = @import("value.zig").Value; |
| 5 | const Type = @import("type.zig").Type; | ||
| 6 | const std = @import("std"); | ||
| 5 | 7 | ||
| 6 | const C = link.File.C; | 8 | const C = link.File.C; |
| 7 | const Decl = Module.Decl; | 9 | const Decl = Module.Decl; |
| ... | @@ -14,36 +16,69 @@ fn map(name: []const u8) ![]const u8 { | ... | @@ -14,36 +16,69 @@ fn map(name: []const u8) ![]const u8 { |
| 14 | return name; | 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 | pub fn generate(file: *C, decl: *Decl, standard: CStandard) !void { | 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 | const tv = decl.typed_value.most_recent.typed_value; | 39 | const tv = decl.typed_value.most_recent.typed_value; |
| 20 | switch (tv.ty.zigTypeTag()) { | 40 | switch (tv.ty.zigTypeTag()) { |
| 21 | .Fn => { | 41 | .Fn => { |
| 22 | const return_type = tv.ty.fnReturnType(); | 42 | try renderFunctionSignature(writer, decl); |
| 23 | switch (return_type.zigTypeTag()) { | 43 | try writer.writeAll(" {"); |
| 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 | } | ||
| 35 | 44 | ||
| 36 | const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func; | 45 | const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func; |
| 37 | const instructions = func.analysis.success.instructions; | 46 | const instructions = func.analysis.success.instructions; |
| 38 | if (instructions.len > 0) { | 47 | if (instructions.len > 0) { |
| 39 | try writer.writeAll("\n\t"); | ||
| 40 | for (instructions) |inst| { | 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 | try writer.writeAll("\n"); | 78 | try writer.writeAll("\n"); |
| 44 | } | 79 | } |
| 45 | 80 | ||
| 46 | try writer.writeAll("}\n"); | 81 | try writer.writeAll("}\n\n"); |
| 47 | }, | 82 | }, |
| 48 | else => return error.Unimplemented, | 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,6 +93,9 @@ pub fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C |
| 93 | .file = file, | 93 | .file = file, |
| 94 | .options = options, | 94 | .options = options, |
| 95 | .owns_file_handle = false, | 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 | errdefer self.deinit(); | 100 | errdefer self.deinit(); |
| 98 | return self; | 101 | return self; |
| ... | @@ -165,9 +168,7 @@ pub const File = struct { | ... | @@ -165,9 +168,7 @@ pub const File = struct { |
| 165 | pub fn flush(base: *File) !void { | 168 | pub fn flush(base: *File) !void { |
| 166 | try switch (base.tag) { | 169 | try switch (base.tag) { |
| 167 | .Elf => @fieldParentPtr(Elf, "base", base).flush(), | 170 | .Elf => @fieldParentPtr(Elf, "base", base).flush(), |
| 168 | .C => { | 171 | .C => @fieldParentPtr(C, "base", base).flush(), |
| 169 | //TODO | ||
| 170 | }, | ||
| 171 | else => unreachable, | 172 | else => unreachable, |
| 172 | }; | 173 | }; |
| 173 | } | 174 | } |
| ... | @@ -208,9 +209,12 @@ pub const File = struct { | ... | @@ -208,9 +209,12 @@ pub const File = struct { |
| 208 | base: File = File{ .tag = base_tag }, | 209 | base: File = File{ .tag = base_tag }, |
| 209 | 210 | ||
| 210 | allocator: *Allocator, | 211 | allocator: *Allocator, |
| 212 | header: std.ArrayList(u8), | ||
| 213 | main: std.ArrayList(u8), | ||
| 211 | file: ?fs.File, | 214 | file: ?fs.File, |
| 212 | owns_file_handle: bool, | 215 | owns_file_handle: bool, |
| 213 | options: Options, | 216 | options: Options, |
| 217 | called: std.StringHashMap(void), | ||
| 214 | 218 | ||
| 215 | pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { | 219 | pub fn makeWritable(self: *File.C, dir: fs.Dir, sub_path: []const u8) !void { |
| 216 | assert(self.owns_file_handle); | 220 | assert(self.owns_file_handle); |
| ... | @@ -223,6 +227,9 @@ pub const File = struct { | ... | @@ -223,6 +227,9 @@ pub const File = struct { |
| 223 | } | 227 | } |
| 224 | 228 | ||
| 225 | pub fn deinit(self: *File.C) void { | 229 | pub fn deinit(self: *File.C) void { |
| 230 | self.main.deinit(); | ||
| 231 | self.header.deinit(); | ||
| 232 | self.called.deinit(); | ||
| 226 | if (self.owns_file_handle) { | 233 | if (self.owns_file_handle) { |
| 227 | if (self.file) |f| | 234 | if (self.file) |f| |
| 228 | f.close(); | 235 | f.close(); |
| ... | @@ -232,6 +239,21 @@ pub const File = struct { | ... | @@ -232,6 +239,21 @@ pub const File = struct { |
| 232 | pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { | 239 | pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void { |
| 233 | try cgen.generate(self, decl, self.options.c_standard.?); | 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 | pub const Elf = struct { | 259 | pub const Elf = struct { |
test/stage2/cbe.zig+17-4| ... | @@ -9,13 +9,26 @@ const linux_x64 = std.zig.CrossTarget{ | ... | @@ -9,13 +9,26 @@ const linux_x64 = std.zig.CrossTarget{ |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | pub fn addCases(ctx: *TestContext) !void { | 11 | pub fn addCases(ctx: *TestContext) !void { |
| 12 | // These tests should work on every platform | ||
| 13 | ctx.c11("empty start function", linux_x64, | 12 | ctx.c11("empty start function", linux_x64, |
| 14 | \\export fn _start() noreturn {} | 13 | \\export fn _start() noreturn {} |
| 15 | , | 14 | , |
| 16 | // A newline is always generated after every function; this ensures, among | 15 | \\_Noreturn void _start(void) {} |
| 17 | // other things, that there is always a newline at the end of the file | 16 | \\ |
| 18 | \\_Noreturn void _start(void) {} | 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 | } |