Commit c4848694d2

Jacob Young <jacobly0@users.noreply.github.com>
2023-08-09 06:24:17
llvm: enable even without libllvm linked
1 parent 151c06c
src/codegen/llvm/Builder.zig
@@ -5868,7 +5868,7 @@ pub const WipFunction = struct {
             vals: []const Value,
             blocks: []const Block.Index,
             wip: *WipFunction,
-        ) if (build_options.have_llvm) Allocator.Error!void else void {
+        ) (if (build_options.have_llvm) Allocator.Error else error{})!void {
             const incoming_len = self.block.ptrConst(wip).incoming;
             assert(vals.len == incoming_len and blocks.len == incoming_len);
             const instruction = wip.instructions.get(@intFromEnum(self.instruction));
@@ -8389,9 +8389,9 @@ pub fn fnType(
     kind: Type.Function.Kind,
 ) Allocator.Error!Type {
     try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
-    return switch (kind) {
-        inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),
-    };
+    switch (kind) {
+        inline else => |comptime_kind| return self.fnTypeAssumeCapacity(ret, params, comptime_kind),
+    }
 }
 
 pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
@@ -8411,9 +8411,9 @@ pub fn vectorType(
     child: Type,
 ) Allocator.Error!Type {
     try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
-    return switch (kind) {
-        inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),
-    };
+    switch (kind) {
+        inline else => |comptime_kind| return self.vectorTypeAssumeCapacity(comptime_kind, len, child),
+    }
 }
 
 pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
@@ -8428,9 +8428,9 @@ pub fn structType(
     fields: []const Type,
 ) Allocator.Error!Type {
     try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
-    return switch (kind) {
-        inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),
-    };
+    switch (kind) {
+        inline else => |comptime_kind| return self.structTypeAssumeCapacity(comptime_kind, fields),
+    }
 }
 
 pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
