mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
stage2 async progress
After analyzing function body, check call instructions and determine whether it is an async function or not. LLVM backend: support lowering trivial async functions
This commit is contained in:
parent
e45b10f3d4
commit
3faa550dc2
4 changed files with 155 additions and 44 deletions
|
|
@ -1,3 +1,9 @@
|
||||||
|
* calling getFuncAsyncStatus is triggering machine code lowering too early,
|
||||||
|
because the function which does not yet know its own async status may get called
|
||||||
|
recursively by one of the callees.
|
||||||
|
- don't do any lowering to machine code until async status has been resolved for
|
||||||
|
the local call graph sub-tree.
|
||||||
|
|
||||||
* detect when a called function is async and make the caller async too
|
* detect when a called function is async and make the caller async too
|
||||||
* generate the async frame type *after* lowering the function to LLVM IR
|
* generate the async frame type *after* lowering the function to LLVM IR
|
||||||
* calculate frame size after llvm lowering, ability to inspect with `@sizeOf`
|
* calculate frame size after llvm lowering, ability to inspect with `@sizeOf`
|
||||||
|
|
@ -11,3 +17,4 @@
|
||||||
* use function pointers instead of resume index to...
|
* use function pointers instead of resume index to...
|
||||||
- reduce the number of runtime branches from 2 to 1
|
- reduce the number of runtime branches from 2 to 1
|
||||||
- pass function arguments as normal arguments to the first segment
|
- pass function arguments as normal arguments to the first segment
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5692,10 +5692,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||||
inner_block.error_return_trace_index = error_return_trace_index;
|
inner_block.error_return_trace_index = error_return_trace_index;
|
||||||
|
|
||||||
sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
|
sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
|
||||||
// TODO make these unreachable instead of @panic
|
error.NeededSourceLocation => unreachable,
|
||||||
error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
|
error.GenericPoison => unreachable,
|
||||||
error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
|
error.ComptimeReturn => unreachable,
|
||||||
error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
|
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -5717,11 +5716,10 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||||
!sema.fn_ret_ty.isError(mod))
|
!sema.fn_ret_ty.isError(mod))
|
||||||
{
|
{
|
||||||
sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
|
sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
|
||||||
// TODO make these unreachable instead of @panic
|
error.NeededSourceLocation => unreachable,
|
||||||
error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
|
error.GenericPoison => unreachable,
|
||||||
error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
|
error.ComptimeReturn => unreachable,
|
||||||
error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
|
error.ComptimeBreak => unreachable,
|
||||||
error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
|
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -5742,6 +5740,59 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||||
sema.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)] = main_block_index;
|
sema.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)] = main_block_index;
|
||||||
|
|
||||||
func.state = .success;
|
func.state = .success;
|
||||||
|
|
||||||
|
// Next we must look at all the function calls and determine two pieces of information:
|
||||||
|
// * for each call, whether the called function is async
|
||||||
|
// * whether this function making the calls is async
|
||||||
|
// This happens *after* setting func.state to success above so that any
|
||||||
|
// recursive check on this function will not cause an infinite loop.
|
||||||
|
// Both of these pieces of information are needed by backends for machine code lowering.
|
||||||
|
{
|
||||||
|
const air = sema.getTmpAir();
|
||||||
|
const air_tags = air.instructions.items(.tag);
|
||||||
|
const air_datas = air.instructions.items(.data);
|
||||||
|
for (air_tags, 0..) |air_tag, inst| {
|
||||||
|
var is_suspend_point = false;
|
||||||
|
const callee = switch (air_tag) {
|
||||||
|
.call, .call_always_tail, .call_never_tail, .call_never_inline => c: {
|
||||||
|
is_suspend_point = true;
|
||||||
|
const pl_op = air_datas[inst].pl_op;
|
||||||
|
break :c pl_op.operand;
|
||||||
|
},
|
||||||
|
.call_async => c: {
|
||||||
|
const pl_op = air_datas[inst].pl_op;
|
||||||
|
break :c pl_op.operand;
|
||||||
|
},
|
||||||
|
.call_async_alloc => c: {
|
||||||
|
const ty_pl = air.instructions.items(.data)[inst].ty_pl;
|
||||||
|
const extra = air.extraData(Air.AsyncCallAlloc, ty_pl.payload);
|
||||||
|
break :c extra.data.callee;
|
||||||
|
},
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
const callee_val = (try air.value(callee, mod)) orelse continue;
|
||||||
|
const callee_decl_index = switch (mod.intern_pool.indexToKey(callee_val.toIntern())) {
|
||||||
|
.extern_func => continue, // extern functions cannot be async
|
||||||
|
.func => |f| mod.funcPtr(f.index).owner_decl,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
const callee_decl = mod.declPtr(callee_decl_index);
|
||||||
|
const callee_func_index = callee_decl.getOwnedFunctionIndex(mod).unwrap() orelse continue;
|
||||||
|
const callee_status = sema.getFuncAsyncStatus(callee_func_index) catch |err| switch (err) {
|
||||||
|
error.NeededSourceLocation => unreachable,
|
||||||
|
error.GenericPoison => unreachable,
|
||||||
|
error.ComptimeReturn => unreachable,
|
||||||
|
error.ComptimeBreak => unreachable,
|
||||||
|
error.AnalysisFail => continue, // treat this callee as non-async
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
if (is_suspend_point) switch (callee_status) {
|
||||||
|
.unknown => unreachable,
|
||||||
|
.not_async => continue,
|
||||||
|
.yes_async => func.async_status = .yes_async,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
if (func.async_status == .unknown) {
|
if (func.async_status == .unknown) {
|
||||||
func.async_status = .not_async;
|
func.async_status = .not_async;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
29
src/Sema.zig
29
src/Sema.zig
|
|
@ -9322,7 +9322,8 @@ fn funcCommon(
|
||||||
return sema.addType(fn_ty);
|
return sema.addType(fn_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_inline = fn_ty.fnCallingConvention(mod) == .Inline;
|
const init_cc = fn_ty.fnCallingConvention(mod);
|
||||||
|
const is_inline = init_cc == .Inline;
|
||||||
const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none;
|
const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none;
|
||||||
|
|
||||||
const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
|
const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
|
||||||
|
|
@ -9334,7 +9335,7 @@ fn funcCommon(
|
||||||
const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
|
const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
|
||||||
new_func.* = .{
|
new_func.* = .{
|
||||||
.state = anal_state,
|
.state = anal_state,
|
||||||
.async_status = .unknown,
|
.async_status = initAsyncSatus(init_cc),
|
||||||
.zir_body_inst = func_inst,
|
.zir_body_inst = func_inst,
|
||||||
.owner_decl = sema.owner_decl_index,
|
.owner_decl = sema.owner_decl_index,
|
||||||
.generic_owner_decl = generic_owner_decl,
|
.generic_owner_decl = generic_owner_decl,
|
||||||
|
|
@ -9353,6 +9354,14 @@ fn funcCommon(
|
||||||
} })).toValue());
|
} })).toValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initAsyncSatus(cc: std.builtin.CallingConvention) Module.Fn.AsyncStatus {
|
||||||
|
return switch (cc) {
|
||||||
|
.Unspecified => .unknown,
|
||||||
|
.Async => .yes_async,
|
||||||
|
else => .not_async,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn analyzeParameter(
|
fn analyzeParameter(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
|
|
@ -30557,6 +30566,22 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getFuncAsyncStatus(sema: *Sema, func_index: Module.Fn.Index) CompileError!Module.Fn.AsyncStatus {
|
||||||
|
const mod = sema.mod;
|
||||||
|
const func = mod.funcPtr(func_index);
|
||||||
|
switch (func.async_status) {
|
||||||
|
.yes_async => return .yes_async,
|
||||||
|
.not_async => return .not_async,
|
||||||
|
.unknown => {
|
||||||
|
try ensureFuncBodyAnalyzed(sema, func_index);
|
||||||
|
switch (func.async_status) {
|
||||||
|
.yes_async => return .yes_async,
|
||||||
|
.not_async, .unknown => return .not_async,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
|
fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
|
||||||
const mod = sema.mod;
|
const mod = sema.mod;
|
||||||
var anon_decl = try block.startAnonDecl();
|
var anon_decl = try block.startAnonDecl();
|
||||||
|
|
|
||||||
|
|
@ -961,7 +961,11 @@ pub const Object = struct {
|
||||||
defer args.deinit();
|
defer args.deinit();
|
||||||
|
|
||||||
{
|
{
|
||||||
var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing);
|
var llvm_arg_i =
|
||||||
|
@as(c_uint, @intFromBool(ret_ptr != null)) +
|
||||||
|
@intFromBool(err_return_tracing) +
|
||||||
|
@intFromBool(func.isAsync());
|
||||||
|
|
||||||
var it = iterateParamTypes(o, fn_info);
|
var it = iterateParamTypes(o, fn_info);
|
||||||
while (it.next()) |lowering| switch (lowering) {
|
while (it.next()) |lowering| switch (lowering) {
|
||||||
.no_bits => continue,
|
.no_bits => continue,
|
||||||
|
|
@ -1215,25 +1219,27 @@ pub const Object = struct {
|
||||||
};
|
};
|
||||||
defer fg.deinit();
|
defer fg.deinit();
|
||||||
|
|
||||||
if (func.isAsync()) {
|
const llvm_usize = o.context.intType(target.ptrBitWidth());
|
||||||
const frame_ty = try mod.asyncFrameType(func_index);
|
|
||||||
const frame_size = frame_ty.abiSize(mod);
|
|
||||||
const llvm_usize = dg.context.intType(target.ptrBitWidth());
|
|
||||||
const size_val = llvm_usize.constInt(frame_size, .False);
|
|
||||||
llvm_func.functionSetPrefixData(size_val);
|
|
||||||
|
|
||||||
const async_preamble_bb = dg.context.appendBasicBlock(llvm_func, "AsyncSwitch");
|
if (func.isAsync()) {
|
||||||
const bad_resume_bb = dg.context.appendBasicBlock(llvm_func, "BadResume");
|
const bad_resume_bb = o.context.appendBasicBlock(llvm_func, "BadResume");
|
||||||
builder.positionBuilderAtEnd(bad_resume_bb);
|
builder.positionBuilderAtEnd(bad_resume_bb);
|
||||||
_ = builder.buildUnreachable(); // TODO make this a safety panic
|
_ = builder.buildUnreachable(); // TODO make this a safety panic
|
||||||
|
|
||||||
builder.positionBuilderAtEnd(async_preamble_bb);
|
builder.positionBuilderAtEnd(entry_block);
|
||||||
const l = asyncFrameLayout();
|
const l = asyncFrameLayout();
|
||||||
const frame_llvm_ty = try dg.lowerType(frame_ty);
|
const frame_llvm_ty = try o.lowerAsyncFrameHeader(fn_info.return_type.toType());
|
||||||
const frame_ptr = llvm_func.getParam(0);
|
const frame_ptr = llvm_func.getParam(0);
|
||||||
fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, "");
|
fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, "");
|
||||||
const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, "");
|
const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, "");
|
||||||
fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4);
|
fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4);
|
||||||
|
|
||||||
|
const init_bb = o.context.appendBasicBlock(llvm_func, "Init");
|
||||||
|
const new_block_index = fg.resume_block_index;
|
||||||
|
fg.resume_block_index += 1;
|
||||||
|
const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False);
|
||||||
|
fg.async_switch.addCase(new_block_index_llvm_val, init_bb);
|
||||||
|
builder.positionBuilderAtEnd(init_bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
fg.genBody(air.getMainBody()) catch |err| switch (err) {
|
fg.genBody(air.getMainBody()) catch |err| switch (err) {
|
||||||
|
|
@ -1246,6 +1252,12 @@ pub const Object = struct {
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (func.isAsync()) {
|
||||||
|
const frame_size = 3 * (target.ptrBitWidth() / 8);
|
||||||
|
const size_val = llvm_usize.constInt(frame_size, .False);
|
||||||
|
llvm_func.functionSetPrefixData(size_val);
|
||||||
|
}
|
||||||
|
|
||||||
try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2499,16 +2511,20 @@ pub const Object = struct {
|
||||||
const mod = o.module;
|
const mod = o.module;
|
||||||
const gpa = o.gpa;
|
const gpa = o.gpa;
|
||||||
const decl = mod.declPtr(decl_index);
|
const decl = mod.declPtr(decl_index);
|
||||||
const zig_fn_type = decl.ty;
|
|
||||||
const gop = try o.decl_map.getOrPut(gpa, decl_index);
|
const gop = try o.decl_map.getOrPut(gpa, decl_index);
|
||||||
if (gop.found_existing) return gop.value_ptr.*;
|
if (gop.found_existing) return gop.value_ptr.*;
|
||||||
|
|
||||||
assert(decl.has_tv);
|
assert(decl.has_tv);
|
||||||
const fn_info = mod.typeToFunc(zig_fn_type).?;
|
const func = decl.getOwnedFunction(mod).?;
|
||||||
|
const zig_fn_type = decl.ty;
|
||||||
|
const fn_info = info: {
|
||||||
|
var info = mod.typeToFunc(zig_fn_type).?;
|
||||||
|
if (func.isAsync()) info.cc = .Async;
|
||||||
|
break :info info;
|
||||||
|
};
|
||||||
const target = mod.getTarget();
|
const target = mod.getTarget();
|
||||||
const sret = firstParamSRet(fn_info, mod);
|
const sret = firstParamSRet(fn_info, mod);
|
||||||
|
const fn_type = try o.lowerTypeFn(fn_info);
|
||||||
const fn_type = try o.lowerType(zig_fn_type);
|
|
||||||
|
|
||||||
const fqn = try decl.getFullyQualifiedName(mod);
|
const fqn = try decl.getFullyQualifiedName(mod);
|
||||||
|
|
||||||
|
|
@ -2531,32 +2547,33 @@ pub const Object = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var llvm_param_i: u32 = 0;
|
||||||
|
|
||||||
if (sret) {
|
if (sret) {
|
||||||
o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
|
o.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); // Sret pointers must not be address 0
|
||||||
o.addArgAttr(llvm_fn, 0, "noalias");
|
o.addArgAttr(llvm_fn, llvm_param_i, "noalias");
|
||||||
|
|
||||||
const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
|
const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType());
|
||||||
llvm_fn.addSretAttr(raw_llvm_ret_ty);
|
llvm_fn.addSretAttr(raw_llvm_ret_ty);
|
||||||
|
|
||||||
|
llvm_param_i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
|
const err_return_tracing = fn_info.return_type.toType().isError(mod) and
|
||||||
mod.comp.bin_file.options.error_return_tracing;
|
mod.comp.bin_file.options.error_return_tracing;
|
||||||
|
|
||||||
if (err_return_tracing) {
|
if (err_return_tracing) {
|
||||||
o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull");
|
o.addArgAttr(llvm_fn, llvm_param_i, "nonnull");
|
||||||
|
llvm_param_i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (fn_info.cc) {
|
switch (fn_info.cc) {
|
||||||
.Unspecified, .Inline => {
|
.Unspecified, .Inline, .Async => {
|
||||||
llvm_fn.setFunctionCallConv(.Fast);
|
llvm_fn.setFunctionCallConv(.Fast);
|
||||||
},
|
},
|
||||||
.Naked => {
|
.Naked => {
|
||||||
o.addFnAttr(llvm_fn, "naked");
|
o.addFnAttr(llvm_fn, "naked");
|
||||||
},
|
},
|
||||||
.Async => {
|
|
||||||
llvm_fn.setFunctionCallConv(.Fast);
|
|
||||||
@panic("TODO: LLVM backend lower async function");
|
|
||||||
},
|
|
||||||
else => {
|
else => {
|
||||||
llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
|
llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
|
||||||
},
|
},
|
||||||
|
|
@ -2577,8 +2594,7 @@ pub const Object = struct {
|
||||||
// because functions with bodies are handled in `updateFunc`.
|
// because functions with bodies are handled in `updateFunc`.
|
||||||
if (is_extern) {
|
if (is_extern) {
|
||||||
var it = iterateParamTypes(o, fn_info);
|
var it = iterateParamTypes(o, fn_info);
|
||||||
it.llvm_index += @intFromBool(sret);
|
it.llvm_index += llvm_param_i;
|
||||||
it.llvm_index += @intFromBool(err_return_tracing);
|
|
||||||
while (it.next()) |lowering| switch (lowering) {
|
while (it.next()) |lowering| switch (lowering) {
|
||||||
.byval => {
|
.byval => {
|
||||||
const param_index = it.zig_index - 1;
|
const param_index = it.zig_index - 1;
|
||||||
|
|
@ -3052,7 +3068,7 @@ pub const Object = struct {
|
||||||
llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
|
llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
|
||||||
return llvm_union_ty;
|
return llvm_union_ty;
|
||||||
},
|
},
|
||||||
.Fn => return lowerTypeFn(o, t),
|
.Fn => return lowerTypeFn(o, mod.typeToFunc(t).?),
|
||||||
.ComptimeInt => unreachable,
|
.ComptimeInt => unreachable,
|
||||||
.ComptimeFloat => unreachable,
|
.ComptimeFloat => unreachable,
|
||||||
.Type => unreachable,
|
.Type => unreachable,
|
||||||
|
|
@ -3089,12 +3105,16 @@ pub const Object = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerAsyncFrameHeader(o: *Object, ret_ty: Type) !*llvm.Type {
|
fn lowerAsyncFrameHeader(o: *Object, ret_ty: Type) !*llvm.Type {
|
||||||
|
const mod = o.module;
|
||||||
const opaque_ptr_ty = o.context.pointerType(0);
|
const opaque_ptr_ty = o.context.pointerType(0);
|
||||||
const l = asyncFrameLayout();
|
const l = asyncFrameLayout();
|
||||||
var fields: [4]*llvm.Type = undefined;
|
var fields: [4]*llvm.Type = undefined;
|
||||||
fields[l.fn_ptr] = opaque_ptr_ty;
|
fields[l.fn_ptr] = opaque_ptr_ty;
|
||||||
fields[l.resume_index] = try o.lowerType(Type.usize);
|
fields[l.resume_index] = try o.lowerType(Type.usize);
|
||||||
fields[l.awaiter] = opaque_ptr_ty;
|
fields[l.awaiter] = opaque_ptr_ty;
|
||||||
|
if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
|
||||||
|
return o.context.structType(&fields, 3, .False);
|
||||||
|
}
|
||||||
fields[l.ret_val] = try o.lowerType(ret_ty);
|
fields[l.ret_val] = try o.lowerType(ret_ty);
|
||||||
return o.context.structType(&fields, fields.len, .False);
|
return o.context.structType(&fields, fields.len, .False);
|
||||||
}
|
}
|
||||||
|
|
@ -3122,23 +3142,29 @@ pub const Object = struct {
|
||||||
return llvm_struct_ty;
|
return llvm_struct_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {
|
fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!*llvm.Type {
|
||||||
const mod = o.module;
|
const mod = o.module;
|
||||||
const fn_info = mod.typeToFunc(fn_ty).?;
|
|
||||||
const llvm_ret_ty = try lowerFnRetTy(o, fn_info);
|
const llvm_ret_ty = try lowerFnRetTy(o, fn_info);
|
||||||
|
|
||||||
var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa);
|
var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa);
|
||||||
defer llvm_params.deinit();
|
defer llvm_params.deinit();
|
||||||
|
|
||||||
|
try llvm_params.ensureUnusedCapacity(3);
|
||||||
|
|
||||||
if (firstParamSRet(fn_info, mod)) {
|
if (firstParamSRet(fn_info, mod)) {
|
||||||
try llvm_params.append(o.context.pointerType(0));
|
llvm_params.appendAssumeCapacity(o.context.pointerType(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fn_info.cc == .Async) {
|
||||||
|
// frame_ptr
|
||||||
|
llvm_params.appendAssumeCapacity(o.context.pointerType(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_info.return_type.toType().isError(mod) and
|
if (fn_info.return_type.toType().isError(mod) and
|
||||||
mod.comp.bin_file.options.error_return_tracing)
|
mod.comp.bin_file.options.error_return_tracing)
|
||||||
{
|
{
|
||||||
const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());
|
const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());
|
||||||
try llvm_params.append(try o.lowerType(ptr_ty));
|
llvm_params.appendAssumeCapacity(try o.lowerType(ptr_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
var it = iterateParamTypes(o, fn_info);
|
var it = iterateParamTypes(o, fn_info);
|
||||||
|
|
@ -4860,9 +4886,11 @@ pub const FuncGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock {
|
fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock {
|
||||||
const target = fg.getTarget();
|
const o = fg.dg.object;
|
||||||
const llvm_usize = fg.dg.context.intType(target.ptrBitWidth());
|
const mod = o.module;
|
||||||
const resume_bb = fg.context.appendBasicBlock(fg.llvm_func, name_hint);
|
const target = mod.getTarget();
|
||||||
|
const llvm_usize = o.context.intType(target.ptrBitWidth());
|
||||||
|
const resume_bb = o.context.appendBasicBlock(fg.llvm_func, name_hint);
|
||||||
const new_block_index = fg.resume_block_index;
|
const new_block_index = fg.resume_block_index;
|
||||||
fg.resume_block_index += 1;
|
fg.resume_block_index += 1;
|
||||||
const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False);
|
const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue