llvm: cleanup init

This commit is contained in:
Jacob Young 2023-07-10 20:30:15 -04:00
parent ff8a49448c
commit 7ec7fe5359
2 changed files with 268 additions and 232 deletions

View file

@ -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);

View file

@ -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;