llvm: cleanup management and implement more const functions

This commit is contained in:
Jacob Young
2023-07-11 02:14:17 -04:00
parent 7ec7fe5359
commit 1f8407c356
3 changed files with 632 additions and 143 deletions

View File

@@ -533,15 +533,6 @@ const DataLayoutBuilder = struct {
}
};
/// TODO can this be done with simpler logic / different API binding?
fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {
if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
llvm_global.deleteFunction();
return;
}
return llvm_global.deleteGlobal();
}
pub const Object = struct {
gpa: Allocator,
builder: Builder,
@@ -818,7 +809,7 @@ pub const Object = struct {
.init = str_init,
};
try o.builder.llvm.globals.append(o.gpa, str_global);
const str_global_index = try o.builder.addGlobal(.none, global);
const str_global_index = try o.builder.addGlobal(.empty, global);
try o.builder.variables.append(o.gpa, variable);
llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
@@ -848,7 +839,7 @@ pub const Object = struct {
.init = error_name_table_init,
};
try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
_ = try o.builder.addGlobal(.none, global);
_ = try o.builder.addGlobal(.empty, global);
try o.builder.variables.append(o.gpa, variable);
const error_name_table_ptr = error_name_table_global;
@@ -904,35 +895,27 @@ pub const Object = struct {
// This map has externs with incorrect symbol names.
for (object.extern_collisions.keys()) |decl_index| {
const global = object.decl_map.get(decl_index) orelse continue;
const llvm_global = global.toLlvm(&object.builder);
// Same logic as below but for externs instead of exports.
const decl_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(mod.declPtr(decl_index).name)) orelse continue;
const other_global = object.builder.getGlobal(decl_name) orelse continue;
const other_llvm_global = other_global.toLlvm(&object.builder);
if (other_llvm_global == llvm_global) continue;
if (other_global.eql(global, &object.builder)) continue;
llvm_global.replaceAllUsesWith(other_llvm_global);
deleteLlvmGlobal(llvm_global);
object.builder.llvm.globals.items[@intFromEnum(global)] = other_llvm_global;
try global.replace(other_global, &object.builder);
}
object.extern_collisions.clearRetainingCapacity();
for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
const global = object.decl_map.get(decl_index) orelse continue;
const llvm_global = global.toLlvm(&object.builder);
for (export_list.items) |exp| {
// Detect if the LLVM global has already been created as an extern. In such
// case, we need to replace all uses of it with this exported global.
const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
const other_global = object.builder.getGlobal(exp_name) orelse continue;
const other_llvm_global = other_global.toLlvm(&object.builder);
if (other_llvm_global == llvm_global) continue;
if (other_global.eql(global, &object.builder)) continue;
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;
try global.takeName(other_global, &object.builder);
try other_global.replace(global, &object.builder);
// 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.
@@ -1519,7 +1502,7 @@ pub const Object = struct {
}
}
try global.rename(&self.builder, decl_name);
try global.rename(decl_name, &self.builder);
global.ptr(&self.builder).unnamed_addr = .default;
llvm_global.setUnnamedAddr(.False);
global.ptr(&self.builder).linkage = .external;
@@ -1558,7 +1541,7 @@ pub const Object = struct {
global.ptr(&self.builder).updateAttributes();
} else if (exports.len != 0) {
const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name));
try global.rename(&self.builder, exp_name);
try global.rename(exp_name, &self.builder);
global.ptr(&self.builder).unnamed_addr = .default;
llvm_global.setUnnamedAddr(.False);
if (mod.wantDllExports()) {
@@ -1641,7 +1624,7 @@ pub const Object = struct {
}
} else {
const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)));
try global.rename(&self.builder, fqn);
try global.rename(fqn, &self.builder);
global.ptr(&self.builder).linkage = .internal;
llvm_global.setLinkage(.Internal);
if (mod.wantDllExports()) {
@@ -2738,7 +2721,7 @@ pub const Object = struct {
.init = llvm_init,
};
try o.builder.llvm.globals.append(o.gpa, llvm_global);
_ = try o.builder.addGlobal(.none, global);
_ = try o.builder.addGlobal(.empty, global);
try o.builder.variables.append(o.gpa, variable);
const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace)
@@ -4473,8 +4456,8 @@ pub const DeclGen = struct {
_ = try o.resolveLlvmFunction(extern_func.decl);
} else {
const target = mod.getTarget();
const object = try o.resolveGlobalDecl(decl_index);
const global = object.ptrConst(&o.builder).global;
const variable = try o.resolveGlobalDecl(decl_index);
const global = variable.ptrConst(&o.builder).global;
var llvm_global = global.toLlvm(&o.builder);
global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
llvm_global.setAlignment(decl.getAlignment(mod));
@@ -4483,18 +4466,18 @@ pub const DeclGen = struct {
llvm_global.setSection(section);
}
assert(decl.has_tv);
const init_val = if (decl.val.getVariable(mod)) |decl_var| init_val: {
object.ptr(&o.builder).mutability = .global;
break :init_val decl_var.init;
} else init_val: {
object.ptr(&o.builder).mutability = .constant;
const init_val = if (decl.val.getVariable(mod)) |decl_var| decl_var.init else init_val: {
variable.ptr(&o.builder).mutability = .constant;
llvm_global.setGlobalConstant(.True);
break :init_val decl.val.toIntern();
};
if (init_val != .none) {
const llvm_init = try o.lowerValue(init_val);
const llvm_init_ty = llvm_init.typeOf(&o.builder);
global.ptr(&o.builder).type = llvm_init_ty;
variable.ptr(&o.builder).mutability = .global;
variable.ptr(&o.builder).init = llvm_init;
if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) {
object.ptr(&o.builder).init = llvm_init;
llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
} else {
// LLVM does not allow us to change the type of globals. So we must
@@ -4512,7 +4495,7 @@ pub const DeclGen = struct {
// Related: https://github.com/ziglang/zig/issues/13265
const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
const new_global = o.llvm_module.addGlobalInAddressSpace(
llvm_init.typeOf(&o.builder).toLlvm(&o.builder),
llvm_init_ty.toLlvm(&o.builder),
"",
@intFromEnum(llvm_global_addrspace),
);
@@ -4525,7 +4508,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(variable.ptrConst(&o.builder).global)] =
new_global;
llvm_global.deleteGlobal();
llvm_global = new_global;
@@ -4672,7 +4655,7 @@ pub const FuncGen = struct {
.init = llvm_val,
};
try o.builder.llvm.globals.append(o.gpa, llvm_global);
_ = try o.builder.addGlobal(.none, global);
_ = try o.builder.addGlobal(.empty, global);
try o.builder.variables.append(o.gpa, variable);
const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
@@ -9312,6 +9295,7 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
.body = {},
};
const prev_block = self.builder.getInsertBlock();
@@ -9395,6 +9379,7 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
.body = {},
};
const prev_block = self.builder.getInsertBlock();
@@ -9485,6 +9470,7 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
.body = {},
};
try o.builder.llvm.globals.append(self.gpa, llvm_fn);

View File

@@ -29,6 +29,7 @@ type_extra: std.ArrayListUnmanaged(u32) = .{},
globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},
next_unnamed_global: String = @enumFromInt(0),
next_replaced_global: String = .none,
next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{},
aliases: std.ArrayListUnmanaged(Alias) = .{},
variables: std.ArrayListUnmanaged(Variable) = .{},
@@ -55,6 +56,11 @@ pub const String = enum(u32) {
empty,
_,
pub fn isAnon(self: String) bool {
assert(self != .none);
return self.toIndex() == null;
}
pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
const index = self.toIndex() orelse return null;
const start = b.string_indices.items[index];
@@ -743,18 +749,36 @@ pub const Global = struct {
alias: Alias.Index,
variable: Variable.Index,
function: Function.Index,
replaced: Global.Index,
},
pub const Index = enum(u32) {
none = std.math.maxInt(u32),
_,
pub fn unwrap(self: Index, builder: *const Builder) Index {
var cur = self;
while (true) {
const replacement = cur.getReplacement(builder);
if (replacement == .none) return cur;
cur = replacement;
}
}
pub fn eql(self: Index, other: Index, builder: *const Builder) bool {
return self.unwrap(builder) == other.unwrap(builder);
}
pub fn name(self: Index, builder: *const Builder) String {
return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
}
pub fn ptr(self: Index, builder: *Builder) *Global {
return &builder.globals.values()[@intFromEnum(self)];
return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
}
pub fn ptrConst(self: Index, builder: *const Builder) *const Global {
return &builder.globals.values()[@intFromEnum(self)];
return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
}
pub fn toConst(self: Index) Constant {
@@ -763,7 +787,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.unwrap(builder))];
}
const FormatData = struct {
@@ -777,44 +801,80 @@ pub const Global = struct {
writer: anytype,
) @TypeOf(writer).Error!void {
try writer.print("@{}", .{
data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder),
data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
});
}
pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
return .{ .data = .{ .global = self, .builder = builder } };
}
pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void {
try builder.ensureUnusedCapacityGlobal(name);
self.renameAssumeCapacity(builder, name);
pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
try builder.ensureUnusedCapacityGlobal(new_name);
self.renameAssumeCapacity(new_name, builder);
}
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]);
_ = builder.addGlobalAssumeCapacity(name, builder.globals.values()[index]);
pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
try builder.ensureUnusedCapacityGlobal(.empty);
self.takeNameAssumeCapacity(other, builder);
}
pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
try builder.ensureUnusedCapacityGlobal(.empty);
self.replaceAssumeCapacity(other, builder);
}
fn renameAssumeCapacity(self: Index, new_name: String, builder: *Builder) void {
const old_name = self.name(builder);
if (new_name == old_name) return;
const index = @intFromEnum(self.unwrap(builder));
if (builder.useLibLlvm())
builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]);
_ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
if (builder.useLibLlvm()) _ = builder.llvm.globals.pop();
builder.globals.swapRemoveAt(index);
self.updateName(builder);
if (!old_name.isAnon()) return;
builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1);
if (builder.next_unnamed_global == old_name) return;
builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder);
}
pub fn takeName(self: Index, builder: *Builder, other: Index) Allocator.Error!void {
try builder.ensureUnusedCapacityGlobal(.empty);
self.takeNameAssumeCapacity(builder, other);
}
pub fn takeNameAssumeCapacity(self: Index, builder: *Builder, other: Index) void {
const other_name = builder.globals.keys()[@intFromEnum(other)];
other.renameAssumeCapacity(builder, .none);
self.renameAssumeCapacity(builder, other_name);
fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
const other_name = other.name(builder);
other.renameAssumeCapacity(.empty, builder);
self.renameAssumeCapacity(other_name, builder);
}
fn updateName(self: Index, builder: *const Builder) void {
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);
const index = @intFromEnum(self.unwrap(builder));
const name_slice = self.name(builder).toSlice(builder) orelse "";
builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
}
fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
if (self.eql(other, builder)) return;
builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1);
self.renameAssumeCapacity(builder.next_replaced_global, builder);
if (builder.useLibLlvm()) {
const self_llvm = self.toLlvm(builder);
self_llvm.replaceAllUsesWith(other.toLlvm(builder));
switch (self.ptr(builder).kind) {
.alias,
.variable,
=> self_llvm.deleteGlobal(),
.function => self_llvm.deleteFunction(),
.replaced => unreachable,
}
}
self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
}
fn getReplacement(self: Index, builder: *const Builder) Index {
return switch (builder.globals.values()[@intFromEnum(self)].kind) {
.replaced => |replacement| replacement,
else => .none,
};
}
};
@@ -1014,8 +1074,14 @@ pub const Constant = enum(u32) {
insertelement,
shufflevector,
add,
@"add nsw",
@"add nuw",
sub,
@"sub nsw",
@"sub nuw",
mul,
@"mul nsw",
@"mul nuw",
shl,
lshr,
ashr,
@@ -1084,24 +1150,24 @@ pub const Constant = enum(u32) {
pub const Kind = enum { normal, inbounds };
};
pub const Compare = struct {
pub const Compare = extern struct {
cond: u32,
lhs: Constant,
rhs: Constant,
};
pub const ExtractElement = struct {
pub const ExtractElement = extern struct {
arg: Constant,
index: Constant,
};
pub const InsertElement = struct {
pub const InsertElement = extern struct {
arg: Constant,
elem: Constant,
index: Constant,
};
pub const ShuffleVector = struct {
pub const ShuffleVector = extern struct {
lhs: Constant,
rhs: Constant,
mask: Constant,
@@ -1243,8 +1309,14 @@ pub const Constant = enum(u32) {
};
},
.add,
.@"add nsw",
.@"add nuw",
.sub,
.@"sub nsw",
.@"sub nuw",
.mul,
.@"mul nsw",
.@"mul nuw",
.shl,
.lshr,
.ashr,
@@ -1326,14 +1398,14 @@ pub const Constant = enum(u32) {
switch (item.tag) {
.positive_integer,
.negative_integer,
=> {
=> |tag| {
const extra: *align(@alignOf(std.math.big.Limb)) Integer =
@ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
const limbs = data.builder.constant_limbs
.items[item.data + Integer.limbs ..][0..extra.limbs_len];
const bigint = std.math.big.int.Const{
.limbs = limbs,
.positive = item.tag == .positive_integer,
.positive = tag == .positive_integer,
};
const ExpectedContents = extern struct {
string: [(64 * 8 / std.math.log2(10)) + 2]u8,
@@ -1352,23 +1424,63 @@ pub const Constant = enum(u32) {
defer allocator.free(str);
try writer.writeAll(str);
},
.half,
.bfloat,
=> |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
.half => 'H',
.bfloat => 'R',
else => unreachable,
}), item.data >> switch (tag) {
.half => 0,
.bfloat => 16,
else => unreachable,
} }),
.float => try writer.print("0x{X:0>16}", .{
@as(u64, @bitCast(@as(f64, @as(f32, @bitCast(item.data))))),
}),
.double => {
const extra = data.builder.constantExtraData(Double, item.data);
try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
},
.fp128,
.ppc_fp128,
=> |tag| {
const extra = data.builder.constantExtraData(Fp128, item.data);
try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
@as(u8, switch (tag) {
.fp128 => 'L',
.ppc_fp128 => 'M',
else => unreachable,
}),
extra.lo_hi,
extra.lo_lo,
extra.hi_hi,
extra.hi_lo,
});
},
.x86_fp80 => {
const extra = data.builder.constantExtraData(Fp80, item.data);
try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
extra.hi, extra.lo_hi, extra.lo_lo,
});
},
.null,
.none,
.zeroinitializer,
.undef,
.poison,
=> try writer.writeAll(@tagName(item.tag)),
=> |tag| try writer.writeAll(@tagName(tag)),
.structure,
.packed_structure,
.array,
.vector,
=> {
=> |tag| {
const extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
const len = extra.data.type.aggregateLen(data.builder);
const vals: []const Constant =
@ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);
try writer.writeAll(switch (item.tag) {
try writer.writeAll(switch (tag) {
.structure => "{ ",
.packed_structure => "<{ ",
.array => "[",
@@ -1379,7 +1491,7 @@ pub const Constant = enum(u32) {
if (index > 0) try writer.writeAll(", ");
try writer.print("{%}", .{val.fmt(data.builder)});
}
try writer.writeAll(switch (item.tag) {
try writer.writeAll(switch (tag) {
.structure => " }",
.packed_structure => " }>",
.array => "]",
@@ -1387,33 +1499,130 @@ pub const Constant = enum(u32) {
else => unreachable,
});
},
.string => try writer.print(
\\c{"}
, .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
.string_null => try writer.print(
\\c{"@}
, .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
.blockaddress => {
inline .string,
.string_null,
=> |tag| try writer.print("c{\"" ++ switch (tag) {
.string => "",
.string_null => "@",
else => unreachable,
} ++ "}", .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
.blockaddress => |tag| {
const extra = data.builder.constantExtraData(BlockAddress, item.data);
const function = extra.function.ptrConst(data.builder);
try writer.print("{s}({}, %{d})", .{
@tagName(item.tag),
@tagName(tag),
function.global.fmt(data.builder),
@intFromEnum(extra.block), // TODO
});
},
.dso_local_equivalent,
.no_cfi,
=> {
=> |tag| {
const extra = data.builder.constantExtraData(FunctionReference, item.data);
try writer.print("{s} {}", .{
@tagName(item.tag),
@tagName(tag),
extra.function.ptrConst(data.builder).global.fmt(data.builder),
});
},
else => try writer.print("<{s}:0x{X}>", .{
@tagName(item.tag), @intFromEnum(data.constant),
}),
.trunc,
.zext,
.sext,
.fptrunc,
.fpext,
.fptoui,
.fptosi,
.uitofp,
.sitofp,
.ptrtoint,
.inttoptr,
.bitcast,
.addrspacecast,
=> |tag| {
const extra = data.builder.constantExtraData(Cast, item.data);
try writer.print("{s} ({%} to {%})", .{
@tagName(tag),
extra.arg.fmt(data.builder),
extra.type.fmt(data.builder),
});
},
.getelementptr,
.@"getelementptr inbounds",
=> |tag| {
const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
const indices: []const Constant = @ptrCast(data.builder.constant_extra
.items[extra.end..][0..extra.data.indices_len]);
try writer.print("{s} ({%}, {%}", .{
@tagName(tag),
extra.data.type.fmt(data.builder),
extra.data.base.fmt(data.builder),
});
for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
try writer.writeByte(')');
},
inline .icmp,
.fcmp,
=> |tag| {
const extra = data.builder.constantExtraData(Compare, item.data);
try writer.print("{s} {s} ({%}, {%})", .{
@tagName(tag),
@tagName(@as(switch (tag) {
.icmp => IntegerCondition,
.fcmp => FloatCondition,
else => unreachable,
}, @enumFromInt(extra.cond))),
extra.lhs.fmt(data.builder),
extra.rhs.fmt(data.builder),
});
},
.extractelement => |tag| {
const extra = data.builder.constantExtraData(ExtractElement, item.data);
try writer.print("{s} ({%}, {%})", .{
@tagName(tag),
extra.arg.fmt(data.builder),
extra.index.fmt(data.builder),
});
},
.insertelement => |tag| {
const extra = data.builder.constantExtraData(InsertElement, item.data);
try writer.print("{s} ({%}, {%}, {%})", .{
@tagName(tag),
extra.arg.fmt(data.builder),
extra.elem.fmt(data.builder),
extra.index.fmt(data.builder),
});
},
.shufflevector => |tag| {
const extra = data.builder.constantExtraData(ShuffleVector, item.data);
try writer.print("{s} ({%}, {%}, {%})", .{
@tagName(tag),
extra.lhs.fmt(data.builder),
extra.rhs.fmt(data.builder),
extra.mask.fmt(data.builder),
});
},
.add,
.@"add nsw",
.@"add nuw",
.sub,
.@"sub nsw",
.@"sub nuw",
.mul,
.@"mul nsw",
.@"mul nuw",
.shl,
.lshr,
.ashr,
.@"and",
.@"or",
.xor,
=> |tag| {
const extra = data.builder.constantExtraData(Binary, item.data);
try writer.print("{s} ({%}, {%})", .{
@tagName(tag),
extra.lhs.fmt(data.builder),
extra.rhs.fmt(data.builder),
});
},
}
},
.global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
@@ -1882,6 +2091,7 @@ pub fn namedTypeSetBody(
}
pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
assert(!name.isAnon());
try self.ensureUnusedTypeCapacity(1, null, 0);
try self.ensureUnusedCapacityGlobal(name);
return self.addGlobalAssumeCapacity(name, global);
@@ -1890,9 +2100,10 @@ pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!G
pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {
_ = self.ptrTypeAssumeCapacity(global.addr_space);
var id = name;
if (id == .none) {
if (name == .empty) {
id = self.next_unnamed_global;
self.next_unnamed_global = @enumFromInt(@intFromEnum(self.next_unnamed_global) + 1);
assert(id != self.next_replaced_global);
self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1);
}
while (true) {
const global_gop = self.globals.getOrPutAssumeCapacity(id);
@@ -2136,7 +2347,7 @@ pub fn binConst(
return self.binConstAssumeCapacity(tag, lhs, rhs);
}
pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
if (self.source_filename != .none) try writer.print(
\\; ModuleID = '{s}'
\\source_filename = {"}
@@ -2157,7 +2368,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
, .{ id.fmt(self), ty.fmt(self) });
try writer.writeByte('\n');
for (self.variables.items) |variable| {
const global = self.globals.values()[@intFromEnum(variable.global)];
if (variable.global.getReplacement(self) != .none) continue;
const global = variable.global.ptrConst(self);
try writer.print(
\\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
\\
@@ -2179,7 +2391,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
}
try writer.writeByte('\n');
for (self.functions.items) |function| {
const global = self.globals.values()[@intFromEnum(function.global)];
if (function.global.getReplacement(self) != .none) continue;
const global = function.global.ptrConst(self);
const item = self.type_items.items[@intFromEnum(global.type)];
const extra = self.typeExtraDataTrail(Type.Function, item.data);
const params: []const Type =
@@ -2207,14 +2420,51 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
},
else => unreachable,
}
try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment });
if (function.body) |_| try writer.print(
\\{{
\\ ret {%}
\\}}
\\
, .{extra.data.ret.fmt(self)});
try writer.writeByte('\n');
try writer.print("){}{}", .{ global.unnamed_addr, global.alignment });
if (function.body) |_| {
try writer.writeAll(" {\n ret ");
void: {
try writer.print("{%}", .{switch (extra.data.ret) {
.void => |tag| {
try writer.writeAll(@tagName(tag));
break :void;
},
inline .half,
.bfloat,
.float,
.double,
.fp128,
.x86_fp80,
=> |tag| try @field(Builder, @tagName(tag) ++ "Const")(self, 0.0),
.ppc_fp128 => try self.ppc_fp128Const(.{ 0.0, 0.0 }),
.x86_amx,
.x86_mmx,
.label,
.metadata,
=> unreachable,
.token => Constant.none,
else => switch (extra.data.ret.tag(self)) {
.simple,
.function,
.vararg_function,
=> unreachable,
.integer => try self.intConst(extra.data.ret, 0),
.pointer => try self.nullConst(extra.data.ret),
.target,
.vector,
.scalable_vector,
.small_array,
.array,
.structure,
.packed_structure,
.named_structure,
=> try self.zeroInitConst(extra.data.ret),
},
}.fmt(self)});
}
try writer.writeAll("\n}");
}
try writer.writeAll("\n\n");
}
}
@@ -2497,11 +2747,11 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
}
};
var id = name;
if (name == .none) {
if (name == .empty) {
id = self.next_unnamed_type;
assert(id != .none);
self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
} else assert(name.toIndex() != null);
} else assert(!name.isAnon());
while (true) {
const type_gop = self.types.getOrPutAssumeCapacity(id);
if (!type_gop.found_existing) {
@@ -2783,8 +3033,8 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
self.constant_items.appendAssumeCapacity(.{
.tag = .double,
.data = self.addConstantExtraAssumeCapacity(Constant.Double{
.lo = @intCast(@as(u64, @bitCast(val)) >> 32),
.hi = @truncate(@as(u64, @bitCast(val))),
.lo = @truncate(@as(u64, @bitCast(val))),
.hi = @intCast(@as(u64, @bitCast(val)) >> 32),
}),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
@@ -3401,6 +3651,190 @@ fn gepConstAssumeCapacity(
return @enumFromInt(gop.index);
}
fn icmpConstAssumeCapacity(
self: *Builder,
cond: IntegerCondition,
lhs: Constant,
rhs: Constant,
) Constant {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant.Compare) u32 {
return @truncate(std.hash.Wyhash.hash(
std.hash.uint32(@intFromEnum(Constant.tag.icmp)),
std.mem.asBytes(&key),
));
}
pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != .icmp) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
return std.meta.eql(lhs_key, rhs_extra);
}
};
const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = .icmp,
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
llvm.constICmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
}
fn fcmpConstAssumeCapacity(
self: *Builder,
cond: FloatCondition,
lhs: Constant,
rhs: Constant,
) Constant {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant.Compare) u32 {
return @truncate(std.hash.Wyhash.hash(
std.hash.uint32(@intFromEnum(Constant.tag.fcmp)),
std.mem.asBytes(&key),
));
}
pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fcmp) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
return std.meta.eql(lhs_key, rhs_extra);
}
};
const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = .fcmp,
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
llvm.constFCmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
}
fn extractElementConstAssumeCapacity(
self: *Builder,
arg: Constant,
index: Constant,
) Constant {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant.ExtractElement) u32 {
return @truncate(std.hash.Wyhash.hash(
comptime std.hash.uint32(@intFromEnum(Constant.Tag.extractelement)),
std.mem.asBytes(&key),
));
}
pub fn eql(ctx: @This(), lhs_key: Constant.ExtractElement, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != .extractelement) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
const rhs_extra = ctx.builder.constantExtraData(Constant.ExtractElement, rhs_data);
return std.meta.eql(lhs_key, rhs_extra);
}
};
const data = Constant.ExtractElement{ .arg = arg, .index = index };
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = .extractelement,
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
arg.toLlvm(self).constExtractElement(index.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
}
fn insertElementConstAssumeCapacity(
self: *Builder,
arg: Constant,
elem: Constant,
index: Constant,
) Constant {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant.InsertElement) u32 {
return @truncate(std.hash.Wyhash.hash(
comptime std.hash.uint32(@intFromEnum(Constant.Tag.insertelement)),
std.mem.asBytes(&key),
));
}
pub fn eql(ctx: @This(), lhs_key: Constant.InsertElement, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != .insertelement) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
const rhs_extra = ctx.builder.constantExtraData(Constant.InsertElement, rhs_data);
return std.meta.eql(lhs_key, rhs_extra);
}
};
const data = Constant.InsertElement{ .arg = arg, .elem = elem, .index = index };
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = .insertelement,
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
arg.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
}
fn shuffleVectorConstAssumeCapacity(
self: *Builder,
lhs: Constant,
rhs: Constant,
mask: Constant,
) Constant {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
return @truncate(std.hash.Wyhash.hash(
comptime std.hash.uint32(@intFromEnum(Constant.Tag.shufflevector)),
std.mem.asBytes(&key),
));
}
pub fn eql(ctx: @This(), lhs_key: Constant.ShuffleVector, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != .shufflevector) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
const rhs_extra = ctx.builder.constantExtraData(Constant.ShuffleVector, rhs_data);
return std.meta.eql(lhs_key, rhs_extra);
}
};
const data = Constant.ShuffleVector{ .lhs = lhs, .rhs = rhs, .mask = mask };
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = .shufflevector,
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
lhs.toLlvm(self).constShuffleVector(rhs.toLlvm(self), mask.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
}
fn binConstAssumeCapacity(
self: *Builder,
tag: Constant.Tag,
@@ -3408,7 +3842,22 @@ fn binConstAssumeCapacity(
rhs: Constant,
) Constant {
switch (tag) {
.add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {},
.add,
.@"add nsw",
.@"add nuw",
.sub,
.@"sub nsw",
.@"sub nuw",
.mul,
.@"mul nsw",
.@"mul nuw",
.shl,
.lshr,
.ashr,
.@"and",
.@"or",
.xor,
=> {},
else => unreachable,
}
const Key = struct { tag: Constant.Tag, bin: Constant.Binary };

View File

@@ -168,6 +168,66 @@ pub const Value = opaque {
pub const setAliasee = LLVMAliasSetAliasee;
extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
pub const constNeg = LLVMConstNeg;
extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
pub const constNSWNeg = LLVMConstNSWNeg;
extern fn LLVMConstNSWNeg(ConstantVal: *Value) *Value;
pub const constNUWNeg = LLVMConstNUWNeg;
extern fn LLVMConstNUWNeg(ConstantVal: *Value) *Value;
pub const constNot = LLVMConstNot;
extern fn LLVMConstNot(ConstantVal: *Value) *Value;
pub const constAdd = LLVMConstAdd;
extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNSWAdd = LLVMConstNSWAdd;
extern fn LLVMConstNSWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNUWAdd = LLVMConstNUWAdd;
extern fn LLVMConstNUWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constSub = LLVMConstSub;
extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNSWSub = LLVMConstNSWSub;
extern fn LLVMConstNSWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNUWSub = LLVMConstNUWSub;
extern fn LLVMConstNUWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constMul = LLVMConstMul;
extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNSWMul = LLVMConstNSWMul;
extern fn LLVMConstNSWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constNUWMul = LLVMConstNUWMul;
extern fn LLVMConstNUWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constAnd = LLVMConstAnd;
extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constOr = LLVMConstOr;
extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constXor = LLVMConstXor;
extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constShl = LLVMConstShl;
extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constLShr = LLVMConstLShr;
extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constAShr = LLVMConstAShr;
extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constTrunc = LLVMConstTrunc;
extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value;
@@ -204,42 +264,36 @@ pub const Value = opaque {
pub const constBitCast = LLVMConstBitCast;
extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
pub const constNot = LLVMConstNot;
extern fn LLVMConstNot(ConstantVal: *Value) *Value;
pub const constAdd = LLVMConstAdd;
extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constSub = LLVMConstSub;
extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constMul = LLVMConstMul;
extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constAnd = LLVMConstAnd;
extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constOr = LLVMConstOr;
extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constXor = LLVMConstXor;
extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constShl = LLVMConstShl;
extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constLShr = LLVMConstLShr;
extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constAShr = LLVMConstAShr;
extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
pub const constSelect = LLVMConstSelect;
extern fn LLVMConstSelect(
ConstantCondition: *Value,
ConstantIfTrue: *Value,
ConstantIfFalse: *Value,
) *Value;
pub const constExtractElement = LLVMConstExtractElement;
extern fn LLVMConstExtractElement(VectorConstant: *Value, IndexConstant: *Value) *Value;
pub const constInsertElement = LLVMConstInsertElement;
extern fn LLVMConstInsertElement(
VectorConstant: *Value,
ElementValueConstant: *Value,
IndexConstant: *Value,
) *Value;
pub const constShuffleVector = LLVMConstShuffleVector;
extern fn LLVMConstShuffleVector(
VectorAConstant: *Value,
VectorBConstant: *Value,
MaskConstant: *Value,
) *Value;
pub const blockAddress = LLVMBlockAddress;
extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
pub const setWeak = LLVMSetWeak;
extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
@@ -323,9 +377,6 @@ pub const Value = opaque {
pub const attachMetaData = ZigLLVMAttachMetaData;
extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
pub const blockAddress = LLVMBlockAddress;
extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
pub const dump = LLVMDumpValue;
extern fn LLVMDumpValue(Val: *Value) void;
};
@@ -522,15 +573,18 @@ pub const VerifierFailureAction = enum(c_int) {
ReturnStatus,
};
pub const constNeg = LLVMConstNeg;
extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
pub const constVector = LLVMConstVector;
extern fn LLVMConstVector(
ScalarConstantVals: [*]*Value,
Size: c_uint,
) *Value;
pub const constICmp = LLVMConstICmp;
extern fn LLVMConstICmp(Predicate: IntPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const constFCmp = LLVMConstFCmp;
extern fn LLVMConstFCmp(Predicate: RealPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;