Commit 95756299af

Andrew Kelley <andrew@ziglang.org>
2021-07-19 07:49:46
stage2: fix compile errors in LLVM backend
1 parent bf8e347
Changed files (3)
src
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.
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,
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 });