@@ -8450,7 +8450,7 @@ pub fn namedTypeSetBody(
     self: *Builder,
     named_type: Type,
     body_type: Type,
-) if (build_options.have_llvm) Allocator.Error!void else void {
+) (if (build_options.have_llvm) Allocator.Error else error{})!void {
     const named_item = self.type_items.items[@intFromEnum(named_type)];
     self.type_extra.items[named_item.data + std.meta.fieldIndex(Type.NamedStructure, "body").?] =
         @intFromEnum(body_type);
@@ -9985,7 +9985,7 @@ fn fnTypeAssumeCapacity(
     ret: Type,
     params: []const Type,
     comptime kind: Type.Function.Kind,
-) if (build_options.have_llvm) Allocator.Error!Type else Type {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Type {
     const tag: Type.Tag = switch (kind) {
         .normal => .function,
         .vararg => .vararg_function,
@@ -10169,7 +10169,7 @@ fn structTypeAssumeCapacity(
     self: *Builder,
     comptime kind: Type.Structure.Kind,
     fields: []const Type,
-) if (build_options.have_llvm) Allocator.Error!Type else Type {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Type {
     const tag: Type.Tag = switch (kind) {
         .normal => .structure,
         .@"packed" => .packed_structure,
@@ -10397,7 +10397,7 @@ fn bigIntConstAssumeCapacity(
     self: *Builder,
     ty: Type,
     value: std.math.big.int.Const,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) Allocator.Error!Constant {
     const type_item = self.type_items.items[@intFromEnum(ty)];
     assert(type_item.tag == .integer);
     const bits = type_item.data;
@@ -10743,7 +10743,7 @@ fn structConstAssumeCapacity(
     self: *Builder,
     ty: Type,
     vals: []const Constant,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Constant {
     const type_item = self.type_items.items[@intFromEnum(ty)];
     var extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
         .structure, .packed_structure => type_item.data,
@@ -10791,7 +10791,7 @@ fn arrayConstAssumeCapacity(
     self: *Builder,
     ty: Type,
     vals: []const Constant,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Constant {
     const type_item = self.type_items.items[@intFromEnum(ty)];
     const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
         inline .small_array, .array => |kind| extra: {
@@ -10859,7 +10859,7 @@ fn vectorConstAssumeCapacity(
     self: *Builder,
     ty: Type,
     vals: []const Constant,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Constant {
     assert(ty.isVector(self));
     assert(ty.vectorLen(self) == vals.len);
     for (vals) |val| assert(ty.childType(self) == val.typeOf(self));
@@ -10893,7 +10893,7 @@ fn splatConstAssumeCapacity(
     self: *Builder,
     ty: Type,
     val: Constant,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Constant {
     assert(ty.scalarType(self) == val.typeOf(self));
 
     if (!ty.isVector(self)) return val;
@@ -11182,7 +11182,7 @@ fn gepConstAssumeCapacity(
     base: Constant,
     inrange: ?u16,
     indices: []const Constant,
-) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
+) (if (build_options.have_llvm) Allocator.Error else error{})!Constant {
     const tag: Constant.Tag = switch (kind) {
         .normal => .getelementptr,
         .inbounds => .@"getelementptr inbounds",
src/codegen/llvm.zig
@@ -8,7 +8,7 @@ const native_endian = builtin.cpu.arch.endian();
 const DW = std.dwarf;
 
 const Builder = @import("llvm/Builder.zig");
-const llvm = if (build_options.have_llvm or true)
+const llvm = if (build_options.have_llvm)
     @import("llvm/bindings.zig")
 else
     @compileError("LLVM unavailable");
@@ -764,15 +764,37 @@ pub const Object = struct {
     builder: Builder,
 
     module: *Module,
-    di_builder: ?*llvm.DIBuilder,
+    di_builder: ?if (build_options.have_llvm) *llvm.DIBuilder else noreturn,
     /// One of these mappings:
     /// - *Module.File => *DIFile
     /// - *Module.Decl (Fn) => *DISubprogram
     /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
-    di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
-    di_compile_unit: ?*llvm.DICompileUnit,
-    target_machine: *llvm.TargetMachine,
-    target_data: *llvm.TargetData,
+    di_map: if (build_options.have_llvm) std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode) else struct {
+        const K = *const anyopaque;
+        const V = noreturn;
+
+        const Self = @This();
+
+        metadata: ?noreturn = null,
+        size: Size = 0,
+        available: Size = 0,
+
+        pub const Size = u0;
+
+        pub fn deinit(self: *Self, allocator: Allocator) void {
+            _ = allocator;
+            self.* = undefined;
+        }
+
+        pub fn get(self: Self, key: K) ?V {
+            _ = self;
+            _ = key;
+            return null;
+        }
+    },
+    di_compile_unit: ?if (build_options.have_llvm) *llvm.DICompileUnit else noreturn,
+    target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void,
+    target_data: if (build_options.have_llvm) *llvm.TargetData else void,
     target: std.Target,
     /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
     /// but that has some downsides:
@@ -830,8 +852,8 @@ pub const Object = struct {
         });
         errdefer builder.deinit();
 
-        var target_machine: *llvm.TargetMachine = undefined;
-        var target_data: *llvm.TargetData = undefined;
+        var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined;
+        var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined;
         if (builder.useLibLlvm()) {
             if (!options.strip) {
                 switch (options.target.ofmt) {
@@ -946,7 +968,7 @@ pub const Object = struct {
             .module = options.module.?,
             .di_map = .{},
             .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO
-            .di_compile_unit = builder.llvm.di_compile_unit,
+            .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null,
             .target_machine = target_machine,
             .target_data = target_data,
             .target = options.target,
@@ -961,9 +983,9 @@ pub const Object = struct {
     }
 
     pub fn deinit(self: *Object, gpa: Allocator) void {
+        self.di_map.deinit(gpa);
+        self.di_type_map.deinit(gpa);
         if (self.builder.useLibLlvm()) {
-            self.di_map.deinit(gpa);
-            self.di_type_map.deinit(gpa);
             self.target_data.dispose();
             self.target_machine.dispose();
         }
@@ -1519,8 +1541,8 @@ pub const Object = struct {
 
         function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
 
-        var di_file: ?*llvm.DIFile = null;
-        var di_scope: ?*llvm.DIScope = null;
+        var di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn = null;
+        var di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn = null;
 
         if (o.di_builder) |dib| {
             di_file = try o.getDIFile(gpa, mod.namespacePtr(decl.src_namespace).file_scope);
@@ -4425,7 +4447,8 @@ pub const DeclGen = struct {
             }, &o.builder);
 
             if (o.di_builder) |dib| {
-                const di_file = try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope);
+                const di_file =
+                    try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope);
 
                 const line_number = decl.src_line + 1;
                 const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
@@ -4453,18 +4476,18 @@ pub const FuncGen = struct {
     air: Air,
     liveness: Liveness,
     wip: Builder.WipFunction,
-    di_scope: ?*llvm.DIScope,
-    di_file: ?*llvm.DIFile,
+    di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn,
+    di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn,
     base_line: u32,
     prev_dbg_line: c_uint,
     prev_dbg_column: c_uint,
 
     /// Stack of locations where a call was inlined.
-    dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
+    dbg_inlined: std.ArrayListUnmanaged(if (build_options.have_llvm) DbgState else void) = .{},
 
     /// Stack of `DILexicalBlock`s. dbg_block instructions cannot happend accross
     /// dbg_inline instructions so no special handling there is required.
-    dbg_block_stack: std.ArrayListUnmanaged(*llvm.DIScope) = .{},
+    dbg_block_stack: std.ArrayListUnmanaged(if (build_options.have_llvm) *llvm.DIScope else void) = .{},
 
     /// This stores the LLVM values used in a function, such that they can be referred to
     /// in other instructions. This table is cleared before every function is generated.
@@ -4495,7 +4518,7 @@ pub const FuncGen = struct {
 
     sync_scope: Builder.SyncScope,
 
-    const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
+    const DbgState = if (build_options.have_llvm) struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 } else struct {};
     const BreakList = union {
         list: std.MultiArrayList(struct {
             bb: Builder.Function.Block.Index,
@@ -6230,8 +6253,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
-        if (!self.dg.object.builder.useLibLlvm()) return .none;
-
         const di_scope = self.di_scope orelse return .none;
         const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
         self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
@@ -6251,8 +6272,6 @@ pub const FuncGen = struct {
 
     fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         const dib = o.di_builder orelse return .none;
         const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
 
@@ -6311,8 +6330,6 @@ pub const FuncGen = struct {
 
     fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         if (o.di_builder == null) return .none;
         const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
 
@@ -6328,8 +6345,6 @@ pub const FuncGen = struct {
 
     fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         const dib = o.di_builder orelse return .none;
         const old_scope = self.di_scope.?;
         try self.dbg_block_stack.append(self.gpa, old_scope);
@@ -6340,8 +6355,6 @@ pub const FuncGen = struct {
 
     fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         if (o.di_builder == null) return .none;
         self.di_scope = self.dbg_block_stack.pop();
         return .none;
@@ -6349,8 +6362,6 @@ pub const FuncGen = struct {
 
     fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         const mod = o.module;
         const dib = o.di_builder orelse return .none;
         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
@@ -6379,8 +6390,6 @@ pub const FuncGen = struct {
 
     fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         const o = self.dg.object;
-        if (!o.builder.useLibLlvm()) return .none;
-
         const dib = o.di_builder orelse return .none;
         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
         const operand = try self.resolveInst(pl_op.operand);
src/link/Coff.zig
@@ -225,7 +225,7 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {
     assert(options.target.ofmt == .coff);
 
-    if (build_options.have_llvm and options.use_llvm) {
+    if (options.use_llvm) {
         return createEmpty(allocator, options);
     }
 
@@ -267,8 +267,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
         .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory),
     };
 
-    const use_llvm = build_options.have_llvm and options.use_llvm;
-    if (use_llvm) {
+    if (options.use_llvm) {
         self.llvm_object = try LlvmObject.create(gpa, options);
     }
     return self;
@@ -277,9 +276,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
 pub fn deinit(self: *Coff) void {
     const gpa = self.base.allocator;
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
-    }
+    if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
 
     for (self.objects.items) |*object| {
         object.deinit(gpa);
@@ -1036,10 +1033,8 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
     if (build_options.skip_non_native and builtin.object_format != .coff) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| {
-            return llvm_object.updateFunc(mod, func_index, air, liveness);
-        }
+    if (self.llvm_object) |llvm_object| {
+        return llvm_object.updateFunc(mod, func_index, air, liveness);
     }
     const tracy = trace(@src());
     defer tracy.end();
@@ -1147,9 +1142,7 @@ pub fn updateDecl(
     if (build_options.skip_non_native and builtin.object_format != .coff) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -1390,9 +1383,7 @@ fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {
 }
 
 pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
 
     const mod = self.base.options.module.?;
     const decl = mod.declPtr(decl_index);
@@ -1419,7 +1410,7 @@ pub fn updateDeclExports(
 
     const ip = &mod.intern_pool;
 
-    if (build_options.have_llvm) {
+    if (self.base.options.use_llvm) {
         // Even in the case of LLVM, we need to notice certain exported symbols in order to
         // detect the default subsystem.
         for (exports) |exp| {
@@ -1448,10 +1439,10 @@ pub fn updateDeclExports(
                 }
             }
         }
-
-        if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
     }
 
+    if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
+
     if (self.base.options.emit == null) return;
 
     const gpa = self.base.allocator;
@@ -1583,10 +1574,8 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
 
 pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
     if (self.base.options.emit == null) {
-        if (build_options.have_llvm) {
-            if (self.llvm_object) |llvm_object| {
-                return try llvm_object.flushModule(comp, prog_node);
-            }
+        if (self.llvm_object) |llvm_object| {
+            return try llvm_object.flushModule(comp, prog_node);
         }
         return;
     }
@@ -1604,10 +1593,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
     const tracy = trace(@src());
     defer tracy.end();
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| {
-            return try llvm_object.flushModule(comp, prog_node);
-        }
+    if (self.llvm_object) |llvm_object| {
+        return try llvm_object.flushModule(comp, prog_node);
     }
 
     var sub_prog_node = prog_node.start("COFF Flush", 0);
src/link/Elf.zig
@@ -225,7 +225,7 @@ pub const PtrWidth = enum { p32, p64 };
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
     assert(options.target.ofmt == .elf);
 
-    if (build_options.have_llvm and options.use_llvm) {
+    if (options.use_llvm) {
         return createEmpty(allocator, options);
     }
 
@@ -304,7 +304,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
         .ptr_width = ptr_width,
         .page_size = page_size,
     };
-    const use_llvm = build_options.have_llvm and options.use_llvm;
+    const use_llvm = options.use_llvm;
     if (use_llvm) {
         self.llvm_object = try LlvmObject.create(gpa, options);
     }
@@ -314,9 +314,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
 pub fn deinit(self: *Elf) void {
     const gpa = self.base.allocator;
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
-    }
+    if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
 
     for (self.sections.items(.free_list)) |*free_list| {
         free_list.deinit(gpa);
@@ -1005,10 +1003,8 @@ pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
 
 pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
     if (self.base.options.emit == null) {
-        if (build_options.have_llvm) {
-            if (self.llvm_object) |llvm_object| {
-                return try llvm_object.flushModule(comp, prog_node);
-            }
+        if (self.llvm_object) |llvm_object| {
+            return try llvm_object.flushModule(comp, prog_node);
         }
         return;
     }
@@ -1026,10 +1022,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
     const tracy = trace(@src());
     defer tracy.end();
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| {
-            return try llvm_object.flushModule(comp, prog_node);
-        }
+    if (self.llvm_object) |llvm_object| {
+        return try llvm_object.flushModule(comp, prog_node);
     }
 
     const gpa = self.base.allocator;
@@ -2392,9 +2386,7 @@ fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
 }
 
 pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
 
     const mod = self.base.options.module.?;
     const decl = mod.declPtr(decl_index);
@@ -2577,9 +2569,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
     if (build_options.skip_non_native and builtin.object_format != .elf) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
 
     const tracy = trace(@src());
     defer tracy.end();
@@ -2637,9 +2627,7 @@ pub fn updateDecl(
     if (build_options.skip_non_native and builtin.object_format != .elf) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
 
     const tracy = trace(@src());
     defer tracy.end();
@@ -2859,9 +2847,7 @@ pub fn updateDeclExports(
     if (build_options.skip_non_native and builtin.object_format != .elf) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
 
     if (self.base.options.emit == null) return;
 
src/link/MachO.zig
@@ -422,7 +422,6 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
 pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
     const cpu_arch = options.target.cpu.arch;
     const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;
-    const use_llvm = build_options.have_llvm and options.use_llvm;
 
     const self = try gpa.create(MachO);
     errdefer gpa.destroy(self);
@@ -435,13 +434,13 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
             .file = null,
         },
         .page_size = page_size,
-        .mode = if (use_llvm or options.module == null or options.cache_mode == .whole)
+        .mode = if (options.use_llvm or options.module == null or options.cache_mode == .whole)
             .zld
         else
             .incremental,
     };
 
-    if (use_llvm) {
+    if (options.use_llvm) {
         self.llvm_object = try LlvmObject.create(gpa, options);
     }
 
@@ -452,10 +451,8 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
 
 pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
     if (self.base.options.emit == null) {
-        if (build_options.have_llvm) {
-            if (self.llvm_object) |llvm_object| {
-                try llvm_object.flushModule(comp, prog_node);
-            }
+        if (self.llvm_object) |llvm_object| {
+            try llvm_object.flushModule(comp, prog_node);
         }
         return;
     }
@@ -479,10 +476,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
     const tracy = trace(@src());
     defer tracy.end();
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| {
-            return try llvm_object.flushModule(comp, prog_node);
-        }
+    if (self.llvm_object) |llvm_object| {
+        return try llvm_object.flushModule(comp, prog_node);
     }
 
     var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
@@ -1622,9 +1617,7 @@ fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction))
 pub fn deinit(self: *MachO) void {
     const gpa = self.base.allocator;
 
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
-    }
+    if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
 
     if (self.d_sym) |*d_sym| {
         d_sym.deinit();
@@ -1855,9 +1848,7 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
     if (build_options.skip_non_native and builtin.object_format != .macho) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -1979,9 +1970,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo
     if (build_options.skip_non_native and builtin.object_format != .macho) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -2387,10 +2376,8 @@ pub fn updateDeclExports(
     if (build_options.skip_non_native and builtin.object_format != .macho) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object|
-            return llvm_object.updateDeclExports(mod, decl_index, exports);
-    }
+    if (self.llvm_object) |llvm_object|
+        return llvm_object.updateDeclExports(mod, decl_index, exports);
 
     if (self.base.options.emit == null) return;
 
@@ -2542,9 +2529,7 @@ fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
 }
 
 pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
-    if (build_options.have_llvm) {
-        if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
-    }
+    if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
     const mod = self.base.options.module.?;
     const decl = mod.declPtr(decl_index);
 
src/link/NvPtx.zig
@@ -27,7 +27,6 @@ llvm_object: *LlvmObject,
 ptx_file_name: []const u8,
 
 pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
-    if (!build_options.have_llvm) return error.PtxArchNotSupported;
     if (!options.use_llvm) return error.PtxArchNotSupported;
 
     if (!options.target.cpu.arch.isNvptx()) return error.PtxArchNotSupported;
@@ -55,7 +54,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
 }
 
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {
-    if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled.");
     if (!options.use_llvm) return error.PtxArchNotSupported;
     assert(options.target.ofmt == .nvptx);
 
@@ -64,18 +62,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
 }
 
 pub fn deinit(self: *NvPtx) void {
-    if (!build_options.have_llvm) return;
     self.llvm_object.destroy(self.base.allocator);
     self.base.allocator.free(self.ptx_file_name);
 }
 
 pub fn updateFunc(self: *NvPtx, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
-    if (!build_options.have_llvm) return;
     try self.llvm_object.updateFunc(module, func_index, air, liveness);
 }
 
 pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index) !void {
-    if (!build_options.have_llvm) return;
     return self.llvm_object.updateDecl(module, decl_index);
 }
 
@@ -85,7 +80,6 @@ pub fn updateDeclExports(
     decl_index: Module.Decl.Index,
     exports: []const *Module.Export,
 ) !void {
-    if (!build_options.have_llvm) return;
     if (build_options.skip_non_native and builtin.object_format != .nvptx) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
@@ -93,7 +87,6 @@ pub fn updateDeclExports(
 }
 
 pub fn freeDecl(self: *NvPtx, decl_index: Module.Decl.Index) void {
-    if (!build_options.have_llvm) return;
     return self.llvm_object.freeDecl(decl_index);
 }
 
@@ -102,7 +95,6 @@ pub fn flush(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) li
 }
 
 pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
-    if (!build_options.have_llvm) return;
     if (build_options.skip_non_native) {
         @panic("Attempted to compile for architecture that was disabled by build configuration");
     }
src/link/Wasm.zig
@@ -360,7 +360,7 @@ pub const StringTable = struct {
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
     assert(options.target.ofmt == .wasm);
 
-    if (build_options.have_llvm and options.use_llvm and options.use_lld) {
+    if (options.use_llvm and options.use_lld) {
         return createEmpty(allocator, options);
     }
 
@@ -522,8 +522,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
         .name = undefined,
     };
 
-    const use_llvm = build_options.have_llvm and options.use_llvm;
-    if (use_llvm) {
+    if (options.use_llvm) {
         wasm.llvm_object = try LlvmObject.create(gpa, options);
     }
     return wasm;
@@ -1273,9 +1272,7 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
 
 pub fn deinit(wasm: *Wasm) void {
     const gpa = wasm.base.allocator;
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
-    }
+    if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
 
     for (wasm.func_types.items) |*func_type| {
         func_type.deinit(gpa);
@@ -1354,9 +1351,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:
     if (build_options.skip_non_native and builtin.object_format != .wasm) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
-    }
+    if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
 
     const tracy = trace(@src());
     defer tracy.end();
@@ -1422,9 +1417,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
     if (build_options.skip_non_native and builtin.object_format != .wasm) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
-    }
+    if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
 
     const tracy = trace(@src());
     defer tracy.end();
@@ -1708,9 +1701,7 @@ pub fn updateDeclExports(
     if (build_options.skip_non_native and builtin.object_format != .wasm) {
         @panic("Attempted to compile for object format that was disabled by build configuration");
     }
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
-    }
+    if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
 
     if (wasm.base.options.emit == null) return;
 
@@ -1811,9 +1802,7 @@ pub fn updateDeclExports(
 }
 
 pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
-    }
+    if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
     const mod = wasm.base.options.module.?;
     const decl = mod.declPtr(decl_index);
     const atom_index = wasm.decls.get(decl_index).?;
@@ -3137,17 +3126,15 @@ fn resetState(wasm: *Wasm) void {
 
 pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
     if (wasm.base.options.emit == null) {
-        if (build_options.have_llvm) {
-            if (wasm.llvm_object) |llvm_object| {
-                return try llvm_object.flushModule(comp, prog_node);
-            }
+        if (wasm.llvm_object) |llvm_object| {
+            return try llvm_object.flushModule(comp, prog_node);
         }
         return;
     }
 
     if (build_options.have_llvm and wasm.base.options.use_lld) {
         return wasm.linkWithLLD(comp, prog_node);
-    } else if (build_options.have_llvm and wasm.base.options.use_llvm and !wasm.base.options.use_lld) {
+    } else if (wasm.base.options.use_llvm and !wasm.base.options.use_lld) {
         return wasm.linkWithZld(comp, prog_node);
     } else {
         return wasm.flushModule(comp, prog_node);
@@ -3365,10 +3352,8 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
     const tracy = trace(@src());
     defer tracy.end();
 
-    if (build_options.have_llvm) {
-        if (wasm.llvm_object) |llvm_object| {
-            return try llvm_object.flushModule(comp, prog_node);
-        }
+    if (wasm.llvm_object) |llvm_object| {
+        return try llvm_object.flushModule(comp, prog_node);
     }
 
     var sub_prog_node = prog_node.start("Wasm Flush", 0);
src/Compilation.zig
@@ -1027,7 +1027,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             return error.TargetRequiresSingleThreaded;
         }
 
-        const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
+        const llvm_cpu_features: ?[*:0]const u8 = if (use_llvm) blk: {
             var buf = std.ArrayList(u8).init(arena);
             for (options.target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
                 const index = @as(Target.Cpu.Feature.Set.Index, @intCast(index_usize));
@@ -5182,7 +5182,7 @@ pub fn dump_argv(argv: []const []const u8) void {
 }
 
 pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend {
-    if (build_options.have_llvm and comp.bin_file.options.use_llvm) return .stage2_llvm;
+    if (comp.bin_file.options.use_llvm) return .stage2_llvm;
     const target = comp.bin_file.options.target;
     if (target.ofmt == .c) return .stage2_c;
     return switch (target.cpu.arch) {