Source
pub fn getIntrinsic(
self: *Builder,
id: Intrinsic,
overload: []const Type,
) Allocator.Error!Function.Index {
const ExpectedContents = extern union {
attrs: extern struct {
params: [expected_args_len]Type,
fn_attrs: [FunctionAttributes.params_index + expected_args_len]Attributes,
attrs: [expected_attrs_len]Attribute.Index,
fields: [expected_fields_len]Type,
},
};
var stack align(@max(@alignOf(std.heap.StackFallbackAllocator(0)), @alignOf(ExpectedContents))) =
std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
const allocator = stack.get();
const name = name: {
const writer = self.strtab_string_bytes.writer(self.gpa);
try writer.print("llvm.{s}", .{@tagName(id)});
for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)});
break :name try self.trailingStrtabString();
};
if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function;
const signature = Intrinsic.signatures.get(id);
const param_types = try allocator.alloc(Type, signature.params.len);
defer allocator.free(param_types);
const function_attributes = try allocator.alloc(
Attributes,
FunctionAttributes.params_index + (signature.params.len - signature.ret_len),
);
defer allocator.free(function_attributes);
var attributes: struct {
builder: *Builder,
list: std.ArrayList(Attribute.Index),
fn deinit(state: *@This()) void {
state.list.deinit();
state.* = undefined;
}
fn get(state: *@This(), attributes: []const Attribute) Allocator.Error!Attributes {
try state.list.resize(attributes.len);
for (state.list.items, attributes) |*item, attribute|
item.* = try state.builder.attr(attribute);
return state.builder.attrs(state.list.items);
}
} = .{ .builder = self, .list = std.ArrayList(Attribute.Index).init(allocator) };
defer attributes.deinit();
var overload_index: usize = 0;
function_attributes[FunctionAttributes.function_index] = try attributes.get(signature.attrs);
function_attributes[FunctionAttributes.return_index] = .none; // needed for void return
for (0.., param_types, signature.params) |param_index, *param_type, signature_param| {
switch (signature_param.kind) {
.type => |ty| param_type.* = ty,
.overloaded => {
param_type.* = overload[overload_index];
overload_index += 1;
},
.matches, .matches_scalar, .matches_changed_scalar => {},
}
function_attributes[
if (param_index < signature.ret_len)
FunctionAttributes.return_index
else
FunctionAttributes.params_index + (param_index - signature.ret_len)
] = try attributes.get(signature_param.attrs);
}
assert(overload_index == overload.len);
for (param_types, signature.params) |*param_type, signature_param| {
param_type.* = switch (signature_param.kind) {
.type, .overloaded => continue,
.matches => |param_index| param_types[param_index],
.matches_scalar => |param_index| param_types[param_index].scalarType(self),
.matches_changed_scalar => |info| try param_types[info.index]
.changeScalar(info.scalar, self),
};
}
const function_index = try self.addFunction(try self.fnType(switch (signature.ret_len) {
0 => .void,
1 => param_types[0],
else => try self.structType(.normal, param_types[0..signature.ret_len]),
}, param_types[signature.ret_len..], .normal), name, .default);
function_index.ptr(self).attributes = try self.fnAttrs(function_attributes);
return function_index;
}