diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ef85f50e31..10127627ca 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -18,12 +18,11 @@ const Inst = ir.Inst; /// General-purpose allocator. allocator: *Allocator, -/// Module owns this resource. +/// Pointer to externally managed resource. root_pkg: *Package, /// Module owns this resource. root_scope: *Scope.ZIRModule, -/// Pointer to externally managed resource. -bin_file: *link.ElfFile, +bin_file: link.ElfFile, /// It's rare for a decl to be exported, so we save memory by having a sparse map of /// Decl pointers to details about them being exported. /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. @@ -422,7 +421,55 @@ pub const AllErrors = struct { } }; +pub const InitOptions = struct { + target: std.Target, + root_pkg: *Package, + output_mode: std.builtin.OutputMode, + bin_file_dir: ?std.fs.Dir = null, + bin_file_path: []const u8, + link_mode: ?std.builtin.LinkMode = null, + object_format: ?std.builtin.ObjectFormat = null, + optimize_mode: std.builtin.Mode = .Debug, +}; + +pub fn init(gpa: *Allocator, options: InitOptions) !Module { + const root_scope = try gpa.create(Scope.ZIRModule); + errdefer gpa.destroy(root_scope); + + root_scope.* = .{ + .sub_file_path = options.root_pkg.root_src_path, + .source = .{ .unloaded = {} }, + .contents = .{ .not_available = {} }, + .status = .never_loaded, + }; + + const bin_file_dir = options.bin_file_dir orelse std.fs.cwd(); + var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{ + .target = options.target, + .output_mode = options.output_mode, + .link_mode = options.link_mode orelse .Static, + .object_format = options.object_format orelse options.target.getObjectFormat(), + }); + errdefer bin_file.deinit(); + + return Module{ + .allocator = gpa, + .root_pkg = options.root_pkg, + .root_scope = root_scope, + .bin_file = bin_file, + .optimize_mode = options.optimize_mode, + .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(gpa), + .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa), + .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa), + .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa), + .failed_files = std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg).init(gpa), + .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa), + .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa), + }; +} + pub fn deinit(self: *Module) void { + self.bin_file.deinit(); const allocator = self.allocator; self.work_queue.deinit(); { @@ -472,7 +519,6 @@ pub fn deinit(self: *Module) void { } self.export_owners.deinit(); } - self.root_pkg.destroy(); { self.root_scope.deinit(allocator); allocator.destroy(self.root_scope); diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 37825550da..162e535a05 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -157,7 +157,7 @@ fn buildOutputType( var color: Color = .Auto; var build_mode: std.builtin.Mode = .Debug; var provided_name: ?[]const u8 = null; - var is_dynamic = false; + var link_mode: ?std.builtin.LinkMode = null; var root_src_file: ?[]const u8 = null; var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 }; var strip = false; @@ -286,7 +286,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-emit-zir")) { emit_zir = .no; } else if (mem.eql(u8, arg, "-dynamic")) { - is_dynamic = true; + link_mode = .Dynamic; + } else if (mem.eql(u8, arg, "-static")) { + link_mode = .Static; } else if (mem.eql(u8, arg, "--strip")) { strip = true; } else if (mem.eql(u8, arg, "--debug-tokenize")) { @@ -427,42 +429,19 @@ fn buildOutputType( .yes => |p| p, }; - var bin_file = try link.openBinFilePath(gpa, fs.cwd(), bin_path, .{ + const root_pkg = try Package.create(gpa, fs.cwd(), ".", src_path); + defer root_pkg.destroy(); + + var module = try Module.init(gpa, .{ .target = target_info.target, .output_mode = output_mode, - .link_mode = if (is_dynamic) .Dynamic else .Static, - .object_format = object_format orelse target_info.target.getObjectFormat(), + .root_pkg = root_pkg, + .bin_file_dir = fs.cwd(), + .bin_file_path = bin_path, + .link_mode = link_mode, + .object_format = object_format, + .optimize_mode = build_mode, }); - defer bin_file.deinit(); - - var module = blk: { - const root_pkg = try Package.create(gpa, fs.cwd(), ".", src_path); - errdefer root_pkg.destroy(); - - const root_scope = try gpa.create(Module.Scope.ZIRModule); - errdefer gpa.destroy(root_scope); - root_scope.* = .{ - .sub_file_path = root_pkg.root_src_path, - .source = .{ .unloaded = {} }, - .contents = .{ .not_available = {} }, - .status = .never_loaded, - }; - - break :blk Module{ - .allocator = gpa, - .root_pkg = root_pkg, - .root_scope = root_scope, - .bin_file = &bin_file, - .optimize_mode = .Debug, - .decl_table = std.AutoHashMap(Module.Decl.Hash, *Module.Decl).init(gpa), - .decl_exports = std.AutoHashMap(*Module.Decl, []*Module.Export).init(gpa), - .export_owners = std.AutoHashMap(*Module.Decl, []*Module.Export).init(gpa), - .failed_decls = std.AutoHashMap(*Module.Decl, *Module.ErrorMsg).init(gpa), - .failed_files = std.AutoHashMap(*Module.Scope.ZIRModule, *Module.ErrorMsg).init(gpa), - .failed_exports = std.AutoHashMap(*Module.Export, *Module.ErrorMsg).init(gpa), - .work_queue = std.fifo.LinearFifo(Module.WorkItem, .Dynamic).init(gpa), - }; - }; defer module.deinit(); const stdin = std.io.getStdIn().inStream(); diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index bac016e1a4..acfd7a0811 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -1,7 +1,9 @@ const std = @import("std"); const link = @import("link.zig"); -const ir = @import("ir.zig"); +const Module = @import("Module.zig"); const Allocator = std.mem.Allocator; +const zir = @import("zir.zig"); +const Package = @import("Package.zig"); test "self-hosted" { var ctx: TestContext = undefined; @@ -98,52 +100,31 @@ pub const TestContext = struct { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); - var prg_node = root_node.start(case.name, 4); + var prg_node = root_node.start(case.name, 2); prg_node.activate(); defer prg_node.end(); - var zir_module = x: { - var parse_node = prg_node.start("parse", null); - parse_node.activate(); - defer parse_node.end(); + const tmp_src_path = "test-case.zir"; + try tmp.dir.writeFile(tmp_src_path, case.src); - break :x try ir.text.parse(allocator, case.src); - }; - defer zir_module.deinit(allocator); - if (zir_module.errors.len != 0) { - debugPrintErrors(case.src, zir_module.errors); - return error.ParseFailure; - } + const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path); + defer root_pkg.destroy(); - var analyzed_module = x: { - var analyze_node = prg_node.start("analyze", null); - analyze_node.activate(); - defer analyze_node.end(); - - break :x try ir.analyze(allocator, zir_module, .{ + { + var module = try Module.init(allocator, .{ .target = target, .output_mode = .Exe, - .link_mode = .Static, .optimize_mode = .Debug, + .bin_file_dir = tmp.dir, + .bin_file_path = "a.out", + .root_pkg = root_pkg, }); - }; - defer analyzed_module.deinit(allocator); - if (analyzed_module.errors.len != 0) { - debugPrintErrors(case.src, analyzed_module.errors); - return error.ParseFailure; - } + defer module.deinit(); - var link_result = x: { - var link_node = prg_node.start("link", null); - link_node.activate(); - defer link_node.end(); - - break :x try link.updateFilePath(allocator, analyzed_module, tmp.dir, "a.out"); - }; - defer link_result.deinit(allocator); - if (link_result.errors.len != 0) { - debugPrintErrors(case.src, link_result.errors); - return error.LinkFailure; + var module_node = prg_node.start("parse,analysis,codegen", null); + module_node.activate(); + try module.update(); + module_node.end(); } var exec_result = x: { @@ -178,38 +159,37 @@ pub const TestContext = struct { case: ZIRTransformCase, target: std.Target, ) !void { - var prg_node = root_node.start(case.name, 4); + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + + var prg_node = root_node.start(case.name, 3); prg_node.activate(); defer prg_node.end(); - var parse_node = prg_node.start("parse", null); - parse_node.activate(); - var zir_module = try ir.text.parse(allocator, case.src); - defer zir_module.deinit(allocator); - if (zir_module.errors.len != 0) { - debugPrintErrors(case.src, zir_module.errors); - return error.ParseFailure; - } - parse_node.end(); + const tmp_src_path = "test-case.zir"; + try tmp.dir.writeFile(tmp_src_path, case.src); - var analyze_node = prg_node.start("analyze", null); - analyze_node.activate(); - var analyzed_module = try ir.analyze(allocator, zir_module, .{ + const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path); + defer root_pkg.destroy(); + + var module = try Module.init(allocator, .{ .target = target, .output_mode = .Obj, - .link_mode = .Static, .optimize_mode = .Debug, + .bin_file_dir = tmp.dir, + .bin_file_path = "test-case.o", + .root_pkg = root_pkg, }); - defer analyzed_module.deinit(allocator); - if (analyzed_module.errors.len != 0) { - debugPrintErrors(case.src, analyzed_module.errors); - return error.ParseFailure; - } - analyze_node.end(); + defer module.deinit(); + + var module_node = prg_node.start("parse/analysis/codegen", null); + module_node.activate(); + try module.update(); + module_node.end(); var emit_node = prg_node.start("emit", null); emit_node.activate(); - var new_zir_module = try ir.text.emit_zir(allocator, analyzed_module); + var new_zir_module = try zir.emit(allocator, module); defer new_zir_module.deinit(allocator); emit_node.end();