stage2: move function types to InternPool

This commit is contained in:
Andrew Kelley
2023-05-15 20:09:54 -07:00
parent 6a9a918fbe
commit 17882162b3
23 changed files with 822 additions and 792 deletions

View File

@@ -1507,7 +1507,7 @@ pub const DeclGen = struct {
const fn_decl = mod.declPtr(fn_decl_index);
const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind);
const fn_info = fn_decl.ty.fnInfo();
const fn_info = mod.typeToFunc(fn_decl.ty).?;
if (fn_info.cc == .Naked) {
switch (kind) {
.forward => try w.writeAll("zig_naked_decl "),
@@ -1517,7 +1517,7 @@ pub const DeclGen = struct {
}
if (fn_decl.val.castTag(.function)) |func_payload|
if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
if (fn_info.return_type.ip_index == .noreturn_type) try w.writeAll("zig_noreturn ");
if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
const trailing = try renderTypePrefix(
dg.decl_index,
@@ -3455,7 +3455,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
} else {
try reap(f, inst, &.{un_op});
// Not even allowed to return void in a naked function.
if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() != .Naked else true)
if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention(mod) != .Naked else true)
try writer.writeAll("return;\n");
}
return .none;
@@ -4094,7 +4094,7 @@ fn airCall(
) !CValue {
const mod = f.object.dg.module;
// Not even allowed to call panic in a naked function.
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none;
const gpa = f.object.dg.gpa;
const writer = f.object.writer();
@@ -4143,7 +4143,7 @@ fn airCall(
else => unreachable,
};
const ret_ty = fn_ty.fnReturnType();
const ret_ty = fn_ty.fnReturnType(mod);
const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod);
const result_local = result: {
@@ -4622,8 +4622,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airUnreach(f: *Function) !CValue {
const mod = f.object.dg.module;
// Not even allowed to call unreachable in a naked function.
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none;
try f.object.writer().writeAll("zig_unreachable();\n");
return .none;

View File

@@ -1720,7 +1720,7 @@ pub const CType = extern union {
.Opaque => self.init(.void),
.Fn => {
const info = ty.fnInfo();
const info = mod.typeToFunc(ty).?;
if (!info.is_generic) {
if (lookup.isMutable()) {
const param_kind: Kind = switch (kind) {
@@ -1728,10 +1728,10 @@ pub const CType = extern union {
.complete, .parameter, .global => .parameter,
.payload => unreachable,
};
_ = try lookup.typeToIndex(info.return_type, param_kind);
_ = try lookup.typeToIndex(info.return_type.toType(), param_kind);
for (info.param_types) |param_type| {
if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue;
_ = try lookup.typeToIndex(param_type, param_kind);
if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
_ = try lookup.typeToIndex(param_type.toType(), param_kind);
}
}
self.init(if (info.is_var_args) .varargs_function else .function);
@@ -2013,7 +2013,7 @@ pub const CType = extern union {
.function,
.varargs_function,
=> {
const info = ty.fnInfo();
const info = mod.typeToFunc(ty).?;
assert(!info.is_generic);
const param_kind: Kind = switch (kind) {
.forward, .forward_parameter => .forward_parameter,
@@ -2023,21 +2023,21 @@ pub const CType = extern union {
var c_params_len: usize = 0;
for (info.param_types) |param_type| {
if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
c_params_len += 1;
}
const params_pl = try arena.alloc(Index, c_params_len);
var c_param_i: usize = 0;
for (info.param_types) |param_type| {
if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue;
params_pl[c_param_i] = store.set.typeToIndex(param_type, mod, param_kind).?;
if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
params_pl[c_param_i] = store.set.typeToIndex(param_type.toType(), mod, param_kind).?;
c_param_i += 1;
}
const fn_pl = try arena.create(Payload.Function);
fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
.return_type = store.set.typeToIndex(info.return_type, mod, param_kind).?,
.return_type = store.set.typeToIndex(info.return_type.toType(), mod, param_kind).?,
.param_types = params_pl,
} };
return initPayload(fn_pl);
@@ -2145,7 +2145,7 @@ pub const CType = extern union {
=> {
if (ty.zigTypeTag(mod) != .Fn) return false;
const info = ty.fnInfo();
const info = mod.typeToFunc(ty).?;
assert(!info.is_generic);
const data = cty.cast(Payload.Function).?.data;
const param_kind: Kind = switch (self.kind) {
@@ -2154,18 +2154,18 @@ pub const CType = extern union {
.payload => unreachable,
};
if (!self.eqlRecurse(info.return_type, data.return_type, param_kind))
if (!self.eqlRecurse(info.return_type.toType(), data.return_type, param_kind))
return false;
var c_param_i: usize = 0;
for (info.param_types) |param_type| {
if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
if (c_param_i >= data.param_types.len) return false;
const param_cty = data.param_types[c_param_i];
c_param_i += 1;
if (!self.eqlRecurse(param_type, param_cty, param_kind))
if (!self.eqlRecurse(param_type.toType(), param_cty, param_kind))
return false;
}
return c_param_i == data.param_types.len;
@@ -2258,7 +2258,7 @@ pub const CType = extern union {
.function,
.varargs_function,
=> {
const info = ty.fnInfo();
const info = mod.typeToFunc(ty).?;
assert(!info.is_generic);
const param_kind: Kind = switch (self.kind) {
.forward, .forward_parameter => .forward_parameter,
@@ -2266,10 +2266,10 @@ pub const CType = extern union {
.payload => unreachable,
};
self.updateHasherRecurse(hasher, info.return_type, param_kind);
self.updateHasherRecurse(hasher, info.return_type.toType(), param_kind);
for (info.param_types) |param_type| {
if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue;
self.updateHasherRecurse(hasher, param_type, param_kind);
if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
self.updateHasherRecurse(hasher, param_type.toType(), param_kind);
}
},

View File

@@ -954,17 +954,17 @@ pub const Object = struct {
builder.positionBuilderAtEnd(entry_block);
// This gets the LLVM values from the function and stores them in `dg.args`.
const fn_info = decl.ty.fnInfo();
const fn_info = mod.typeToFunc(decl.ty).?;
const sret = firstParamSRet(fn_info, mod);
const ret_ptr = if (sret) llvm_func.getParam(0) else null;
const gpa = dg.gpa;
if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type)) |s| switch (s) {
if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
.signed => dg.addAttr(llvm_func, 0, "signext"),
.unsigned => dg.addAttr(llvm_func, 0, "zeroext"),
};
const err_return_tracing = fn_info.return_type.isError(mod) and
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
mod.comp.bin_file.options.error_return_tracing;
const err_ret_trace = if (err_return_tracing)
@@ -986,7 +986,7 @@ pub const Object = struct {
.byval => {
assert(!it.byval_attr);
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types[param_index];
const param_ty = fn_info.param_types[param_index].toType();
const param = llvm_func.getParam(llvm_arg_i);
try args.ensureUnusedCapacity(1);
@@ -1005,7 +1005,7 @@ pub const Object = struct {
llvm_arg_i += 1;
},
.byref => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param_llvm_ty = try dg.lowerType(param_ty);
const param = llvm_func.getParam(llvm_arg_i);
const alignment = param_ty.abiAlignment(mod);
@@ -1024,7 +1024,7 @@ pub const Object = struct {
}
},
.byref_mut => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param_llvm_ty = try dg.lowerType(param_ty);
const param = llvm_func.getParam(llvm_arg_i);
const alignment = param_ty.abiAlignment(mod);
@@ -1044,7 +1044,7 @@ pub const Object = struct {
},
.abi_sized_int => {
assert(!it.byval_attr);
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param = llvm_func.getParam(llvm_arg_i);
llvm_arg_i += 1;
@@ -1071,7 +1071,7 @@ pub const Object = struct {
},
.slice => {
assert(!it.byval_attr);
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const ptr_info = param_ty.ptrInfo(mod);
if (math.cast(u5, it.zig_index - 1)) |i| {
@@ -1104,7 +1104,7 @@ pub const Object = struct {
.multiple_llvm_types => {
assert(!it.byval_attr);
const field_types = it.llvm_types_buffer[0..it.llvm_types_len];
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param_llvm_ty = try dg.lowerType(param_ty);
const param_alignment = param_ty.abiAlignment(mod);
const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, param_alignment, target);
@@ -1135,7 +1135,7 @@ pub const Object = struct {
args.appendAssumeCapacity(casted);
},
.float_array => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param_llvm_ty = try dg.lowerType(param_ty);
const param = llvm_func.getParam(llvm_arg_i);
llvm_arg_i += 1;
@@ -1153,7 +1153,7 @@ pub const Object = struct {
}
},
.i32_array, .i64_array => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const param_llvm_ty = try dg.lowerType(param_ty);
const param = llvm_func.getParam(llvm_arg_i);
llvm_arg_i += 1;
@@ -1182,7 +1182,7 @@ pub const Object = struct {
const line_number = decl.src_line + 1;
const is_internal_linkage = decl.val.tag() != .extern_fn and
!mod.decl_exports.contains(decl_index);
const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type)
llvm.DIFlags.NoReturn
else
0;
@@ -2331,26 +2331,26 @@ pub const Object = struct {
return full_di_ty;
},
.Fn => {
const fn_info = ty.fnInfo();
const fn_info = mod.typeToFunc(ty).?;
var param_di_types = std.ArrayList(*llvm.DIType).init(gpa);
defer param_di_types.deinit();
// Return type goes first.
if (fn_info.return_type.hasRuntimeBitsIgnoreComptime(mod)) {
if (fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) {
const sret = firstParamSRet(fn_info, mod);
const di_ret_ty = if (sret) Type.void else fn_info.return_type;
const di_ret_ty = if (sret) Type.void else fn_info.return_type.toType();
try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full));
if (sret) {
const ptr_ty = try mod.singleMutPtrType(fn_info.return_type);
const ptr_ty = try mod.singleMutPtrType(fn_info.return_type.toType());
try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
}
} else {
try param_di_types.append(try o.lowerDebugType(Type.void, .full));
}
if (fn_info.return_type.isError(mod) and
if (fn_info.return_type.toType().isError(mod) and
o.module.comp.bin_file.options.error_return_tracing)
{
const ptr_ty = try mod.singleMutPtrType(o.getStackTraceType());
@@ -2358,13 +2358,13 @@ pub const Object = struct {
}
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!param_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
if (isByRef(param_ty, mod)) {
const ptr_ty = try mod.singleMutPtrType(param_ty);
if (isByRef(param_ty.toType(), mod)) {
const ptr_ty = try mod.singleMutPtrType(param_ty.toType());
try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
} else {
try param_di_types.append(try o.lowerDebugType(param_ty, .full));
try param_di_types.append(try o.lowerDebugType(param_ty.toType(), .full));
}
}
@@ -2565,7 +2565,7 @@ pub const DeclGen = struct {
if (gop.found_existing) return gop.value_ptr.*;
assert(decl.has_tv);
const fn_info = zig_fn_type.fnInfo();
const fn_info = mod.typeToFunc(zig_fn_type).?;
const target = mod.getTarget();
const sret = firstParamSRet(fn_info, mod);
@@ -2598,11 +2598,11 @@ pub const DeclGen = struct {
dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
dg.addArgAttr(llvm_fn, 0, "noalias");
const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type);
const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type.toType());
llvm_fn.addSretAttr(raw_llvm_ret_ty);
}
const err_return_tracing = fn_info.return_type.isError(mod) and
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
mod.comp.bin_file.options.error_return_tracing;
if (err_return_tracing) {
@@ -2626,13 +2626,13 @@ pub const DeclGen = struct {
}
if (fn_info.alignment != 0) {
llvm_fn.setAlignment(fn_info.alignment);
llvm_fn.setAlignment(@intCast(c_uint, fn_info.alignment));
}
// Function attributes that are independent of analysis results of the function body.
dg.addCommonFnAttributes(llvm_fn);
if (fn_info.return_type.isNoReturn()) {
if (fn_info.return_type == .noreturn_type) {
dg.addFnAttr(llvm_fn, "noreturn");
}
@@ -2645,15 +2645,15 @@ pub const DeclGen = struct {
while (it.next()) |lowering| switch (lowering) {
.byval => {
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types[param_index];
const param_ty = fn_info.param_types[param_index].toType();
if (!isByRef(param_ty, mod)) {
dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1);
}
},
.byref => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_llvm_ty = try dg.lowerType(param_ty);
const alignment = param_ty.abiAlignment(mod);
const param_llvm_ty = try dg.lowerType(param_ty.toType());
const alignment = param_ty.toType().abiAlignment(mod);
dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
},
.byref_mut => {
@@ -3142,7 +3142,7 @@ pub const DeclGen = struct {
fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*llvm.Type {
const mod = dg.module;
const fn_info = fn_ty.fnInfo();
const fn_info = mod.typeToFunc(fn_ty).?;
const llvm_ret_ty = try lowerFnRetTy(dg, fn_info);
var llvm_params = std.ArrayList(*llvm.Type).init(dg.gpa);
@@ -3152,7 +3152,7 @@ pub const DeclGen = struct {
try llvm_params.append(dg.context.pointerType(0));
}
if (fn_info.return_type.isError(mod) and
if (fn_info.return_type.toType().isError(mod) and
mod.comp.bin_file.options.error_return_tracing)
{
const ptr_ty = try mod.singleMutPtrType(dg.object.getStackTraceType());
@@ -3163,19 +3163,19 @@ pub const DeclGen = struct {
while (it.next()) |lowering| switch (lowering) {
.no_bits => continue,
.byval => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
try llvm_params.append(try dg.lowerType(param_ty));
},
.byref, .byref_mut => {
try llvm_params.append(dg.context.pointerType(0));
},
.abi_sized_int => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const abi_size = @intCast(c_uint, param_ty.abiSize(mod));
try llvm_params.append(dg.context.intType(abi_size * 8));
},
.slice => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional)
param_ty.optionalChild(mod).slicePtrFieldType(&buf, mod)
@@ -3195,7 +3195,7 @@ pub const DeclGen = struct {
try llvm_params.append(dg.context.intType(16));
},
.float_array => |count| {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?);
const field_count = @intCast(c_uint, count);
const arr_ty = float_ty.arrayType(field_count);
@@ -3223,7 +3223,7 @@ pub const DeclGen = struct {
const mod = dg.module;
const lower_elem_ty = switch (elem_ty.zigTypeTag(mod)) {
.Opaque => true,
.Fn => !elem_ty.fnInfo().is_generic,
.Fn => !mod.typeToFunc(elem_ty).?.is_generic,
.Array => elem_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod),
else => elem_ty.hasRuntimeBitsIgnoreComptime(mod),
};
@@ -4204,7 +4204,7 @@ pub const DeclGen = struct {
const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
(is_fn_body and decl.ty.fnInfo().is_generic))
(is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))
{
return self.lowerPtrToVoid(tv.ty);
}
@@ -4354,7 +4354,7 @@ pub const DeclGen = struct {
llvm_fn: *llvm.Value,
param_ty: Type,
param_index: u32,
fn_info: Type.Payload.Function.Data,
fn_info: InternPool.Key.FuncType,
llvm_arg_i: u32,
) void {
const mod = dg.module;
@@ -4774,8 +4774,8 @@ pub const FuncGen = struct {
.Pointer => callee_ty.childType(mod),
else => unreachable,
};
const fn_info = zig_fn_ty.fnInfo();
const return_type = fn_info.return_type;
const fn_info = mod.typeToFunc(zig_fn_ty).?;
const return_type = fn_info.return_type.toType();
const llvm_fn = try self.resolveInst(pl_op.operand);
const target = mod.getTarget();
const sret = firstParamSRet(fn_info, mod);
@@ -4790,7 +4790,7 @@ pub const FuncGen = struct {
break :blk ret_ptr;
};
const err_return_tracing = fn_info.return_type.isError(mod) and
const err_return_tracing = return_type.isError(mod) and
self.dg.module.comp.bin_file.options.error_return_tracing;
if (err_return_tracing) {
try llvm_args.append(self.err_ret_trace.?);
@@ -4971,14 +4971,14 @@ pub const FuncGen = struct {
while (it.next()) |lowering| switch (lowering) {
.byval => {
const param_index = it.zig_index - 1;
const param_ty = fn_info.param_types[param_index];
const param_ty = fn_info.param_types[param_index].toType();
if (!isByRef(param_ty, mod)) {
self.dg.addByValParamAttrs(call, 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[param_index];
const param_ty = fn_info.param_types[param_index].toType();
const param_llvm_ty = try self.dg.lowerType(param_ty);
const alignment = param_ty.abiAlignment(mod);
self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
@@ -4998,7 +4998,7 @@ pub const FuncGen = struct {
.slice => {
assert(!it.byval_attr);
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_ty = fn_info.param_types[it.zig_index - 1].toType();
const ptr_info = param_ty.ptrInfo(mod);
const llvm_arg_i = it.llvm_index - 2;
@@ -5023,7 +5023,7 @@ pub const FuncGen = struct {
};
}
if (return_type.isNoReturn() and attr != .AlwaysTail) {
if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
return null;
}
@@ -5088,9 +5088,9 @@ pub const FuncGen = struct {
_ = self.builder.buildRetVoid();
return null;
}
const fn_info = self.dg.decl.ty.fnInfo();
const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
if (fn_info.return_type.isError(mod)) {
if (fn_info.return_type.toType().isError(mod)) {
// Functions with an empty error set are emitted with an error code
// return type and return zero so they can be function pointers coerced
// to functions that return anyerror.
@@ -5135,9 +5135,9 @@ pub const FuncGen = struct {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const ptr_ty = self.typeOf(un_op);
const ret_ty = ptr_ty.childType(mod);
const fn_info = self.dg.decl.ty.fnInfo();
const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
if (fn_info.return_type.isError(mod)) {
if (fn_info.return_type.toType().isError(mod)) {
// Functions with an empty error set are emitted with an error code
// return type and return zero so they can be function pointers coerced
// to functions that return anyerror.
@@ -6148,25 +6148,21 @@ pub const FuncGen = struct {
defer self.gpa.free(fqn);
const is_internal_linkage = !mod.decl_exports.contains(decl_index);
var fn_ty_pl: Type.Payload.Function = .{
.base = .{ .tag = .function },
.data = .{
.param_types = &.{},
.comptime_params = undefined,
.return_type = Type.void,
.alignment = 0,
.noalias_bits = 0,
.cc = .Unspecified,
.is_var_args = false,
.is_generic = false,
.is_noinline = false,
.align_is_generic = false,
.cc_is_generic = false,
.section_is_generic = false,
.addrspace_is_generic = false,
},
};
const fn_ty = Type.initPayload(&fn_ty_pl.base);
const fn_ty = try mod.funcType(.{
.param_types = &.{},
.return_type = .void_type,
.alignment = 0,
.noalias_bits = 0,
.comptime_bits = 0,
.cc = .Unspecified,
.is_var_args = false,
.is_generic = false,
.is_noinline = false,
.align_is_generic = false,
.cc_is_generic = false,
.section_is_generic = false,
.addrspace_is_generic = false,
});
const subprogram = dib.createFunction(
di_file.toScope(),
decl.name,
@@ -10546,31 +10542,31 @@ fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField {
}
}
fn firstParamSRet(fn_info: Type.Payload.Function.Data, mod: *Module) bool {
if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime(mod)) return false;
fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool {
if (!fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) return false;
const target = mod.getTarget();
switch (fn_info.cc) {
.Unspecified, .Inline => return isByRef(fn_info.return_type, mod),
.Unspecified, .Inline => return isByRef(fn_info.return_type.toType(), mod),
.C => switch (target.cpu.arch) {
.mips, .mipsel => return false,
.x86_64 => switch (target.os.tag) {
.windows => return x86_64_abi.classifyWindows(fn_info.return_type, mod) == .memory,
else => return firstParamSRetSystemV(fn_info.return_type, mod),
.windows => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory,
else => return firstParamSRetSystemV(fn_info.return_type.toType(), mod),
},
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, mod)[0] == .indirect,
.aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, mod) == .memory,
.arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, mod, .ret)) {
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type.toType(), mod)[0] == .indirect,
.aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type.toType(), mod) == .memory,
.arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type.toType(), mod, .ret)) {
.memory, .i64_array => return true,
.i32_array => |size| return size != 1,
.byval => return false,
},
.riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, mod) == .memory,
.riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type.toType(), mod) == .memory,
else => return false, // TODO investigate C ABI for other architectures
},
.SysV => return firstParamSRetSystemV(fn_info.return_type, mod),
.Win64 => return x86_64_abi.classifyWindows(fn_info.return_type, mod) == .memory,
.Stdcall => return !isScalar(mod, fn_info.return_type),
.SysV => return firstParamSRetSystemV(fn_info.return_type.toType(), mod),
.Win64 => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory,
.Stdcall => return !isScalar(mod, fn_info.return_type.toType()),
else => return false,
}
}
@@ -10585,13 +10581,14 @@ fn firstParamSRetSystemV(ty: Type, mod: *Module) bool {
/// In order to support the C calling convention, some return types need to be lowered
/// completely differently in the function prototype to honor the C ABI, and then
/// be effectively bitcasted to the actual return type.
fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
fn lowerFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type {
const mod = dg.module;
if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime(mod)) {
const return_type = fn_info.return_type.toType();
if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) {
// If the return type is an error set or an error union, then we make this
// anyerror return type instead, so that it can be coerced into a function
// pointer type which has anyerror as the return type.
if (fn_info.return_type.isError(mod)) {
if (return_type.isError(mod)) {
return dg.lowerType(Type.anyerror);
} else {
return dg.context.voidType();
@@ -10600,61 +10597,61 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
const target = mod.getTarget();
switch (fn_info.cc) {
.Unspecified, .Inline => {
if (isByRef(fn_info.return_type, mod)) {
if (isByRef(return_type, mod)) {
return dg.context.voidType();
} else {
return dg.lowerType(fn_info.return_type);
return dg.lowerType(return_type);
}
},
.C => {
switch (target.cpu.arch) {
.mips, .mipsel => return dg.lowerType(fn_info.return_type),
.mips, .mipsel => return dg.lowerType(return_type),
.x86_64 => switch (target.os.tag) {
.windows => return lowerWin64FnRetTy(dg, fn_info),
else => return lowerSystemVFnRetTy(dg, fn_info),
},
.wasm32 => {
if (isScalar(mod, fn_info.return_type)) {
return dg.lowerType(fn_info.return_type);
if (isScalar(mod, return_type)) {
return dg.lowerType(return_type);
}
const classes = wasm_c_abi.classifyType(fn_info.return_type, mod);
const classes = wasm_c_abi.classifyType(return_type, mod);
if (classes[0] == .indirect or classes[0] == .none) {
return dg.context.voidType();
}
assert(classes[0] == .direct and classes[1] == .none);
const scalar_type = wasm_c_abi.scalarType(fn_info.return_type, mod);
const scalar_type = wasm_c_abi.scalarType(return_type, mod);
const abi_size = scalar_type.abiSize(mod);
return dg.context.intType(@intCast(c_uint, abi_size * 8));
},
.aarch64, .aarch64_be => {
switch (aarch64_c_abi.classifyType(fn_info.return_type, mod)) {
switch (aarch64_c_abi.classifyType(return_type, mod)) {
.memory => return dg.context.voidType(),
.float_array => return dg.lowerType(fn_info.return_type),
.byval => return dg.lowerType(fn_info.return_type),
.float_array => return dg.lowerType(return_type),
.byval => return dg.lowerType(return_type),
.integer => {
const bit_size = fn_info.return_type.bitSize(mod);
const bit_size = return_type.bitSize(mod);
return dg.context.intType(@intCast(c_uint, bit_size));
},
.double_integer => return dg.context.intType(64).arrayType(2),
}
},
.arm, .armeb => {
switch (arm_c_abi.classifyType(fn_info.return_type, mod, .ret)) {
switch (arm_c_abi.classifyType(return_type, mod, .ret)) {
.memory, .i64_array => return dg.context.voidType(),
.i32_array => |len| if (len == 1) {
return dg.context.intType(32);
} else {
return dg.context.voidType();
},
.byval => return dg.lowerType(fn_info.return_type),
.byval => return dg.lowerType(return_type),
}
},
.riscv32, .riscv64 => {
switch (riscv_c_abi.classifyType(fn_info.return_type, mod)) {
switch (riscv_c_abi.classifyType(return_type, mod)) {
.memory => return dg.context.voidType(),
.integer => {
const bit_size = fn_info.return_type.bitSize(mod);
const bit_size = return_type.bitSize(mod);
return dg.context.intType(@intCast(c_uint, bit_size));
},
.double_integer => {
@@ -10664,50 +10661,52 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
};
return dg.context.structType(&llvm_types_buffer, 2, .False);
},
.byval => return dg.lowerType(fn_info.return_type),
.byval => return dg.lowerType(return_type),
}
},
// TODO investigate C ABI for other architectures
else => return dg.lowerType(fn_info.return_type),
else => return dg.lowerType(return_type),
}
},
.Win64 => return lowerWin64FnRetTy(dg, fn_info),
.SysV => return lowerSystemVFnRetTy(dg, fn_info),
.Stdcall => {
if (isScalar(mod, fn_info.return_type)) {
return dg.lowerType(fn_info.return_type);
if (isScalar(mod, return_type)) {
return dg.lowerType(return_type);
} else {
return dg.context.voidType();
}
},
else => return dg.lowerType(fn_info.return_type),
else => return dg.lowerType(return_type),
}
}
fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type {
const mod = dg.module;
switch (x86_64_abi.classifyWindows(fn_info.return_type, mod)) {
const return_type = fn_info.return_type.toType();
switch (x86_64_abi.classifyWindows(return_type, mod)) {
.integer => {
if (isScalar(mod, fn_info.return_type)) {
return dg.lowerType(fn_info.return_type);
if (isScalar(mod, return_type)) {
return dg.lowerType(return_type);
} else {
const abi_size = fn_info.return_type.abiSize(mod);
const abi_size = return_type.abiSize(mod);
return dg.context.intType(@intCast(c_uint, abi_size * 8));
}
},
.win_i128 => return dg.context.intType(64).vectorType(2),
.memory => return dg.context.voidType(),
.sse => return dg.lowerType(fn_info.return_type),
.sse => return dg.lowerType(return_type),
else => unreachable,
}
}
fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type {
const mod = dg.module;
if (isScalar(mod, fn_info.return_type)) {
return dg.lowerType(fn_info.return_type);
const return_type = fn_info.return_type.toType();
if (isScalar(mod, return_type)) {
return dg.lowerType(return_type);
}
const classes = x86_64_abi.classifySystemV(fn_info.return_type, mod, .ret);
const classes = x86_64_abi.classifySystemV(return_type, mod, .ret);
if (classes[0] == .memory) {
return dg.context.voidType();
}
@@ -10748,7 +10747,7 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm
}
}
if (classes[0] == .integer and classes[1] == .none) {
const abi_size = fn_info.return_type.abiSize(mod);
const abi_size = return_type.abiSize(mod);
return dg.context.intType(@intCast(c_uint, abi_size * 8));
}
return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
@@ -10756,7 +10755,7 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm
const ParamTypeIterator = struct {
dg: *DeclGen,
fn_info: Type.Payload.Function.Data,
fn_info: InternPool.Key.FuncType,
zig_index: u32,
llvm_index: u32,
llvm_types_len: u32,
@@ -10781,7 +10780,7 @@ const ParamTypeIterator = struct {
if (it.zig_index >= it.fn_info.param_types.len) return null;
const ty = it.fn_info.param_types[it.zig_index];
it.byval_attr = false;
return nextInner(it, ty);
return nextInner(it, ty.toType());
}
/// `airCall` uses this instead of `next` so that it can take into account variadic functions.
@@ -10793,7 +10792,7 @@ const ParamTypeIterator = struct {
return nextInner(it, fg.typeOf(args[it.zig_index]));
}
} else {
return nextInner(it, it.fn_info.param_types[it.zig_index]);
return nextInner(it, it.fn_info.param_types[it.zig_index].toType());
}
}
@@ -11009,7 +11008,7 @@ const ParamTypeIterator = struct {
}
};
fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTypeIterator {
fn iterateParamTypes(dg: *DeclGen, fn_info: InternPool.Key.FuncType) ParamTypeIterator {
return .{
.dg = dg,
.fn_info = fn_info,

View File

@@ -1227,8 +1227,9 @@ pub const DeclGen = struct {
},
.Fn => switch (repr) {
.direct => {
const fn_info = mod.typeToFunc(ty).?;
// TODO: Put this somewhere in Sema.zig
if (ty.fnIsVarArgs())
if (fn_info.is_var_args)
return self.fail("VarArgs functions are unsupported for SPIR-V", .{});
const param_ty_refs = try self.gpa.alloc(CacheRef, ty.fnParamLen());
@@ -1546,18 +1547,17 @@ pub const DeclGen = struct {
assert(decl.ty.zigTypeTag(mod) == .Fn);
const prototype_id = try self.resolveTypeId(decl.ty);
try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
.id_result_type = try self.resolveTypeId(decl.ty.fnReturnType()),
.id_result_type = try self.resolveTypeId(decl.ty.fnReturnType(mod)),
.id_result = decl_id,
.function_control = .{}, // TODO: We can set inline here if the type requires it.
.function_type = prototype_id,
});
const params = decl.ty.fnParamLen();
var i: usize = 0;
const fn_info = mod.typeToFunc(decl.ty).?;
try self.args.ensureUnusedCapacity(self.gpa, params);
while (i < params) : (i += 1) {
const param_type_id = try self.resolveTypeId(decl.ty.fnParamType(i));
try self.args.ensureUnusedCapacity(self.gpa, fn_info.param_types.len);
for (fn_info.param_types) |param_type| {
const param_type_id = try self.resolveTypeId(param_type.toType());
const arg_result_id = self.spv.allocId();
try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{
.id_result_type = param_type_id,
@@ -3338,10 +3338,10 @@ pub const DeclGen = struct {
.Pointer => return self.fail("cannot call function pointers", .{}),
else => unreachable,
};
const fn_info = zig_fn_ty.fnInfo();
const fn_info = mod.typeToFunc(zig_fn_ty).?;
const return_type = fn_info.return_type;
const result_type_id = try self.resolveTypeId(return_type);
const result_type_id = try self.resolveTypeId(return_type.toType());
const result_id = self.spv.allocId();
const callee_id = try self.resolve(pl_op.operand);
@@ -3368,11 +3368,11 @@ pub const DeclGen = struct {
.id_ref_3 = params[0..n_params],
});
if (return_type.isNoReturn()) {
if (return_type == .noreturn_type) {
try self.func.body.emit(self.spv.gpa, .OpUnreachable, {});
}
if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {
if (self.liveness.isUnused(inst) or !return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) {
return null;
}