diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 511c3fabf2..81484e93db 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -276,10 +276,71 @@ pub const Object = struct { } } - pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { - const tracy = trace(@src()); - defer tracy.end(); + pub fn updateFunc( + self: *Object, + module: *Module, + func: *Module.Fn, + air: Air, + liveness: Liveness, + ) !void { + var dg: DeclGen = .{ + .object = self, + .module = module, + .decl = func.owner_decl, + .err_msg = null, + .gpa = module.gpa, + }; + const llvm_func = try dg.resolveLLVMFunction(func.owner_decl); + + // This gets the LLVM values from the function and stores them in `dg.args`. + const fn_param_len = func.owner_decl.ty.fnParamLen(); + var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len); + + for (args) |*arg, i| { + arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i)); + } + + // We remove all the basic blocks of a function to support incremental + // compilation! + // TODO: remove all basic blocks if functions can have more than one + if (llvm_func.getFirstBasicBlock()) |bb| { + bb.deleteBasicBlock(); + } + + const builder = dg.context().createBuilder(); + + const entry_block = dg.context().appendBasicBlock(llvm_func, "Entry"); + builder.positionBuilderAtEnd(entry_block); + + var fg: FuncGen = .{ + .gpa = dg.gpa, + .air = air, + .liveness = liveness, + .dg = &dg, + .builder = builder, + .args = args, + .arg_index = 0, + .func_inst_table = .{}, + .entry_block = entry_block, + .latest_alloca_inst = null, + .llvm_func = llvm_func, + .blocks = .{}, + }; + defer fg.deinit(); + + fg.genBody(air.getMainBody()) catch |err| switch (err) { + error.CodegenFail => { + func.owner_decl.analysis = .codegen_failure; + try module.failed_decls.put(module.gpa, func.owner_decl, dg.err_msg.?); + dg.err_msg = null; + return; + }, + else => |e| return e, + }; + } + + pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { var dg: DeclGen = .{ .object = self, .module = module, @@ -330,45 +391,8 @@ pub const DeclGen = struct { log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); if (decl.val.castTag(.function)) |func_payload| { - const func = func_payload.data; - - const llvm_func = try self.resolveLLVMFunction(func.owner_decl); - - // This gets the LLVM values from the function and stores them in `self.args`. - const fn_param_len = func.owner_decl.ty.fnParamLen(); - var args = try self.gpa.alloc(*const llvm.Value, fn_param_len); - - for (args) |*arg, i| { - arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i)); - } - - // We remove all the basic blocks of a function to support incremental - // compilation! - // TODO: remove all basic blocks if functions can have more than one - if (llvm_func.getFirstBasicBlock()) |bb| { - bb.deleteBasicBlock(); - } - - const builder = self.context().createBuilder(); - - const entry_block = self.context().appendBasicBlock(llvm_func, "Entry"); - builder.positionBuilderAtEnd(entry_block); - - var fg: FuncGen = .{ - .gpa = self.gpa, - .dg = self, - .builder = builder, - .args = args, - .arg_index = 0, - .func_inst_table = .{}, - .entry_block = entry_block, - .latest_alloca_inst = null, - .llvm_func = llvm_func, - .blocks = .{}, - }; - defer fg.deinit(); - - try fg.genBody(func.body); + _ = func_payload; + @panic("TODO llvm backend genDecl function pointer"); } else if (decl.val.castTag(.extern_fn)) |extern_fn| { _ = try self.resolveLLVMFunction(extern_fn.data); } else { @@ -596,6 +620,8 @@ pub const DeclGen = struct { pub const FuncGen = struct { gpa: *Allocator, dg: *DeclGen, + air: Air, + liveness: Liveness, builder: *const llvm.Builder, @@ -649,14 +675,15 @@ pub const FuncGen = struct { if (self.air.value(inst)) |val| { return self.dg.genTypedValue(.{ .ty = self.air.typeOf(inst), .val = val }, self); } - if (self.func_inst_table.get(inst)) |value| return value; + const inst_index = Air.refToIndex(inst).?; + if (self.func_inst_table.get(inst_index)) |value| return value; return self.todo("implement global llvm values (or the value is not in the func_inst_table table)", .{}); } - fn genBody(self: *FuncGen, body: ir.Body) error{ OutOfMemory, CodegenFail }!void { + fn genBody(self: *FuncGen, body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void { const air_tags = self.air.instructions.items(.tag); - for (body.instructions) |inst| { + for (body) |inst| { const opt_value = switch (air_tags[inst]) { .add => try self.airAdd(inst), .sub => try self.airSub(inst), @@ -828,8 +855,8 @@ pub const FuncGen = struct { // If the break doesn't break a value, then we don't have to add // the values to the lists. - if (self.air.typeOf(branch.result).hasCodeGenBits()) { - const val = try self.resolveInst(branch.result); + if (self.air.typeOf(branch.operand).hasCodeGenBits()) { + const val = try self.resolveInst(branch.operand); // For the phi node, we need the basic blocks and the values of the // break instructions. diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 4107607924..02ea5856f4 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -30,6 +30,7 @@ const DebugSymbols = @import("MachO/DebugSymbols.zig"); const Trie = @import("MachO/Trie.zig"); const CodeSignature = @import("MachO/CodeSignature.zig"); const Zld = @import("MachO/Zld.zig"); +const llvm_backend = @import("../codegen/llvm.zig"); usingnamespace @import("MachO/commands.zig"); @@ -37,6 +38,9 @@ pub const base_tag: File.Tag = File.Tag.macho; base: File, +/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. +llvm_object: ?*llvm_backend.Object = null, + /// Debug symbols bundle (or dSym). d_sym: ?DebugSymbols = null, @@ -347,8 +351,13 @@ pub const SrcFn = struct { pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*MachO { assert(options.object_format == .macho); - if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO - if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO + if (build_options.have_llvm and options.use_llvm) { + const self = try createEmpty(allocator, options); + errdefer self.base.destroy(); + + self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options); + return self; + } const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = false, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index d9139a178c..f478d2ee47 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -19,12 +19,15 @@ const build_options = @import("build_options"); const wasi_libc = @import("../wasi_libc.zig"); const Cache = @import("../Cache.zig"); const TypedValue = @import("../TypedValue.zig"); +const llvm_backend = @import("../codegen/llvm.zig"); const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); pub const base_tag = link.File.Tag.wasm; base: link.File, +/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. +llvm_object: ?*llvm_backend.Object = null, /// List of all function Decls to be written to the output file. The index of /// each Decl in this list at the time of writing the binary is used as the /// function index. In the event where ext_funcs' size is not 0, the index of @@ -114,8 +117,13 @@ pub const DeclBlock = struct { pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm { assert(options.object_format == .wasm); - if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO - if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO + if (build_options.have_llvm and options.use_llvm) { + const self = try createEmpty(allocator, options); + errdefer self.base.destroy(); + + self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options); + return self; + } // TODO: read the file and keep valid parts instead of truncating const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });