llvm: finish converting attributes to use Builder and the C LLVM API

This commit is contained in:
Jacob Young 2023-08-07 03:36:11 -04:00
parent b63d9745b5
commit 5b79f08ee8
5 changed files with 133 additions and 288 deletions

View File

@ -1314,28 +1314,21 @@ pub const Object = struct {
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
@ -1346,10 +1339,6 @@ pub const Object = struct {
.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");
o.addFnAttrString(llvm_func, "stack-protector-buffer-size", arg);
}
// TODO: disable this if safety is off for the function scope
@ -1358,13 +1347,11 @@ pub const Object = struct {
.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", "");
}
if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| {
@ -1389,14 +1376,8 @@ pub const Object = struct {
} else .none;
if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
.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");
},
.signed => try attributes.addRetAttr(.signext, &o.builder),
.unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
};
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
@ -1437,7 +1418,7 @@ pub const Object = struct {
} else {
args.appendAssumeCapacity(param);
try o.addByValParamAttrsOld(&attributes, llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, llvm_arg_i);
}
llvm_arg_i += 1;
},
@ -1447,7 +1428,7 @@ pub const Object = struct {
const param = wip.arg(llvm_arg_i);
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
try o.addByRefParamAttrsOld(&attributes, llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
llvm_arg_i += 1;
if (isByRef(param_ty, mod)) {
@ -1463,7 +1444,6 @@ pub const Object = struct {
const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
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)) {
@ -1500,23 +1480,19 @@ pub const Object = struct {
if (math.cast(u5, it.zig_index - 1)) |i| {
if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
}
}
if (param_ty.zigTypeTag(mod) != .Optional) {
try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
}
if (ptr_info.flags.is_const) {
try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
}
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);
@ -1590,7 +1566,7 @@ pub const Object = struct {
}
}
function.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
function.setAttributes(try attributes.finish(&o.builder), &o.builder);
var di_file: ?*llvm.DIFile = null;
var di_scope: ?*llvm.DIScope = null;
@ -2951,15 +2927,11 @@ pub const Object = struct {
.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);
}
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);
}
}
}
@ -2969,12 +2941,9 @@ pub const Object = struct {
// 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());
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;
}
@ -2984,7 +2953,6 @@ pub const Object = struct {
if (err_return_tracing) {
try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
o.addArgAttr(llvm_fn, llvm_arg_i, "nonnull");
llvm_arg_i += 1;
}
@ -2995,7 +2963,6 @@ pub const Object = struct {
},
.Naked => {
try attributes.addFnAttr(.naked, &o.builder);
o.addFnAttr(llvm_fn, "naked");
},
.Async => {
function.call_conv = .fastcc;
@ -3014,11 +2981,10 @@ pub const Object = struct {
}
// Function attributes that are independent of analysis results of the function body.
try o.addCommonFnAttributes(&attributes, llvm_fn);
try o.addCommonFnAttributes(&attributes);
if (fn_info.return_type == .noreturn_type) {
try attributes.addFnAttr(.noreturn, &o.builder);
o.addFnAttr(llvm_fn, "noreturn");
}
// Add parameter attributes. We handle only the case of extern functions (no body)
@ -3031,7 +2997,7 @@ pub const Object = 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)) {
try o.addByValParamAttrsOld(&attributes, llvm_fn, 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 => {
@ -3039,11 +3005,10 @@ pub const Object = struct {
const param_llvm_ty = try o.lowerType(param_ty.toType());
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);
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);
o.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
},
// No attributes needed for these.
.no_bits,
@ -3060,43 +3025,36 @@ 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);
global.kind.function.setAttributes(try attributes.finish(&o.builder), &o.builder);
return global.kind.function;
}
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
comp.bin_file.options.no_builtin)
@ -3107,38 +3065,31 @@ pub const Object = struct {
// 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", "");
}
}
@ -4483,69 +4434,6 @@ pub const Object = struct {
return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty);
}
fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
return o.addAttrInt(val, index, name, 0);
}
fn addArgAttr(o: *Object, fn_val: *llvm.Value, param_index: u32, attr_name: []const u8) void {
return o.addAttr(fn_val, param_index + 1, attr_name);
}
fn addArgAttrInt(o: *Object, fn_val: *llvm.Value, param_index: u32, attr_name: []const u8, int: u64) void {
return o.addAttrInt(fn_val, param_index + 1, attr_name, int);
}
fn removeAttr(val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
assert(kind_id != 0);
val.removeEnumAttributeAtIndex(index, kind_id);
}
fn addAttrInt(
o: *Object,
val: *llvm.Value,
index: llvm.AttributeIndex,
name: []const u8,
int: u64,
) void {
const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
assert(kind_id != 0);
const llvm_attr = o.builder.llvm.context.createEnumAttribute(kind_id, int);
val.addAttributeAtIndex(index, llvm_attr);
}
fn addAttrString(
o: *Object,
val: *llvm.Value,
index: llvm.AttributeIndex,
name: []const u8,
value: []const u8,
) void {
const llvm_attr = o.builder.llvm.context.createStringAttribute(
name.ptr,
@intCast(name.len),
value.ptr,
@intCast(value.len),
);
val.addAttributeAtIndex(index, llvm_attr);
}
fn addFnAttr(o: *Object, val: *llvm.Value, name: []const u8) void {
o.addAttr(val, std.math.maxInt(llvm.AttributeIndex), name);
}
fn addFnAttrString(o: *Object, val: *llvm.Value, name: []const u8, value: []const u8) void {
o.addAttrString(val, std.math.maxInt(llvm.AttributeIndex), name, value);
}
fn removeFnAttr(fn_val: *llvm.Value, name: []const u8) void {
removeAttr(fn_val, std.math.maxInt(llvm.AttributeIndex), name);
}
fn addFnAttrInt(o: *Object, fn_val: *llvm.Value, name: []const u8, int: u64) void {
return o.addAttrInt(fn_val, std.math.maxInt(llvm.AttributeIndex), name, int);
}
/// If the operand type of an atomic operation is not byte sized we need to
/// widen it before using it and then truncate the result.
/// RMW exchange of floating-point values is bitcasted to same-sized integer
@ -4608,80 +4496,13 @@ pub const Object = struct {
attributes: *Builder.FunctionAttributes.Wip,
llvm_arg_i: u32,
alignment: Builder.Alignment,
byval_attr: bool,
byval: 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,
) 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 = 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 => {
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 addByRefParamAttrsOld(
o: *Object,
attributes: *Builder.FunctionAttributes.Wip,
llvm_fn: *llvm.Value,
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);
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.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));
}
if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
}
};
@ -9503,16 +9324,16 @@ pub const FuncGen = struct {
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
try o.addCommonFnAttributes(&attributes, function_index.toLlvm(&o.builder));
try o.addCommonFnAttributes(&attributes);
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
function_index.ptrConst(&o.builder).global.ptr(&o.builder).linkage = .internal;
function_index.ptr(&o.builder).call_conv = .fastcc;
function_index.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
gop.value_ptr.* = function_index;
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
var wip = try Builder.WipFunction.init(&o.builder, function_index);
defer wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
@ -9577,16 +9398,16 @@ pub const FuncGen = struct {
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
try o.addCommonFnAttributes(&attributes, function_index.toLlvm(&o.builder));
try o.addCommonFnAttributes(&attributes);
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
function_index.ptrConst(&o.builder).global.ptr(&o.builder).linkage = .internal;
function_index.ptr(&o.builder).call_conv = .fastcc;
function_index.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
var wip = try Builder.WipFunction.init(&o.builder, function_index);
defer wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
@ -9659,14 +9480,14 @@ pub const FuncGen = struct {
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
try o.addCommonFnAttributes(&attributes, function_index.toLlvm(&o.builder));
try o.addCommonFnAttributes(&attributes);
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
function_index.ptrConst(&o.builder).global.ptr(&o.builder).linkage = .internal;
function_index.ptr(&o.builder).call_conv = .fastcc;
function_index.ptr(&o.builder).attributes = try attributes.finish(&o.builder);
function_index.toLlvm(&o.builder).setLinkage(.Internal);
function_index.toLlvm(&o.builder).setFunctionCallConv(.Fast);
return function_index;
}

View File

@ -1349,21 +1349,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) {
@ -3147,6 +3155,86 @@ pub const Function = struct {
return self.toConst(builder).toValue();
}
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()) |name| {
const slice = name.slice(builder).?;
llvm_function.removeStringAttributeAtIndex(
llvm_attribute_index,
slice.ptr,
@intCast(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 toLlvm(self: Index, builder: *const Builder) *llvm.Value {
return self.ptrConst(builder).global.toLlvm(builder);
}
@ -5048,9 +5136,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),
);
}
@ -7368,16 +7455,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,
@ -7411,7 +7498,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,
};
},

