From 7ec7fe53597a70a3f2c9f040d7da978ae3a52a6b Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 10 Jul 2023 20:30:15 -0400 Subject: [PATCH] llvm: cleanup init --- src/codegen/llvm.zig | 304 ++++++++++++++++------------------- src/codegen/llvm/Builder.zig | 196 ++++++++++++++-------- 2 files changed, 268 insertions(+), 232 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 0ac30e00e7..c34e241fa4 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -35,7 +35,7 @@ const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; const Error = error{ OutOfMemory, CodegenFail }; -pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { +pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 { var llvm_triple = std.ArrayList(u8).init(allocator); defer llvm_triple.deinit(); @@ -208,7 +208,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { }; try llvm_triple.appendSlice(llvm_abi); - return llvm_triple.toOwnedSliceSentinel(0); + return llvm_triple.toOwnedSlice(); } pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType { @@ -602,160 +602,137 @@ pub const Object = struct { } pub fn init(gpa: Allocator, options: link.Options) !Object { - var builder = Builder{ - .gpa = gpa, - .use_lib_llvm = options.use_lib_llvm, - - .llvm_context = llvm.Context.create(), - .llvm_module = undefined, - }; - errdefer builder.llvm_context.dispose(); - - builder.initializeLLVMTarget(options.target.cpu.arch); - - builder.llvm_module = llvm.Module.createWithName(options.root_name.ptr, builder.llvm_context); - errdefer builder.llvm_module.dispose(); - const llvm_target_triple = try targetTriple(gpa, options.target); defer gpa.free(llvm_target_triple); - var error_message: [*:0]const u8 = undefined; - var target: *llvm.Target = undefined; - if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) { - defer llvm.disposeMessage(error_message); - - log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message }); - return error.InvalidLlvmTriple; - } - - builder.llvm_module.setTarget(llvm_target_triple.ptr); - var opt_di_builder: ?*llvm.DIBuilder = null; - errdefer if (opt_di_builder) |di_builder| di_builder.dispose(); - - var di_compile_unit: ?*llvm.DICompileUnit = null; - - if (!options.strip) { - switch (options.target.ofmt) { - .coff => builder.llvm_module.addModuleCodeViewFlag(), - else => builder.llvm_module.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"), - } - const di_builder = builder.llvm_module.createDIBuilder(true); - opt_di_builder = di_builder; - - // Don't use the version string here; LLVM misparses it when it - // includes the git revision. - const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{ - build_options.semver.major, - build_options.semver.minor, - build_options.semver.patch, - }); - defer gpa.free(producer); - - // We fully resolve all paths at this point to avoid lack of source line info in stack - // traces or lack of debugging information which, if relative paths were used, would - // be very location dependent. - // TODO: the only concern I have with this is WASI as either host or target, should - // we leave the paths as relative then? - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const compile_unit_dir = blk: { - const path = d: { - const mod = options.module orelse break :d "."; - break :d mod.root_pkg.root_src_directory.path orelse "."; - }; - if (std.fs.path.isAbsolute(path)) break :blk path; - break :blk std.os.realpath(path, &buf) catch path; // If realpath fails, fallback to whatever path was - }; - const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir); - defer gpa.free(compile_unit_dir_z); - - di_compile_unit = di_builder.createCompileUnit( - DW.LANG.C99, - di_builder.createFile(options.root_name, compile_unit_dir_z), - producer, - options.optimize_mode != .Debug, - "", // flags - 0, // runtime version - "", // split name - 0, // dwo id - true, // emit debug info - ); - } - - const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) - .None - else - .Aggressive; - - const reloc_mode: llvm.RelocMode = if (options.pic) - .PIC - else if (options.link_mode == .Dynamic) - llvm.RelocMode.DynamicNoPIC - else - .Static; - - const code_model: llvm.CodeModel = switch (options.machine_code_model) { - .default => .Default, - .tiny => .Tiny, - .small => .Small, - .kernel => .Kernel, - .medium => .Medium, - .large => .Large, - }; - - // TODO handle float ABI better- it should depend on the ABI portion of std.Target - const float_abi: llvm.ABIType = .Default; - - const target_machine = llvm.TargetMachine.create( - target, - llvm_target_triple.ptr, - if (options.target.cpu.model.llvm_name) |s| s.ptr else null, - options.llvm_cpu_features, - opt_level, - reloc_mode, - code_model, - options.function_sections, - float_abi, - if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null, - ); - errdefer target_machine.dispose(); - - const target_data = target_machine.createTargetDataLayout(); - errdefer target_data.dispose(); - - builder.llvm_module.setModuleDataLayout(target_data); - - if (options.pic) builder.llvm_module.setModulePICLevel(); - if (options.pie) builder.llvm_module.setModulePIELevel(); - if (code_model != .Default) builder.llvm_module.setModuleCodeModel(code_model); - - if (options.opt_bisect_limit >= 0) { - builder.llvm_context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit)); - } - - try builder.init(); + var builder = try Builder.init(.{ + .allocator = gpa, + .use_lib_llvm = options.use_lib_llvm, + .name = options.root_name, + .target = options.target, + .triple = llvm_target_triple, + }); errdefer builder.deinit(); - builder.source_filename = try builder.string(options.root_name); - builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }}); - builder.target_triple = try builder.string(llvm_target_triple); - if (std.debug.runtime_safety) { - const rep = target_data.stringRep(); - defer llvm.disposeMessage(rep); - std.testing.expectEqualStrings( - std.mem.span(rep), - builder.data_layout.toSlice(&builder).?, - ) catch unreachable; + var target_machine: *llvm.TargetMachine = undefined; + var target_data: *llvm.TargetData = undefined; + if (builder.useLibLlvm()) { + if (!options.strip) { + switch (options.target.ofmt) { + .coff => builder.llvm.module.?.addModuleCodeViewFlag(), + else => builder.llvm.module.?.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"), + } + builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true); + + // Don't use the version string here; LLVM misparses it when it + // includes the git revision. + const producer = try builder.fmt("zig {d}.{d}.{d}", .{ + build_options.semver.major, + build_options.semver.minor, + build_options.semver.patch, + }); + + // We fully resolve all paths at this point to avoid lack of source line info in stack + // traces or lack of debugging information which, if relative paths were used, would + // be very location dependent. + // TODO: the only concern I have with this is WASI as either host or target, should + // we leave the paths as relative then? + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const compile_unit_dir = blk: { + const path = d: { + const mod = options.module orelse break :d "."; + break :d mod.root_pkg.root_src_directory.path orelse "."; + }; + if (std.fs.path.isAbsolute(path)) break :blk path; + break :blk std.os.realpath(path, &buf) catch path; // If realpath fails, fallback to whatever path was + }; + const compile_unit_dir_z = try builder.gpa.dupeZ(u8, compile_unit_dir); + defer builder.gpa.free(compile_unit_dir_z); + + builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit( + DW.LANG.C99, + builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z), + producer.toSlice(&builder).?, + options.optimize_mode != .Debug, + "", // flags + 0, // runtime version + "", // split name + 0, // dwo id + true, // emit debug info + ); + } + + const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) + .None + else + .Aggressive; + + const reloc_mode: llvm.RelocMode = if (options.pic) + .PIC + else if (options.link_mode == .Dynamic) + llvm.RelocMode.DynamicNoPIC + else + .Static; + + const code_model: llvm.CodeModel = switch (options.machine_code_model) { + .default => .Default, + .tiny => .Tiny, + .small => .Small, + .kernel => .Kernel, + .medium => .Medium, + .large => .Large, + }; + + // TODO handle float ABI better- it should depend on the ABI portion of std.Target + const float_abi: llvm.ABIType = .Default; + + target_machine = llvm.TargetMachine.create( + builder.llvm.target.?, + builder.target_triple.toSlice(&builder).?.ptr, + if (options.target.cpu.model.llvm_name) |s| s.ptr else null, + options.llvm_cpu_features, + opt_level, + reloc_mode, + code_model, + options.function_sections, + float_abi, + if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null, + ); + errdefer target_machine.dispose(); + + target_data = target_machine.createTargetDataLayout(); + errdefer target_data.dispose(); + + builder.llvm.module.?.setModuleDataLayout(target_data); + + if (options.pic) builder.llvm.module.?.setModulePICLevel(); + if (options.pie) builder.llvm.module.?.setModulePIELevel(); + if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model); + + if (options.opt_bisect_limit >= 0) { + builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit)); + } + + builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }}); + if (std.debug.runtime_safety) { + const rep = target_data.stringRep(); + defer llvm.disposeMessage(rep); + std.testing.expectEqualStrings( + std.mem.span(rep), + builder.data_layout.toSlice(&builder).?, + ) catch unreachable; + } } - return Object{ + return .{ .gpa = gpa, .builder = builder, .module = options.module.?, - .llvm_module = builder.llvm_module, + .llvm_module = builder.llvm.module.?, .di_map = .{}, - .di_builder = opt_di_builder, - .di_compile_unit = di_compile_unit, - .context = builder.llvm_context, + .di_builder = builder.llvm.di_builder, + .di_compile_unit = builder.llvm.di_compile_unit, + .context = builder.llvm.context, .target_machine = target_machine, .target_data = target_data, .target = options.target, @@ -770,15 +747,10 @@ pub const Object = struct { } pub fn deinit(self: *Object, gpa: Allocator) void { - if (self.di_builder) |dib| { - dib.dispose(); - self.di_map.deinit(gpa); - self.di_type_map.deinit(gpa); - } + self.di_map.deinit(gpa); + self.di_type_map.deinit(gpa); self.target_data.dispose(); self.target_machine.dispose(); - self.llvm_module.dispose(); - self.context.dispose(); self.decl_map.deinit(gpa); self.named_enum_map.deinit(gpa); self.type_map.deinit(gpa); @@ -845,7 +817,7 @@ pub const Object = struct { .mutability = .constant, .init = str_init, }; - try o.builder.llvm_globals.append(o.gpa, str_global); + try o.builder.llvm.globals.append(o.gpa, str_global); const str_global_index = try o.builder.addGlobal(.none, global); try o.builder.variables.append(o.gpa, variable); @@ -875,7 +847,7 @@ pub const Object = struct { .mutability = .constant, .init = error_name_table_init, }; - try o.builder.llvm_globals.append(o.gpa, error_name_table_global); + try o.builder.llvm.globals.append(o.gpa, error_name_table_global); _ = try o.builder.addGlobal(.none, global); try o.builder.variables.append(o.gpa, variable); @@ -941,7 +913,7 @@ pub const Object = struct { llvm_global.replaceAllUsesWith(other_llvm_global); deleteLlvmGlobal(llvm_global); - object.builder.llvm_globals.items[@intFromEnum(global)] = other_llvm_global; + object.builder.llvm.globals.items[@intFromEnum(global)] = other_llvm_global; } object.extern_collisions.clearRetainingCapacity(); @@ -960,7 +932,7 @@ pub const Object = struct { other_llvm_global.replaceAllUsesWith(llvm_global); try global.takeName(&object.builder, other_global); deleteLlvmGlobal(other_llvm_global); - object.builder.llvm_globals.items[@intFromEnum(other_global)] = llvm_global; + object.builder.llvm.globals.items[@intFromEnum(other_global)] = llvm_global; // Problem: now we need to replace in the decl_map that // the extern decl index points to this new global. However we don't // know the decl index. @@ -2765,7 +2737,7 @@ pub const Object = struct { .global = @enumFromInt(o.builder.globals.count()), .init = llvm_init, }; - try o.builder.llvm_globals.append(o.gpa, llvm_global); + try o.builder.llvm.globals.append(o.gpa, llvm_global); _ = try o.builder.addGlobal(.none, global); try o.builder.variables.append(o.gpa, variable); @@ -2908,7 +2880,7 @@ pub const Object = struct { }; } - try o.builder.llvm_globals.append(o.gpa, llvm_fn); + try o.builder.llvm.globals.append(o.gpa, llvm_fn); gop.value_ptr.* = try o.builder.addGlobal(fqn, global); try o.builder.functions.append(o.gpa, function); return global.kind.function; @@ -3017,7 +2989,7 @@ pub const Object = struct { llvm_global.setUnnamedAddr(.True); } - try o.builder.llvm_globals.append(o.gpa, llvm_global); + try o.builder.llvm.globals.append(o.gpa, llvm_global); gop.value_ptr.* = try o.builder.addGlobal(name, global); try o.builder.variables.append(o.gpa, variable); return global.kind.variable; @@ -4553,7 +4525,7 @@ pub const DeclGen = struct { // TODO: How should this work then the address space of a global changed? llvm_global.replaceAllUsesWith(new_global); new_global.takeName(llvm_global); - o.builder.llvm_globals.items[@intFromEnum(object.ptrConst(&o.builder).global)] = + o.builder.llvm.globals.items[@intFromEnum(object.ptrConst(&o.builder).global)] = new_global; llvm_global.deleteGlobal(); llvm_global = new_global; @@ -4699,7 +4671,7 @@ pub const FuncGen = struct { .mutability = .constant, .init = llvm_val, }; - try o.builder.llvm_globals.append(o.gpa, llvm_global); + try o.builder.llvm.globals.append(o.gpa, llvm_global); _ = try o.builder.addGlobal(.none, global); try o.builder.variables.append(o.gpa, variable); @@ -7855,7 +7827,7 @@ pub const FuncGen = struct { .global = @enumFromInt(o.builder.globals.count()), }; - try o.builder.llvm_globals.append(self.gpa, f); + try o.builder.llvm.globals.append(self.gpa, f); _ = try o.builder.addGlobal(fn_name, global); try o.builder.functions.append(self.gpa, function); break :b f; @@ -9372,7 +9344,7 @@ pub const FuncGen = struct { self.builder.positionBuilderAtEnd(unnamed_block); _ = self.builder.buildRet(Builder.Constant.false.toLlvm(&o.builder)); - try o.builder.llvm_globals.append(self.gpa, fn_val); + try o.builder.llvm.globals.append(self.gpa, fn_val); _ = try o.builder.addGlobal(llvm_fn_name, global); try o.builder.functions.append(self.gpa, function); gop.value_ptr.* = global.kind.function; @@ -9484,7 +9456,7 @@ pub const FuncGen = struct { self.builder.positionBuilderAtEnd(bad_value_block); _ = self.builder.buildUnreachable(); - try o.builder.llvm_globals.append(self.gpa, fn_val); + try o.builder.llvm.globals.append(self.gpa, fn_val); gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global); try o.builder.functions.append(self.gpa, function); return fn_val; @@ -9515,7 +9487,7 @@ pub const FuncGen = struct { .global = @enumFromInt(o.builder.globals.count()), }; - try o.builder.llvm_globals.append(self.gpa, llvm_fn); + try o.builder.llvm.globals.append(self.gpa, llvm_fn); _ = try o.builder.addGlobal(try o.builder.string(lt_errors_fn_name), global); try o.builder.functions.append(self.gpa, function); return llvm_fn; @@ -10156,7 +10128,7 @@ pub const FuncGen = struct { .mutability = .constant, .init = undef_init, }; - try o.builder.llvm_globals.append(o.gpa, error_name_table_global); + try o.builder.llvm.globals.append(o.gpa, error_name_table_global); _ = try o.builder.addGlobal(name, global); try o.builder.variables.append(o.gpa, variable); diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 1381e5d9d0..22df52753a 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -1,12 +1,16 @@ gpa: Allocator, use_lib_llvm: bool, -llvm_context: *llvm.Context, -llvm_module: *llvm.Module, -di_builder: ?*llvm.DIBuilder = null, -llvm_types: std.ArrayListUnmanaged(*llvm.Type) = .{}, -llvm_globals: std.ArrayListUnmanaged(*llvm.Value) = .{}, -llvm_constants: std.ArrayListUnmanaged(*llvm.Value) = .{}, +llvm: if (build_options.have_llvm) struct { + context: *llvm.Context, + module: ?*llvm.Module = null, + target: ?*llvm.Target = null, + di_builder: ?*llvm.DIBuilder = null, + di_compile_unit: ?*llvm.DICompileUnit = null, + types: std.ArrayListUnmanaged(*llvm.Type) = .{}, + globals: std.ArrayListUnmanaged(*llvm.Value) = .{}, + constants: std.ArrayListUnmanaged(*llvm.Value) = .{}, +} else void, source_filename: String = .none, data_layout: String = .none, @@ -38,6 +42,14 @@ constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{}, pub const expected_fields_len = 32; pub const expected_gep_indices_len = 8; +pub const Options = struct { + allocator: Allocator, + use_lib_llvm: bool = false, + name: []const u8 = &.{}, + target: std.Target = builtin.target, + triple: []const u8 = &.{}, +}; + pub const String = enum(u32) { none = std.math.maxInt(u31), empty, @@ -481,7 +493,7 @@ pub const Type = enum(u32) { pub fn toLlvm(self: Type, builder: *const Builder) *llvm.Type { assert(builder.useLibLlvm()); - return builder.llvm_types.items[@intFromEnum(self)]; + return builder.llvm.types.items[@intFromEnum(self)]; } }; @@ -751,7 +763,7 @@ pub const Global = struct { pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { assert(builder.useLibLlvm()); - return builder.llvm_globals.items[@intFromEnum(self)]; + return builder.llvm.globals.items[@intFromEnum(self)]; } const FormatData = struct { @@ -780,9 +792,9 @@ pub const Global = struct { pub fn renameAssumeCapacity(self: Index, builder: *Builder, name: String) void { const index = @intFromEnum(self); if (builder.globals.keys()[index] == name) return; - if (builder.useLibLlvm()) builder.llvm_globals.appendAssumeCapacity(builder.llvm_globals.items[index]); + if (builder.useLibLlvm()) builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]); _ = builder.addGlobalAssumeCapacity(name, builder.globals.values()[index]); - if (builder.useLibLlvm()) _ = builder.llvm_globals.pop(); + if (builder.useLibLlvm()) _ = builder.llvm.globals.pop(); builder.globals.swapRemoveAt(index); self.updateName(builder); } @@ -802,7 +814,7 @@ pub const Global = struct { if (!builder.useLibLlvm()) return; const index = @intFromEnum(self); const slice = builder.globals.keys()[index].toSlice(builder) orelse ""; - builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len); + builder.llvm.globals.items[index].setValueName2(slice.ptr, slice.len); } }; @@ -1414,7 +1426,7 @@ pub const Constant = enum(u32) { pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value { assert(builder.useLibLlvm()); return switch (self.unwrap()) { - .constant => |constant| builder.llvm_constants.items[constant], + .constant => |constant| builder.llvm.constants.items[constant], .global => |global| global.toLlvm(builder), }; } @@ -1436,26 +1448,70 @@ pub const Value = enum(u32) { } }; -pub fn init(self: *Builder) Allocator.Error!void { +pub const InitError = error{ + InvalidLlvmTriple, +} || Allocator.Error; + +pub fn init(options: Options) InitError!Builder { + var self = Builder{ + .gpa = options.allocator, + .use_lib_llvm = options.use_lib_llvm, + .llvm = undefined, + }; + if (self.useLibLlvm()) self.llvm = .{ .context = llvm.Context.create() }; + errdefer self.deinit(); + try self.string_indices.append(self.gpa, 0); assert(try self.string("") == .empty); + if (options.name.len > 0) self.source_filename = try self.string(options.name); + self.initializeLLVMTarget(options.target.cpu.arch); + if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName( + (self.source_filename.toSlice(&self) orelse "").ptr, + self.llvm.context, + ); + + if (options.triple.len > 0) { + self.target_triple = try self.string(options.triple); + + if (self.useLibLlvm()) { + var error_message: [*:0]const u8 = undefined; + var target: *llvm.Target = undefined; + if (llvm.Target.getFromTriple( + self.target_triple.toSlice(&self).?.ptr, + &target, + &error_message, + ).toBool()) { + defer llvm.disposeMessage(error_message); + + log.err("LLVM failed to parse '{s}': {s}", .{ + self.target_triple.toSlice(&self).?, + error_message, + }); + return InitError.InvalidLlvmTriple; + } + self.llvm.target = target; + self.llvm.module.?.setTarget(self.target_triple.toSlice(&self).?.ptr); + } + } + { const static_len = @typeInfo(Type).Enum.fields.len - 1; try self.type_map.ensureTotalCapacity(self.gpa, static_len); try self.type_items.ensureTotalCapacity(self.gpa, static_len); - if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len); + if (self.useLibLlvm()) try self.llvm.types.ensureTotalCapacity(self.gpa, static_len); inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| { const result = self.getOrPutTypeNoExtraAssumeCapacity( .{ .tag = .simple, .data = simple_field.value }, ); assert(result.new and result.type == @field(Type, simple_field.name)); - if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity( - @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context), + if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity( + @field(llvm.Context, simple_field.name ++ "Type")(self.llvm.context), ); } - inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits| assert(self.intTypeAssumeCapacity(bits) == - @field(Type, std.fmt.comptimePrint("i{d}", .{bits}))); + inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits| + assert(self.intTypeAssumeCapacity(bits) == + @field(Type, std.fmt.comptimePrint("i{d}", .{bits}))); inline for (.{0}) |addr_space| assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr); } @@ -1463,13 +1519,11 @@ pub fn init(self: *Builder) Allocator.Error!void { assert(try self.intConst(.i1, 0) == .false); assert(try self.intConst(.i1, 1) == .true); assert(try self.noneConst(.token) == .none); + + return self; } pub fn deinit(self: *Builder) void { - self.llvm_types.deinit(self.gpa); - self.llvm_globals.deinit(self.gpa); - self.llvm_constants.deinit(self.gpa); - self.string_map.deinit(self.gpa); self.string_bytes.deinit(self.gpa); self.string_indices.deinit(self.gpa); @@ -1492,6 +1546,14 @@ pub fn deinit(self: *Builder) void { self.constant_extra.deinit(self.gpa); self.constant_limbs.deinit(self.gpa); + if (self.useLibLlvm()) { + self.llvm.constants.deinit(self.gpa); + self.llvm.globals.deinit(self.gpa); + self.llvm.types.deinit(self.gpa); + if (self.llvm.di_builder) |di_builder| di_builder.dispose(); + if (self.llvm.module) |module| module.dispose(); + self.llvm.context.dispose(); + } self.* = undefined; } @@ -1807,7 +1869,7 @@ pub fn namedTypeSetBody( const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len); defer self.gpa.free(llvm_fields); for (llvm_fields, body_fields) |*llvm_field, body_field| llvm_field.* = body_field.toLlvm(self); - self.llvm_types.items[@intFromEnum(named_type)].structSetBody( + self.llvm.types.items[@intFromEnum(named_type)].structSetBody( llvm_fields.ptr, @intCast(llvm_fields.len), switch (body_item.tag) { @@ -1869,7 +1931,7 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo try self.constant_map.ensureUnusedCapacity(self.gpa, 1); try self.constant_items.ensureUnusedCapacity(self.gpa, 1); try self.constant_limbs.ensureUnusedCapacity(self.gpa, Constant.Integer.limbs + value.limbs.len); - if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, 1); + if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, 1); return self.bigIntConstAssumeCapacity(ty, value); } @@ -2166,7 +2228,7 @@ fn isValidIdentifier(id: []const u8) bool { } fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void { - if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1); + if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1); try self.string_map.ensureUnusedCapacity(self.gpa, 1); if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)})); @@ -2222,7 +2284,7 @@ fn fnTypeAssumeCapacity( const llvm_params = try self.gpa.alloc(*llvm.Type, params.len); defer self.gpa.free(llvm_params); for (llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(self); - self.llvm_types.appendAssumeCapacity(llvm.functionType( + self.llvm.types.appendAssumeCapacity(llvm.functionType( ret.toLlvm(self), llvm_params.ptr, @intCast(llvm_params.len), @@ -2240,7 +2302,7 @@ fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type { assert(bits > 0); const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits }); if (self.useLibLlvm() and result.new) - self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits)); + self.llvm.types.appendAssumeCapacity(self.llvm.context.intType(bits)); return result.type; } @@ -2249,7 +2311,7 @@ fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type { .{ .tag = .pointer, .data = @intFromEnum(addr_space) }, ); if (self.useLibLlvm() and result.new) - self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space))); + self.llvm.types.appendAssumeCapacity(self.llvm.context.pointerType(@intFromEnum(addr_space))); return result.type; } @@ -2286,7 +2348,7 @@ fn vectorTypeAssumeCapacity( .tag = tag, .data = self.addTypeExtraAssumeCapacity(data), }); - if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(switch (kind) { + if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity(switch (kind) { .normal => &llvm.Type.vectorType, .scalable => &llvm.Type.scalableVectorType, }(child.toLlvm(self), @intCast(len))); @@ -2319,7 +2381,7 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type { .tag = .small_array, .data = self.addTypeExtraAssumeCapacity(data), }); - if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity( + if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity( child.toLlvm(self).arrayType(@intCast(len)), ); } @@ -2352,7 +2414,7 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type { .tag = .array, .data = self.addTypeExtraAssumeCapacity(data), }); - if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity( + if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity( child.toLlvm(self).arrayType(@intCast(len)), ); } @@ -2406,7 +2468,7 @@ fn structTypeAssumeCapacity( defer allocator.free(llvm_fields); for (llvm_fields, fields) |*llvm_field, field| llvm_field.* = field.toLlvm(self); - self.llvm_types.appendAssumeCapacity(self.llvm_context.structType( + self.llvm.types.appendAssumeCapacity(self.llvm.context.structType( llvm_fields.ptr, @intCast(llvm_fields.len), switch (kind) { @@ -2456,8 +2518,8 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { }); const result: Type = @enumFromInt(gop.index); type_gop.value_ptr.* = result; - if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity( - self.llvm_context.structCreateNamed(id.toSlice(self) orelse ""), + if (self.useLibLlvm()) self.llvm.types.appendAssumeCapacity( + self.llvm.context.structCreateNamed(id.toSlice(self) orelse ""), ); return result; } @@ -2481,7 +2543,7 @@ fn ensureUnusedTypeCapacity( self.gpa, count * (@typeInfo(E).Struct.fields.len + trail_len), ) else assert(trail_len == 0); - if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count); + if (self.useLibLlvm()) try self.llvm.types.ensureUnusedCapacity(self.gpa, count); } fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } { @@ -2613,9 +2675,9 @@ fn bigIntConstAssumeCapacity( if (self.useLibLlvm()) { const llvm_type = ty.toLlvm(self); if (canonical_value.to(c_longlong)) |small| { - self.llvm_constants.appendAssumeCapacity(llvm_type.constInt(@bitCast(small), .True)); + self.llvm.constants.appendAssumeCapacity(llvm_type.constInt(@bitCast(small), .True)); } else |_| if (canonical_value.to(c_ulonglong)) |small| { - self.llvm_constants.appendAssumeCapacity(llvm_type.constInt(small, .False)); + self.llvm.constants.appendAssumeCapacity(llvm_type.constInt(small, .False)); } else |_| { const llvm_limbs = try allocator.alloc(u64, std.math.divCeil( usize, @@ -2643,7 +2705,7 @@ fn bigIntConstAssumeCapacity( } result_limb.* = llvm_limb; } - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( llvm_type.constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs.ptr), ); } @@ -2656,7 +2718,7 @@ fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .half, .data = @as(u16, @bitCast(val)) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity( if (std.math.isSignalNan(val)) Type.i16.toLlvm(self).constInt(@as(u16, @bitCast(val)), .False) .constBitCast(Type.half.toLlvm(self)) @@ -2671,7 +2733,7 @@ fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .bfloat, .data = @bitCast(val) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity( if (std.math.isSignalNan(val)) Type.i16.toLlvm(self).constInt(@as(u32, @bitCast(val)) >> 16, .False) .constBitCast(Type.bfloat.toLlvm(self)) @@ -2680,7 +2742,7 @@ fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant { ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val)); + self.llvm.constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val)); return result.constant; } @@ -2688,7 +2750,7 @@ fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .float, .data = @bitCast(val) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity( if (std.math.isSignalNan(val)) Type.i32.toLlvm(self).constInt(@as(u32, @bitCast(val)), .False) .constBitCast(Type.float.toLlvm(self)) @@ -2725,7 +2787,7 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant { .hi = @truncate(@as(u64, @bitCast(val))), }), }); - if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity( + if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( if (std.math.isSignalNan(val)) Type.i64.toLlvm(self).constInt(@as(u64, @bitCast(val)), .False) .constBitCast(Type.double.toLlvm(self)) @@ -2771,7 +2833,7 @@ fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant { @truncate(@as(u128, @bitCast(val))), @intCast(@as(u128, @bitCast(val)) >> 64), }; - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( Type.i128.toLlvm(self) .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs) .constBitCast(Type.fp128.toLlvm(self)), @@ -2815,7 +2877,7 @@ fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant { @truncate(@as(u80, @bitCast(val))), @intCast(@as(u80, @bitCast(val)) >> 64), }; - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( Type.i80.toLlvm(self) .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs) .constBitCast(Type.x86_fp80.toLlvm(self)), @@ -2857,7 +2919,7 @@ fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant { }); if (self.useLibLlvm()) { const llvm_limbs: *const [2]u64 = @ptrCast(&val); - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( Type.i128.toLlvm(self) .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs) .constBitCast(Type.ppc_fp128.toLlvm(self)), @@ -2873,7 +2935,7 @@ fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant { .{ .tag = .null, .data = @intFromEnum(ty) }, ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); + self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); return result.constant; } @@ -2883,7 +2945,7 @@ fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant { .{ .tag = .none, .data = @intFromEnum(ty) }, ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); + self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); return result.constant; } @@ -2929,7 +2991,7 @@ fn structConstAssumeCapacity( defer allocator.free(llvm_vals); for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( ty.toLlvm(self).constNamedStruct(llvm_vals.ptr, @intCast(llvm_vals.len)), ); } @@ -2971,7 +3033,7 @@ fn arrayConstAssumeCapacity( defer allocator.free(llvm_vals); for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( type_extra.child.toLlvm(self).constArray(llvm_vals.ptr, @intCast(llvm_vals.len)), ); } @@ -2985,8 +3047,8 @@ fn stringConstAssumeCapacity(self: *Builder, val: String) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .string, .data = @intFromEnum(val) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( - self.llvm_context.constString(slice.ptr, @intCast(slice.len), .True), + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity( + self.llvm.context.constString(slice.ptr, @intCast(slice.len), .True), ); return result.constant; } @@ -2998,8 +3060,8 @@ fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .string_null, .data = @intFromEnum(val) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( - self.llvm_context.constString(slice.ptr, @intCast(slice.len + 1), .True), + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity( + self.llvm.context.constString(slice.ptr, @intCast(slice.len + 1), .True), ); return result.constant; } @@ -3032,7 +3094,7 @@ fn vectorConstAssumeCapacity( defer allocator.free(llvm_vals); for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); - self.llvm_constants.appendAssumeCapacity( + self.llvm.constants.appendAssumeCapacity( llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)), ); } @@ -3061,7 +3123,7 @@ fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant { .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) }, ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); + self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); return result.constant; } @@ -3078,7 +3140,7 @@ fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant { .{ .tag = .undef, .data = @intFromEnum(ty) }, ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); + self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); return result.constant; } @@ -3095,7 +3157,7 @@ fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant { .{ .tag = .poison, .data = @intFromEnum(ty) }, ); if (self.useLibLlvm() and result.new) - self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); + self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); return result.constant; } @@ -3128,7 +3190,7 @@ fn blockAddrConstAssumeCapacity( .tag = .blockaddress, .data = self.addConstantExtraAssumeCapacity(data), }); - if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity( + if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity( function.toLlvm(self).blockAddress(block.toValue(self, function).toLlvm(self, function)), ); } @@ -3139,7 +3201,7 @@ fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Inde const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined); + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(undefined); return result.constant; } @@ -3147,7 +3209,7 @@ fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant { const result = self.getOrPutConstantNoExtraAssumeCapacity( .{ .tag = .no_cfi, .data = @intFromEnum(function) }, ); - if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined); + if (self.useLibLlvm() and result.new) self.llvm.constants.appendAssumeCapacity(undefined); return result.constant; } @@ -3226,7 +3288,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty: .tag = tag, .data = self.addConstantExtraAssumeCapacity(data.cast), }); - if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) { + if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) { .trunc => &llvm.Value.constTrunc, .zext => &llvm.Value.constZExt, .sext => &llvm.Value.constSExt, @@ -3330,7 +3392,7 @@ fn gepConstAssumeCapacity( defer allocator.free(llvm_indices); for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self); - self.llvm_constants.appendAssumeCapacity(switch (kind) { + self.llvm.constants.appendAssumeCapacity(switch (kind) { .normal => &llvm.Type.constGEP, .inbounds => &llvm.Type.constInBoundsGEP, }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(indices.len))); @@ -3374,7 +3436,7 @@ fn binConstAssumeCapacity( .tag = tag, .data = self.addConstantExtraAssumeCapacity(data.bin), }); - if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) { + if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) { .add => &llvm.Value.constAdd, .sub => &llvm.Value.constSub, .mul => &llvm.Value.constMul, @@ -3402,7 +3464,7 @@ fn ensureUnusedConstantCapacity( self.gpa, count * (@typeInfo(E).Struct.fields.len + trail_len), ) else assert(trail_len == 0); - if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, count); + if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, count); } fn getOrPutConstantNoExtraAssumeCapacity( @@ -3516,13 +3578,15 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite return self.constantExtraDataTrail(T, index).data; } -inline fn useLibLlvm(self: *const Builder) bool { +pub inline fn useLibLlvm(self: *const Builder) bool { return build_options.have_llvm and self.use_lib_llvm; } const assert = std.debug.assert; const build_options = @import("build_options"); +const builtin = @import("builtin"); const llvm = @import("bindings.zig"); +const log = std.log.scoped(.llvm); const std = @import("std"); const Allocator = std.mem.Allocator;