Commit 7ec7fe5359
Changed files (2)
src
codegen
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;
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 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();
- var di_compile_unit: ?*llvm.DICompileUnit = null;
+ 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,
+ });
- 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 ".";
+ // 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
};
- 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 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 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,
- };
+ const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
+ .None
+ else
+ .Aggressive;
- // 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 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,
+ };
- const target_data = target_machine.createTargetDataLayout();
- errdefer target_data.dispose();
+ // 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();
- builder.llvm_module.setModuleDataLayout(target_data);
+ target_data = target_machine.createTargetDataLayout();
+ errdefer target_data.dispose();
- if (options.pic) builder.llvm_module.setModulePICLevel();
- if (options.pie) builder.llvm_module.setModulePIELevel();
- if (code_model != .Default) builder.llvm_module.setModuleCodeModel(code_model);
+ builder.llvm.module.?.setModuleDataLayout(target_data);
- if (options.opt_bisect_limit >= 0) {
- builder.llvm_context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
- }
+ if (options.pic) builder.llvm.module.?.setModulePICLevel();
+ if (options.pie) builder.llvm.module.?.setModulePIELevel();
+ if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);
- try builder.init();
- 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 (options.opt_bisect_limit >= 0) {
+ builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
+ }
- 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;
+ 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);