Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 69 additions & 24 deletions src/Compilation.zig
Original file line numberDiff line numberDiff line change
Expand Up@@ -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");

Expand DownExpand Up@@ -126,12 +128,13 @@ 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;

pub const CRTFile = struct {
Expand DownExpand Up@@ -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);
Expand DownExpand Up@@ -974,7 +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, options.emit_h) else null,
.emit_asm = options.emit_asm,
.emit_llvm_ir = options.emit_llvm_ir,
.emit_analysis = options.emit_analysis,
Expand DownExpand Up@@ -1185,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();

Expand DownExpand Up@@ -1286,6 +1289,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 = 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|
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
Expand DownExpand Up@@ -1385,6 +1402,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();

Expand DownExpand Up@@ -1432,22 +1452,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| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the formatting change deliberate?

@tetsuo-cpptetsuo-cppNov 15, 2020

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a return after catching an error. My thinking is that there's no point in doing the header generation if the code generation for that decl didn't work.

Otherwise, the same decl may even get flagged twice.

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 => {
Comment thread
tetsuo-cpp marked this conversation as resolved.
decl.analysis = .dependency_failure;
},
else => {
try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense. If emit-h is desired and fails, it should be treated as a failed compilation.

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| {
Expand DownExpand Up@@ -2913,7 +2955,10 @@ 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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a addOptionalEmitLoc(header.emit_loc.?) here if c_header != null.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Expand DownExpand Up@@ -3012,10 +3057,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);
Expand Down
Loading