aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm/Builder.zig
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-08-09 03:16:55 -0400
committerGitHub <noreply@github.com>2023-08-09 03:16:55 -0400
commitcd7998096b624b326dddcbb2752fe4bcdac8df9f (patch)
tree3a67b92da2378f614bc52bf23133bcf22b5a5c4b /src/codegen/llvm/Builder.zig
parentd34201c8491007c5a24b4175a5170a5b6cc3d55e (diff)
parent3e1dd93bb2ac7e9d99fb340f1f4ca6868a52cb6b (diff)
downloadzig-cd7998096b624b326dddcbb2752fe4bcdac8df9f.tar.gz
zig-cd7998096b624b326dddcbb2752fe4bcdac8df9f.zip
Merge pull request #16708 from jacobly0/llvm-builder
llvm: convert more things to use Builder * finish converting intrinsics * finish converting attributes * finish converting instructions * finish converting globals * pass behavior tests with no dependence on the llvm api (`-fno-libllvm`)
Diffstat (limited to 'src/codegen/llvm/Builder.zig')
-rw-r--r--src/codegen/llvm/Builder.zig4071
1 files changed, 3021 insertions, 1050 deletions
diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig
index 640cde8409..316aca7a24 100644
--- a/src/codegen/llvm/Builder.zig
+++ b/src/codegen/llvm/Builder.zig
@@ -13,6 +13,7 @@ llvm: if (build_options.have_llvm) struct {
types: std.ArrayListUnmanaged(*llvm.Type),
globals: std.ArrayListUnmanaged(*llvm.Value),
constants: std.ArrayListUnmanaged(*llvm.Value),
+ replacements: std.AutoHashMapUnmanaged(*llvm.Value, Global.Index),
} else void,
source_filename: String,
@@ -50,10 +51,12 @@ constant_extra: std.ArrayListUnmanaged(u32),
constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
pub const expected_args_len = 16;
+pub const expected_attrs_len = 16;
pub const expected_fields_len = 32;
pub const expected_gep_indices_len = 8;
pub const expected_cases_len = 8;
pub const expected_incoming_len = 8;
+pub const expected_intrinsic_name_len = 64;
pub const Options = struct {
allocator: Allocator,
@@ -151,11 +154,14 @@ pub const Type = enum(u32) {
i80,
i128,
ptr,
+ @"ptr addrspace(4)",
none = std.math.maxInt(u32),
_,
pub const err_int = Type.i16;
+ pub const ptr_amdgpu_constant =
+ @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant}));
pub const Tag = enum(u4) {
simple,
@@ -391,7 +397,7 @@ pub const Type = enum(u32) {
.double, .i64, .x86_mmx => 64,
.x86_fp80, .i80 => 80,
.fp128, .ppc_fp128, .i128 => 128,
- .ptr => @panic("TODO: query data layout"),
+ .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"),
_ => {
const item = builder.type_items.items[@intFromEnum(self)];
return switch (item.tag) {
@@ -690,7 +696,7 @@ pub const Type = enum(u32) {
}
},
.integer => try writer.print("i{d}", .{item.data}),
- .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(item.data))}),
+ .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}),
.target => {
var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
const types = extra.trail.next(extra.data.types_len, Type, data.builder);
@@ -795,6 +801,7 @@ pub const Type = enum(u32) {
.i80,
.i128,
.ptr,
+ .@"ptr addrspace(4)",
=> true,
.none => unreachable,
_ => {
@@ -1151,13 +1158,13 @@ pub const Attribute = union(Kind) {
.sret,
.elementtype,
=> |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
- .@"align" => |alignment| try writer.print("{}", .{alignment}),
+ .@"align" => |alignment| try writer.print("{ }", .{alignment}),
.dereferenceable,
.dereferenceable_or_null,
=> |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
.nofpclass => |fpclass| {
const Int = @typeInfo(FpClass).Struct.backing_integer.?;
- try writer.print("{s}(", .{@tagName(attribute)});
+ try writer.print(" {s}(", .{@tagName(attribute)});
var any = false;
var remaining: Int = @bitCast(fpclass);
inline for (@typeInfo(FpClass).Struct.decls) |decl| {
@@ -1175,13 +1182,13 @@ pub const Attribute = union(Kind) {
},
.alignstack => |alignment| try writer.print(
if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
- "{s}={d}"
+ " {s}={d}"
else
- "{s}({d})",
+ " {s}({d})",
.{ @tagName(attribute), alignment.toByteUnits() orelse return },
),
.allockind => |allockind| {
- try writer.print("{s}(\"", .{@tagName(attribute)});
+ try writer.print(" {s}(\"", .{@tagName(attribute)});
var any = false;
inline for (@typeInfo(AllocKind).Struct.fields) |field| {
if (comptime std.mem.eql(u8, field.name, "_")) continue;
@@ -1196,22 +1203,30 @@ pub const Attribute = union(Kind) {
try writer.writeAll("\")");
},
.allocsize => |allocsize| {
- try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size });
+ try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size });
if (allocsize.num_elems != AllocSize.none)
try writer.print(",{d}", .{allocsize.num_elems});
try writer.writeByte(')');
},
- .memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{
- @tagName(attribute),
- @tagName(memory.other),
- @tagName(memory.argmem),
- @tagName(memory.inaccessiblemem),
- }),
+ .memory => |memory| {
+ try writer.print(" {s}(", .{@tagName(attribute)});
+ var any = memory.other != .none or
+ (memory.argmem == .none and memory.inaccessiblemem == .none);
+ if (any) try writer.writeAll(@tagName(memory.other));
+ inline for (.{ "argmem", "inaccessiblemem" }) |kind| {
+ if (@field(memory, kind) != memory.other) {
+ if (any) try writer.writeAll(", ");
+ try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
+ any = true;
+ }
+ }
+ try writer.writeByte(')');
+ },
.uwtable => |uwtable| if (uwtable != .none) {
- try writer.writeAll(@tagName(attribute));
+ try writer.print(" {s}", .{@tagName(attribute)});
if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
},
- .vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{
+ .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{
@tagName(attribute),
vscale_range.min.toByteUnits().?,
vscale_range.max.toByteUnits() orelse 0,
@@ -1335,21 +1350,29 @@ pub const Attribute = union(Kind) {
//sanitize_memtag,
sanitize_address_dyninit,
- string = std.math.maxInt(u31) - 1,
- none = std.math.maxInt(u31),
+ string = std.math.maxInt(u31),
+ none = std.math.maxInt(u32),
_,
pub const len = @typeInfo(Kind).Enum.fields.len - 2;
pub fn fromString(str: String) Kind {
assert(!str.isAnon());
- return @enumFromInt(@intFromEnum(str));
+ const kind: Kind = @enumFromInt(@intFromEnum(str));
+ assert(kind != .none);
+ return kind;
}
fn toString(self: Kind) ?String {
+ assert(self != .none);
const str: String = @enumFromInt(@intFromEnum(self));
return if (str.isAnon()) null else str;
}
+
+ fn toLlvm(self: Kind, builder: *const Builder) *c_uint {
+ assert(builder.useLibLlvm());
+ return &builder.llvm.attribute_kind_ids.?[@intFromEnum(self)];
+ }
};
pub const FpClass = packed struct(u32) {
@@ -1424,12 +1447,16 @@ pub const Attribute = union(Kind) {
};
pub const Memory = packed struct(u32) {
- argmem: Effect,
- inaccessiblemem: Effect,
- other: Effect,
+ argmem: Effect = .none,
+ inaccessiblemem: Effect = .none,
+ other: Effect = .none,
_: u26 = 0,
pub const Effect = enum(u2) { none, read, write, readwrite };
+
+ fn all(effect: Effect) Memory {
+ return .{ .argmem = effect, .inaccessiblemem = effect, .other = effect };
+ }
};
pub const UwTable = enum(u32) {
@@ -1683,17 +1710,17 @@ pub const FunctionAttributes = enum(u32) {
};
pub const Linkage = enum {
- external,
private,
internal,
- available_externally,
- linkonce,
weak,
- common,
+ weak_odr,
+ linkonce,
+ linkonce_odr,
+ available_externally,
appending,
+ common,
extern_weak,
- linkonce_odr,
- weak_odr,
+ external,
pub fn format(
self: Linkage,
@@ -1703,6 +1730,22 @@ pub const Linkage = enum {
) @TypeOf(writer).Error!void {
if (self != .external) try writer.print(" {s}", .{@tagName(self)});
}
+
+ fn toLlvm(self: Linkage) llvm.Linkage {
+ return switch (self) {
+ .private => .Private,
+ .internal => .Internal,
+ .weak => .WeakAny,
+ .weak_odr => .WeakODR,
+ .linkonce => .LinkOnceAny,
+ .linkonce_odr => .LinkOnceODR,
+ .available_externally => .AvailableExternally,
+ .appending => .Appending,
+ .common => .Common,
+ .extern_weak => .ExternalWeak,
+ .external => .External,
+ };
+ }
};
pub const Preemption = enum {
@@ -1733,6 +1776,14 @@ pub const Visibility = enum {
) @TypeOf(writer).Error!void {
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
}
+
+ fn toLlvm(self: Visibility) llvm.Visibility {
+ return switch (self) {
+ .default => .Default,
+ .hidden => .Hidden,
+ .protected => .Protected,
+ };
+ }
};
pub const DllStorageClass = enum {
@@ -1748,6 +1799,14 @@ pub const DllStorageClass = enum {
) @TypeOf(writer).Error!void {
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
}
+
+ fn toLlvm(self: DllStorageClass) llvm.DLLStorageClass {
+ return switch (self) {
+ .default => .Default,
+ .dllimport => .DLLImport,
+ .dllexport => .DLLExport,
+ };
+ }
};
pub const ThreadLocal = enum {
@@ -1759,20 +1818,28 @@ pub const ThreadLocal = enum {
pub fn format(
self: ThreadLocal,
- comptime _: []const u8,
+ comptime prefix: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
if (self == .default) return;
- try writer.writeAll(" thread_local");
- if (self != .generaldynamic) {
- try writer.writeByte('(');
- try writer.writeAll(@tagName(self));
- try writer.writeByte(')');
- }
+ try writer.print("{s}thread_local", .{prefix});
+ if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)});
+ }
+
+ fn toLlvm(self: ThreadLocal) llvm.ThreadLocalMode {
+ return switch (self) {
+ .default => .NotThreadLocal,
+ .generaldynamic => .GeneralDynamicTLSModel,
+ .localdynamic => .LocalDynamicTLSModel,
+ .initialexec => .InitialExecTLSModel,
+ .localexec => .LocalExecTLSModel,
+ };
}
};
+pub const Mutability = enum { global, constant };
+
pub const UnnamedAddr = enum {
default,
unnamed_addr,
@@ -1867,7 +1934,7 @@ pub const AddrSpace = enum(u24) {
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- if (self != .default) try writer.print("{s} addrspace({d})", .{ prefix, @intFromEnum(self) });
+ if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) });
}
};
@@ -1908,7 +1975,7 @@ pub const Alignment = enum(u6) {
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- try writer.print("{s} align {d}", .{ prefix, self.toByteUnits() orelse return });
+ try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return });
}
};
@@ -2031,6 +2098,11 @@ pub const CallConv = enum(u10) {
_ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
}
}
+
+ fn toLlvm(self: CallConv) llvm.CallConv {
+ // These enum values appear in LLVM IR, and so are guaranteed to be stable.
+ return @enumFromInt(@intFromEnum(self));
+ }
};
pub const Global = struct {
@@ -2067,10 +2139,6 @@ pub const Global = struct {
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.unwrap(builder))];
}
@@ -2079,6 +2147,10 @@ pub const Global = struct {
return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
}
+ pub fn name(self: Index, builder: *const Builder) String {
+ return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
+ }
+
pub fn typeOf(self: Index, builder: *const Builder) Type {
return self.ptrConst(builder).type;
}
@@ -2087,6 +2159,30 @@ pub const Global = struct {
return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
}
+ pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setLinkage(linkage.toLlvm());
+ self.ptr(builder).linkage = linkage;
+ self.updateDsoLocal(builder);
+ }
+
+ pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setVisibility(visibility.toLlvm());
+ self.ptr(builder).visibility = visibility;
+ self.updateDsoLocal(builder);
+ }
+
+ pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setDLLStorageClass(class.toLlvm());
+ self.ptr(builder).dll_storage_class = class;
+ }
+
+ pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setUnnamedAddr(
+ llvm.Bool.fromBool(unnamed_addr != .default),
+ );
+ self.ptr(builder).unnamed_addr = unnamed_addr;
+ }
+
pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
assert(builder.useLibLlvm());
return builder.llvm.globals.items[@intFromEnum(self.unwrap(builder))];
@@ -2122,9 +2218,36 @@ pub const Global = struct {
pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
try builder.ensureUnusedGlobalCapacity(.empty);
+ if (builder.useLibLlvm())
+ try builder.llvm.replacements.ensureUnusedCapacity(builder.gpa, 1);
self.replaceAssumeCapacity(other, builder);
}
+ pub fn delete(self: Index, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).eraseGlobalValue();
+ self.ptr(builder).kind = .{ .replaced = .none };
+ }
+
+ fn updateDsoLocal(self: Index, builder: *Builder) void {
+ const self_ptr = self.ptr(builder);
+ switch (self_ptr.linkage) {
+ .private, .internal => {
+ self_ptr.visibility = .default;
+ self_ptr.dll_storage_class = .default;
+ self_ptr.preemption = .implicit_dso_local;
+ },
+ .extern_weak => if (self_ptr.preemption == .implicit_dso_local) {
+ self_ptr.preemption = .dso_local;
+ },
+ else => switch (self_ptr.visibility) {
+ .default => if (self_ptr.preemption == .implicit_dso_local) {
+ self_ptr.preemption = .dso_local;
+ },
+ else => self_ptr.preemption = .implicit_dso_local,
+ },
+ }
+ }
+
fn renameAssumeCapacity(self: Index, new_name: String, builder: *Builder) void {
const old_name = self.name(builder);
if (new_name == old_name) return;
@@ -2151,7 +2274,7 @@ pub const Global = struct {
if (!builder.useLibLlvm()) return;
const index = @intFromEnum(self.unwrap(builder));
const name_slice = self.name(builder).slice(builder) orelse "";
- builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
+ builder.llvm.globals.items[index].setValueName(name_slice.ptr, name_slice.len);
}
fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
@@ -2161,13 +2284,8 @@ pub const Global = struct {
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_llvm.removeGlobalValue();
+ builder.llvm.replacements.putAssumeCapacityNoClobber(self_llvm, other);
}
self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
}
@@ -2179,42 +2297,17 @@ pub const Global = struct {
};
}
};
-
- pub fn updateAttributes(self: *Global) void {
- switch (self.linkage) {
- .private, .internal => {
- self.visibility = .default;
- self.dll_storage_class = .default;
- self.preemption = .implicit_dso_local;
- },
- .extern_weak => if (self.preemption == .implicit_dso_local) {
- self.preemption = .dso_local;
- },
- else => switch (self.visibility) {
- .default => if (self.preemption == .implicit_dso_local) {
- self.preemption = .dso_local;
- },
- else => self.preemption = .implicit_dso_local,
- },
- }
- }
};
pub const Alias = struct {
global: Global.Index,
thread_local: ThreadLocal = .default,
- init: Constant = .no_init,
+ aliasee: Constant = .no_init,
pub const Index = enum(u32) {
none = std.math.maxInt(u32),
_,
- pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
- const aliasee = self.ptrConst(builder).init.getBase(builder);
- assert(aliasee != .none);
- return aliasee;
- }
-
pub fn ptr(self: Index, builder: *Builder) *Alias {
return &builder.aliases.items[@intFromEnum(self)];
}
@@ -2223,6 +2316,14 @@ pub const Alias = struct {
return &builder.aliases.items[@intFromEnum(self)];
}
+ pub fn name(self: Index, builder: *const Builder) String {
+ return self.ptrConst(builder).global.name(builder);
+ }
+
+ pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
+ return self.ptrConst(builder).global.rename(new_name, builder);
+ }
+
pub fn typeOf(self: Index, builder: *const Builder) Type {
return self.ptrConst(builder).global.typeOf(builder);
}
@@ -2235,7 +2336,18 @@ pub const Alias = struct {
return self.toConst(builder).toValue();
}
- pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
+ pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
+ const aliasee = self.ptrConst(builder).aliasee.getBase(builder);
+ assert(aliasee != .none);
+ return aliasee;
+ }
+
+ pub fn setAliasee(self: Index, aliasee: Constant, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setAliasee(aliasee.toLlvm(builder));
+ self.ptr(builder).aliasee = aliasee;
+ }
+
+ fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
return self.ptrConst(builder).global.toLlvm(builder);
}
};
@@ -2244,7 +2356,7 @@ pub const Alias = struct {
pub const Variable = struct {
global: Global.Index,
thread_local: ThreadLocal = .default,
- mutability: enum { global, constant } = .global,
+ mutability: Mutability = .global,
init: Constant = .no_init,
section: String = .none,
alignment: Alignment = .default,
@@ -2261,6 +2373,14 @@ pub const Variable = struct {
return &builder.variables.items[@intFromEnum(self)];
}
+ pub fn name(self: Index, builder: *const Builder) String {
+ return self.ptrConst(builder).global.name(builder);
+ }
+
+ pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
+ return self.ptrConst(builder).global.rename(new_name, builder);
+ }
+
pub fn typeOf(self: Index, builder: *const Builder) Type {
return self.ptrConst(builder).global.typeOf(builder);
}
@@ -2273,12 +2393,1405 @@ pub const Variable = struct {
return self.toConst(builder).toValue();
}
+ pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
+ return self.ptrConst(builder).global.setLinkage(linkage, builder);
+ }
+
+ pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
+ return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
+ }
+
+ pub fn setThreadLocal(self: Index, thread_local: ThreadLocal, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setThreadLocalMode(thread_local.toLlvm());
+ self.ptr(builder).thread_local = thread_local;
+ }
+
+ pub fn setMutability(self: Index, mutability: Mutability, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setGlobalConstant(
+ llvm.Bool.fromBool(mutability == .constant),
+ );
+ self.ptr(builder).mutability = mutability;
+ }
+
+ pub fn setInitializer(
+ self: Index,
+ initializer: Constant,
+ builder: *Builder,
+ ) Allocator.Error!void {
+ if (initializer != .no_init) {
+ const variable = self.ptrConst(builder);
+ const global = variable.global.ptr(builder);
+ const initializer_type = initializer.typeOf(builder);
+ if (builder.useLibLlvm() and global.type != initializer_type) {
+ try builder.llvm.replacements.ensureUnusedCapacity(builder.gpa, 1);
+ // LLVM does not allow us to change the type of globals. So we must
+ // create a new global with the correct type, copy all its attributes,
+ // and then update all references to point to the new global,
+ // delete the original, and rename the new one to the old one's name.
+ // This is necessary because LLVM does not support const bitcasting
+ // a struct with padding bytes, which is needed to lower a const union value
+ // to LLVM, when a field other than the most-aligned is active. Instead,
+ // we must lower to an unnamed struct, and pointer cast at usage sites
+ // of the global. Such an unnamed struct is the cause of the global type
+ // mismatch, because we don't have the LLVM type until the *value* is created,
+ // whereas the global needs to be created based on the type alone, because
+ // lowering the value may reference the global as a pointer.
+ // Related: https://github.com/ziglang/zig/issues/13265
+ const old_global = &builder.llvm.globals.items[@intFromEnum(variable.global)];
+ const new_global = builder.llvm.module.?.addGlobalInAddressSpace(
+ initializer_type.toLlvm(builder),
+ "",
+ @intFromEnum(global.addr_space),
+ );
+ new_global.setLinkage(global.linkage.toLlvm());
+ new_global.setUnnamedAddr(llvm.Bool.fromBool(global.unnamed_addr != .default));
+ new_global.setAlignment(@intCast(variable.alignment.toByteUnits() orelse 0));
+ if (variable.section != .none)
+ new_global.setSection(variable.section.slice(builder).?);
+ old_global.*.replaceAllUsesWith(new_global);
+ builder.llvm.replacements.putAssumeCapacityNoClobber(old_global.*, variable.global);
+ new_global.takeName(old_global.*);
+ old_global.*.removeGlobalValue();
+ old_global.* = new_global;
+ self.ptr(builder).mutability = .global;
+ }
+ global.type = initializer_type;
+ }
+ if (builder.useLibLlvm()) self.toLlvm(builder).setInitializer(switch (initializer) {
+ .no_init => null,
+ else => initializer.toLlvm(builder),
+ });
+ self.ptr(builder).init = initializer;
+ }
+
+ pub fn setSection(self: Index, section: String, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setSection(section.slice(builder).?);
+ self.ptr(builder).section = section;
+ }
+
+ pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
+ if (builder.useLibLlvm())
+ self.toLlvm(builder).setAlignment(@intCast(alignment.toByteUnits() orelse 0));
+ self.ptr(builder).alignment = alignment;
+ }
+
pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
return self.ptrConst(builder).global.toLlvm(builder);
}
};
};
+pub const Intrinsic = enum {
+ // Variable Argument Handling
+ va_start,
+ va_end,
+ va_copy,
+
+ // Code Generator
+ returnaddress,
+ addressofreturnaddress,
+ sponentry,
+ frameaddress,
+ prefetch,
+ @"thread.pointer",
+
+ // Standard C/C++ Library
+ abs,
+ smax,
+ smin,
+ umax,
+ umin,
+ memcpy,
+ @"memcpy.inline",
+ memmove,
+ memset,
+ @"memset.inline",
+ sqrt,
+ powi,
+ sin,
+ cos,
+ pow,
+ exp,
+ exp2,
+ ldexp,
+ frexp,
+ log,
+ log10,
+ log2,
+ fma,
+ fabs,
+ minnum,
+ maxnum,
+ minimum,
+ maximum,
+ copysign,
+ floor,
+ ceil,
+ trunc,
+ rint,
+ nearbyint,
+ round,
+ roundeven,
+ lround,
+ llround,
+ lrint,
+ llrint,
+
+ // Bit Manipulation
+ bitreverse,
+ bswap,
+ ctpop,
+ ctlz,
+ cttz,
+ fshl,
+ fshr,
+
+ // Arithmetic with Overflow
+ @"sadd.with.overflow",
+ @"uadd.with.overflow",
+ @"ssub.with.overflow",
+ @"usub.with.overflow",
+ @"smul.with.overflow",
+ @"umul.with.overflow",
+
+ // Saturation Arithmetic
+ @"sadd.sat",
+ @"uadd.sat",
+ @"ssub.sat",
+ @"usub.sat",
+ @"sshl.sat",
+ @"ushl.sat",
+
+ // Fixed Point Arithmetic
+ @"smul.fix",
+ @"umul.fix",
+ @"smul.fix.sat",
+ @"umul.fix.sat",
+ @"sdiv.fix",
+ @"udiv.fix",
+ @"sdiv.fix.sat",
+ @"udiv.fix.sat",
+
+ // Specialised Arithmetic
+ canonicalize,
+ fmuladd,
+
+ // Vector Reduction
+ @"vector.reduce.add",
+ @"vector.reduce.fadd",
+ @"vector.reduce.mul",
+ @"vector.reduce.fmul",
+ @"vector.reduce.and",
+ @"vector.reduce.or",
+ @"vector.reduce.xor",
+ @"vector.reduce.smax",
+ @"vector.reduce.smin",
+ @"vector.reduce.umax",
+ @"vector.reduce.umin",
+ @"vector.reduce.fmax",
+ @"vector.reduce.fmin",
+ @"vector.reduce.fmaximum",
+ @"vector.reduce.fminimum",
+ @"vector.insert",
+ @"vector.extract",
+
+ // Floating-Point Test
+ @"is.fpclass",
+
+ // General
+ @"var.annotation",
+ @"ptr.annotation",
+ annotation,
+ @"codeview.annotation",
+ trap,
+ debugtrap,
+ ubsantrap,
+ stackprotector,
+ stackguard,
+ objectsize,
+ expect,
+ @"expect.with.probability",
+ assume,
+ @"ssa.copy",
+ @"type.test",
+ @"type.checked.load",
+ @"type.checked.load.relative",
+ @"arithmetic.fence",
+ donothing,
+ @"load.relative",
+ sideeffect,
+ @"is.constant",
+ ptrmask,
+ @"threadlocal.address",
+ vscale,
+
+ // AMDGPU
+ @"amdgcn.workitem.id.x",
+ @"amdgcn.workitem.id.y",
+ @"amdgcn.workitem.id.z",
+ @"amdgcn.workgroup.id.x",
+ @"amdgcn.workgroup.id.y",
+ @"amdgcn.workgroup.id.z",
+ @"amdgcn.dispatch.ptr",
+
+ // WebAssembly
+ @"wasm.memory.size",
+ @"wasm.memory.grow",
+
+ const Signature = struct {
+ ret_len: u8,
+ params: []const Parameter,
+ attrs: []const Attribute = &.{},
+
+ const Parameter = struct {
+ kind: Kind,
+ attrs: []const Attribute = &.{},
+
+ const Kind = union(enum) {
+ type: Type,
+ overloaded,
+ matches: u8,
+ matches_scalar: u8,
+ matches_changed_scalar: struct {
+ index: u8,
+ scalar: Type,
+ },
+ };
+ };
+ };
+
+ const signatures = std.enums.EnumArray(Intrinsic, Signature).init(.{
+ .va_start = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+ .va_end = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+ .va_copy = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+
+ .returnaddress = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .addressofreturnaddress = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .sponentry = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .frameaddress = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .prefetch = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.readwrite) } },
+ },
+ .@"thread.pointer" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .abs = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .smax = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .smin = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .umax = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .umin = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .memcpy = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
+ .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+ },
+ .@"memcpy.inline" = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
+ .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
+ .{ .kind = .overloaded, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+ },
+ .memmove = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+ .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+ },
+ .memset = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+ .{ .kind = .{ .type = .i8 } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
+ },
+ .@"memset.inline" = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+ .{ .kind = .{ .type = .i8 } },
+ .{ .kind = .overloaded, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
+ },
+ .sqrt = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .powi = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .sin = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .cos = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .pow = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .exp = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .exp2 = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .ldexp = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .frexp = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .log = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .log10 = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .log2 = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .fma = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .fabs = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .minnum = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .maxnum = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .minimum = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .maximum = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .copysign = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .floor = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .ceil = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .trunc = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .rint = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .nearbyint = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .round = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .roundeven = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .lround = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .llround = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .lrint = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .llrint = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .bitreverse = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .bswap = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .ctpop = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .ctlz = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .cttz = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .fshl = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .fshr = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"sadd.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"uadd.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"ssub.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"usub.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"smul.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"umul.with.overflow" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 0, .scalar = .i1 } } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"sadd.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"uadd.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"ssub.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"usub.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"sshl.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"ushl.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"smul.fix" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"umul.fix" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"smul.fix.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"umul.fix.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"sdiv.fix" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"udiv.fix" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"sdiv.fix.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"udiv.fix.sat" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .canonicalize = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .fmuladd = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"vector.reduce.add" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fadd" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 2 } },
+ .{ .kind = .{ .matches_scalar = 2 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.mul" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fmul" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 2 } },
+ .{ .kind = .{ .matches_scalar = 2 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.and" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.or" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.xor" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.smax" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.smin" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.umax" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.umin" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fmax" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fmin" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fmaximum" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.reduce.fminimum" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_scalar = 1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.insert" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i64 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"vector.extract" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i64 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"is.fpclass" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .matches_changed_scalar = .{ .index = 1, .scalar = .i1 } } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"var.annotation" = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 1 } },
+ .{ .kind = .{ .type = .i32 } },
+ .{ .kind = .{ .matches = 1 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+ },
+ .@"ptr.annotation" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 2 } },
+ .{ .kind = .{ .type = .i32 } },
+ .{ .kind = .{ .matches = 2 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+ },
+ .annotation = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 2 } },
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+ },
+ .@"codeview.annotation" = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .metadata } },
+ },
+ .attrs = &.{ .nocallback, .noduplicate, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+ },
+ .trap = .{
+ .ret_len = 0,
+ .params = &.{},
+ .attrs = &.{ .cold, .noreturn, .nounwind, .{ .memory = .{ .inaccessiblemem = .write } } },
+ },
+ .debugtrap = .{
+ .ret_len = 0,
+ .params = &.{},
+ .attrs = &.{.nounwind},
+ },
+ .ubsantrap = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .i8 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .cold, .noreturn, .nounwind },
+ },
+ .stackprotector = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+ .stackguard = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+ .objectsize = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .expect = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"expect.with.probability" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .assume = .{
+ .ret_len = 0,
+ .params = &.{
+ .{ .kind = .{ .type = .i1 }, .attrs = &.{.noundef} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .write } } },
+ },
+ .@"ssa.copy" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"type.test" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i1 } },
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .metadata } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"type.checked.load" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .i1 } },
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .i32 } },
+ .{ .kind = .{ .type = .metadata } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"type.checked.load.relative" = .{
+ .ret_len = 2,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .i1 } },
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .i32 } },
+ .{ .kind = .{ .type = .metadata } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"arithmetic.fence" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .donothing = .{
+ .ret_len = 0,
+ .params = &.{},
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"load.relative" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .{ .type = .ptr } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .argmem = .read } } },
+ },
+ .sideeffect = .{
+ .ret_len = 0,
+ .params = &.{},
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+ },
+ .@"is.constant" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i1 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .ptrmask = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .matches = 0 } },
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"threadlocal.address" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded, .attrs = &.{.nonnull} },
+ .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .vscale = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"amdgcn.workitem.id.x" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.workitem.id.y" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.workitem.id.z" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.workgroup.id.x" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.workgroup.id.y" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.workgroup.id.z" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"amdgcn.dispatch.ptr" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{
+ .kind = .{ .type = Type.ptr_amdgpu_constant },
+ .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},
+ },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+
+ .@"wasm.memory.size" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i32 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+ },
+ .@"wasm.memory.grow" = .{
+ .ret_len = 1,
+ .params = &.{
+ .{ .kind = .overloaded },
+ .{ .kind = .{ .type = .i32 } },
+ .{ .kind = .{ .matches = 0 } },
+ },
+ .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+ },
+ });
+};
+
pub const Function = struct {
global: Global.Index,
call_conv: CallConv = CallConv.default,
@@ -2303,6 +3816,14 @@ pub const Function = struct {
return &builder.functions.items[@intFromEnum(self)];
}
+ pub fn name(self: Index, builder: *const Builder) String {
+ return self.ptrConst(builder).global.name(builder);
+ }
+
+ pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
+ return self.ptrConst(builder).global.rename(new_name, builder);
+ }
+
pub fn typeOf(self: Index, builder: *const Builder) Type {
return self.ptrConst(builder).global.typeOf(builder);
}
@@ -2315,6 +3836,110 @@ pub const Function = struct {
return self.toConst(builder).toValue();
}
+ pub fn setLinkage(self: Index, linkage: Linkage, builder: *Builder) void {
+ return self.ptrConst(builder).global.setLinkage(linkage, builder);
+ }
+
+ pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
+ return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
+ }
+
+ pub fn setCallConv(self: Index, call_conv: CallConv, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setFunctionCallConv(call_conv.toLlvm());
+ self.ptr(builder).call_conv = call_conv;
+ }
+
+ pub fn setAttributes(
+ self: Index,
+ new_function_attributes: FunctionAttributes,
+ builder: *Builder,
+ ) void {
+ if (builder.useLibLlvm()) {
+ const llvm_function = self.toLlvm(builder);
+ const old_function_attributes = self.ptrConst(builder).attributes;
+ for (0..@max(
+ old_function_attributes.slice(builder).len,
+ new_function_attributes.slice(builder).len,
+ )) |function_attribute_index| {
+ const llvm_attribute_index =
+ @as(llvm.AttributeIndex, @intCast(function_attribute_index)) -% 1;
+ const old_attributes_slice =
+ old_function_attributes.get(function_attribute_index, builder).slice(builder);
+ const new_attributes_slice =
+ new_function_attributes.get(function_attribute_index, builder).slice(builder);
+ var old_attribute_index: usize = 0;
+ var new_attribute_index: usize = 0;
+ while (true) {
+ const old_attribute_kind = if (old_attribute_index < old_attributes_slice.len)
+ old_attributes_slice[old_attribute_index].getKind(builder)
+ else
+ .none;
+ const new_attribute_kind = if (new_attribute_index < new_attributes_slice.len)
+ new_attributes_slice[new_attribute_index].getKind(builder)
+ else
+ .none;
+ switch (std.math.order(
+ @intFromEnum(old_attribute_kind),
+ @intFromEnum(new_attribute_kind),
+ )) {
+ .lt => {
+ // Removed
+ if (old_attribute_kind.toString()) |attribute_name| {
+ const attribute_name_slice = attribute_name.slice(builder).?;
+ llvm_function.removeStringAttributeAtIndex(
+ llvm_attribute_index,
+ attribute_name_slice.ptr,
+ @intCast(attribute_name_slice.len),
+ );
+ } else {
+ const llvm_kind_id = old_attribute_kind.toLlvm(builder).*;
+ assert(llvm_kind_id != 0);
+ llvm_function.removeEnumAttributeAtIndex(
+ llvm_attribute_index,
+ llvm_kind_id,
+ );
+ }
+ old_attribute_index += 1;
+ continue;
+ },
+ .eq => {
+ // Iteration finished
+ if (old_attribute_kind == .none) break;
+ // No change
+ if (old_attributes_slice[old_attribute_index] ==
+ new_attributes_slice[new_attribute_index])
+ {
+ old_attribute_index += 1;
+ new_attribute_index += 1;
+ continue;
+ }
+ old_attribute_index += 1;
+ },
+ .gt => {},
+ }
+ // New or changed
+ llvm_function.addAttributeAtIndex(
+ llvm_attribute_index,
+ new_attributes_slice[new_attribute_index].toLlvm(builder),
+ );
+ new_attribute_index += 1;
+ }
+ }
+ }
+ self.ptr(builder).attributes = new_function_attributes;
+ }
+
+ pub fn setSection(self: Index, section: String, builder: *Builder) void {
+ if (builder.useLibLlvm()) self.toLlvm(builder).setSection(section.slice(builder).?);
+ self.ptr(builder).section = section;
+ }
+
+ pub fn setAlignment(self: Index, alignment: Alignment, builder: *Builder) void {
+ if (builder.useLibLlvm())
+ self.toLlvm(builder).setAlignment(@intCast(alignment.toByteUnits() orelse 0));
+ self.ptr(builder).alignment = alignment;
+ }
+
pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
return self.ptrConst(builder).global.toLlvm(builder);
}
@@ -2342,12 +3967,15 @@ pub const Function = struct {
arg,
ashr,
@"ashr exact",
+ atomicrmw,
bitcast,
block,
br,
br_cond,
call,
@"call fast",
+ cmpxchg,
+ @"cmpxchg weak",
extractelement,
extractvalue,
fadd,
@@ -2414,43 +4042,8 @@ pub const Function = struct {
insertelement,
insertvalue,
inttoptr,
- @"llvm.maxnum.",
- @"llvm.minnum.",
- @"llvm.ceil.",
- @"llvm.cos.",
- @"llvm.exp.",
- @"llvm.exp2.",
- @"llvm.fabs.",
- @"llvm.floor.",
- @"llvm.log.",
- @"llvm.log10.",
- @"llvm.log2.",
- @"llvm.round.",
- @"llvm.sin.",
- @"llvm.sqrt.",
- @"llvm.trunc.",
- @"llvm.fma.",
- @"llvm.bitreverse.",
- @"llvm.bswap.",
- @"llvm.ctpop.",
- @"llvm.ctlz.",
- @"llvm.cttz.",
- @"llvm.sadd.sat.",
- @"llvm.smax.",
- @"llvm.smin.",
- @"llvm.smul.fix.sat.",
- @"llvm.sshl.sat.",
- @"llvm.ssub.sat.",
- @"llvm.uadd.sat.",
- @"llvm.umax.",
- @"llvm.umin.",
- @"llvm.umul.fix.sat.",
- @"llvm.ushl.sat.",
- @"llvm.usub.sat.",
load,
@"load atomic",
- @"load atomic volatile",
- @"load volatile",
lshr,
@"lshr exact",
mul,
@@ -2481,8 +4074,6 @@ pub const Function = struct {
srem,
store,
@"store atomic",
- @"store atomic volatile",
- @"store volatile",
sub,
@"sub nsw",
@"sub nuw",
@@ -2495,7 +4086,6 @@ pub const Function = struct {
@"udiv exact",
urem,
uitofp,
- unimplemented,
@"unreachable",
va_arg,
xor,
@@ -2536,8 +4126,6 @@ pub const Function = struct {
.@"ret void",
.store,
.@"store atomic",
- .@"store atomic volatile",
- .@"store volatile",
.@"switch",
.@"unreachable",
=> false,
@@ -2549,7 +4137,6 @@ pub const Function = struct {
.@"notail call fast",
.@"tail call",
.@"tail call fast",
- .unimplemented,
=> self.typeOfWip(wip) != .void,
else => true,
};
@@ -2575,22 +4162,6 @@ pub const Function = struct {
.@"frem fast",
.fsub,
.@"fsub fast",
- .@"llvm.maxnum.",
- .@"llvm.minnum.",
- .@"llvm.ctlz.",
- .@"llvm.cttz.",
- .@"llvm.sadd.sat.",
- .@"llvm.smax.",
- .@"llvm.smin.",
- .@"llvm.smul.fix.sat.",
- .@"llvm.sshl.sat.",
- .@"llvm.ssub.sat.",
- .@"llvm.uadd.sat.",
- .@"llvm.umax.",
- .@"llvm.umin.",
- .@"llvm.umul.fix.sat.",
- .@"llvm.ushl.sat.",
- .@"llvm.usub.sat.",
.lshr,
.@"lshr exact",
.mul,
@@ -2635,6 +4206,7 @@ pub const Function = struct {
),
.arg => wip.function.typeOf(wip.builder)
.functionParameters(wip.builder)[instruction.data],
+ .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
.block => .label,
.br,
.br_cond,
@@ -2643,8 +4215,6 @@ pub const Function = struct {
.@"ret void",
.store,
.@"store atomic",
- .@"store atomic volatile",
- .@"store volatile",
.@"switch",
.@"unreachable",
=> .none,
@@ -2657,6 +4227,12 @@ pub const Function = struct {
.@"tail call",
.@"tail call fast",
=> wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
+ .cmpxchg,
+ .@"cmpxchg weak",
+ => wip.builder.structTypeAssumeCapacity(.normal, &.{
+ wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
+ .i1,
+ }) catch unreachable,
.extractelement => wip.extraData(ExtractElement, instruction.data)
.val.typeOfWip(wip).childType(wip.builder),
.extractvalue => {
@@ -2710,22 +4286,6 @@ pub const Function = struct {
.changeScalarAssumeCapacity(.i1, wip.builder),
.fneg,
.@"fneg fast",
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
=> @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
.getelementptr,
.@"getelementptr inbounds",
@@ -2744,8 +4304,6 @@ pub const Function = struct {
.insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
.load,
.@"load atomic",
- .@"load atomic volatile",
- .@"load volatile",
=> wip.extraData(Load, instruction.data).type,
.phi,
.@"phi fast",
@@ -2760,9 +4318,7 @@ pub const Function = struct {
wip.builder,
);
},
- .unimplemented => @enumFromInt(instruction.data),
.va_arg => wip.extraData(VaArg, instruction.data).type,
- .@"llvm.fma." => wip.extraData(FusedMultiplyAdd, instruction.data).a.typeOfWip(wip),
};
}
@@ -2791,22 +4347,6 @@ pub const Function = struct {
.@"frem fast",
.fsub,
.@"fsub fast",
- .@"llvm.maxnum.",
- .@"llvm.minnum.",
- .@"llvm.ctlz.",
- .@"llvm.cttz.",
- .@"llvm.sadd.sat.",
- .@"llvm.smax.",
- .@"llvm.smin.",
- .@"llvm.smul.fix.sat.",
- .@"llvm.sshl.sat.",
- .@"llvm.ssub.sat.",
- .@"llvm.uadd.sat.",
- .@"llvm.umax.",
- .@"llvm.umin.",
- .@"llvm.umul.fix.sat.",
- .@"llvm.ushl.sat.",
- .@"llvm.usub.sat.",
.lshr,
.@"lshr exact",
.mul,
@@ -2851,6 +4391,8 @@ pub const Function = struct {
),
.arg => function.global.typeOf(builder)
.functionParameters(builder)[instruction.data],
+ .atomicrmw => function.extraData(AtomicRmw, instruction.data)
+ .val.typeOf(function_index, builder),
.block => .label,
.br,
.br_cond,
@@ -2859,8 +4401,6 @@ pub const Function = struct {
.@"ret void",
.store,
.@"store atomic",
- .@"store atomic volatile",
- .@"store volatile",
.@"switch",
.@"unreachable",
=> .none,
@@ -2873,6 +4413,13 @@ pub const Function = struct {
.@"tail call",
.@"tail call fast",
=> function.extraData(Call, instruction.data).ty.functionReturn(builder),
+ .cmpxchg,
+ .@"cmpxchg weak",
+ => builder.structTypeAssumeCapacity(.normal, &.{
+ function.extraData(CmpXchg, instruction.data)
+ .cmp.typeOf(function_index, builder),
+ .i1,
+ }) catch unreachable,
.extractelement => function.extraData(ExtractElement, instruction.data)
.val.typeOf(function_index, builder).childType(builder),
.extractvalue => {
@@ -2927,22 +4474,6 @@ pub const Function = struct {
.changeScalarAssumeCapacity(.i1, builder),
.fneg,
.@"fneg fast",
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
=> @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
.getelementptr,
.@"getelementptr inbounds",
@@ -2963,8 +4494,6 @@ pub const Function = struct {
.val.typeOf(function_index, builder),
.load,
.@"load atomic",
- .@"load atomic volatile",
- .@"load volatile",
=> function.extraData(Load, instruction.data).type,
.phi,
.@"phi fast",
@@ -2979,9 +4508,7 @@ pub const Function = struct {
builder,
);
},
- .unimplemented => @enumFromInt(instruction.data),
.va_arg => function.extraData(VaArg, instruction.data).type,
- .@"llvm.fma." => function.extraData(FusedMultiplyAdd, instruction.data).a.typeOf(function_index, builder),
};
}
@@ -3023,12 +4550,14 @@ pub const Function = struct {
return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
}
- pub fn toLlvm(self: Instruction.Index, wip: *const WipFunction) *llvm.Value {
+ fn toLlvm(self: Instruction.Index, wip: *const WipFunction) *llvm.Value {
assert(wip.builder.useLibLlvm());
- return wip.llvm.instructions.items[@intFromEnum(self)];
+ const llvm_value = wip.llvm.instructions.items[@intFromEnum(self)];
+ const global = wip.builder.llvm.replacements.get(llvm_value) orelse return llvm_value;
+ return global.toLlvm(wip.builder);
}
- fn llvmName(self: Instruction.Index, wip: *const WipFunction) [*:0]const u8 {
+ fn llvmName(self: Instruction.Index, wip: *const WipFunction) [:0]const u8 {
return if (wip.builder.strip)
""
else
@@ -3074,12 +4603,6 @@ pub const Function = struct {
mask: Value,
};
- pub const FusedMultiplyAdd = struct {
- a: Value,
- b: Value,
- c: Value,
- };
-
pub const ExtractValue = struct {
val: Value,
indices_len: u32,
@@ -3107,15 +4630,70 @@ pub const Function = struct {
};
pub const Load = struct {
+ info: MemoryAccessInfo,
type: Type,
ptr: Value,
- info: MemoryAccessInfo,
};
pub const Store = struct {
+ info: MemoryAccessInfo,
val: Value,
ptr: Value,
+ };
+
+ pub const CmpXchg = struct {
+ info: MemoryAccessInfo,
+ ptr: Value,
+ cmp: Value,
+ new: Value,
+
+ pub const Kind = enum { strong, weak };
+ };
+
+ pub const AtomicRmw = struct {
info: MemoryAccessInfo,
+ ptr: Value,
+ val: Value,
+
+ pub const Operation = enum(u5) {
+ xchg,
+ add,
+ sub,
+ @"and",
+ nand,
+ @"or",
+ xor,
+ max,
+ min,
+ umax,
+ umin,
+ fadd,
+ fsub,
+ fmax,
+ fmin,
+ none = std.math.maxInt(u5),
+
+ fn toLlvm(self: Operation) llvm.AtomicRMWBinOp {
+ return switch (self) {
+ .xchg => .Xchg,
+ .add => .Add,
+ .sub => .Sub,
+ .@"and" => .And,
+ .nand => .Nand,
+ .@"or" => .Or,
+ .xor => .Xor,
+ .max => .Max,
+ .min => .Min,
+ .umax => .UMax,
+ .umin => .UMin,
+ .fadd => .FAdd,
+ .fsub => .FSub,
+ .fmax => .FMax,
+ .fmin => .FMin,
+ .none => unreachable,
+ };
+ }
+ };
};
pub const GetElementPtr = struct {
@@ -3487,24 +5065,7 @@ pub const WipFunction = struct {
switch (tag) {
.fneg,
.@"fneg fast",
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
=> assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
- => assert(val.typeOfWip(self).scalarType(self.builder).isInteger(self.builder)),
else => unreachable,
}
try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
@@ -3513,43 +5074,10 @@ pub const WipFunction = struct {
switch (tag) {
.fneg => self.llvm.builder.setFastMath(false),
.@"fneg fast" => self.llvm.builder.setFastMath(true),
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
- => {},
else => unreachable,
}
self.llvm.instructions.appendAssumeCapacity(switch (tag) {
.fneg, .@"fneg fast" => &llvm.Builder.buildFNeg,
- .@"llvm.ceil." => &llvm.Builder.buildCeil,
- .@"llvm.cos." => &llvm.Builder.buildCos,
- .@"llvm.exp." => &llvm.Builder.buildExp,
- .@"llvm.exp2." => &llvm.Builder.buildExp2,
- .@"llvm.fabs." => &llvm.Builder.buildFAbs,
- .@"llvm.floor." => &llvm.Builder.buildFloor,
- .@"llvm.log." => &llvm.Builder.buildLog,
- .@"llvm.log10." => &llvm.Builder.buildLog10,
- .@"llvm.log2." => &llvm.Builder.buildLog2,
- .@"llvm.round." => &llvm.Builder.buildRound,
- .@"llvm.sin." => &llvm.Builder.buildSin,
- .@"llvm.sqrt." => &llvm.Builder.buildSqrt,
- .@"llvm.trunc." => &llvm.Builder.buildFTrunc,
- .@"llvm.bitreverse." => &llvm.Builder.buildBitReverse,
- .@"llvm.bswap." => &llvm.Builder.buildBSwap,
- .@"llvm.ctpop." => &llvm.Builder.buildCTPop,
else => unreachable,
}(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self)));
}
@@ -3593,20 +5121,6 @@ pub const WipFunction = struct {
.@"frem fast",
.fsub,
.@"fsub fast",
- .@"llvm.maxnum.",
- .@"llvm.minnum.",
- .@"llvm.sadd.sat.",
- .@"llvm.smax.",
- .@"llvm.smin.",
- .@"llvm.smul.fix.sat.",
- .@"llvm.sshl.sat.",
- .@"llvm.ssub.sat.",
- .@"llvm.uadd.sat.",
- .@"llvm.umax.",
- .@"llvm.umin.",
- .@"llvm.umul.fix.sat.",
- .@"llvm.ushl.sat.",
- .@"llvm.usub.sat.",
.lshr,
.@"lshr exact",
.mul,
@@ -3627,9 +5141,6 @@ pub const WipFunction = struct {
.urem,
.xor,
=> assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
- .@"llvm.ctlz.",
- .@"llvm.cttz.",
- => assert(lhs.typeOfWip(self).scalarType(self.builder).isInteger(self.builder) and rhs.typeOfWip(self) == .i1),
else => unreachable,
}
try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
@@ -3665,22 +5176,6 @@ pub const WipFunction = struct {
.fmul, .@"fmul fast" => &llvm.Builder.buildFMul,
.frem, .@"frem fast" => &llvm.Builder.buildFRem,
.fsub, .@"fsub fast" => &llvm.Builder.buildFSub,
- .@"llvm.maxnum." => &llvm.Builder.buildMaxNum,
- .@"llvm.minnum." => &llvm.Builder.buildMinNum,
- .@"llvm.ctlz." => &llvm.Builder.buildCTLZ,
- .@"llvm.cttz." => &llvm.Builder.buildCTTZ,
- .@"llvm.sadd.sat." => &llvm.Builder.buildSAddSat,
- .@"llvm.smax." => &llvm.Builder.buildSMax,
- .@"llvm.smin." => &llvm.Builder.buildSMin,
- .@"llvm.smul.fix.sat." => &llvm.Builder.buildSMulFixSat,
- .@"llvm.sshl.sat." => &llvm.Builder.buildSShlSat,
- .@"llvm.ssub.sat." => &llvm.Builder.buildSSubSat,
- .@"llvm.uadd.sat." => &llvm.Builder.buildUAddSat,
- .@"llvm.umax." => &llvm.Builder.buildUMax,
- .@"llvm.umin." => &llvm.Builder.buildUMin,
- .@"llvm.umul.fix.sat." => &llvm.Builder.buildUMulFixSat,
- .@"llvm.ushl.sat." => &llvm.Builder.buildUShlSat,
- .@"llvm.usub.sat." => &llvm.Builder.buildUSubSat,
.lshr => &llvm.Builder.buildLShr,
.@"lshr exact" => &llvm.Builder.buildLShrExact,
.mul => &llvm.Builder.buildMul,
@@ -3934,21 +5429,21 @@ pub const WipFunction = struct {
pub fn load(
self: *WipFunction,
- kind: MemoryAccessKind,
+ access_kind: MemoryAccessKind,
ty: Type,
ptr: Value,
alignment: Alignment,
name: []const u8,
) Allocator.Error!Value {
- return self.loadAtomic(kind, ty, ptr, .system, .none, alignment, name);
+ return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);
}
pub fn loadAtomic(
self: *WipFunction,
- kind: MemoryAccessKind,
+ access_kind: MemoryAccessKind,
ty: Type,
ptr: Value,
- scope: SyncScope,
+ sync_scope: SyncScope,
ordering: AtomicOrdering,
alignment: Alignment,
name: []const u8,
@@ -3957,22 +5452,21 @@ pub const WipFunction = struct {
try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
const instruction = try self.addInst(name, .{
.tag = switch (ordering) {
- .none => switch (kind) {
- .normal => .load,
- .@"volatile" => .@"load volatile",
- },
- else => switch (kind) {
- .normal => .@"load atomic",
- .@"volatile" => .@"load atomic volatile",
- },
+ .none => .load,
+ else => .@"load atomic",
},
.data = self.addExtraAssumeCapacity(Instruction.Load{
+ .info = .{
+ .access_kind = access_kind,
+ .sync_scope = switch (ordering) {
+ .none => .system,
+ else => sync_scope,
+ },
+ .success_ordering = ordering,
+ .alignment = alignment,
+ },
.type = ty,
.ptr = ptr,
- .info = .{ .scope = switch (ordering) {
- .none => .system,
- else => scope,
- }, .ordering = ordering, .alignment = alignment },
}),
});
if (self.builder.useLibLlvm()) {
@@ -3981,7 +5475,8 @@ pub const WipFunction = struct {
ptr.toLlvm(self),
instruction.llvmName(self),
);
- if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
+ if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+ if (ordering != .none) llvm_instruction.setOrdering(ordering.toLlvm());
if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
}
@@ -4000,10 +5495,10 @@ pub const WipFunction = struct {
pub fn storeAtomic(
self: *WipFunction,
- kind: MemoryAccessKind,
+ access_kind: MemoryAccessKind,
val: Value,
ptr: Value,
- scope: SyncScope,
+ sync_scope: SyncScope,
ordering: AtomicOrdering,
alignment: Alignment,
) Allocator.Error!Instruction.Index {
@@ -4011,31 +5506,27 @@ pub const WipFunction = struct {
try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
const instruction = try self.addInst(null, .{
.tag = switch (ordering) {
- .none => switch (kind) {
- .normal => .store,
- .@"volatile" => .@"store volatile",
- },
- else => switch (kind) {
- .normal => .@"store atomic",
- .@"volatile" => .@"store atomic volatile",
- },
+ .none => .store,
+ else => .@"store atomic",
},
.data = self.addExtraAssumeCapacity(Instruction.Store{
+ .info = .{
+ .access_kind = access_kind,
+ .sync_scope = switch (ordering) {
+ .none => .system,
+ else => sync_scope,
+ },
+ .success_ordering = ordering,
+ .alignment = alignment,
+ },
.val = val,
.ptr = ptr,
- .info = .{ .scope = switch (ordering) {
- .none => .system,
- else => scope,
- }, .ordering = ordering, .alignment = alignment },
}),
});
if (self.builder.useLibLlvm()) {
const llvm_instruction = self.llvm.builder.buildStore(val.toLlvm(self), ptr.toLlvm(self));
- switch (kind) {
- .normal => {},
- .@"volatile" => llvm_instruction.setVolatile(.True),
- }
- if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
+ if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+ if (ordering != .none) llvm_instruction.setOrdering(ordering.toLlvm());
if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
}
@@ -4044,7 +5535,7 @@ pub const WipFunction = struct {
pub fn fence(
self: *WipFunction,
- scope: SyncScope,
+ sync_scope: SyncScope,
ordering: AtomicOrdering,
) Allocator.Error!Instruction.Index {
assert(ordering != .none);
@@ -4052,21 +5543,130 @@ pub const WipFunction = struct {
const instruction = try self.addInst(null, .{
.tag = .fence,
.data = @bitCast(MemoryAccessInfo{
- .scope = scope,
- .ordering = ordering,
- .alignment = undefined,
+ .sync_scope = sync_scope,
+ .success_ordering = ordering,
}),
});
if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
self.llvm.builder.buildFence(
- @enumFromInt(@intFromEnum(ordering)),
- llvm.Bool.fromBool(scope == .singlethread),
+ ordering.toLlvm(),
+ llvm.Bool.fromBool(sync_scope == .singlethread),
"",
),
);
return instruction;
}
+ pub fn cmpxchg(
+ self: *WipFunction,
+ kind: Instruction.CmpXchg.Kind,
+ access_kind: MemoryAccessKind,
+ ptr: Value,
+ cmp: Value,
+ new: Value,
+ sync_scope: SyncScope,
+ success_ordering: AtomicOrdering,
+ failure_ordering: AtomicOrdering,
+ alignment: Alignment,
+ name: []const u8,
+ ) Allocator.Error!Value {
+ assert(ptr.typeOfWip(self).isPointer(self.builder));
+ const ty = cmp.typeOfWip(self);
+ assert(ty == new.typeOfWip(self));
+ assert(success_ordering != .none);
+ assert(failure_ordering != .none);
+
+ _ = try self.builder.structType(.normal, &.{ ty, .i1 });
+ try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
+ const instruction = try self.addInst(name, .{
+ .tag = switch (kind) {
+ .strong => .cmpxchg,
+ .weak => .@"cmpxchg weak",
+ },
+ .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
+ .info = .{
+ .access_kind = access_kind,
+ .sync_scope = sync_scope,
+ .success_ordering = success_ordering,
+ .failure_ordering = failure_ordering,
+ .alignment = alignment,
+ },
+ .ptr = ptr,
+ .cmp = cmp,
+ .new = new,
+ }),
+ });
+ if (self.builder.useLibLlvm()) {
+ const llvm_instruction = self.llvm.builder.buildAtomicCmpXchg(
+ ptr.toLlvm(self),
+ cmp.toLlvm(self),
+ new.toLlvm(self),
+ success_ordering.toLlvm(),
+ failure_ordering.toLlvm(),
+ llvm.Bool.fromBool(sync_scope == .singlethread),
+ );
+ if (kind == .weak) llvm_instruction.setWeak(.True);
+ if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+ if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
+ const llvm_name = instruction.llvmName(self);
+ if (llvm_name.len > 0) llvm_instruction.setValueName(
+ llvm_name.ptr,
+ @intCast(llvm_name.len),
+ );
+ self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
+ }
+ return instruction.toValue();
+ }
+
+ pub fn atomicrmw(
+ self: *WipFunction,
+ access_kind: MemoryAccessKind,
+ operation: Instruction.AtomicRmw.Operation,
+ ptr: Value,
+ val: Value,
+ sync_scope: SyncScope,
+ ordering: AtomicOrdering,
+ alignment: Alignment,
+ name: []const u8,
+ ) Allocator.Error!Value {
+ assert(ptr.typeOfWip(self).isPointer(self.builder));
+ assert(ordering != .none);
+
+ try self.ensureUnusedExtraCapacity(1, Instruction.AtomicRmw, 0);
+ const instruction = try self.addInst(name, .{
+ .tag = .atomicrmw,
+ .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
+ .info = .{
+ .access_kind = access_kind,
+ .atomic_rmw_operation = operation,
+ .sync_scope = sync_scope,
+ .success_ordering = ordering,
+ .alignment = alignment,
+ },
+ .ptr = ptr,
+ .val = val,
+ }),
+ });
+ if (self.builder.useLibLlvm()) {
+ const llvm_instruction = self.llvm.builder.buildAtomicRmw(
+ operation.toLlvm(),
+ ptr.toLlvm(self),
+ val.toLlvm(self),
+ ordering.toLlvm(),
+ llvm.Bool.fromBool(sync_scope == .singlethread),
+ );
+ if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+ if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
+ const llvm_name = instruction.llvmName(self);
+ if (llvm_name.len > 0) llvm_instruction.setValueName(
+ llvm_name.ptr,
+ @intCast(llvm_name.len),
+ );
+ self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
+ }
+ return instruction.toValue();
+ }
+
pub fn gep(
self: *WipFunction,
kind: Instruction.GetElementPtr.Kind,
@@ -4239,25 +5839,19 @@ pub const WipFunction = struct {
pub fn fcmp(
self: *WipFunction,
+ fast: FastMathKind,
cond: FloatCondition,
lhs: Value,
rhs: Value,
name: []const u8,
) Allocator.Error!Value {
- return self.cmpTag(switch (cond) {
- inline else => |tag| @field(Instruction.Tag, "fcmp " ++ @tagName(tag)),
- }, @intFromEnum(cond), lhs, rhs, name);
- }
-
- pub fn fcmpFast(
- self: *WipFunction,
- cond: FloatCondition,
- lhs: Value,
- rhs: Value,
- name: []const u8,
- ) Allocator.Error!Value {
- return self.cmpTag(switch (cond) {
- inline else => |tag| @field(Instruction.Tag, "fcmp fast " ++ @tagName(tag)),
+ return self.cmpTag(switch (fast) {
+ inline else => |fast_tag| switch (cond) {
+ inline else => |cond_tag| @field(Instruction.Tag, "fcmp " ++ switch (fast_tag) {
+ .normal => "",
+ .fast => "fast ",
+ } ++ @tagName(cond_tag)),
+ },
}, @intFromEnum(cond), lhs, rhs, name);
}
@@ -4315,22 +5909,16 @@ pub const WipFunction = struct {
pub fn select(
self: *WipFunction,
+ fast: FastMathKind,
cond: Value,
lhs: Value,
rhs: Value,
name: []const u8,
) Allocator.Error!Value {
- return self.selectTag(.select, cond, lhs, rhs, name);
- }
-
- pub fn selectFast(
- self: *WipFunction,
- cond: Value,
- lhs: Value,
- rhs: Value,
- name: []const u8,
- ) Allocator.Error!Value {
- return self.selectTag(.@"select fast", cond, lhs, rhs, name);
+ return self.selectTag(switch (fast) {
+ .normal => .select,
+ .fast => .@"select fast",
+ }, cond, lhs, rhs, name);
}
pub fn call(
@@ -4354,7 +5942,16 @@ pub const WipFunction = struct {
.void => null,
else => name,
}, .{
- .tag = .call,
+ .tag = switch (kind) {
+ .normal => .call,
+ .fast => .@"call fast",
+ .musttail => .@"musttail call",
+ .musttail_fast => .@"musttail call fast",
+ .notail => .@"notail call",
+ .notail_fast => .@"notail call fast",
+ .tail => .@"tail call",
+ .tail_fast => .@"tail call fast",
+ },
.data = self.addExtraAssumeCapacity(Instruction.Call{
.info = .{ .call_conv = call_conv },
.attributes = function_attributes,
@@ -4396,7 +5993,7 @@ pub const WipFunction = struct {
else => instruction.llvmName(self),
},
);
- llvm_instruction.setInstructionCallConv(@enumFromInt(@intFromEnum(call_conv)));
+ llvm_instruction.setInstructionCallConv(call_conv.toLlvm());
llvm_instruction.setTailCallKind(switch (kind) {
.normal, .fast => .None,
.musttail, .musttail_fast => .MustTail,
@@ -4404,9 +6001,8 @@ pub const WipFunction = struct {
.tail, .tail_fast => .Tail,
});
for (0.., function_attributes.slice(self.builder)) |index, attributes| {
- const attribute_index = @as(llvm.AttributeIndex, @intCast(index)) -% 1;
for (attributes.slice(self.builder)) |attribute| llvm_instruction.addCallSiteAttribute(
- attribute_index,
+ @as(llvm.AttributeIndex, @intCast(index)) -% 1,
attribute.toLlvm(self.builder),
);
}
@@ -4419,7 +6015,7 @@ pub const WipFunction = struct {
self: *WipFunction,
function_attributes: FunctionAttributes,
ty: Type,
- kind: Constant.Asm.Info,
+ kind: Constant.Assembly.Info,
assembly: String,
constraints: String,
args: []const Value,
@@ -4429,6 +6025,80 @@ pub const WipFunction = struct {
return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
}
+ pub fn callIntrinsic(
+ self: *WipFunction,
+ fast: FastMathKind,
+ function_attributes: FunctionAttributes,
+ id: Intrinsic,
+ overload: []const Type,
+ args: []const Value,
+ name: []const u8,
+ ) Allocator.Error!Value {
+ const intrinsic = try self.builder.getIntrinsic(id, overload);
+ return self.call(
+ fast.toCallKind(),
+ CallConv.default,
+ function_attributes,
+ intrinsic.typeOf(self.builder),
+ intrinsic.toValue(self.builder),
+ args,
+ name,
+ );
+ }
+
+ pub fn callMemCpy(
+ self: *WipFunction,
+ dst: Value,
+ dst_align: Alignment,
+ src: Value,
+ src_align: Alignment,
+ len: Value,
+ kind: MemoryAccessKind,
+ ) Allocator.Error!Instruction.Index {
+ var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
+ var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
+ const value = try self.callIntrinsic(
+ .normal,
+ try self.builder.fnAttrs(&.{
+ .none,
+ .none,
+ try self.builder.attrs(&dst_attrs),
+ try self.builder.attrs(&src_attrs),
+ }),
+ .memcpy,
+ &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },
+ &.{ dst, src, len, switch (kind) {
+ .normal => Value.false,
+ .@"volatile" => Value.true,
+ } },
+ undefined,
+ );
+ return value.unwrap().instruction;
+ }
+
+ pub fn callMemSet(
+ self: *WipFunction,
+ dst: Value,
+ dst_align: Alignment,
+ val: Value,
+ len: Value,
+ kind: MemoryAccessKind,
+ ) Allocator.Error!Instruction.Index {
+ var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
+ const value = try self.callIntrinsic(
+ .normal,
+ try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
+ .memset,
+ &.{ dst.typeOfWip(self), len.typeOfWip(self) },
+ &.{ dst, val, len, switch (kind) {
+ .normal => Value.false,
+ .@"volatile" => Value.true,
+ } },
+ undefined,
+ );
+ return value.unwrap().instruction;
+ }
+
pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
const instruction = try self.addInst(name, .{
@@ -4448,53 +6118,6 @@ pub const WipFunction = struct {
return instruction.toValue();
}
- pub fn fusedMultiplyAdd(self: *WipFunction, a: Value, b: Value, c: Value) Allocator.Error!Value {
- assert(a.typeOfWip(self) == b.typeOfWip(self) and a.typeOfWip(self) == c.typeOfWip(self));
- try self.ensureUnusedExtraCapacity(1, Instruction.FusedMultiplyAdd, 0);
- const instruction = try self.addInst("", .{
- .tag = .@"llvm.fma.",
- .data = self.addExtraAssumeCapacity(Instruction.FusedMultiplyAdd{
- .a = a,
- .b = b,
- .c = c,
- }),
- });
- if (self.builder.useLibLlvm()) {
- self.llvm.instructions.appendAssumeCapacity(llvm.Builder.buildFMA(
- self.llvm.builder,
- a.toLlvm(self),
- b.toLlvm(self),
- c.toLlvm(self),
- instruction.llvmName(self),
- ));
- }
- return instruction.toValue();
- }
-
- pub const WipUnimplemented = struct {
- instruction: Instruction.Index,
-
- pub fn finish(self: WipUnimplemented, val: *llvm.Value, wip: *WipFunction) Value {
- assert(wip.builder.useLibLlvm());
- wip.llvm.instructions.items[@intFromEnum(self.instruction)] = val;
- return self.instruction.toValue();
- }
- };
-
- pub fn unimplemented(
- self: *WipFunction,
- ty: Type,
- name: []const u8,
- ) Allocator.Error!WipUnimplemented {
- try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
- const instruction = try self.addInst(name, .{
- .tag = .unimplemented,
- .data = @intFromEnum(ty),
- });
- if (self.builder.useLibLlvm()) _ = self.llvm.instructions.addOneAssumeCapacity();
- return .{ .instruction = instruction };
- }
-
pub fn finish(self: *WipFunction) Allocator.Error!void {
const gpa = self.builder.gpa;
const function = self.function.ptr(self.builder);
@@ -4697,22 +6320,6 @@ pub const WipFunction = struct {
.@"icmp ugt",
.@"icmp ule",
.@"icmp ult",
- .@"llvm.maxnum.",
- .@"llvm.minnum.",
- .@"llvm.ctlz.",
- .@"llvm.cttz.",
- .@"llvm.sadd.sat.",
- .@"llvm.smax.",
- .@"llvm.smin.",
- .@"llvm.smul.fix.sat.",
- .@"llvm.sshl.sat.",
- .@"llvm.ssub.sat.",
- .@"llvm.uadd.sat.",
- .@"llvm.umax.",
- .@"llvm.umin.",
- .@"llvm.umul.fix.sat.",
- .@"llvm.ushl.sat.",
- .@"llvm.usub.sat.",
.lshr,
.@"lshr exact",
.mul,
@@ -4775,19 +6382,19 @@ pub const WipFunction = struct {
.arg,
.block,
=> unreachable,
+ .atomicrmw => {
+ const extra = self.extraData(Instruction.AtomicRmw, instruction.data);
+ instruction.data = wip_extra.addExtra(Instruction.AtomicRmw{
+ .info = extra.info,
+ .ptr = instructions.map(extra.ptr),
+ .val = instructions.map(extra.val),
+ });
+ },
.br,
.fence,
.@"ret void",
- .unimplemented,
.@"unreachable",
=> {},
- .extractelement => {
- const extra = self.extraData(Instruction.ExtractElement, instruction.data);
- instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
- .val = instructions.map(extra.val),
- .index = instructions.map(extra.index),
- });
- },
.br_cond => {
const extra = self.extraData(Instruction.BrCond, instruction.data);
instruction.data = wip_extra.addExtra(Instruction.BrCond{
@@ -4816,6 +6423,24 @@ pub const WipFunction = struct {
});
wip_extra.appendMappedValues(args, instructions);
},
+ .cmpxchg,
+ .@"cmpxchg weak",
+ => {
+ const extra = self.extraData(Instruction.CmpXchg, instruction.data);
+ instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
+ .info = extra.info,
+ .ptr = instructions.map(extra.ptr),
+ .cmp = instructions.map(extra.cmp),
+ .new = instructions.map(extra.new),
+ });
+ },
+ .extractelement => {
+ const extra = self.extraData(Instruction.ExtractElement, instruction.data);
+ instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
+ .val = instructions.map(extra.val),
+ .index = instructions.map(extra.index),
+ });
+ },
.extractvalue => {
var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
const indices = extra.trail.next(extra.data.indices_len, u32, self);
@@ -4828,22 +6453,6 @@ pub const WipFunction = struct {
.fneg,
.@"fneg fast",
.ret,
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
=> instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
.getelementptr,
.@"getelementptr inbounds",
@@ -4877,8 +6486,6 @@ pub const WipFunction = struct {
},
.load,
.@"load atomic",
- .@"load atomic volatile",
- .@"load volatile",
=> {
const extra = self.extraData(Instruction.Load, instruction.data);
instruction.data = wip_extra.addExtra(Instruction.Load{
@@ -4920,8 +6527,6 @@ pub const WipFunction = struct {
},
.store,
.@"store atomic",
- .@"store atomic volatile",
- .@"store volatile",
=> {
const extra = self.extraData(Instruction.Store, instruction.data);
instruction.data = wip_extra.addExtra(Instruction.Store{
@@ -4949,14 +6554,6 @@ pub const WipFunction = struct {
.type = extra.type,
});
},
- .@"llvm.fma." => {
- const extra = self.extraData(Instruction.FusedMultiplyAdd, instruction.data);
- instruction.data = wip_extra.addExtra(Instruction.FusedMultiplyAdd{
- .a = instructions.map(extra.a),
- .b = instructions.map(extra.b),
- .c = instructions.map(extra.c),
- });
- },
}
function.instructions.appendAssumeCapacity(instruction);
names[@intFromEnum(new_instruction_index)] = wip_name.map(if (self.builder.strip)
@@ -5365,6 +6962,24 @@ pub const FloatCondition = enum(u4) {
ult = 12,
ule = 13,
une = 14,
+
+ fn toLlvm(self: FloatCondition) llvm.RealPredicate {
+ return switch (self) {
+ .oeq => .OEQ,
+ .ogt => .OGT,
+ .oge => .OGE,
+ .olt => .OLT,
+ .ole => .OLE,
+ .one => .ONE,
+ .ord => .ORD,
+ .uno => .UNO,
+ .ueq => .UEQ,
+ .ugt => .UGT,
+ .uge => .UGE,
+ .ult => .ULT,
+ .uno => .UNE,
+ };
+ }
};
pub const IntegerCondition = enum(u6) {
@@ -5378,11 +6993,34 @@ pub const IntegerCondition = enum(u6) {
sge = 39,
slt = 40,
sle = 41,
+
+ fn toLlvm(self: IntegerCondition) llvm.IntPredicate {
+ return switch (self) {
+ .eq => .EQ,
+ .ne => .NE,
+ .ugt => .UGT,
+ .uge => .UGE,
+ .ult => .ULT,
+ .sgt => .SGT,
+ .sge => .SGE,
+ .slt => .SLT,
+ .sle => .SLE,
+ };
+ }
};
pub const MemoryAccessKind = enum(u1) {
normal,
@"volatile",
+
+ pub fn format(
+ self: MemoryAccessKind,
+ comptime prefix: []const u8,
+ _: std.fmt.FormatOptions,
+ writer: anytype,
+ ) @TypeOf(writer).Error!void {
+ if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
+ }
};
pub const SyncScope = enum(u1) {
@@ -5396,7 +7034,7 @@ pub const SyncScope = enum(u1) {
writer: anytype,
) @TypeOf(writer).Error!void {
if (self != .system) try writer.print(
- \\{s} syncscope("{s}")
+ \\{s}syncscope("{s}")
, .{ prefix, @tagName(self) });
}
};
@@ -5416,15 +7054,30 @@ pub const AtomicOrdering = enum(u3) {
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- if (self != .none) try writer.print("{s} {s}", .{ prefix, @tagName(self) });
+ if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
+ }
+
+ fn toLlvm(self: AtomicOrdering) llvm.AtomicOrdering {
+ return switch (self) {
+ .none => .NotAtomic,
+ .unordered => .Unordered,
+ .monotonic => .Monotonic,
+ .acquire => .Acquire,
+ .release => .Release,
+ .acq_rel => .AcquireRelease,
+ .seq_cst => .SequentiallyConsistent,
+ };
}
};
const MemoryAccessInfo = packed struct(u32) {
- scope: SyncScope,
- ordering: AtomicOrdering,
- alignment: Alignment,
- _: u22 = undefined,
+ access_kind: MemoryAccessKind = .normal,
+ atomic_rmw_operation: Function.Instruction.AtomicRmw.Operation = .none,
+ sync_scope: SyncScope,
+ success_ordering: AtomicOrdering,
+ failure_ordering: AtomicOrdering = .none,
+ alignment: Alignment = .default,
+ _: u13 = undefined,
};
pub const FastMath = packed struct(u32) {
@@ -5447,6 +7100,18 @@ pub const FastMath = packed struct(u32) {
};
};
+pub const FastMathKind = enum {
+ normal,
+ fast,
+
+ pub fn toCallKind(self: FastMathKind) Function.Instruction.Call.Kind {
+ return switch (self) {
+ .normal => .normal,
+ .fast => .fast,
+ };
+ }
+};
+
pub const Constant = enum(u32) {
false,
true,
@@ -5516,6 +7181,7 @@ pub const Constant = enum(u32) {
@"and",
@"or",
xor,
+ select,
@"asm",
@"asm sideeffect",
@"asm alignstack",
@@ -5627,7 +7293,13 @@ pub const Constant = enum(u32) {
rhs: Constant,
};
- pub const Asm = extern struct {
+ pub const Select = extern struct {
+ cond: Constant,
+ lhs: Constant,
+ rhs: Constant,
+ };
+
+ pub const Assembly = extern struct {
type: Type,
assembly: String,
constraints: String,
@@ -5651,7 +7323,7 @@ pub const Constant = enum(u32) {
}
pub fn toValue(self: Constant) Value {
- return @enumFromInt(@intFromEnum(Value.first_constant) + @intFromEnum(self));
+ return @enumFromInt(Value.first_constant + @intFromEnum(self));
}
pub fn typeOf(self: Constant, builder: *Builder) Type {
@@ -5758,6 +7430,7 @@ pub const Constant = enum(u32) {
.@"or",
.xor,
=> builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
+ .select => builder.constantExtraData(Select, item.data).lhs.typeOf(builder),
.@"asm",
.@"asm sideeffect",
.@"asm alignstack",
@@ -5852,7 +7525,7 @@ pub const Constant = enum(u32) {
}
},
.global => |global| switch (global.ptrConst(builder).kind) {
- .alias => |alias| cur = alias.ptrConst(builder).init,
+ .alias => |alias| cur = alias.ptrConst(builder).aliasee,
.variable, .function => return global,
.replaced => unreachable,
},
@@ -5926,9 +7599,34 @@ pub const Constant = enum(u32) {
.bfloat => 16,
else => unreachable,
} }),
- .float => try writer.print("0x{X:0>16}", .{
- @as(u64, @bitCast(@as(f64, @as(f32, @bitCast(item.data))))),
- }),
+ .float => {
+ const Float = struct {
+ fn Repr(comptime T: type) type {
+ return packed struct(std.meta.Int(.unsigned, @bitSizeOf(T))) {
+ mantissa: std.meta.Int(.unsigned, std.math.floatMantissaBits(T)),
+ exponent: std.meta.Int(.unsigned, std.math.floatExponentBits(T)),
+ sign: u1,
+ };
+ }
+ };
+ const Exponent32 = std.meta.FieldType(Float.Repr(f32), .exponent);
+ const Exponent64 = std.meta.FieldType(Float.Repr(f64), .exponent);
+ const repr: Float.Repr(f32) = @bitCast(item.data);
+ try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
+ .mantissa = std.math.shl(
+ std.meta.FieldType(Float.Repr(f64), .mantissa),
+ repr.mantissa,
+ std.math.floatMantissaBits(f64) - std.math.floatMantissaBits(f32),
+ ),
+ .exponent = switch (repr.exponent) {
+ std.math.minInt(Exponent32) => std.math.minInt(Exponent64),
+ else => @as(Exponent64, repr.exponent) +
+ (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
+ std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
+ },
+ .sign = repr.sign,
+ }))});
+ },
.double => {
const extra = data.builder.constantExtraData(Double, item.data);
try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
@@ -6122,6 +7820,15 @@ pub const Constant = enum(u32) {
extra.rhs.fmt(data.builder),
});
},
+ .select => |tag| {
+ const extra = data.builder.constantExtraData(Select, item.data);
+ try writer.print("{s} ({%}, {%}, {%})", .{
+ @tagName(tag),
+ extra.cond.fmt(data.builder),
+ extra.lhs.fmt(data.builder),
+ extra.rhs.fmt(data.builder),
+ });
+ },
.@"asm",
.@"asm sideeffect",
.@"asm alignstack",
@@ -6139,7 +7846,7 @@ pub const Constant = enum(u32) {
.@"asm alignstack inteldialect unwind",
.@"asm sideeffect alignstack inteldialect unwind",
=> |tag| {
- const extra = data.builder.constantExtraData(Asm, item.data);
+ const extra = data.builder.constantExtraData(Assembly, item.data);
try writer.print("{s} {\"}, {\"}", .{
@tagName(tag),
extra.assembly.fmt(data.builder),
@@ -6157,27 +7864,31 @@ pub const Constant = enum(u32) {
pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {
assert(builder.useLibLlvm());
- return switch (self.unwrap()) {
+ const llvm_value = switch (self.unwrap()) {
.constant => |constant| builder.llvm.constants.items[constant],
- .global => |global| global.toLlvm(builder),
+ .global => |global| return global.toLlvm(builder),
};
+ const global = builder.llvm.replacements.get(llvm_value) orelse return llvm_value;
+ return global.toLlvm(builder);
}
};
pub const Value = enum(u32) {
none = std.math.maxInt(u31),
+ false = first_constant + @intFromEnum(Constant.false),
+ true = first_constant + @intFromEnum(Constant.true),
_,
- const first_constant: Value = @enumFromInt(1 << 31);
+ const first_constant = 1 << 31;
pub fn unwrap(self: Value) union(enum) {
instruction: Function.Instruction.Index,
constant: Constant,
} {
- return if (@intFromEnum(self) < @intFromEnum(first_constant))
+ return if (@intFromEnum(self) < first_constant)
.{ .instruction = @enumFromInt(@intFromEnum(self)) }
else
- .{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };
+ .{ .constant = @enumFromInt(@intFromEnum(self) - first_constant) };
}
pub fn typeOfWip(self: Value, wip: *const WipFunction) Type {
@@ -6295,6 +8006,7 @@ pub fn init(options: Options) InitError!Builder {
.types = .{},
.globals = .{},
.constants = .{},
+ .replacements = .{},
};
errdefer self.deinit();
@@ -6304,7 +8016,7 @@ pub fn init(options: Options) InitError!Builder {
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.slice(&self) orelse "").ptr,
+ (self.source_filename.slice(&self) orelse ""),
self.llvm.context,
);
@@ -6349,8 +8061,11 @@ pub fn init(options: Options) InitError!Builder {
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);
+ inline for (.{ 0, 4 }) |addr_space_index| {
+ const addr_space: AddrSpace = @enumFromInt(addr_space_index);
+ assert(self.ptrTypeAssumeCapacity(addr_space) ==
+ @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space})));
+ }
}
{
@@ -6371,6 +8086,20 @@ pub fn init(options: Options) InitError!Builder {
}
pub fn deinit(self: *Builder) void {
+ if (self.useLibLlvm()) {
+ var replacement_it = self.llvm.replacements.keyIterator();
+ while (replacement_it.next()) |replacement| replacement.*.deleteGlobalValue();
+ self.llvm.replacements.deinit(self.gpa);
+ self.llvm.constants.deinit(self.gpa);
+ self.llvm.globals.deinit(self.gpa);
+ self.llvm.types.deinit(self.gpa);
+ self.llvm.attributes.deinit(self.gpa);
+ if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids);
+ if (self.llvm.di_builder) |di_builder| di_builder.dispose();
+ if (self.llvm.module) |module| module.dispose();
+ self.llvm.context.dispose();
+ }
+
self.module_asm.deinit(self.gpa);
self.string_map.deinit(self.gpa);
@@ -6400,16 +8129,6 @@ 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);
- self.llvm.attributes.deinit(self.gpa);
- if (self.llvm.attribute_kind_ids) |attribute_kind_ids| self.gpa.destroy(attribute_kind_ids);
- if (self.llvm.di_builder) |di_builder| di_builder.dispose();
- if (self.llvm.module) |module| module.dispose();
- self.llvm.context.dispose();
- }
self.* = undefined;
}
@@ -6763,16 +8482,16 @@ pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Inde
gop.value_ptr.* = {};
if (self.useLibLlvm()) self.llvm.attributes.appendAssumeCapacity(switch (attribute) {
else => llvm_attr: {
- const kind_id = &self.llvm.attribute_kind_ids.?[@intFromEnum(attribute)];
- if (kind_id.* == 0) {
+ const llvm_kind_id = attribute.getKind().toLlvm(self);
+ if (llvm_kind_id.* == 0) {
const name = @tagName(attribute);
- kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len);
- assert(kind_id.* != 0);
+ llvm_kind_id.* = llvm.getEnumAttributeKindForName(name.ptr, name.len);
+ assert(llvm_kind_id.* != 0);
}
break :llvm_attr switch (attribute) {
else => switch (attribute) {
inline else => |value| self.llvm.context.createEnumAttribute(
- kind_id.*,
+ llvm_kind_id.*,
switch (@TypeOf(value)) {
void => 0,
u32 => value,
@@ -6806,7 +8525,7 @@ pub fn attr(self: *Builder, attribute: Attribute) Allocator.Error!Attribute.Inde
.inalloca,
.sret,
.elementtype,
- => |ty| self.llvm.context.createTypeAttribute(kind_id.*, ty.toLlvm(self)),
+ => |ty| self.llvm.context.createTypeAttribute(llvm_kind_id.*, ty.toLlvm(self)),
.string, .none => unreachable,
};
},
@@ -6866,10 +8585,10 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
const global_gop = self.globals.getOrPutAssumeCapacity(id);
if (!global_gop.found_existing) {
global_gop.value_ptr.* = global;
- global_gop.value_ptr.updateAttributes();
- const index: Global.Index = @enumFromInt(global_gop.index);
- index.updateName(self);
- return index;
+ const global_index: Global.Index = @enumFromInt(global_gop.index);
+ global_index.updateDsoLocal(self);
+ global_index.updateName(self);
+ return global_index;
}
const unique_gop = self.next_unique_global_id.getOrPutAssumeCapacity(name);
@@ -6883,17 +8602,221 @@ pub fn getGlobal(self: *const Builder, name: String) ?Global.Index {
return @enumFromInt(self.globals.getIndex(name) orelse return null);
}
+pub fn addAlias(
+ self: *Builder,
+ name: String,
+ ty: Type,
+ addr_space: AddrSpace,
+ aliasee: Constant,
+) Allocator.Error!Alias.Index {
+ assert(!name.isAnon());
+ try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
+ try self.ensureUnusedGlobalCapacity(name);
+ try self.aliases.ensureUnusedCapacity(self.gpa, 1);
+ return self.addAliasAssumeCapacity(name, ty, addr_space, aliasee);
+}
+
+pub fn addAliasAssumeCapacity(
+ self: *Builder,
+ name: String,
+ ty: Type,
+ addr_space: AddrSpace,
+ aliasee: Constant,
+) Alias.Index {
+ if (self.useLibLlvm()) self.llvm.globals.appendAssumeCapacity(self.llvm.module.?.addAlias(
+ ty.toLlvm(self),
+ @intFromEnum(addr_space),
+ aliasee.toLlvm(self),
+ name.slice(self).?,
+ ));
+ const alias_index: Alias.Index = @enumFromInt(self.aliases.items.len);
+ self.aliases.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
+ .addr_space = addr_space,
+ .type = ty,
+ .kind = .{ .alias = alias_index },
+ }), .aliasee = aliasee });
+ return alias_index;
+}
+
+pub fn addVariable(
+ self: *Builder,
+ name: String,
+ ty: Type,
+ addr_space: AddrSpace,
+) Allocator.Error!Variable.Index {
+ assert(!name.isAnon());
+ try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
+ try self.ensureUnusedGlobalCapacity(name);
+ try self.variables.ensureUnusedCapacity(self.gpa, 1);
+ return self.addVariableAssumeCapacity(ty, name, addr_space);
+}
+
+pub fn addVariableAssumeCapacity(
+ self: *Builder,
+ ty: Type,
+ name: String,
+ addr_space: AddrSpace,
+) Variable.Index {
+ if (self.useLibLlvm()) self.llvm.globals.appendAssumeCapacity(
+ self.llvm.module.?.addGlobalInAddressSpace(
+ ty.toLlvm(self),
+ name.slice(self).?,
+ @intFromEnum(addr_space),
+ ),
+ );
+ const variable_index: Variable.Index = @enumFromInt(self.variables.items.len);
+ self.variables.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
+ .addr_space = addr_space,
+ .type = ty,
+ .kind = .{ .variable = variable_index },
+ }) });
+ return variable_index;
+}
+
+pub fn addFunction(
+ self: *Builder,
+ ty: Type,
+ name: String,
+ addr_space: AddrSpace,
+) Allocator.Error!Function.Index {
+ assert(!name.isAnon());
+ try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
+ try self.ensureUnusedGlobalCapacity(name);
+ try self.functions.ensureUnusedCapacity(self.gpa, 1);
+ return self.addFunctionAssumeCapacity(ty, name, addr_space);
+}
+
+pub fn addFunctionAssumeCapacity(
+ self: *Builder,
+ ty: Type,
+ name: String,
+ addr_space: AddrSpace,
+) Function.Index {
+ assert(ty.isFunction(self));
+ if (self.useLibLlvm()) self.llvm.globals.appendAssumeCapacity(
+ self.llvm.module.?.addFunctionInAddressSpace(
+ name.slice(self).?,
+ ty.toLlvm(self),
+ @intFromEnum(addr_space),
+ ),
+ );
+ const function_index: Function.Index = @enumFromInt(self.functions.items.len);
+ self.functions.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
+ .addr_space = addr_space,
+ .type = ty,
+ .kind = .{ .function = function_index },
+ }) });
+ return function_index;
+}
+
+pub fn getIntrinsic(
+ self: *Builder,
+ id: Intrinsic,
+ overload: []const Type,
+) Allocator.Error!Function.Index {
+ const ExpectedContents = extern union {
+ name: [expected_intrinsic_name_len]u8,
+ attrs: extern struct {
+ params: [expected_args_len]Type,
+ fn_attrs: [FunctionAttributes.params_index + expected_args_len]Attributes,
+ attrs: [expected_attrs_len]Attribute.Index,
+ fields: [expected_fields_len]Type,
+ },
+ };
+ var stack align(@max(@alignOf(std.heap.StackFallbackAllocator(0)), @alignOf(ExpectedContents))) =
+ std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
+ const allocator = stack.get();
+
+ const name = name: {
+ var buffer = std.ArrayList(u8).init(allocator);
+ defer buffer.deinit();
+
+ try buffer.writer().print("llvm.{s}", .{@tagName(id)});
+ for (overload) |ty| try buffer.writer().print(".{m}", .{ty.fmt(self)});
+ break :name try self.string(buffer.items);
+ };
+ if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function;
+
+ const signature = Intrinsic.signatures.get(id);
+ const param_types = try allocator.alloc(Type, signature.params.len);
+ defer allocator.free(param_types);
+ const function_attributes = try allocator.alloc(
+ Attributes,
+ FunctionAttributes.params_index + (signature.params.len - signature.ret_len),
+ );
+ defer allocator.free(function_attributes);
+
+ var attributes: struct {
+ builder: *Builder,
+ list: std.ArrayList(Attribute.Index),
+
+ fn deinit(state: *@This()) void {
+ state.list.deinit();
+ state.* = undefined;
+ }
+
+ fn get(state: *@This(), attributes: []const Attribute) Allocator.Error!Attributes {
+ try state.list.resize(attributes.len);
+ for (state.list.items, attributes) |*item, attribute|
+ item.* = try state.builder.attr(attribute);
+ return state.builder.attrs(state.list.items);
+ }
+ } = .{ .builder = self, .list = std.ArrayList(Attribute.Index).init(allocator) };
+ defer attributes.deinit();
+
+ var overload_index: usize = 0;
+ function_attributes[FunctionAttributes.function_index] = try attributes.get(signature.attrs);
+ function_attributes[FunctionAttributes.return_index] = .none; // needed for void return
+ for (0.., param_types, signature.params) |param_index, *param_type, signature_param| {
+ switch (signature_param.kind) {
+ .type => |ty| param_type.* = ty,
+ .overloaded => {
+ param_type.* = overload[overload_index];
+ overload_index += 1;
+ },
+ .matches, .matches_scalar, .matches_changed_scalar => {},
+ }
+ function_attributes[
+ if (param_index < signature.ret_len)
+ FunctionAttributes.return_index
+ else
+ FunctionAttributes.params_index + (param_index - signature.ret_len)
+ ] = try attributes.get(signature_param.attrs);
+ }
+ assert(overload_index == overload.len);
+ for (param_types, signature.params) |*param_type, signature_param| {
+ param_type.* = switch (signature_param.kind) {
+ .type, .overloaded => continue,
+ .matches => |param_index| param_types[param_index],
+ .matches_scalar => |param_index| param_types[param_index].scalarType(self),
+ .matches_changed_scalar => |info| try param_types[info.index]
+ .changeScalar(info.scalar, self),
+ };
+ }
+
+ const function_index = try self.addFunction(try self.fnType(switch (signature.ret_len) {
+ 0 => .void,
+ 1 => param_types[0],
+ else => try self.structType(.normal, param_types[0..signature.ret_len]),
+ }, param_types[signature.ret_len..], .normal), name, .default);
+ function_index.ptr(self).attributes = try self.fnAttrs(function_attributes);
+ return function_index;
+}
+
pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Constant {
+ const int_value = switch (@typeInfo(@TypeOf(value))) {
+ .Int, .ComptimeInt => value,
+ .Enum => @intFromEnum(value),
+ else => @compileError("intConst expected an integral value, got " ++ @typeName(@TypeOf(value))),
+ };
var limbs: [
- switch (@typeInfo(@TypeOf(value))) {
+ switch (@typeInfo(@TypeOf(int_value))) {
.Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
- .ComptimeInt => std.math.big.int.calcLimbLen(value),
- else => @compileError(
- "intConst expected an integral value, got " ++ @typeName(@TypeOf(value)),
- ),
+ .ComptimeInt => std.math.big.int.calcLimbLen(int_value),
+ else => unreachable,
}
]std.math.big.Limb = undefined;
- return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
+ return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, int_value).toConst());
}
pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
@@ -7301,27 +9224,75 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)
return (try self.binConst(tag, lhs, rhs)).toValue();
}
+pub fn selectConst(
+ self: *Builder,
+ cond: Constant,
+ lhs: Constant,
+ rhs: Constant,
+) Allocator.Error!Constant {
+ try self.ensureUnusedConstantCapacity(1, Constant.Select, 0);
+ return self.selectConstAssumeCapacity(cond, lhs, rhs);
+}
+
+pub fn selectValue(self: *Builder, cond: Constant, lhs: Constant, rhs: Constant) Allocator.Error!Value {
+ return (try self.selectConst(cond, lhs, rhs)).toValue();
+}
+
pub fn asmConst(
self: *Builder,
ty: Type,
- info: Constant.Asm.Info,
+ info: Constant.Assembly.Info,
assembly: String,
constraints: String,
) Allocator.Error!Constant {
- try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0);
+ try self.ensureUnusedConstantCapacity(1, Constant.Assembly, 0);
return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
}
pub fn asmValue(
self: *Builder,
ty: Type,
- info: Constant.Asm.Info,
+ info: Constant.Assembly.Info,
assembly: String,
constraints: String,
) Allocator.Error!Value {
return (try self.asmConst(ty, info, assembly, constraints)).toValue();
}
+pub fn verify(self: *Builder) error{}!bool {
+ if (self.useLibLlvm()) {
+ var error_message: [*:0]const u8 = undefined;
+ // verifyModule always allocs the error_message even if there is no error
+ defer llvm.disposeMessage(error_message);
+
+ if (self.llvm.module.?.verify(.ReturnStatus, &error_message).toBool()) {
+ log.err("failed verification of LLVM module:\n{s}\n", .{error_message});
+ return false;
+ }
+ }
+ return true;
+}
+
+pub fn writeBitcodeToFile(self: *Builder, path: []const u8) Allocator.Error!bool {
+ const path_z = try self.gpa.dupeZ(u8, path);
+ defer self.gpa.free(path_z);
+ return self.writeBitcodeToFileZ(path_z);
+}
+
+pub fn writeBitcodeToFileZ(self: *Builder, path: [*:0]const u8) bool {
+ if (self.useLibLlvm()) {
+ const error_code = self.llvm.module.?.writeBitcodeToFile(path);
+ if (error_code != 0) {
+ log.err("failed dumping LLVM module to \"{s}\": {d}", .{ path, error_code });
+ return false;
+ }
+ } else {
+ log.err("writing bitcode without libllvm not implemented", .{});
+ return false;
+ }
+ return true;
+}
+
pub fn dump(self: *Builder) void {
if (self.useLibLlvm())
self.llvm.module.?.dump()
@@ -7413,7 +9384,7 @@ pub fn printUnbuffered(
if (variable.global.getReplacement(self) != .none) continue;
const global = variable.global.ptrConst(self);
try writer.print(
- \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
+ \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }
\\
, .{
variable.global.fmt(self),
@@ -7434,557 +9405,521 @@ pub fn printUnbuffered(
need_newline = true;
}
- var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
- defer attribute_groups.deinit(self.gpa);
-
- if (self.functions.items.len > 0) {
+ if (self.aliases.items.len > 0) {
if (need_newline) try writer.writeByte('\n');
- for (0.., self.functions.items) |function_i, function| {
- if (function_i > 0) try writer.writeByte('\n');
- const function_index: Function.Index = @enumFromInt(function_i);
- if (function.global.getReplacement(self) != .none) continue;
- const global = function.global.ptrConst(self);
- const params_len = global.type.functionParameters(self).len;
- const function_attributes = function.attributes.func(self);
- if (function_attributes != .none) try writer.print(
- \\; Function Attrs:{}
- \\
- , .{function_attributes.fmt(self)});
+ for (self.aliases.items) |alias| {
+ if (alias.global.getReplacement(self) != .none) continue;
+ const global = alias.global.ptrConst(self);
try writer.print(
- \\{s}{}{}{}{}{}{"} {} {}(
+ \\{} ={}{}{}{}{ }{} alias {%}, {%}
+ \\
, .{
- if (function.instructions.len > 0) "define" else "declare",
+ alias.global.fmt(self),
global.linkage,
global.preemption,
global.visibility,
global.dll_storage_class,
- function.call_conv,
- function.attributes.ret(self).fmt(self),
- global.type.functionReturn(self).fmt(self),
- function.global.fmt(self),
+ alias.thread_local,
+ global.unnamed_addr,
+ global.type.fmt(self),
+ alias.aliasee.fmt(self),
});
- for (0..params_len) |arg| {
- if (arg > 0) try writer.writeAll(", ");
- try writer.print(
- \\{%}{"}
- , .{
- global.type.functionParameters(self)[arg].fmt(self),
- function.attributes.param(arg, self).fmt(self),
- });
- if (function.instructions.len > 0)
- try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
- }
- switch (global.type.functionKind(self)) {
- .normal => {},
- .vararg => {
- if (params_len > 0) try writer.writeAll(", ");
- try writer.writeAll("...");
- },
- }
- try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space });
- if (function_attributes != .none) try writer.print(" #{d}", .{
- (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
+ }
+ need_newline = true;
+ }
+
+ var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{};
+ defer attribute_groups.deinit(self.gpa);
+
+ for (0.., self.functions.items) |function_i, function| {
+ if (function.global.getReplacement(self) != .none) continue;
+ if (need_newline) try writer.writeByte('\n');
+ const function_index: Function.Index = @enumFromInt(function_i);
+ const global = function.global.ptrConst(self);
+ const params_len = global.type.functionParameters(self).len;
+ const function_attributes = function.attributes.func(self);
+ if (function_attributes != .none) try writer.print(
+ \\; Function Attrs:{}
+ \\
+ , .{function_attributes.fmt(self)});
+ try writer.print(
+ \\{s}{}{}{}{}{}{"} {} {}(
+ , .{
+ if (function.instructions.len > 0) "define" else "declare",
+ global.linkage,
+ global.preemption,
+ global.visibility,
+ global.dll_storage_class,
+ function.call_conv,
+ function.attributes.ret(self).fmt(self),
+ global.type.functionReturn(self).fmt(self),
+ function.global.fmt(self),
+ });
+ for (0..params_len) |arg| {
+ if (arg > 0) try writer.writeAll(", ");
+ try writer.print(
+ \\{%}{"}
+ , .{
+ global.type.functionParameters(self)[arg].fmt(self),
+ function.attributes.param(arg, self).fmt(self),
});
- try writer.print("{}", .{function.alignment});
- if (function.instructions.len > 0) {
- var block_incoming_len: u32 = undefined;
- try writer.writeAll(" {\n");
- for (params_len..function.instructions.len) |instruction_i| {
- const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
- const instruction = function.instructions.get(@intFromEnum(instruction_index));
- switch (instruction.tag) {
- .add,
- .@"add nsw",
- .@"add nuw",
- .@"add nuw nsw",
- .@"and",
- .ashr,
- .@"ashr exact",
- .fadd,
- .@"fadd fast",
- .@"fcmp false",
- .@"fcmp fast false",
- .@"fcmp fast oeq",
- .@"fcmp fast oge",
- .@"fcmp fast ogt",
- .@"fcmp fast ole",
- .@"fcmp fast olt",
- .@"fcmp fast one",
- .@"fcmp fast ord",
- .@"fcmp fast true",
- .@"fcmp fast ueq",
- .@"fcmp fast uge",
- .@"fcmp fast ugt",
- .@"fcmp fast ule",
- .@"fcmp fast ult",
- .@"fcmp fast une",
- .@"fcmp fast uno",
- .@"fcmp oeq",
- .@"fcmp oge",
- .@"fcmp ogt",
- .@"fcmp ole",
- .@"fcmp olt",
- .@"fcmp one",
- .@"fcmp ord",
- .@"fcmp true",
- .@"fcmp ueq",
- .@"fcmp uge",
- .@"fcmp ugt",
- .@"fcmp ule",
- .@"fcmp ult",
- .@"fcmp une",
- .@"fcmp uno",
- .fdiv,
- .@"fdiv fast",
- .fmul,
- .@"fmul fast",
- .frem,
- .@"frem fast",
- .fsub,
- .@"fsub fast",
- .@"icmp eq",
- .@"icmp ne",
- .@"icmp sge",
- .@"icmp sgt",
- .@"icmp sle",
- .@"icmp slt",
- .@"icmp uge",
- .@"icmp ugt",
- .@"icmp ule",
- .@"icmp ult",
- .lshr,
- .@"lshr exact",
- .mul,
- .@"mul nsw",
- .@"mul nuw",
- .@"mul nuw nsw",
- .@"or",
- .sdiv,
- .@"sdiv exact",
- .srem,
- .shl,
- .@"shl nsw",
- .@"shl nuw",
- .@"shl nuw nsw",
- .sub,
- .@"sub nsw",
- .@"sub nuw",
- .@"sub nuw nsw",
- .udiv,
- .@"udiv exact",
- .urem,
- .xor,
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Binary, instruction.data);
- try writer.print(" %{} = {s} {%}, {}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.lhs.fmt(function_index, self),
- extra.rhs.fmt(function_index, self),
- });
- },
- .addrspacecast,
- .bitcast,
- .fpext,
- .fptosi,
- .fptoui,
- .fptrunc,
- .inttoptr,
- .ptrtoint,
- .sext,
- .sitofp,
- .trunc,
- .uitofp,
- .zext,
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Cast, instruction.data);
- try writer.print(" %{} = {s} {%} to {%}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.val.fmt(function_index, self),
- extra.type.fmt(self),
- });
- },
- .alloca,
- .@"alloca inalloca",
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Alloca, instruction.data);
- try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.type.fmt(self),
- extra.len.fmt(function_index, self),
- extra.info.alignment,
- extra.info.addr_space,
- });
- },
- .arg => unreachable,
- .block => {
- block_incoming_len = instruction.data;
- const name = instruction_index.name(&function);
- if (@intFromEnum(instruction_index) > params_len)
- try writer.writeByte('\n');
- try writer.print("{}:\n", .{name.fmt(self)});
- },
- .br => |tag| {
- const target: Function.Block.Index = @enumFromInt(instruction.data);
- try writer.print(" {s} {%}\n", .{
- @tagName(tag), target.toInst(&function).fmt(function_index, self),
- });
- },
- .br_cond => {
- const extra =
- function.extraData(Function.Instruction.BrCond, instruction.data);
- try writer.print(" br {%}, {%}, {%}\n", .{
- extra.cond.fmt(function_index, self),
- extra.then.toInst(&function).fmt(function_index, self),
- extra.@"else".toInst(&function).fmt(function_index, self),
- });
- },
- .call,
- .@"call fast",
- .@"musttail call",
- .@"musttail call fast",
- .@"notail call",
- .@"notail call fast",
- .@"tail call",
- .@"tail call fast",
- => |tag| {
- var extra =
- function.extraDataTrail(Function.Instruction.Call, instruction.data);
- const args = extra.trail.next(extra.data.args_len, Value, &function);
- try writer.writeAll(" ");
- const ret_ty = extra.data.ty.functionReturn(self);
- switch (ret_ty) {
- .void => {},
- else => try writer.print("%{} = ", .{
- instruction_index.name(&function).fmt(self),
- }),
- .none => unreachable,
- }
- try writer.print("{s}{}{}{} {%} {}(", .{
- @tagName(tag),
- extra.data.info.call_conv,
- extra.data.attributes.ret(self).fmt(self),
- extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
- switch (extra.data.ty.functionKind(self)) {
- .normal => ret_ty,
- .vararg => extra.data.ty,
- }.fmt(self),
- extra.data.callee.fmt(function_index, self),
- });
- for (0.., args) |arg_index, arg| {
- if (arg_index > 0) try writer.writeAll(", ");
- try writer.print("{%}{} {}", .{
- arg.typeOf(function_index, self).fmt(self),
- extra.data.attributes.param(arg_index, self).fmt(self),
- arg.fmt(function_index, self),
- });
- }
- try writer.writeByte(')');
- const call_function_attributes = extra.data.attributes.func(self);
- if (call_function_attributes != .none) try writer.print(" #{d}", .{
- (try attribute_groups.getOrPutValue(
- self.gpa,
- call_function_attributes,
- {},
- )).index,
- });
- try writer.writeByte('\n');
- },
- .extractelement => |tag| {
- const extra = function.extraData(
- Function.Instruction.ExtractElement,
- instruction.data,
- );
- try writer.print(" %{} = {s} {%}, {%}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.val.fmt(function_index, self),
- extra.index.fmt(function_index, self),
- });
- },
- .extractvalue => |tag| {
- var extra = function.extraDataTrail(
- Function.Instruction.ExtractValue,
- instruction.data,
- );
- const indices = extra.trail.next(extra.data.indices_len, u32, &function);
- try writer.print(" %{} = {s} {%}", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.data.val.fmt(function_index, self),
- });
- for (indices) |index| try writer.print(", {d}", .{index});
- try writer.writeByte('\n');
- },
- .fence => |tag| {
- const info: MemoryAccessInfo = @bitCast(instruction.data);
- try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
- },
- .fneg,
- .@"fneg fast",
- .ret,
- .@"llvm.ceil.",
- .@"llvm.cos.",
- .@"llvm.exp.",
- .@"llvm.exp2.",
- .@"llvm.fabs.",
- .@"llvm.floor.",
- .@"llvm.log.",
- .@"llvm.log10.",
- .@"llvm.log2.",
- .@"llvm.round.",
- .@"llvm.sin.",
- .@"llvm.sqrt.",
- .@"llvm.trunc.",
- .@"llvm.bitreverse.",
- .@"llvm.bswap.",
- .@"llvm.ctpop.",
- => |tag| {
- const val: Value = @enumFromInt(instruction.data);
- try writer.print(" {s} {%}\n", .{
- @tagName(tag),
- val.fmt(function_index, self),
- });
- },
- .getelementptr,
- .@"getelementptr inbounds",
- => |tag| {
- var extra = function.extraDataTrail(
- Function.Instruction.GetElementPtr,
- instruction.data,
- );
- const indices = extra.trail.next(extra.data.indices_len, Value, &function);
- try writer.print(" %{} = {s} {%}, {%}", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.data.type.fmt(self),
- extra.data.base.fmt(function_index, self),
- });
- for (indices) |index| try writer.print(", {%}", .{
- index.fmt(function_index, self),
- });
- try writer.writeByte('\n');
- },
- .insertelement => |tag| {
- const extra = function.extraData(
- Function.Instruction.InsertElement,
- instruction.data,
- );
- try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.val.fmt(function_index, self),
- extra.elem.fmt(function_index, self),
- extra.index.fmt(function_index, self),
- });
- },
- .insertvalue => |tag| {
- var extra = function.extraDataTrail(
- Function.Instruction.InsertValue,
- instruction.data,
- );
- const indices = extra.trail.next(extra.data.indices_len, u32, &function);
- try writer.print(" %{} = {s} {%}, {%}", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.data.val.fmt(function_index, self),
- extra.data.elem.fmt(function_index, self),
- });
- for (indices) |index| try writer.print(", {d}", .{index});
- try writer.writeByte('\n');
- },
- .@"llvm.maxnum.",
- .@"llvm.minnum.",
- .@"llvm.ctlz.",
- .@"llvm.cttz.",
- .@"llvm.sadd.sat.",
- .@"llvm.smax.",
- .@"llvm.smin.",
- .@"llvm.smul.fix.sat.",
- .@"llvm.sshl.sat.",
- .@"llvm.ssub.sat.",
- .@"llvm.uadd.sat.",
- .@"llvm.umax.",
- .@"llvm.umin.",
- .@"llvm.umul.fix.sat.",
- .@"llvm.ushl.sat.",
- .@"llvm.usub.sat.",
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Binary, instruction.data);
- const ty = instruction_index.typeOf(function_index, self);
- try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{
- instruction_index.name(&function).fmt(self),
- ty.fmt(self),
- @tagName(tag),
- ty.fmt(self),
- extra.lhs.fmt(function_index, self),
- extra.rhs.fmt(function_index, self),
- switch (tag) {
- .@"llvm.smul.fix.sat.",
- .@"llvm.umul.fix.sat.",
- => ", i32 0",
- else => "",
- },
- });
- },
- .load,
- .@"load atomic",
- .@"load atomic volatile",
- .@"load volatile",
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Load, instruction.data);
- try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.type.fmt(self),
- extra.ptr.fmt(function_index, self),
- extra.info.scope,
- extra.info.ordering,
- extra.info.alignment,
- });
- },
- .phi,
- .@"phi fast",
- => |tag| {
- var extra =
- function.extraDataTrail(Function.Instruction.Phi, instruction.data);
- const vals = extra.trail.next(block_incoming_len, Value, &function);
- const blocks =
- extra.trail.next(block_incoming_len, Function.Block.Index, &function);
- try writer.print(" %{} = {s} {%} ", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- vals[0].typeOf(function_index, self).fmt(self),
- });
- for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
- if (incoming_index > 0) try writer.writeAll(", ");
- try writer.print("[ {}, {} ]", .{
- incoming_val.fmt(function_index, self),
- incoming_block.toInst(&function).fmt(function_index, self),
- });
- }
+ if (function.instructions.len > 0)
+ try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
+ else
+ try writer.print(" %{d}", .{arg});
+ }
+ switch (global.type.functionKind(self)) {
+ .normal => {},
+ .vararg => {
+ if (params_len > 0) try writer.writeAll(", ");
+ try writer.writeAll("...");
+ },
+ }
+ try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space });
+ if (function_attributes != .none) try writer.print(" #{d}", .{
+ (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
+ });
+ try writer.print("{ }", .{function.alignment});
+ if (function.instructions.len > 0) {
+ var block_incoming_len: u32 = undefined;
+ try writer.writeAll(" {\n");
+ for (params_len..function.instructions.len) |instruction_i| {
+ const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
+ const instruction = function.instructions.get(@intFromEnum(instruction_index));
+ switch (instruction.tag) {
+ .add,
+ .@"add nsw",
+ .@"add nuw",
+ .@"add nuw nsw",
+ .@"and",
+ .ashr,
+ .@"ashr exact",
+ .fadd,
+ .@"fadd fast",
+ .@"fcmp false",
+ .@"fcmp fast false",
+ .@"fcmp fast oeq",
+ .@"fcmp fast oge",
+ .@"fcmp fast ogt",
+ .@"fcmp fast ole",
+ .@"fcmp fast olt",
+ .@"fcmp fast one",
+ .@"fcmp fast ord",
+ .@"fcmp fast true",
+ .@"fcmp fast ueq",
+ .@"fcmp fast uge",
+ .@"fcmp fast ugt",
+ .@"fcmp fast ule",
+ .@"fcmp fast ult",
+ .@"fcmp fast une",
+ .@"fcmp fast uno",
+ .@"fcmp oeq",
+ .@"fcmp oge",
+ .@"fcmp ogt",
+ .@"fcmp ole",
+ .@"fcmp olt",
+ .@"fcmp one",
+ .@"fcmp ord",
+ .@"fcmp true",
+ .@"fcmp ueq",
+ .@"fcmp uge",
+ .@"fcmp ugt",
+ .@"fcmp ule",
+ .@"fcmp ult",
+ .@"fcmp une",
+ .@"fcmp uno",
+ .fdiv,
+ .@"fdiv fast",
+ .fmul,
+ .@"fmul fast",
+ .frem,
+ .@"frem fast",
+ .fsub,
+ .@"fsub fast",
+ .@"icmp eq",
+ .@"icmp ne",
+ .@"icmp sge",
+ .@"icmp sgt",
+ .@"icmp sle",
+ .@"icmp slt",
+ .@"icmp uge",
+ .@"icmp ugt",
+ .@"icmp ule",
+ .@"icmp ult",
+ .lshr,
+ .@"lshr exact",
+ .mul,
+ .@"mul nsw",
+ .@"mul nuw",
+ .@"mul nuw nsw",
+ .@"or",
+ .sdiv,
+ .@"sdiv exact",
+ .srem,
+ .shl,
+ .@"shl nsw",
+ .@"shl nuw",
+ .@"shl nuw nsw",
+ .sub,
+ .@"sub nsw",
+ .@"sub nuw",
+ .@"sub nuw nsw",
+ .udiv,
+ .@"udiv exact",
+ .urem,
+ .xor,
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Binary, instruction.data);
+ try writer.print(" %{} = {s} {%}, {}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.lhs.fmt(function_index, self),
+ extra.rhs.fmt(function_index, self),
+ });
+ },
+ .addrspacecast,
+ .bitcast,
+ .fpext,
+ .fptosi,
+ .fptoui,
+ .fptrunc,
+ .inttoptr,
+ .ptrtoint,
+ .sext,
+ .sitofp,
+ .trunc,
+ .uitofp,
+ .zext,
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Cast, instruction.data);
+ try writer.print(" %{} = {s} {%} to {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.val.fmt(function_index, self),
+ extra.type.fmt(self),
+ });
+ },
+ .alloca,
+ .@"alloca inalloca",
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
+ try writer.print(" %{} = {s} {%}{,%}{, }{, }\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.type.fmt(self),
+ extra.len.fmt(function_index, self),
+ extra.info.alignment,
+ extra.info.addr_space,
+ });
+ },
+ .arg => unreachable,
+ .atomicrmw => |tag| {
+ const extra =
+ function.extraData(Function.Instruction.AtomicRmw, instruction.data);
+ try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.info.access_kind,
+ @tagName(extra.info.atomic_rmw_operation),
+ extra.ptr.fmt(function_index, self),
+ extra.val.fmt(function_index, self),
+ extra.info.sync_scope,
+ extra.info.success_ordering,
+ extra.info.alignment,
+ });
+ },
+ .block => {
+ block_incoming_len = instruction.data;
+ const name = instruction_index.name(&function);
+ if (@intFromEnum(instruction_index) > params_len)
try writer.writeByte('\n');
- },
- .@"ret void",
- .@"unreachable",
- => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
- .select,
- .@"select fast",
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Select, instruction.data);
- try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.cond.fmt(function_index, self),
- extra.lhs.fmt(function_index, self),
- extra.rhs.fmt(function_index, self),
- });
- },
- .shufflevector => |tag| {
- const extra = function.extraData(
- Function.Instruction.ShuffleVector,
- instruction.data,
- );
- try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
- instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.lhs.fmt(function_index, self),
- extra.rhs.fmt(function_index, self),
- extra.mask.fmt(function_index, self),
- });
- },
- .store,
- .@"store atomic",
- .@"store atomic volatile",
- .@"store volatile",
- => |tag| {
- const extra =
- function.extraData(Function.Instruction.Store, instruction.data);
- try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
- @tagName(tag),
- extra.val.fmt(function_index, self),
- extra.ptr.fmt(function_index, self),
- extra.info.scope,
- extra.info.ordering,
- extra.info.alignment,
- });
- },
- .@"switch" => |tag| {
- var extra =
- function.extraDataTrail(Function.Instruction.Switch, instruction.data);
- const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
- const blocks =
- extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
- try writer.print(" {s} {%}, {%} [\n", .{
- @tagName(tag),
- extra.data.val.fmt(function_index, self),
- extra.data.default.toInst(&function).fmt(function_index, self),
- });
- for (vals, blocks) |case_val, case_block| try writer.print(
- " {%}, {%}\n",
- .{
- case_val.fmt(self),
- case_block.toInst(&function).fmt(function_index, self),
- },
- );
- try writer.writeAll(" ]\n");
- },
- .unimplemented => |tag| {
- const ty: Type = @enumFromInt(instruction.data);
- if (true) {
- try writer.writeAll(" ");
- switch (ty) {
- .none, .void => {},
- else => try writer.print("%{} = ", .{
- instruction_index.name(&function).fmt(self),
- }),
- }
- try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
- } else switch (ty) {
- .none, .void => {},
- else => try writer.print(" %{} = load {%}, ptr undef\n", .{
- instruction_index.name(&function).fmt(self),
- ty.fmt(self),
- }),
- }
- },
- .va_arg => |tag| {
- const extra =
- function.extraData(Function.Instruction.VaArg, instruction.data);
- try writer.print(" %{} = {s} {%}, {%}\n", .{
+ try writer.print("{}:\n", .{name.fmt(self)});
+ },
+ .br => |tag| {
+ const target: Function.Block.Index = @enumFromInt(instruction.data);
+ try writer.print(" {s} {%}\n", .{
+ @tagName(tag), target.toInst(&function).fmt(function_index, self),
+ });
+ },
+ .br_cond => {
+ const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
+ try writer.print(" br {%}, {%}, {%}\n", .{
+ extra.cond.fmt(function_index, self),
+ extra.then.toInst(&function).fmt(function_index, self),
+ extra.@"else".toInst(&function).fmt(function_index, self),
+ });
+ },
+ .call,
+ .@"call fast",
+ .@"musttail call",
+ .@"musttail call fast",
+ .@"notail call",
+ .@"notail call fast",
+ .@"tail call",
+ .@"tail call fast",
+ => |tag| {
+ var extra =
+ function.extraDataTrail(Function.Instruction.Call, instruction.data);
+ const args = extra.trail.next(extra.data.args_len, Value, &function);
+ try writer.writeAll(" ");
+ const ret_ty = extra.data.ty.functionReturn(self);
+ switch (ret_ty) {
+ .void => {},
+ else => try writer.print("%{} = ", .{
instruction_index.name(&function).fmt(self),
- @tagName(tag),
- extra.list.fmt(function_index, self),
- extra.type.fmt(self),
+ }),
+ .none => unreachable,
+ }
+ try writer.print("{s}{}{}{} {%} {}(", .{
+ @tagName(tag),
+ extra.data.info.call_conv,
+ extra.data.attributes.ret(self).fmt(self),
+ extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
+ switch (extra.data.ty.functionKind(self)) {
+ .normal => ret_ty,
+ .vararg => extra.data.ty,
+ }.fmt(self),
+ extra.data.callee.fmt(function_index, self),
+ });
+ for (0.., args) |arg_index, arg| {
+ if (arg_index > 0) try writer.writeAll(", ");
+ try writer.print("{%}{} {}", .{
+ arg.typeOf(function_index, self).fmt(self),
+ extra.data.attributes.param(arg_index, self).fmt(self),
+ arg.fmt(function_index, self),
});
- },
- .@"llvm.fma." => {
- const extra =
- function.extraData(Function.Instruction.FusedMultiplyAdd, instruction.data);
- const ty = instruction_index.typeOf(function_index, self);
- try writer.print(" %{} = call {%} @llvm.fma.{m}({%}, {%}, {%})\n", .{
- instruction_index.name(&function).fmt(self),
- ty.fmt(self),
- ty.fmt(self),
- extra.a.fmt(function_index, self),
- extra.b.fmt(function_index, self),
- extra.c.fmt(function_index, self),
+ }
+ try writer.writeByte(')');
+ const call_function_attributes = extra.data.attributes.func(self);
+ if (call_function_attributes != .none) try writer.print(" #{d}", .{
+ (try attribute_groups.getOrPutValue(
+ self.gpa,
+ call_function_attributes,
+ {},
+ )).index,
+ });
+ try writer.writeByte('\n');
+ },
+ .cmpxchg,
+ .@"cmpxchg weak",
+ => |tag| {
+ const extra =
+ function.extraData(Function.Instruction.CmpXchg, instruction.data);
+ try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.info.access_kind,
+ extra.ptr.fmt(function_index, self),
+ extra.cmp.fmt(function_index, self),
+ extra.new.fmt(function_index, self),
+ extra.info.sync_scope,
+ extra.info.success_ordering,
+ extra.info.failure_ordering,
+ extra.info.alignment,
+ });
+ },
+ .extractelement => |tag| {
+ const extra =
+ function.extraData(Function.Instruction.ExtractElement, instruction.data);
+ try writer.print(" %{} = {s} {%}, {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.val.fmt(function_index, self),
+ extra.index.fmt(function_index, self),
+ });
+ },
+ .extractvalue => |tag| {
+ var extra = function.extraDataTrail(
+ Function.Instruction.ExtractValue,
+ instruction.data,
+ );
+ const indices = extra.trail.next(extra.data.indices_len, u32, &function);
+ try writer.print(" %{} = {s} {%}", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.data.val.fmt(function_index, self),
+ });
+ for (indices) |index| try writer.print(", {d}", .{index});
+ try writer.writeByte('\n');
+ },
+ .fence => |tag| {
+ const info: MemoryAccessInfo = @bitCast(instruction.data);
+ try writer.print(" {s}{ }{ }", .{
+ @tagName(tag),
+ info.sync_scope,
+ info.success_ordering,
+ });
+ },
+ .fneg,
+ .@"fneg fast",
+ => |tag| {
+ const val: Value = @enumFromInt(instruction.data);
+ try writer.print(" %{} = {s} {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ val.fmt(function_index, self),
+ });
+ },
+ .getelementptr,
+ .@"getelementptr inbounds",
+ => |tag| {
+ var extra = function.extraDataTrail(
+ Function.Instruction.GetElementPtr,
+ instruction.data,
+ );
+ const indices = extra.trail.next(extra.data.indices_len, Value, &function);
+ try writer.print(" %{} = {s} {%}, {%}", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.data.type.fmt(self),
+ extra.data.base.fmt(function_index, self),
+ });
+ for (indices) |index| try writer.print(", {%}", .{
+ index.fmt(function_index, self),
+ });
+ try writer.writeByte('\n');
+ },
+ .insertelement => |tag| {
+ const extra =
+ function.extraData(Function.Instruction.InsertElement, instruction.data);
+ try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.val.fmt(function_index, self),
+ extra.elem.fmt(function_index, self),
+ extra.index.fmt(function_index, self),
+ });
+ },
+ .insertvalue => |tag| {
+ var extra =
+ function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
+ const indices = extra.trail.next(extra.data.indices_len, u32, &function);
+ try writer.print(" %{} = {s} {%}, {%}", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.data.val.fmt(function_index, self),
+ extra.data.elem.fmt(function_index, self),
+ });
+ for (indices) |index| try writer.print(", {d}", .{index});
+ try writer.writeByte('\n');
+ },
+ .load,
+ .@"load atomic",
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Load, instruction.data);
+ try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.info.access_kind,
+ extra.type.fmt(self),
+ extra.ptr.fmt(function_index, self),
+ extra.info.sync_scope,
+ extra.info.success_ordering,
+ extra.info.alignment,
+ });
+ },
+ .phi,
+ .@"phi fast",
+ => |tag| {
+ var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data);
+ const vals = extra.trail.next(block_incoming_len, Value, &function);
+ const blocks =
+ extra.trail.next(block_incoming_len, Function.Block.Index, &function);
+ try writer.print(" %{} = {s} {%} ", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ vals[0].typeOf(function_index, self).fmt(self),
+ });
+ for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
+ if (incoming_index > 0) try writer.writeAll(", ");
+ try writer.print("[ {}, {} ]", .{
+ incoming_val.fmt(function_index, self),
+ incoming_block.toInst(&function).fmt(function_index, self),
});
- },
- }
+ }
+ try writer.writeByte('\n');
+ },
+ .ret => |tag| {
+ const val: Value = @enumFromInt(instruction.data);
+ try writer.print(" {s} {%}\n", .{
+ @tagName(tag),
+ val.fmt(function_index, self),
+ });
+ },
+ .@"ret void",
+ .@"unreachable",
+ => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
+ .select,
+ .@"select fast",
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Select, instruction.data);
+ try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.cond.fmt(function_index, self),
+ extra.lhs.fmt(function_index, self),
+ extra.rhs.fmt(function_index, self),
+ });
+ },
+ .shufflevector => |tag| {
+ const extra =
+ function.extraData(Function.Instruction.ShuffleVector, instruction.data);
+ try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.lhs.fmt(function_index, self),
+ extra.rhs.fmt(function_index, self),
+ extra.mask.fmt(function_index, self),
+ });
+ },
+ .store,
+ .@"store atomic",
+ => |tag| {
+ const extra = function.extraData(Function.Instruction.Store, instruction.data);
+ try writer.print(" {s}{ } {%}, {%}{ }{ }{, }\n", .{
+ @tagName(tag),
+ extra.info.access_kind,
+ extra.val.fmt(function_index, self),
+ extra.ptr.fmt(function_index, self),
+ extra.info.sync_scope,
+ extra.info.success_ordering,
+ extra.info.alignment,
+ });
+ },
+ .@"switch" => |tag| {
+ var extra =
+ function.extraDataTrail(Function.Instruction.Switch, instruction.data);
+ const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
+ const blocks =
+ extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
+ try writer.print(" {s} {%}, {%} [\n", .{
+ @tagName(tag),
+ extra.data.val.fmt(function_index, self),
+ extra.data.default.toInst(&function).fmt(function_index, self),
+ });
+ for (vals, blocks) |case_val, case_block| try writer.print(
+ " {%}, {%}\n",
+ .{
+ case_val.fmt(self),
+ case_block.toInst(&function).fmt(function_index, self),
+ },
+ );
+ try writer.writeAll(" ]\n");
+ },
+ .va_arg => |tag| {
+ const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
+ try writer.print(" %{} = {s} {%}, {%}\n", .{
+ instruction_index.name(&function).fmt(self),
+ @tagName(tag),
+ extra.list.fmt(function_index, self),
+ extra.type.fmt(self),
+ });
+ },
}
- try writer.writeByte('}');
}
- try writer.writeByte('\n');
+ try writer.writeByte('}');
}
+ try writer.writeByte('\n');
need_newline = true;
}
@@ -8080,7 +10015,7 @@ fn fnTypeAssumeCapacity(
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.type_items.appendAssumeCapacity(.{
- .tag = .function,
+ .tag = tag,
.data = self.addTypeExtraAssumeCapacity(Type.Function{
.ret = ret,
.params_len = @intCast(params.len),
@@ -9378,7 +11313,7 @@ fn icmpConstAssumeCapacity(
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
- llvm.constICmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
+ llvm.constICmp(cond.toLlvm(), lhs.toLlvm(self), rhs.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
@@ -9415,7 +11350,7 @@ fn fcmpConstAssumeCapacity(
.data = self.addConstantExtraAssumeCapacity(data),
});
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
- llvm.constFCmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
+ llvm.constFCmp(cond.toLlvm(), lhs.toLlvm(self), rhs.toLlvm(self)),
);
}
return @enumFromInt(gop.index);
@@ -9601,16 +11536,52 @@ fn binConstAssumeCapacity(
return @enumFromInt(gop.index);
}
+comptime {
+ _ = &selectValue;
+}
+
+fn selectConstAssumeCapacity(self: *Builder, cond: Constant, lhs: Constant, rhs: Constant) Constant {
+ const Adapter = struct {
+ builder: *const Builder,
+ pub fn hash(_: @This(), key: Constant.Select) u32 {
+ return @truncate(std.hash.Wyhash.hash(
+ std.hash.uint32(@intFromEnum(Constant.Tag.select)),
+ std.mem.asBytes(&key),
+ ));
+ }
+ pub fn eql(ctx: @This(), lhs_key: Constant.Select, _: void, rhs_index: usize) bool {
+ if (ctx.builder.constant_items.items(.tag)[rhs_index] != .select) return false;
+ const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+ const rhs_extra = ctx.builder.constantExtraData(Constant.Select, rhs_data);
+ return std.meta.eql(lhs_key, rhs_extra);
+ }
+ };
+ const data = Constant.Select{ .cond = 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 = .select,
+ .data = self.addConstantExtraAssumeCapacity(data),
+ });
+ if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+ cond.toLlvm(self).constSelect(lhs.toLlvm(self), rhs.toLlvm(self)),
+ );
+ }
+ return @enumFromInt(gop.index);
+}
+
fn asmConstAssumeCapacity(
self: *Builder,
ty: Type,
- info: Constant.Asm.Info,
+ info: Constant.Assembly.Info,
assembly: String,
constraints: String,
) Constant {
assert(ty.functionKind(self) == .normal);
- const Key = struct { tag: Constant.Tag, extra: Constant.Asm };
+ const Key = struct { tag: Constant.Tag, extra: Constant.Assembly };
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Key) u32 {
@@ -9622,7 +11593,7 @@ fn asmConstAssumeCapacity(
pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
- const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data);
+ const rhs_extra = ctx.builder.constantExtraData(Constant.Assembly, rhs_data);
return std.meta.eql(lhs_key.extra, rhs_extra);
}
};