From 40f0275e7cb7f3f4b2c382e5b457e714080c4cf2 Mon Sep 17 00:00:00 2001 From: Alex Cameron Date: Fri, 13 Nov 2020 00:50:02 +1100 Subject: Implement emit-h --- src/Compilation.zig | 77 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 19 deletions(-) (limited to 'src/Compilation.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 23f67f5b37..5b06bd6370 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -26,6 +26,8 @@ const Module = @import("Module.zig"); const Cache = @import("Cache.zig"); const stage1 = @import("stage1.zig"); const translate_c = @import("translate_c.zig"); +const c_codegen = @import("codegen/c.zig"); +const c_link = @import("link/C.zig"); const ThreadPool = @import("ThreadPool.zig"); const WaitGroup = @import("WaitGroup.zig"); @@ -131,6 +133,7 @@ emit_asm: ?EmitLoc, emit_llvm_ir: ?EmitLoc, emit_analysis: ?EmitLoc, emit_docs: ?EmitLoc, +c_header: ?c_link.Header, pub const InnerError = Module.InnerError; @@ -895,10 +898,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { }; }; - if (!use_llvm and options.emit_h != null) { - fatal("TODO implement support for -femit-h in the self-hosted backend", .{}); - } - var system_libs: std.StringArrayHashMapUnmanaged(void) = .{}; errdefer system_libs.deinit(gpa); try system_libs.ensureCapacity(gpa, options.system_libs.len); @@ -975,6 +974,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .global_cache_directory = options.global_cache_directory, .bin_file = bin_file, .emit_h = options.emit_h, + .c_header = if (!use_llvm and options.emit_h != null) c_link.Header.init(gpa) else null, .emit_asm = options.emit_asm, .emit_llvm_ir = options.emit_llvm_ir, .emit_analysis = options.emit_analysis, @@ -1286,6 +1286,20 @@ pub fn update(self: *Compilation) !void { module.root_scope.unload(self.gpa); } } + + // If we've chosen to emit a C header, flush the header to the disk. + if (self.c_header) |header| { + const header_path = self.emit_h.?; + // If a directory has been provided, write the header there. Otherwise, just write it to the + // cache directory. + const header_dir = if (header_path.directory) |dir| + dir.handle + else + self.local_cache_directory.handle; + const header_file = try header_dir.createFile(header_path.basename, .{}); + defer header_file.close(); + try header.flush(header_file.writer()); + } } /// Having the file open for writing is problematic as far as executing the @@ -1385,6 +1399,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len); defer c_comp_progress_node.end(); + var arena = std.heap.ArenaAllocator.init(self.gpa); + defer arena.deinit(); + var wg = WaitGroup{}; defer wg.wait(); @@ -1432,22 +1449,44 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits()); - self.bin_file.updateDecl(module, decl) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.AnalysisFail => { - decl.analysis = .dependency_failure; - }, - else => { - try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1); - module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( - module.gpa, - decl.src(), - "unable to codegen: {}", - .{@errorName(err)}, - )); - decl.analysis = .codegen_failure_retryable; - }, + self.bin_file.updateDecl(module, decl) catch |err| { + switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + decl.analysis = .dependency_failure; + }, + else => { + try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1); + module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( + module.gpa, + decl.src(), + "unable to codegen: {}", + .{@errorName(err)}, + )); + decl.analysis = .codegen_failure_retryable; + }, + } + return; }; + + if (self.c_header) |*header| { + c_codegen.generateHeader(&arena, module, &header.*, decl) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + decl.analysis = .dependency_failure; + }, + else => { + try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1); + module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( + module.gpa, + decl.src(), + "unable to generate C header: {}", + .{@errorName(err)}, + )); + decl.analysis = .codegen_failure_retryable; + }, + }; + } }, }, .analyze_decl => |decl| { -- cgit v1.2.3 From c87da2f45afedb33b5d1531ee0e4f67675aa9f78 Mon Sep 17 00:00:00 2001 From: Alex Cameron Date: Thu, 19 Nov 2020 19:57:22 +1100 Subject: Remove redundant emit_h member in Compilation struct. --- src/Compilation.zig | 13 ++++++------- src/link/C.zig | 6 ++++-- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/Compilation.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 5b06bd6370..2754141370 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -128,11 +128,11 @@ test_filter: ?[]const u8, test_name_prefix: ?[]const u8, test_evented_io: bool, -emit_h: ?EmitLoc, emit_asm: ?EmitLoc, emit_llvm_ir: ?EmitLoc, emit_analysis: ?EmitLoc, emit_docs: ?EmitLoc, + c_header: ?c_link.Header, pub const InnerError = Module.InnerError; @@ -973,8 +973,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .local_cache_directory = options.local_cache_directory, .global_cache_directory = options.global_cache_directory, .bin_file = bin_file, - .emit_h = options.emit_h, - .c_header = if (!use_llvm and options.emit_h != null) c_link.Header.init(gpa) else null, + .c_header = if (!use_llvm and options.emit_h != null) c_link.Header.init(gpa, options.emit_h) else null, .emit_asm = options.emit_asm, .emit_llvm_ir = options.emit_llvm_ir, .emit_analysis = options.emit_analysis, @@ -1289,7 +1288,7 @@ pub fn update(self: *Compilation) !void { // If we've chosen to emit a C header, flush the header to the disk. if (self.c_header) |header| { - const header_path = self.emit_h.?; + const header_path = header.emit_loc.?; // If a directory has been provided, write the header there. Otherwise, just write it to the // cache directory. const header_dir = if (header_path.directory) |dir| @@ -2952,7 +2951,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node man.hash.add(comp.bin_file.options.function_sections); man.hash.add(comp.bin_file.options.is_test); man.hash.add(comp.bin_file.options.emit != null); - man.hash.addOptionalEmitLoc(comp.emit_h); + man.hash.add(comp.c_header != null); man.hash.addOptionalEmitLoc(comp.emit_asm); man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); man.hash.addOptionalEmitLoc(comp.emit_analysis); @@ -3051,10 +3050,10 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node }); break :blk try directory.join(arena, &[_][]const u8{bin_basename}); } else ""; - if (comp.emit_h != null) { + if (comp.c_header != null) { log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); } - const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory); + const emit_h_path = try stage1LocPath(arena, if (comp.c_header) |header| header.emit_loc else null, directory); const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory); diff --git a/src/link/C.zig b/src/link/C.zig index 0906482dd1..839c8cabfe 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -17,10 +17,12 @@ pub const Header = struct { buf: std.ArrayList(u8), need_stddef: bool = false, need_stdint: bool = false, + emit_loc: ?Compilation.EmitLoc, - pub fn init(allocator: *Allocator) Header { + pub fn init(allocator: *Allocator, emit_loc: ?Compilation.EmitLoc) Header { return .{ .buf = std.ArrayList(u8).init(allocator), + .emit_loc = emit_loc, }; } @@ -81,7 +83,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio .allocator = allocator, }, .main = std.ArrayList(u8).init(allocator), - .header = Header.init(allocator), + .header = Header.init(allocator, null), .constants = std.ArrayList(u8).init(allocator), .called = std.StringHashMap(void).init(allocator), }; -- cgit v1.2.3 From 15a148db01896d8ef7290593755d185292584510 Mon Sep 17 00:00:00 2001 From: Noam Preil Date: Wed, 18 Nov 2020 20:50:12 -0500 Subject: Fix memory leak --- src/Compilation.zig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/Compilation.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 2754141370..8f1c9ac29d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1184,6 +1184,10 @@ pub fn destroy(self: *Compilation) void { } self.failed_c_objects.deinit(gpa); + if (self.c_header) |*header| { + header.deinit(); + } + self.cache_parent.manifest_dir.close(); if (self.owned_link_dir) |*dir| dir.close(); -- cgit v1.2.3 From 9849e894d52dd7b9aedc149011cb19d2bccaab70 Mon Sep 17 00:00:00 2001 From: Alex Cameron Date: Sat, 19 Dec 2020 05:31:00 +0000 Subject: Add emit_h path to compilation hash. --- src/Compilation.zig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/Compilation.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 8f1c9ac29d..11521e5a52 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2956,6 +2956,9 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node man.hash.add(comp.bin_file.options.is_test); man.hash.add(comp.bin_file.options.emit != null); man.hash.add(comp.c_header != null); + if (comp.c_header) |header| { + man.hash.addEmitLoc(header.emit_loc.?); + } man.hash.addOptionalEmitLoc(comp.emit_asm); man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); man.hash.addOptionalEmitLoc(comp.emit_analysis); -- cgit v1.2.3