Commit 9360e5887c

Noam Preil <noam@pixelhero.dev>
2020-12-30 11:22:50
integrate CBE with Compilation.update pipeline (closes #7589)
* CBE buffers are only valid during a flush() * the file is reopened and truncated during each flush() * CBE now explicitly ignores updateDecl and deleteDecl * CBE updateDecl is gone * test case is enabled
1 parent 6c49244
Changed files (3)
src
test
stage2
src/link/C.zig
@@ -8,10 +8,9 @@ const fs = std.fs;
 const codegen = @import("../codegen/c.zig");
 const link = @import("../link.zig");
 const trace = @import("../tracy.zig").trace;
-const File = link.File;
 const C = @This();
 
-pub const base_tag: File.Tag = .c;
+pub const base_tag: link.File.Tag = .c;
 
 pub const Header = struct {
     buf: std.ArrayList(u8),
@@ -40,13 +39,16 @@ pub const Header = struct {
     }
 };
 
-base: File,
+base: link.File,
 
+path: []const u8,
+
+// These are only valid during a flush()!
 header: Header,
 constants: std.ArrayList(u8),
 main: std.ArrayList(u8),
-
 called: std.StringHashMap(void),
+
 error_msg: *Compilation.ErrorMsg = undefined,
 
 pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*C {
@@ -55,9 +57,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
     if (options.use_llvm) return error.LLVMHasNoCBackend;
     if (options.use_lld) return error.LLDHasNoCBackend;
 
-    const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
-    errdefer file.close();
-
     var c_file = try allocator.create(C);
     errdefer allocator.destroy(c_file);
 
@@ -65,13 +64,14 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
         .base = .{
             .tag = .c,
             .options = options,
-            .file = file,
+            .file = null,
             .allocator = allocator,
         },
-        .main = std.ArrayList(u8).init(allocator),
-        .header = Header.init(allocator, null),
-        .constants = std.ArrayList(u8).init(allocator),
-        .called = std.StringHashMap(void).init(allocator),
+        .main = undefined,
+        .header = undefined,
+        .constants = undefined,
+        .called = undefined,
+        .path = sub_path,
     };
 
     return c_file;
@@ -82,21 +82,7 @@ pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) er
     return error.AnalysisFail;
 }
 
-pub fn deinit(self: *C) void {
-    self.main.deinit();
-    self.header.deinit();
-    self.constants.deinit();
-    self.called.deinit();
-}
-
-pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
-    codegen.generate(self, module, decl) catch |err| {
-        if (err == error.AnalysisFail) {
-            try module.failed_decls.put(module.gpa, decl, self.error_msg);
-        }
-        return err;
-    };
-}
+pub fn deinit(self: *C) void {}
 
 pub fn flush(self: *C, comp: *Compilation) !void {
     return self.flushModule(comp);
@@ -106,7 +92,29 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
-    const writer = self.base.file.?.writer();
+    self.main = std.ArrayList(u8).init(self.base.allocator);
+    self.header = Header.init(self.base.allocator, null);
+    self.constants = std.ArrayList(u8).init(self.base.allocator);
+    self.called = std.StringHashMap(void).init(self.base.allocator);
+    defer self.main.deinit();
+    defer self.header.deinit();
+    defer self.constants.deinit();
+    defer self.called.deinit();
+
+    const module = self.base.options.module.?;
+    for (self.base.options.module.?.decl_table.entries.items) |kv| {
+        codegen.generate(self, module, kv.value) catch |err| {
+            if (err == error.AnalysisFail) {
+                try module.failed_decls.put(module.gpa, kv.value, self.error_msg);
+            }
+            return err;
+        };
+    }
+
+    const file = try self.base.options.emit.?.directory.handle.createFile(self.path, .{ .truncate = true, .read = true, .mode = link.determineMode(self.base.options) });
+    defer file.close();
+
+    const writer = file.writer();
     try self.header.flush(writer);
     if (self.header.buf.items.len > 0) {
         try writer.writeByte('\n');
@@ -121,6 +129,4 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
         }
     }
     try writer.writeAll(self.main.items);
-    self.base.file.?.close();
-    self.base.file = null;
 }
src/link.zig
@@ -291,7 +291,7 @@ pub const File = struct {
             .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
             .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
             .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl),
-            .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
+            .c => {},
             .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
         }
     }
@@ -412,7 +412,7 @@ pub const File = struct {
             .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl),
             .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl),
             .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl),
-            .c => unreachable,
+            .c => {},
             .wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl),
         }
     }
test/stage2/cbe.zig
@@ -24,13 +24,13 @@ pub fn addCases(ctx: *TestContext) !void {
         // Now change the message only
         // TODO fix C backend not supporting updates
         // https://github.com/ziglang/zig/issues/7589
-        //case.addCompareOutput(
-        //    \\extern fn puts(s: [*:0]const u8) c_int;
-        //    \\export fn main() c_int {
-        //    \\    _ = puts("yo");
-        //    \\    return 0;
-        //    \\}
-        //, "yo" ++ std.cstr.line_sep);
+        case.addCompareOutput(
+            \\extern fn puts(s: [*:0]const u8) c_int;
+            \\export fn main() c_int {
+            \\    _ = puts("yo");
+            \\    return 0;
+            \\}
+        , "yo" ++ std.cstr.line_sep);
     }
 
     {
@@ -111,15 +111,15 @@ pub fn addCases(ctx: *TestContext) !void {
     ,
         \\static zig_noreturn void main(void);
         \\
-        \\zig_noreturn void _start(void) {
-        \\    main();
-        \\}
-        \\
         \\static zig_noreturn void main(void) {
         \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
+        \\zig_noreturn void _start(void) {
+        \\    main();
+        \\}
+        \\
     );
     // TODO: implement return values
     // TODO: figure out a way to prevent asm constants from being generated
@@ -143,10 +143,6 @@ pub fn addCases(ctx: *TestContext) !void {
         \\static uint8_t exitGood__anon_1[6] = "{rdi}";
         \\static uint8_t exitGood__anon_2[8] = "syscall";
         \\
-        \\zig_noreturn void _start(void) {
-        \\    exitGood();
-        \\}
-        \\
         \\static zig_noreturn void exitGood(void) {
         \\    register uintptr_t rax_constant __asm__("rax") = 231;
         \\    register uintptr_t rdi_constant __asm__("rdi") = 0;
@@ -155,6 +151,10 @@ pub fn addCases(ctx: *TestContext) !void {
         \\    zig_unreachable();
         \\}
         \\
+        \\zig_noreturn void _start(void) {
+        \\    exitGood();
+        \\}
+        \\
     );
     ctx.c("exit with parameter", linux_x64,
         \\export fn _start() noreturn {