10351
10352
10353
10354
10355
10356
10357
10358
10359
10360
10361
10362
10363
10364
10365
10366
10367
10368
10369
10370
10371
10372
10373
10374
10375
10376
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393
10394
10395
10396
10397
10398
10399
10400
10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416
10417
10418
10419
10420
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436
10437
10438
10439
10440
10441
10442
10443
10444
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 bfa_buf: ExpectedContents = undefined;
var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa);
const allocator = bfa.allocator();
const name = name: {
{
var aw: Writer.Allocating = .fromArrayList(self.gpa, &self.strtab_string_bytes);
const w = &aw.writer;
defer self.strtab_string_bytes = aw.toArrayList();
w.print("llvm.{s}", .{@tagName(id)}) catch return error.OutOfMemory;
for (overload) |ty| w.print(".{f}", .{ty.fmt(self, .m)}) catch return error.OutOfMemory;
}
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.array_list.Managed(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.array_list.Managed(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;
}