aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-07-24 02:16:00 -0700
committerGitHub <noreply@github.com>2023-07-24 02:16:00 -0700
commitd21d1d4ba25701410b9ae99921326f8bfc8a44dd (patch)
treec56738ededf5966ce448e57be393996f76976426 /src/codegen/llvm.zig
parent98c7aec4e4ae7deac5e802a8c592c2d91b6b77af (diff)
parent3fc2e36de2d125b2de255b03abc24bea30899caf (diff)
downloadzig-d21d1d4ba25701410b9ae99921326f8bfc8a44dd.tar.gz
zig-d21d1d4ba25701410b9ae99921326f8bfc8a44dd.zip
Merge pull request #16487 from jacobly0/llvm-builder
llvm: incremental Builder improvements
Diffstat (limited to 'src/codegen/llvm.zig')
-rw-r--r--src/codegen/llvm.zig836
1 files changed, 505 insertions, 331 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 57842ef1e0..87ed52c31b 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -340,7 +340,6 @@ const DataLayoutBuilder = struct {
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- const is_aarch64_windows = self.target.cpu.arch == .aarch64 and self.target.os.tag == .windows;
try writer.writeByte(switch (self.target.cpu.arch.endian()) {
.Little => 'e',
.Big => 'E',
@@ -359,7 +358,7 @@ const DataLayoutBuilder = struct {
.macho => 'o', // Mach-O mangling: Private symbols get `L` prefix.
// Other symbols get a `_` prefix.
.coff => switch (self.target.os.tag) {
- .windows => switch (self.target.cpu.arch) {
+ .uefi, .windows => switch (self.target.cpu.arch) {
.x86 => 'x', // Windows x86 COFF mangling: Private symbols get the usual
// prefix. Regular C symbols get a `_` prefix. Functions with `__stdcall`,
//`__fastcall`, and `__vectorcall` have custom mangling that appends `@N`
@@ -407,7 +406,8 @@ const DataLayoutBuilder = struct {
};
if (self.target.cpu.arch == .aarch64_32) continue;
if (!info.force_in_data_layout and matches_default and
- self.target.cpu.arch != .riscv64 and !is_aarch64_windows and
+ self.target.cpu.arch != .riscv64 and !(self.target.cpu.arch == .aarch64 and
+ (self.target.os.tag == .uefi or self.target.os.tag == .windows)) and
self.target.cpu.arch != .bpfeb and self.target.cpu.arch != .bpfel) continue;
try writer.writeAll("-p");
if (info.llvm != .default) try writer.print("{d}", .{@intFromEnum(info.llvm)});
@@ -423,7 +423,7 @@ const DataLayoutBuilder = struct {
if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);
try self.typeAlignment(.integer, 8, 8, 8, false, writer);
try self.typeAlignment(.integer, 16, 16, 16, false, writer);
- try self.typeAlignment(.integer, 32, if (is_aarch64_windows) 0 else 32, 32, false, writer);
+ try self.typeAlignment(.integer, 32, 32, 32, false, writer);
try self.typeAlignment(.integer, 64, 32, 64, false, writer);
try self.typeAlignment(.integer, 128, 32, 64, false, writer);
if (backendSupportsF16(self.target)) try self.typeAlignment(.float, 16, 16, 16, false, writer);
@@ -453,8 +453,15 @@ const DataLayoutBuilder = struct {
try self.typeAlignment(.vector, 128, 128, 128, true, writer);
},
}
- if (self.target.os.tag != .windows and self.target.cpu.arch != .avr)
- try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
+ const swap_agg_nat = switch (self.target.cpu.arch) {
+ .x86, .x86_64 => switch (self.target.os.tag) {
+ .uefi, .windows => true,
+ else => false,
+ },
+ .avr => true,
+ else => false,
+ };
+ if (!swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
for (@as([]const u24, switch (self.target.cpu.arch) {
.avr => &.{8},
.msp430 => &.{ 8, 16 },
@@ -498,6 +505,7 @@ const DataLayoutBuilder = struct {
0 => try writer.print("-n{d}", .{natural}),
else => try writer.print(":{d}", .{natural}),
};
+ if (swap_agg_nat) try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
if (self.target.cpu.arch == .hexagon) {
try self.typeAlignment(.integer, 64, 64, 64, true, writer);
try self.typeAlignment(.integer, 32, 32, 32, true, writer);
@@ -506,11 +514,9 @@ const DataLayoutBuilder = struct {
try self.typeAlignment(.float, 32, 32, 32, true, writer);
try self.typeAlignment(.float, 64, 64, 64, true, writer);
}
- if (self.target.os.tag == .windows or self.target.cpu.arch == .avr)
- try self.typeAlignment(.aggregate, 0, 0, 64, false, writer);
const stack_abi = self.target.stackAlignment() * 8;
- if (self.target.os.tag == .windows or self.target.cpu.arch == .msp430 or
- stack_abi != ptr_bit_width)
+ if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
+ self.target.cpu.arch == .msp430 or stack_abi != ptr_bit_width)
try writer.print("-S{d}", .{stack_abi});
switch (self.target.cpu.arch) {
.hexagon, .ve => {
@@ -571,22 +577,21 @@ const DataLayoutBuilder = struct {
.integer => {
if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
abi = @min(abi, self.target.maxIntAlignment() * 8);
- switch (self.target.os.tag) {
- .linux => switch (self.target.cpu.arch) {
- .aarch64,
- .aarch64_be,
- .aarch64_32,
- .mips,
- .mipsel,
- => pref = @max(pref, 32),
- else => {},
- },
- else => {},
- }
switch (self.target.cpu.arch) {
.aarch64,
.aarch64_be,
.aarch64_32,
+ => if (size == 128) {
+ abi = size;
+ pref = size;
+ } else switch (self.target.os.tag) {
+ .macos => {},
+ .uefi, .windows => {
+ pref = size;
+ force_abi = size >= 32;
+ },
+ else => pref = @max(pref, 32),
+ },
.bpfeb,
.bpfel,
.nvptx,
@@ -597,6 +602,9 @@ const DataLayoutBuilder = struct {
pref = size;
},
.hexagon => force_abi = true,
+ .mips,
+ .mipsel,
+ => pref = @max(pref, 32),
.mips64,
.mips64el,
=> if (size <= 32) {
@@ -617,7 +625,8 @@ const DataLayoutBuilder = struct {
128 => abi = 64,
else => {},
}
- } else if ((self.target.cpu.arch.isPPC64() and (size == 256 or size == 512)) or
+ } else if ((self.target.cpu.arch.isPPC64() and self.target.os.tag == .linux and
+ (size == 256 or size == 512)) or
(self.target.cpu.arch.isNvptx() and (size == 16 or size == 32)))
{
force_abi = true;
@@ -646,17 +655,21 @@ const DataLayoutBuilder = struct {
.hexagon => if (size == 32 or size == 64) {
force_abi = true;
},
- .aarch64_32 => if (size == 128) {
+ .aarch64_32, .amdgcn => if (size == 128) {
abi = size;
pref = size;
},
+ .wasm32, .wasm64 => if (self.target.os.tag == .emscripten and size == 128) {
+ abi = 64;
+ pref = 64;
+ },
.ve => if (size == 64) {
abi = size;
pref = size;
},
else => {},
},
- .aggregate => if (self.target.os.tag == .windows or
+ .aggregate => if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
{
pref = @min(pref, self.target.ptrBitWidth());
@@ -794,7 +807,7 @@ pub const Object = struct {
builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
DW.LANG.C99,
builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
- producer.toSlice(&builder).?,
+ producer.slice(&builder).?,
options.optimize_mode != .Debug,
"", // flags
0, // runtime version
@@ -830,7 +843,7 @@ pub const Object = struct {
target_machine = llvm.TargetMachine.create(
builder.llvm.target.?,
- builder.target_triple.toSlice(&builder).?,
+ builder.target_triple.slice(&builder).?,
if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
options.llvm_cpu_features,
opt_level,
@@ -861,7 +874,7 @@ pub const Object = struct {
defer llvm.disposeMessage(rep);
std.testing.expectEqualStrings(
std.mem.span(rep),
- builder.data_layout.toSlice(&builder).?,
+ builder.data_layout.slice(&builder).?,
) catch unreachable;
}
}
@@ -963,7 +976,7 @@ pub const Object = struct {
llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
global_index.toConst(),
- try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
+ try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len),
});
}
@@ -1021,15 +1034,11 @@ pub const Object = struct {
fn genModuleLevelAssembly(object: *Object) !void {
const mod = object.module;
- if (mod.global_assembly.count() == 0) return;
- var buffer = std.ArrayList(u8).init(mod.gpa);
- defer buffer.deinit();
- var it = mod.global_assembly.iterator();
- while (it.next()) |kv| {
- try buffer.appendSlice(kv.value_ptr.*);
- try buffer.append('\n');
- }
- object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
+
+ const writer = object.builder.setModuleAsm();
+ var it = mod.global_assembly.valueIterator();
+ while (it.next()) |assembly| try writer.print("{s}\n", .{assembly.*});
+ try object.builder.finishModuleAsm();
}
fn resolveExportExternCollisions(object: *Object) !void {
@@ -1223,6 +1232,7 @@ pub const Object = struct {
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
+ const fn_info = mod.typeToFunc(decl.ty).?;
const target = mod.getTarget();
const ip = &mod.intern_pool;
@@ -1237,28 +1247,43 @@ pub const Object = struct {
const global = function.ptrConst(&o.builder).global;
const llvm_func = global.toLlvm(&o.builder);
+ var attributes = try function.ptrConst(&o.builder).attributes.toWip(&o.builder);
+ defer attributes.deinit(&o.builder);
+
if (func.analysis(ip).is_noinline) {
+ try attributes.addFnAttr(.@"noinline", &o.builder);
o.addFnAttr(llvm_func, "noinline");
} else {
+ _ = try attributes.removeFnAttr(.@"noinline");
Object.removeFnAttr(llvm_func, "noinline");
}
if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
+ try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
+ try attributes.addFnAttr(.@"noinline", &o.builder);
o.addFnAttrInt(llvm_func, "alignstack", alignment);
o.addFnAttr(llvm_func, "noinline");
} else {
+ _ = try attributes.removeFnAttr(.alignstack);
Object.removeFnAttr(llvm_func, "alignstack");
}
if (func.analysis(ip).is_cold) {
+ try attributes.addFnAttr(.cold, &o.builder);
o.addFnAttr(llvm_func, "cold");
} else {
+ _ = try attributes.removeFnAttr(.cold);
Object.removeFnAttr(llvm_func, "cold");
}
// TODO: disable this if safety is off for the function scope
const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
if (ssp_buf_size != 0) {
+ try attributes.addFnAttr(.sspstrong, &o.builder);
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("stack-protector-buffer-size"),
+ .value = try o.builder.fmt("{d}", .{ssp_buf_size}),
+ } }, &o.builder);
var buf: [12]u8 = undefined;
const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
o.addFnAttr(llvm_func, "sspstrong");
@@ -1267,8 +1292,16 @@ pub const Object = struct {
// TODO: disable this if safety is off for the function scope
if (mod.comp.bin_file.options.stack_check) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("probe-stack"),
+ .value = try o.builder.string("__zig_probe_stack"),
+ } }, &o.builder);
o.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack");
} else if (target.os.tag == .uefi) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("no-stack-arg-probe"),
+ .value = .empty,
+ } }, &o.builder);
o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
}
@@ -1286,18 +1319,22 @@ pub const Object = struct {
var llvm_arg_i: u32 = 0;
// This gets the LLVM values from the function and stores them in `dg.args`.
- const fn_info = mod.typeToFunc(decl.ty).?;
const sret = firstParamSRet(fn_info, mod);
const ret_ptr: Builder.Value = if (sret) param: {
const param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
break :param param;
} else .none;
- const gpa = o.gpa;
if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
- .signed => o.addAttr(llvm_func, 0, "signext"),
- .unsigned => o.addAttr(llvm_func, 0, "zeroext"),
+ .signed => {
+ try attributes.addRetAttr(.signext, &o.builder);
+ o.addAttr(llvm_func, 0, "signext");
+ },
+ .unsigned => {
+ try attributes.addRetAttr(.zeroext, &o.builder);
+ o.addAttr(llvm_func, 0, "zeroext");
+ },
};
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
@@ -1312,6 +1349,7 @@ pub const Object = struct {
// This is the list of args we will use that correspond directly to the AIR arg
// instructions. Depending on the calling convention, this list is not necessarily
// a bijection with the actual LLVM parameters of the function.
+ const gpa = o.gpa;
var args: std.ArrayListUnmanaged(Builder.Value) = .{};
defer args.deinit(gpa);
@@ -1337,7 +1375,7 @@ pub const Object = struct {
} else {
args.appendAssumeCapacity(param);
- o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
+ try o.addByValParamAttrsOld(&attributes, llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
}
llvm_arg_i += 1;
},
@@ -1347,7 +1385,7 @@ pub const Object = struct {
const param = wip.arg(llvm_arg_i);
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
- o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
+ try o.addByRefParamAttrsOld(&attributes, llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
llvm_arg_i += 1;
if (isByRef(param_ty, mod)) {
@@ -1362,7 +1400,8 @@ pub const Object = struct {
const param = wip.arg(llvm_arg_i);
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
- o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
+ try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
+ o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
llvm_arg_i += 1;
if (isByRef(param_ty, mod)) {
@@ -1398,21 +1437,28 @@ pub const Object = struct {
if (math.cast(u5, it.zig_index - 1)) |i| {
if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
- o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");
+ try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
+ o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
}
}
if (param_ty.zigTypeTag(mod) != .Optional) {
- o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
}
if (ptr_info.flags.is_const) {
- o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
+ o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
}
- const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
- @max(ptr_info.child.toType().abiAlignment(mod), 1);
- o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);
- const ptr_param = wip.arg(llvm_arg_i + 0);
- const len_param = wip.arg(llvm_arg_i + 1);
- llvm_arg_i += 2;
+ const elem_align = Builder.Alignment.fromByteUnits(
+ ptr_info.flags.alignment.toByteUnitsOptional() orelse
+ @max(ptr_info.child.toType().abiAlignment(mod), 1),
+ );
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
+ o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
+ const ptr_param = wip.arg(llvm_arg_i);
+ llvm_arg_i += 1;
+ const len_param = wip.arg(llvm_arg_i);
+ llvm_arg_i += 1;
const slice_llvm_ty = try o.lowerType(param_ty);
args.appendAssumeCapacity(
@@ -1482,6 +1528,8 @@ pub const Object = struct {
}
}
+ function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
+
var di_file: ?*llvm.DIFile = null;
var di_scope: ?*llvm.DIScope = null;
@@ -1618,7 +1666,7 @@ pub const Object = struct {
llvm_global.setDLLStorageClass(.Default);
}
if (self.di_map.get(decl)) |di_node| {
- const decl_name_slice = decl_name.toSlice(&self.builder).?;
+ const decl_name_slice = decl_name.slice(&self.builder).?;
if (try decl.isFunction(mod)) {
const di_func: *llvm.DISubprogram = @ptrCast(di_node);
const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
@@ -1655,7 +1703,7 @@ pub const Object = struct {
llvm_global.setDLLStorageClass(.DLLExport);
}
if (self.di_map.get(decl)) |di_node| {
- const exp_name_slice = exp_name.toSlice(&self.builder).?;
+ const exp_name_slice = exp_name.slice(&self.builder).?;
if (try decl.isFunction(mod)) {
const di_func: *llvm.DISubprogram = @ptrCast(di_node);
const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
@@ -2816,7 +2864,7 @@ pub const Object = struct {
const fqn = try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod)));
const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
- const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
+ const llvm_fn = o.llvm_module.addFunctionInAddressSpace(fqn.slice(&o.builder).?, fn_type.toLlvm(&o.builder), @intFromEnum(llvm_addrspace));
var global = Builder.Global{
.type = fn_type,
@@ -2826,6 +2874,9 @@ pub const Object = struct {
.global = @enumFromInt(o.builder.globals.count()),
};
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+
const is_extern = decl.isExtern(mod);
if (!is_extern) {
global.linkage = .internal;
@@ -2834,43 +2885,64 @@ pub const Object = struct {
llvm_fn.setUnnamedAddr(.True);
} else {
if (target.isWasm()) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("wasm-import-name"),
+ .value = try o.builder.string(ip.stringToSlice(decl.name)),
+ } }, &o.builder);
o.addFnAttrString(llvm_fn, "wasm-import-name", ip.stringToSlice(decl.name));
if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
if (!std.mem.eql(u8, lib_name, "c")) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("wasm-import-module"),
+ .value = try o.builder.string(lib_name),
+ } }, &o.builder);
o.addFnAttrString(llvm_fn, "wasm-import-module", lib_name);
}
}
}
}
+ var llvm_arg_i: u32 = 0;
if (sret) {
- o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
- o.addArgAttr(llvm_fn, 0, "noalias");
+ // Sret pointers must not be address 0
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
+ o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); // Sret pointers must not be address 0
+ o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
- const raw_llvm_ret_ty = (try o.lowerType(fn_info.return_type.toType())).toLlvm(&o.builder);
- llvm_fn.addSretAttr(raw_llvm_ret_ty);
+ const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
+ try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder);
+ llvm_fn.addSretAttr(raw_llvm_ret_ty.toLlvm(&o.builder));
+
+ llvm_arg_i += 1;
}
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
mod.comp.bin_file.options.error_return_tracing;
if (err_return_tracing) {
- o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull");
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
+ llvm_arg_i += 1;
}
switch (fn_info.cc) {
.Unspecified, .Inline => {
+ function.call_conv = .fastcc;
llvm_fn.setFunctionCallConv(.Fast);
},
.Naked => {
+ try attributes.addFnAttr(.naked, &o.builder);
o.addFnAttr(llvm_fn, "naked");
},
.Async => {
+ function.call_conv = .fastcc;
llvm_fn.setFunctionCallConv(.Fast);
@panic("TODO: LLVM backend lower async function");
},
else => {
- llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
+ function.call_conv = toLlvmCallConv(fn_info.cc, target);
+ llvm_fn.setFunctionCallConv(@enumFromInt(@intFromEnum(function.call_conv)));
},
}
@@ -2880,9 +2952,10 @@ pub const Object = struct {
}
// Function attributes that are independent of analysis results of the function body.
- o.addCommonFnAttributes(llvm_fn);
+ try o.addCommonFnAttributes(&attributes, llvm_fn);
if (fn_info.return_type == .noreturn_type) {
+ try attributes.addFnAttr(.noreturn, &o.builder);
o.addFnAttr(llvm_fn, "noreturn");
}
@@ -2890,23 +2963,24 @@ pub const Object = struct {
// because functions with bodies are handled in `updateFunc`.
if (is_extern) {
var it = iterateParamTypes(o, fn_info);
- it.llvm_index += @intFromBool(sret);
- it.llvm_index += @intFromBool(err_return_tracing);
+ it.llvm_index = llvm_arg_i;
while (try it.next()) |lowering| switch (lowering) {
.byval => {
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types.get(ip)[param_index].toType();
if (!isByRef(param_ty, mod)) {
- o.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
+ try o.addByValParamAttrsOld(&attributes, llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
}
},
.byref => {
const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
const param_llvm_ty = try o.lowerType(param_ty.toType());
- const alignment = param_ty.toType().abiAlignment(mod);
- o.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
+ const alignment =
+ Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));
+ try o.addByRefParamAttrsOld(&attributes, llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
},
.byref_mut => {
+ try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder);
o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
},
// No attributes needed for these.
@@ -2924,25 +2998,42 @@ pub const Object = struct {
};
}
+ function.attributes = try attributes.finish(&o.builder);
+
try o.builder.llvm.globals.append(o.gpa, llvm_fn);
gop.value_ptr.* = try o.builder.addGlobal(fqn, global);
try o.builder.functions.append(o.gpa, function);
return global.kind.function;
}
- fn addCommonFnAttributes(o: *Object, llvm_fn: *llvm.Value) void {
+ fn addCommonFnAttributes(
+ o: *Object,
+ attributes: *Builder.FunctionAttributes.Wip,
+ llvm_fn: *llvm.Value,
+ ) Allocator.Error!void {
const comp = o.module.comp;
if (!comp.bin_file.options.red_zone) {
+ try attributes.addFnAttr(.noredzone, &o.builder);
o.addFnAttr(llvm_fn, "noredzone");
}
if (comp.bin_file.options.omit_frame_pointer) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("frame-pointer"),
+ .value = try o.builder.string("none"),
+ } }, &o.builder);
o.addFnAttrString(llvm_fn, "frame-pointer", "none");
} else {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("frame-pointer"),
+ .value = try o.builder.string("all"),
+ } }, &o.builder);
o.addFnAttrString(llvm_fn, "frame-pointer", "all");
}
+ try attributes.addFnAttr(.nounwind, &o.builder);
o.addFnAttr(llvm_fn, "nounwind");
if (comp.unwind_tables) {
+ try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
o.addFnAttrInt(llvm_fn, "uwtable", 2);
}
if (comp.bin_file.options.skip_linker_dependencies or
@@ -2953,22 +3044,38 @@ pub const Object = struct {
// and llvm detects that the body is equivalent to memcpy, it may replace the
// body of memcpy with a call to memcpy, which would then cause a stack
// overflow instead of performing memcpy.
+ try attributes.addFnAttr(.nobuiltin, &o.builder);
o.addFnAttr(llvm_fn, "nobuiltin");
}
if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
+ try attributes.addFnAttr(.minsize, &o.builder);
+ try attributes.addFnAttr(.optsize, &o.builder);
o.addFnAttr(llvm_fn, "minsize");
o.addFnAttr(llvm_fn, "optsize");
}
if (comp.bin_file.options.tsan) {
+ try attributes.addFnAttr(.sanitize_thread, &o.builder);
o.addFnAttr(llvm_fn, "sanitize_thread");
}
if (comp.getTarget().cpu.model.llvm_name) |s| {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("target-cpu"),
+ .value = try o.builder.string(s),
+ } }, &o.builder);
llvm_fn.addFunctionAttr("target-cpu", s);
}
if (comp.bin_file.options.llvm_cpu_features) |s| {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("target-features"),
+ .value = try o.builder.string(std.mem.span(s)),
+ } }, &o.builder);
llvm_fn.addFunctionAttr("target-features", s);
}
if (comp.getTarget().cpu.arch.isBpf()) {
+ try attributes.addFnAttr(.{ .string = .{
+ .kind = try o.builder.string("no-builtins"),
+ .value = .empty,
+ } }, &o.builder);
llvm_fn.addFunctionAttr("no-builtins", "");
}
}
@@ -3002,7 +3109,7 @@ pub const Object = struct {
fqn;
const llvm_global = o.llvm_module.addGlobalInAddressSpace(
global.type.toLlvm(&o.builder),
- fqn.toSlice(&o.builder).?,
+ fqn.slice(&o.builder).?,
@intFromEnum(global.addr_space),
);
@@ -4403,47 +4510,114 @@ pub const Object = struct {
fn addByValParamAttrs(
o: *Object,
+ attributes: *Builder.FunctionAttributes.Wip,
+ param_ty: Type,
+ param_index: u32,
+ fn_info: InternPool.Key.FuncType,
+ llvm_arg_i: u32,
+ ) Allocator.Error!void {
+ const mod = o.module;
+ if (param_ty.isPtrAtRuntime(mod)) {
+ const ptr_info = param_ty.ptrInfo(mod);
+ if (math.cast(u5, param_index)) |i| {
+ if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
+ try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
+ }
+ }
+ if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ }
+ if (ptr_info.flags.is_const) {
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
+ }
+ const elem_align = Builder.Alignment.fromByteUnits(
+ ptr_info.flags.alignment.toByteUnitsOptional() orelse
+ @max(ptr_info.child.toType().abiAlignment(mod), 1),
+ );
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
+ } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
+ .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
+ .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
+ };
+ }
+
+ fn addByRefParamAttrs(
+ o: *Object,
+ attributes: *Builder.FunctionAttributes.Wip,
+ llvm_arg_i: u32,
+ alignment: Builder.Alignment,
+ byval_attr: bool,
+ param_llvm_ty: Builder.Type,
+ ) Allocator.Error!void {
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
+ if (byval_attr) {
+ try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
+ }
+ }
+
+ fn addByValParamAttrsOld(
+ o: *Object,
+ attributes: *Builder.FunctionAttributes.Wip,
llvm_fn: *llvm.Value,
param_ty: Type,
param_index: u32,
fn_info: InternPool.Key.FuncType,
llvm_arg_i: u32,
- ) void {
+ ) Allocator.Error!void {
const mod = o.module;
if (param_ty.isPtrAtRuntime(mod)) {
const ptr_info = param_ty.ptrInfo(mod);
if (math.cast(u5, param_index)) |i| {
if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
+ try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
o.addArgAttr(llvm_fn, llvm_arg_i, "noalias");
}
}
if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.flags.is_allowzero) {
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
}
if (ptr_info.flags.is_const) {
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
}
- const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
- @max(ptr_info.child.toType().abiAlignment(mod), 1);
- o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align);
+ const elem_align = Builder.Alignment.fromByteUnits(
+ ptr_info.flags.alignment.toByteUnitsOptional() orelse
+ @max(ptr_info.child.toType().abiAlignment(mod), 1),
+ );
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
+ o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align.toByteUnits() orelse 0);
} else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
- .signed => o.addArgAttr(llvm_fn, llvm_arg_i, "signext"),
- .unsigned => o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"),
+ .signed => {
+ try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder);
+ o.addArgAttr(llvm_fn, llvm_arg_i, "signext");
+ },
+ .unsigned => {
+ try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder);
+ o.addArgAttr(llvm_fn, llvm_arg_i, "zeroext");
+ },
};
}
- fn addByRefParamAttrs(
+ fn addByRefParamAttrsOld(
o: *Object,
+ attributes: *Builder.FunctionAttributes.Wip,
llvm_fn: *llvm.Value,
llvm_arg_i: u32,
- alignment: u32,
+ alignment: Builder.Alignment,
byval_attr: bool,
param_llvm_ty: Builder.Type,
- ) void {
+ ) Allocator.Error!void {
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
o.addArgAttr(llvm_fn, llvm_arg_i, "readonly");
- o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment);
+ o.addArgAttrInt(llvm_fn, llvm_arg_i, "align", alignment.toByteUnits() orelse 0);
if (byval_attr) {
+ try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
}
}
@@ -4841,10 +5015,10 @@ pub const FuncGen = struct {
.slice_ptr => try self.airSliceField(inst, 0),
.slice_len => try self.airSliceField(inst, 1),
- .call => try self.airCall(inst, .Auto),
- .call_always_tail => try self.airCall(inst, .AlwaysTail),
- .call_never_tail => try self.airCall(inst, .NeverTail),
- .call_never_inline => try self.airCall(inst, .NeverInline),
+ .call => try self.airCall(inst, .auto),
+ .call_always_tail => try self.airCall(inst, .always_tail),
+ .call_never_tail => try self.airCall(inst, .never_tail),
+ .call_never_inline => try self.airCall(inst, .never_inline),
.ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
.ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
@@ -4953,7 +5127,15 @@ pub const FuncGen = struct {
}
}
- fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {
+ pub const CallAttr = enum {
+ Auto,
+ NeverTail,
+ NeverInline,
+ AlwaysTail,
+ AlwaysInline,
+ };
+
+ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Call, pl_op.payload);
const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
@@ -4972,14 +5154,25 @@ pub const FuncGen = struct {
const target = mod.getTarget();
const sret = firstParamSRet(fn_info, mod);
- var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa);
+ var llvm_args = std.ArrayList(Builder.Value).init(self.gpa);
defer llvm_args.deinit();
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+
+ switch (modifier) {
+ .auto, .never_tail, .always_tail => {},
+ .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder),
+ .async_kw, .no_async, .always_inline, .compile_time => unreachable,
+ }
+
const ret_ptr = if (!sret) null else blk: {
const llvm_ret_ty = try o.lowerType(return_type);
+ try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
+
const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
- try llvm_args.append(ret_ptr.toLlvm(&self.wip));
+ try llvm_args.append(ret_ptr);
break :blk ret_ptr;
};
@@ -4987,7 +5180,7 @@ pub const FuncGen = struct {
o.module.comp.bin_file.options.error_return_tracing;
if (err_return_tracing) {
assert(self.err_ret_trace != .none);
- try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));
+ try llvm_args.append(self.err_ret_trace);
}
var it = iterateParamTypes(o, fn_info);
@@ -5001,9 +5194,9 @@ pub const FuncGen = struct {
if (isByRef(param_ty, mod)) {
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
- try llvm_args.append(loaded.toLlvm(&self.wip));
+ try llvm_args.append(loaded);
} else {
- try llvm_args.append(llvm_arg.toLlvm(&self.wip));
+ try llvm_args.append(llvm_arg);
}
},
.byref => {
@@ -5011,13 +5204,13 @@ pub const FuncGen = struct {
const param_ty = self.typeOf(arg);
const llvm_arg = try self.resolveInst(arg);
if (isByRef(param_ty, mod)) {
- try llvm_args.append(llvm_arg.toLlvm(&self.wip));
+ try llvm_args.append(llvm_arg);
} else {
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
_ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
- try llvm_args.append(arg_ptr.toLlvm(&self.wip));
+ try llvm_args.append(arg_ptr);
}
},
.byref_mut => {
@@ -5034,7 +5227,7 @@ pub const FuncGen = struct {
} else {
_ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
}
- try llvm_args.append(arg_ptr.toLlvm(&self.wip));
+ try llvm_args.append(arg_ptr);
},
.abi_sized_int => {
const arg = args[it.zig_index - 1];
@@ -5045,7 +5238,7 @@ pub const FuncGen = struct {
if (isByRef(param_ty, mod)) {
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
- try llvm_args.append(loaded.toLlvm(&self.wip));
+ try llvm_args.append(loaded);
} else {
// LLVM does not allow bitcasting structs so we must allocate
// a local, store as one type, and then load as another type.
@@ -5056,7 +5249,7 @@ pub const FuncGen = struct {
const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
_ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
- try llvm_args.append(loaded.toLlvm(&self.wip));
+ try llvm_args.append(loaded);
}
},
.slice => {
@@ -5064,7 +5257,7 @@ pub const FuncGen = struct {
const llvm_arg = try self.resolveInst(arg);
const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
- try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
+ try llvm_args.appendSlice(&.{ ptr, len });
},
.multiple_llvm_types => {
const arg = args[it.zig_index - 1];
@@ -5086,14 +5279,14 @@ pub const FuncGen = struct {
Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
- llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
+ llvm_args.appendAssumeCapacity(loaded);
}
},
.as_u16 => {
const arg = args[it.zig_index - 1];
const llvm_arg = try self.resolveInst(arg);
const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
- try llvm_args.append(casted.toLlvm(&self.wip));
+ try llvm_args.append(casted);
},
.float_array => |count| {
const arg = args[it.zig_index - 1];
@@ -5110,7 +5303,7 @@ pub const FuncGen = struct {
const array_ty = try o.builder.arrayType(count, float_ty);
const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
- try llvm_args.append(loaded.toLlvm(&self.wip));
+ try llvm_args.append(loaded);
},
.i32_array, .i64_array => |arr_len| {
const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
@@ -5127,24 +5320,10 @@ pub const FuncGen = struct {
const array_ty =
try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
- try llvm_args.append(loaded.toLlvm(&self.wip));
+ try llvm_args.append(loaded);
},
};
- const llvm_fn_ty = try o.lowerType(zig_fn_ty);
- const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
- self.builder.buildCall(
- llvm_fn_ty.toLlvm(&o.builder),
- llvm_fn.toLlvm(&self.wip),
- llvm_args.items.ptr,
- @intCast(llvm_args.items.len),
- toLlvmCallConv(fn_info.cc, target),
- attr,
- "",
- ),
- &self.wip,
- );
-
if (callee_ty.zigTypeTag(mod) == .Pointer) {
// Add argument attributes for function pointer calls.
it = iterateParamTypes(o, fn_info);
@@ -5155,19 +5334,17 @@ pub const FuncGen = struct {
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types.get(ip)[param_index].toType();
if (!isByRef(param_ty, mod)) {
- o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);
+ try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
}
},
.byref => {
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types.get(ip)[param_index].toType();
const param_llvm_ty = try o.lowerType(param_ty);
- const alignment = param_ty.abiAlignment(mod);
- o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
- },
- .byref_mut => {
- o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
+ const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
+ try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
},
+ .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
// No attributes needed for these.
.no_bits,
.abi_sized_int,
@@ -5186,23 +5363,40 @@ pub const FuncGen = struct {
if (math.cast(u5, it.zig_index - 1)) |i| {
if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
- o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");
+ try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
}
}
if (param_ty.zigTypeTag(mod) != .Optional) {
- o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");
+ try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
}
if (ptr_info.flags.is_const) {
- o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");
+ try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
}
- const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
- @max(ptr_info.child.toType().abiAlignment(mod), 1);
- o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);
+ const elem_align = Builder.Alignment.fromByteUnits(
+ ptr_info.flags.alignment.toByteUnitsOptional() orelse
+ @max(ptr_info.child.toType().abiAlignment(mod), 1),
+ );
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
},
};
}
- if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
+ const call = try self.wip.call(
+ switch (modifier) {
+ .auto, .never_inline => .normal,
+ .never_tail => .notail,
+ .always_tail => .musttail,
+ .async_kw, .no_async, .always_inline, .compile_time => unreachable,
+ },
+ toLlvmCallConv(fn_info.cc, target),
+ try attributes.finish(&o.builder),
+ try o.lowerType(zig_fn_ty),
+ llvm_fn,
+ llvm_args.items,
+ "",
+ );
+
+ if (fn_info.return_type == .noreturn_type and modifier != .always_tail) {
return .none;
}
@@ -5211,9 +5405,7 @@ pub const FuncGen = struct {
}
const llvm_ret_ty = try o.lowerType(return_type);
-
if (ret_ptr) |rp| {
- call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
if (isByRef(return_type, mod)) {
return rp;
} else {
@@ -5269,25 +5461,24 @@ pub const FuncGen = struct {
// ptr null, ; stack trace
// ptr @2, ; addr (null ?usize)
// )
- const args = [4]*llvm.Value{
- msg_ptr.toLlvm(&o.builder),
- (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
- (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
- null_opt_addr_global.toLlvm(&o.builder),
- };
const panic_func = mod.funcInfo(mod.panic_func_index);
const panic_decl = mod.declPtr(panic_func.owner_decl);
const fn_info = mod.typeToFunc(panic_decl.ty).?;
const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
- _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
- (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
- panic_global.toLlvm(&o.builder),
- &args,
- args.len,
+ _ = try fg.wip.call(
+ .normal,
toLlvmCallConv(fn_info.cc, target),
- .Auto,
+ .none,
+ panic_global.typeOf(&o.builder),
+ panic_global.toValue(&o.builder),
+ &.{
+ msg_ptr.toValue(),
+ try o.builder.intValue(llvm_usize, msg_len),
+ try o.builder.nullValue(.ptr),
+ null_opt_addr_global.toValue(),
+ },
"",
- ), &fg.wip);
+ );
_ = try fg.wip.@"unreachable"();
}
@@ -5395,7 +5586,7 @@ pub const FuncGen = struct {
o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&args,
@@ -5422,7 +5613,7 @@ pub const FuncGen = struct {
o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&args,
@@ -5449,7 +5640,7 @@ pub const FuncGen = struct {
o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&args,
@@ -5495,16 +5686,15 @@ pub const FuncGen = struct {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const llvm_fn = try self.getCmpLtErrorsLenFunction();
- const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
- llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &args,
- args.len,
- .Fast,
- .Auto,
+ return self.wip.call(
+ .normal,
+ .fastcc,
+ .none,
+ llvm_fn.typeOf(&o.builder),
+ llvm_fn.toValue(&o.builder),
+ &.{operand},
"",
- ), &self.wip);
+ );
}
fn cmp(
@@ -5953,16 +6143,15 @@ pub const FuncGen = struct {
}
const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
- const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
- libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
- libc_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .C,
- .Auto,
+ return self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &.{extended},
"",
- ), &self.wip);
+ );
}
fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
@@ -6013,16 +6202,15 @@ pub const FuncGen = struct {
const operand_llvm_ty = try o.lowerType(operand_ty);
const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
- const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
- var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
- libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
- libc_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .C,
- .Auto,
+ var result = try self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &.{operand},
"",
- ), &self.wip);
+ );
if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
@@ -6588,7 +6776,7 @@ pub const FuncGen = struct {
const max_param_count = inputs.len + outputs.len;
const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
- const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
+ const llvm_param_values = try arena.alloc(Builder.Value, max_param_count);
// This stores whether we need to add an elementtype attribute and
// if so, the element type itself.
const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
@@ -6628,7 +6816,7 @@ pub const FuncGen = struct {
// Pass the result by reference as an indirect output (e.g. "=*m")
llvm_constraints.appendAssumeCapacity('*');
- llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
+ llvm_param_values[llvm_param_i] = output_inst;
llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
llvm_param_i += 1;
@@ -6678,25 +6866,25 @@ pub const FuncGen = struct {
if (isByRef(arg_ty, mod)) {
llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
if (constraintAllowsMemory(constraint)) {
- llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
+ llvm_param_values[llvm_param_i] = arg_llvm_value;
llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
} else {
const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
const arg_llvm_ty = try o.lowerType(arg_ty);
const load_inst =
try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
- llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
+ llvm_param_values[llvm_param_i] = load_inst;
llvm_param_types[llvm_param_i] = arg_llvm_ty;
}
} else {
if (constraintAllowsRegister(constraint)) {
- llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
+ llvm_param_values[llvm_param_i] = arg_llvm_value;
llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
} else {
const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
_ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
- llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
+ llvm_param_values[llvm_param_i] = arg_ptr;
llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
}
}
@@ -6843,38 +7031,26 @@ pub const FuncGen = struct {
}
}
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+ for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| if (llvm_elem_ty != .none)
+ try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
+
const ret_llvm_ty = switch (return_count) {
0 => .void,
1 => llvm_ret_types[0],
else => try o.builder.structType(.normal, llvm_ret_types),
};
-
const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
- const asm_fn = llvm.getInlineAsm(
- llvm_fn_ty.toLlvm(&o.builder),
- rendered_template.items.ptr,
- rendered_template.items.len,
- llvm_constraints.items.ptr,
- llvm_constraints.items.len,
- llvm.Bool.fromBool(is_volatile),
- .False,
- .ATT,
- .False,
- );
- const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
- llvm_fn_ty.toLlvm(&o.builder),
- asm_fn,
- llvm_param_values.ptr,
- @intCast(param_count),
- .C,
- .Auto,
+ const call = try self.wip.callAsm(
+ try attributes.finish(&o.builder),
+ llvm_fn_ty,
+ .{ .sideeffect = is_volatile },
+ try o.builder.string(rendered_template.items),
+ try o.builder.string(llvm_constraints.items),
+ llvm_param_values[0..param_count],
"",
- ), &self.wip);
- for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
- if (llvm_elem_ty != .none) {
- llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
- }
- }
+ );
var ret_val = call;
llvm_ret_i = 0;
@@ -7287,7 +7463,7 @@ pub const FuncGen = struct {
const args: [1]*llvm.Value = .{
(try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
};
- return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
+ return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
llvm_fn,
&args,
@@ -7308,7 +7484,7 @@ pub const FuncGen = struct {
(try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
operand.toLlvm(&self.wip),
};
- return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
+ return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
llvm_fn,
&args,
@@ -7425,7 +7601,7 @@ pub const FuncGen = struct {
});
const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
- const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCall(
+ const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
@@ -7768,7 +7944,7 @@ pub const FuncGen = struct {
);
const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
- self.builder.buildCall(
+ self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
@@ -7818,29 +7994,23 @@ pub const FuncGen = struct {
const o = self.dg.object;
assert(args_vectors.len <= 3);
- const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
- const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
-
var i: usize = 0;
var result = result_vector;
while (i < vector_len) : (i += 1) {
const index_i32 = try o.builder.intValue(.i32, i);
- var args: [3]*llvm.Value = undefined;
+ var args: [3]Builder.Value = undefined;
for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
- arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
+ arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, "");
}
- const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
- self.builder.buildCall(
- llvm_fn_ty.toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &args,
- @intCast(args_vectors.len),
- .C,
- .Auto,
- "",
- ),
- &self.wip,
+ const result_elem = try self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ llvm_fn.typeOf(&o.builder),
+ llvm_fn.toValue(&o.builder),
+ args[0..args_vectors.len],
+ "",
);
result = try self.wip.insertElement(result, result_elem, index_i32, "");
}
@@ -7861,7 +8031,7 @@ pub const FuncGen = struct {
};
const fn_type = try o.builder.fnType(return_type, param_types, .normal);
- const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
+ const f = o.llvm_module.addFunction(fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
var global = Builder.Global{
.type = fn_type,
@@ -7942,20 +8112,15 @@ pub const FuncGen = struct {
return self.wip.icmp(int_cond, result, zero_vector, "");
}
- const llvm_fn_ty = libc_fn.typeOf(&o.builder);
- const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };
- const result = (try self.wip.unimplemented(
- llvm_fn_ty.functionReturn(&o.builder),
- "",
- )).finish(self.builder.buildCall(
- libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
- libc_fn.toLlvm(&o.builder),
- &llvm_params,
- llvm_params.len,
- .C,
- .Auto,
+ const result = try self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &params,
"",
- ), &self.wip);
+ );
return self.wip.icmp(int_cond, result, zero.toValue(), "");
}
@@ -8085,7 +8250,7 @@ pub const FuncGen = struct {
);
var llvm_params: [params_len]*llvm.Value = undefined;
for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);
- return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCall(
+ return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&llvm_params,
@@ -8311,17 +8476,16 @@ pub const FuncGen = struct {
compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
});
- const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
- const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
- llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .C,
- .Auto,
+ const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
+ return self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &.{operand},
"",
- ), &self.wip);
+ );
}
}
@@ -8346,17 +8510,16 @@ pub const FuncGen = struct {
compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
});
- const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
- const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
- llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .C,
- .Auto,
+ const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
+ return self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ libc_fn.typeOf(&o.builder),
+ libc_fn.toValue(&o.builder),
+ &.{operand},
"",
- ), &self.wip);
+ );
}
}
@@ -8657,7 +8820,7 @@ pub const FuncGen = struct {
_ = inst;
const o = self.dg.object;
const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
llvm_fn,
undefined,
@@ -8674,7 +8837,7 @@ pub const FuncGen = struct {
_ = inst;
const o = self.dg.object;
const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
llvm_fn,
undefined,
@@ -8701,7 +8864,7 @@ pub const FuncGen = struct {
const params = [_]*llvm.Value{
(try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
};
- const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
+ const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
llvm_fn,
&params,
@@ -8727,7 +8890,7 @@ pub const FuncGen = struct {
(try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
};
const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
- self.builder.buildCall(
+ self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
llvm_fn,
&params,
@@ -9256,7 +9419,7 @@ pub const FuncGen = struct {
Builder.Constant.false.toLlvm(&o.builder),
};
const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCall(
+ self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
fn_val,
&params,
@@ -9283,7 +9446,7 @@ pub const FuncGen = struct {
const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCall(
+ self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
fn_val,
&params,
@@ -9331,7 +9494,7 @@ pub const FuncGen = struct {
const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
- self.builder.buildCall(
+ self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
fn_val,
&params,
@@ -9389,16 +9552,15 @@ pub const FuncGen = struct {
const enum_ty = self.typeOf(un_op);
const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
- const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
- llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .Fast,
- .Auto,
+ return self.wip.call(
+ .normal,
+ .fastcc,
+ .none,
+ llvm_fn.typeOf(&o.builder),
+ llvm_fn.toValue(&o.builder),
+ &.{operand},
"",
- ), &self.wip);
+ );
}
fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
@@ -9416,13 +9578,16 @@ pub const FuncGen = struct {
fqn.fmt(&mod.intern_pool),
});
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+
const fn_type = try o.builder.fnType(.i1, &.{
try o.lowerType(enum_type.tag_ty.toType()),
}, .normal);
- const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
+ const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
fn_val.setLinkage(.Internal);
fn_val.setFunctionCallConv(.Fast);
- o.addCommonFnAttributes(fn_val);
+ try o.addCommonFnAttributes(&attributes, fn_val);
var global = Builder.Global{
.linkage = .internal,
@@ -9431,6 +9596,8 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
+ .call_conv = .fastcc,
+ .attributes = try attributes.finish(&o.builder),
};
try o.builder.llvm.globals.append(self.gpa, fn_val);
_ = try o.builder.addGlobal(llvm_fn_name, global);
@@ -9470,19 +9637,14 @@ pub const FuncGen = struct {
const enum_ty = self.typeOf(un_op);
const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
- const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
- const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
- return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
- self.builder.buildCall(
- llvm_fn_ty.toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .Fast,
- .Auto,
- "",
- ),
- &self.wip,
+ return self.wip.call(
+ .normal,
+ .fastcc,
+ .none,
+ llvm_fn.typeOf(&o.builder),
+ llvm_fn.toValue(&o.builder),
+ &.{operand},
+ "",
);
}
@@ -9499,16 +9661,19 @@ pub const FuncGen = struct {
const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+
const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
const usize_ty = try o.lowerType(Type.usize);
const fn_type = try o.builder.fnType(ret_ty, &.{
try o.lowerType(enum_type.tag_ty.toType()),
}, .normal);
- const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
+ const fn_val = o.llvm_module.addFunction(llvm_fn_name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
fn_val.setLinkage(.Internal);
fn_val.setFunctionCallConv(.Fast);
- o.addCommonFnAttributes(fn_val);
+ try o.addCommonFnAttributes(&attributes, fn_val);
var global = Builder.Global{
.linkage = .internal,
@@ -9517,6 +9682,8 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
+ .call_conv = .fastcc,
+ .attributes = try attributes.finish(&o.builder),
};
try o.builder.llvm.globals.append(self.gpa, fn_val);
gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
@@ -9561,7 +9728,7 @@ pub const FuncGen = struct {
const slice_val = try o.builder.structValue(ret_ty, &.{
global_index.toConst(),
- try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
+ try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
});
const return_block = try wip.block(1, "Name");
@@ -9590,11 +9757,14 @@ pub const FuncGen = struct {
// Function signature: fn (anyerror) bool
const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
- const llvm_fn = o.llvm_module.addFunction(name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
+ const llvm_fn = o.llvm_module.addFunction(name.slice(&o.builder).?, fn_type.toLlvm(&o.builder));
+
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
llvm_fn.setLinkage(.Internal);
llvm_fn.setFunctionCallConv(.Fast);
- o.addCommonFnAttributes(llvm_fn);
+ try o.addCommonFnAttributes(&attributes, llvm_fn);
var global = Builder.Global{
.linkage = .internal,
@@ -9603,6 +9773,8 @@ pub const FuncGen = struct {
};
var function = Builder.Function{
.global = @enumFromInt(o.builder.globals.count()),
+ .call_conv = .fastcc,
+ .attributes = try attributes.finish(&o.builder),
};
try o.builder.llvm.globals.append(self.gpa, llvm_fn);
@@ -9731,18 +9903,14 @@ pub const FuncGen = struct {
// accum = f(accum, vec[i]);
const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
const element = try self.wip.extractElement(operand_vector, i, "");
- const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
- const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
- self.builder.buildCall(
- llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
- llvm_fn.toLlvm(&o.builder),
- &params,
- params.len,
- .C,
- .Auto,
- "",
- ),
- &self.wip,
+ const new_accum = try self.wip.call(
+ .normal,
+ .ccc,
+ .none,
+ llvm_fn.typeOf(&o.builder),
+ llvm_fn.toValue(&o.builder),
+ &.{ accum, element },
+ "",
);
_ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
@@ -10190,7 +10358,7 @@ pub const FuncGen = struct {
(try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
(try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
};
- _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
+ _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCallOld(
llvm_fn_ty.toLlvm(&o.builder),
fn_val,
&params,
@@ -10222,7 +10390,7 @@ pub const FuncGen = struct {
const args: [0]*llvm.Value = .{};
const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
- return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
+ return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
llvm_fn,
&args,
@@ -10252,12 +10420,15 @@ pub const FuncGen = struct {
const dimension = pl_op.payload;
if (dimension >= 3) return o.builder.intValue(.i32, 1);
+ var attributes: Builder.FunctionAttributes.Wip = .{};
+ defer attributes.deinit(&o.builder);
+
// Fetch the dispatch pointer, which points to this structure:
// https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
const args: [0]*llvm.Value = .{};
const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
- const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCall(
+ const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCallOld(
(try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
llvm_fn,
&args,
@@ -10266,6 +10437,9 @@ pub const FuncGen = struct {
.Auto,
"",
), &self.wip);
+ try attributes.addRetAttr(.{
+ .@"align" = comptime Builder.Alignment.fromByteUnits(4),
+ }, &o.builder);
o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
// Load the work_group_* member from the struct as u16.
@@ -10298,7 +10472,7 @@ pub const FuncGen = struct {
const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
const name = try o.builder.string("__zig_err_name_table");
- const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?);
+ const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.slice(&o.builder).?);
error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
error_name_table_global.setLinkage(.Private);
error_name_table_global.setGlobalConstant(.True);
@@ -10751,7 +10925,7 @@ pub const FuncGen = struct {
);
const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
- fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
+ fg.builder.buildCallOld(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
&fg.wip,
);
return call;
@@ -10991,33 +11165,33 @@ fn toLlvmAtomicRmwBinOp(
};
}
-fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {
+fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) Builder.CallConv {
return switch (cc) {
- .Unspecified, .Inline, .Async => .Fast,
- .C, .Naked => .C,
- .Stdcall => .X86_StdCall,
- .Fastcall => .X86_FastCall,
+ .Unspecified, .Inline, .Async => .fastcc,
+ .C, .Naked => .ccc,
+ .Stdcall => .x86_stdcallcc,
+ .Fastcall => .x86_fastcallcc,
.Vectorcall => return switch (target.cpu.arch) {
- .x86, .x86_64 => .X86_VectorCall,
- .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,
+ .x86, .x86_64 => .x86_vectorcallcc,
+ .aarch64, .aarch64_be, .aarch64_32 => .aarch64_vector_pcs,
else => unreachable,
},
- .Thiscall => .X86_ThisCall,
- .APCS => .ARM_APCS,
- .AAPCS => .ARM_AAPCS,
- .AAPCSVFP => .ARM_AAPCS_VFP,
+ .Thiscall => .x86_thiscallcc,
+ .APCS => .arm_apcscc,
+ .AAPCS => .arm_aapcscc,
+ .AAPCSVFP => .arm_aapcs_vfpcc,
.Interrupt => return switch (target.cpu.arch) {
- .x86, .x86_64 => .X86_INTR,
- .avr => .AVR_INTR,
- .msp430 => .MSP430_INTR,
+ .x86, .x86_64 => .x86_intrcc,
+ .avr => .avr_intrcc,
+ .msp430 => .msp430_intrcc,
else => unreachable,
},
- .Signal => .AVR_SIGNAL,
- .SysV => .X86_64_SysV,
- .Win64 => .Win64,
+ .Signal => .avr_signalcc,
+ .SysV => .x86_64_sysvcc,
+ .Win64 => .win64cc,
.Kernel => return switch (target.cpu.arch) {
- .nvptx, .nvptx64 => .PTX_Kernel,
- .amdgcn => .AMDGPU_KERNEL,
+ .nvptx, .nvptx64 => .ptx_kernel,
+ .amdgcn => .amdgpu_kernel,
else => unreachable,
},
};