View File

@ -115,12 +115,15 @@ pub const Context = opaque {
};
pub const Value = opaque {
pub const addAttributeAtIndex = ZigLLVMAddAttributeAtIndex;
extern fn ZigLLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
extern fn LLVMAddAttributeAtIndex(F: *Value, Idx: AttributeIndex, A: *Attribute) void;
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void;
pub const removeStringAttributeAtIndex = LLVMRemoveStringAttributeAtIndex;
extern fn LLVMRemoveStringAttributeAtIndex(F: *Value, Idx: AttributeIndex, K: [*]const u8, KLen: c_uint) void;
pub const getFirstBasicBlock = LLVMGetFirstBasicBlock;
extern fn LLVMGetFirstBasicBlock(Fn: *Value) ?*BasicBlock;
@ -342,9 +345,6 @@ pub const Value = opaque {
pub const deleteFunction = LLVMDeleteFunction;
extern fn LLVMDeleteFunction(Fn: *Value) void;
pub const addSretAttr = ZigLLVMAddSretAttr;
extern fn ZigLLVMAddSretAttr(fn_ref: *Value, type_val: *Type) void;
pub const getParam = LLVMGetParam;
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
@ -369,9 +369,6 @@ pub const Value = opaque {
pub const getAlignment = LLVMGetAlignment;
extern fn LLVMGetAlignment(V: *Value) c_uint;
pub const addFunctionAttr = ZigLLVMAddFunctionAttr;
extern fn ZigLLVMAddFunctionAttr(Fn: *Value, attr_name: [*:0]const u8, attr_value: [*:0]const u8) void;
pub const addByValAttr = ZigLLVMAddByValAttr;
extern fn ZigLLVMAddByValAttr(Fn: *Value, ArgNo: c_uint, type: *Type) void;

View File

@ -408,14 +408,6 @@ void ZigLLVMSetTailCallKind(LLVMValueRef Call, enum ZigLLVMTailCallKind TailCall
unwrap<CallInst>(Call)->setTailCallKind(TCK);
}
void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
if (isa<Function>(unwrap(Val))) {
unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
} else {
unwrap<CallInst>(Val)->addAttributeAtIndex(Idx, unwrap(A));
}
}
LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
{
@ -950,36 +942,6 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
}
}
void ZigLLVMAddByValAttr(LLVMValueRef Val, unsigned ArgNo, LLVMTypeRef type_val) {
if (isa<Function>(unwrap(Val))) {
Function *func = unwrap<Function>(Val);
AttrBuilder attr_builder(func->getContext());
Type *llvm_type = unwrap<Type>(type_val);
attr_builder.addByValAttr(llvm_type);
func->addParamAttrs(ArgNo, attr_builder);
} else {
CallInst *call = unwrap<CallInst>(Val);
AttrBuilder attr_builder(call->getContext());
Type *llvm_type = unwrap<Type>(type_val);
attr_builder.addByValAttr(llvm_type);
// NOTE: +1 here since index 0 refers to the return value
call->addAttributeAtIndex(ArgNo + 1, attr_builder.getAttribute(Attribute::ByVal));
}
}
void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {
Function *func = unwrap<Function>(fn_ref);
AttrBuilder attr_builder(func->getContext());
Type *llvm_type = unwrap<Type>(type_val);
attr_builder.addStructRetAttr(llvm_type);
func->addParamAttrs(0, attr_builder);
}
void ZigLLVMAddFunctionAttr(LLVMValueRef fn_ref, const char *attr_name, const char *attr_value) {
Function *func = unwrap<Function>(fn_ref);
func->addFnAttr(attr_name, attr_value);
}
void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
cl::ParseCommandLineOptions(argc, argv);
}
@ -1172,14 +1134,6 @@ bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early, bool disab
return lld::wasm::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output);
}
inline LLVMAttributeRef wrap(Attribute Attr) {
return reinterpret_cast<LLVMAttributeRef>(Attr.getRawPointer());
}
inline Attribute unwrap(LLVMAttributeRef Attr) {
return Attribute::fromRawPointer(Attr);
}
LLVMValueRef ZigLLVMBuildAndReduce(LLVMBuilderRef B, LLVMValueRef Val) {
return wrap(unwrap(B)->CreateAndReduce(unwrap(Val)));
}

View File

@ -122,15 +122,6 @@ enum ZigLLVM_CallingConv {
ZigLLVM_MaxID = 1023,
};
enum ZigLLVM_CallAttr {
ZigLLVM_CallAttrAuto,
ZigLLVM_CallAttrNeverTail,
ZigLLVM_CallAttrNeverInline,
ZigLLVM_CallAttrAlwaysTail,
ZigLLVM_CallAttrAlwaysInline,
};
ZIG_EXTERN_C void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A);
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
@ -301,11 +292,6 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDbgValueIntrinsicAtEnd(struct ZigLLVMDIBu
ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
ZIG_EXTERN_C void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val);
ZIG_EXTERN_C void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val);
ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv);
ZIG_EXTERN_C ZigLLVMDIGlobalVariable* ZigLLVMGlobalGetVariable(ZigLLVMDIGlobalVariableExpression *global_variable_expression);