Skip to content

Commit 1f602fe

Browse files
committed
implement @call
closes #3732
1 parent 38791ac commit 1f602fe

14 files changed

+529
-188
lines changed

lib/std/builtin.zig

+18
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,24 @@ pub const Version = struct {
372372
patch: u32,
373373
};
374374

375+
/// This data structure is used by the Zig language code generation and
376+
/// therefore must be kept in sync with the compiler implementation.
377+
pub const CallOptions = struct {
378+
modifier: Modifier = .auto,
379+
stack: ?[]align(std.Target.stack_align) u8 = null,
380+
381+
pub const Modifier = enum {
382+
auto,
383+
no_async,
384+
async_call,
385+
never_tail,
386+
never_inline,
387+
always_tail,
388+
always_inline,
389+
compile_time,
390+
};
391+
};
392+
375393
/// This function type is used by the Zig language code generation and
376394
/// therefore must be kept in sync with the compiler implementation.
377395
pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;

src-self-hosted/llvm.zig

+6-4
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,12 @@ pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv;
260260
pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv;
261261
pub const CallConv = c.LLVMCallConv;
262262

263-
pub const FnInline = extern enum {
263+
pub const CallAttr = extern enum {
264264
Auto,
265-
Always,
266-
Never,
265+
NeverTail,
266+
NeverInline,
267+
AlwaysTail,
268+
AlwaysInline,
267269
};
268270

269271
fn removeNullability(comptime T: type) type {
@@ -286,6 +288,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
286288
) bool;
287289

288290
pub const BuildCall = ZigLLVMBuildCall;
289-
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*:0]const u8) ?*Value;
291+
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value;
290292

291293
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;

src/all_types.hpp

+23-5
Original file line numberDiff line numberDiff line change
@@ -767,10 +767,18 @@ struct AstNodeUnwrapOptional {
767767
AstNode *expr;
768768
};
769769

770+
// Must be synchronized with std.builtin.CallOptions.Modifier
770771
enum CallModifier {
771772
CallModifierNone,
772-
CallModifierAsync,
773773
CallModifierNoAsync,
774+
CallModifierAsync,
775+
CallModifierNeverTail,
776+
CallModifierNeverInline,
777+
CallModifierAlwaysTail,
778+
CallModifierAlwaysInline,
779+
CallModifierCompileTime,
780+
781+
// This is an additional tag in the compiler, but not exposed in the std lib.
774782
CallModifierBuiltin,
775783
};
776784

@@ -1717,6 +1725,7 @@ enum BuiltinFnId {
17171725
BuiltinFnIdFrameHandle,
17181726
BuiltinFnIdFrameSize,
17191727
BuiltinFnIdAs,
1728+
BuiltinFnIdCall,
17201729
};
17211730

17221731
struct BuiltinFnEntry {
@@ -2479,6 +2488,7 @@ enum IrInstructionId {
24792488
IrInstructionIdVarPtr,
24802489
IrInstructionIdReturnPtr,
24812490
IrInstructionIdCallSrc,
2491+
IrInstructionIdCallExtra,
24822492
IrInstructionIdCallGen,
24832493
IrInstructionIdConst,
24842494
IrInstructionIdReturn,
@@ -2886,15 +2896,24 @@ struct IrInstructionCallSrc {
28862896
ZigFn *fn_entry;
28872897
size_t arg_count;
28882898
IrInstruction **args;
2899+
IrInstruction *ret_ptr;
28892900
ResultLoc *result_loc;
28902901

28912902
IrInstruction *new_stack;
28922903

2893-
FnInline fn_inline;
28942904
CallModifier modifier;
2895-
28962905
bool is_async_call_builtin;
2897-
bool is_comptime;
2906+
};
2907+
2908+
/// This is a pass1 instruction, used by @call.
2909+
/// `args` is expected to be either a struct or a tuple.
2910+
struct IrInstructionCallExtra {
2911+
IrInstruction base;
2912+
2913+
IrInstruction *options;
2914+
IrInstruction *fn_ref;
2915+
IrInstruction *args;
2916+
ResultLoc *result_loc;
28982917
};
28992918

29002919
struct IrInstructionCallGen {
@@ -2908,7 +2927,6 @@ struct IrInstructionCallGen {
29082927
IrInstruction *frame_result_loc;
29092928
IrInstruction *new_stack;
29102929

2911-
FnInline fn_inline;
29122930
CallModifier modifier;
29132931

29142932
bool is_async_call_builtin;

src/analyze.cpp

+10-7
Original file line numberDiff line numberDiff line change
@@ -956,10 +956,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
956956

957957
ZigType *get_stack_trace_type(CodeGen *g) {
958958
if (g->stack_trace_type == nullptr) {
959-
ZigValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
960-
assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);
961-
962-
g->stack_trace_type = stack_trace_type_val->data.x_type;
959+
g->stack_trace_type = get_builtin_type(g, "StackTrace");
963960
assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));
964961
}
965962
return g->stack_trace_type;
@@ -2717,10 +2714,10 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
27172714
src_assert(struct_type->data.structure.fields == nullptr, decl_node);
27182715
struct_type->data.structure.fields = alloc_type_struct_fields(field_count);
27192716
} else if (decl_node->type == NodeTypeContainerInitExpr) {
2720-
src_assert(struct_type->data.structure.is_inferred, decl_node);
2721-
src_assert(struct_type->data.structure.fields != nullptr, decl_node);
2722-
27232717
field_count = struct_type->data.structure.src_field_count;
2718+
2719+
src_assert(struct_type->data.structure.is_inferred, decl_node);
2720+
src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node);
27242721
} else zig_unreachable();
27252722

27262723
struct_type->data.structure.fields_by_name.init(field_count);
@@ -7531,6 +7528,12 @@ ZigValue *get_builtin_value(CodeGen *codegen, const char *name) {
75317528
return var_value;
75327529
}
75337530

7531+
ZigType *get_builtin_type(CodeGen *codegen, const char *name) {
7532+
ZigValue *type_val = get_builtin_value(codegen, name);
7533+
assert(type_val->type->id == ZigTypeIdMetaType);
7534+
return type_val->data.x_type;
7535+
}
7536+
75347537
bool type_is_global_error_set(ZigType *err_set_type) {
75357538
assert(err_set_type->id == ZigTypeIdErrorSet);
75367539
assert(!err_set_type->data.error_set.incomplete);

src/analyze.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name,
207207

208208

209209
ZigValue *get_builtin_value(CodeGen *codegen, const char *name);
210+
ZigType *get_builtin_type(CodeGen *codegen, const char *name);
210211
ZigType *get_stack_trace_type(CodeGen *g);
211212
bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);
212213

src/ast_render.cpp

+19-4
Original file line numberDiff line numberDiff line change
@@ -702,14 +702,29 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
702702
switch (node->data.fn_call_expr.modifier) {
703703
case CallModifierNone:
704704
break;
705-
case CallModifierBuiltin:
706-
fprintf(ar->f, "@");
705+
case CallModifierNoAsync:
706+
fprintf(ar->f, "noasync ");
707707
break;
708708
case CallModifierAsync:
709709
fprintf(ar->f, "async ");
710710
break;
711-
case CallModifierNoAsync:
712-
fprintf(ar->f, "noasync ");
711+
case CallModifierNeverTail:
712+
fprintf(ar->f, "notail ");
713+
break;
714+
case CallModifierNeverInline:
715+
fprintf(ar->f, "noinline ");
716+
break;
717+
case CallModifierAlwaysTail:
718+
fprintf(ar->f, "tail ");
719+
break;
720+
case CallModifierAlwaysInline:
721+
fprintf(ar->f, "inline ");
722+
break;
723+
case CallModifierCompileTime:
724+
fprintf(ar->f, "comptime ");
725+
break;
726+
case CallModifierBuiltin:
727+
fprintf(ar->f, "@");
713728
break;
714729
}
715730
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;

src/codegen.cpp

+35-20
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
981981
msg_arg,
982982
stack_trace_arg,
983983
};
984-
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
984+
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_CallAttrAuto, "");
985985
if (!stack_trace_is_llvm_alloca) {
986986
// The stack trace argument is not in the stack of the caller, so
987987
// we'd like to set tail call here, but because slices (the type of msg_arg) are
@@ -1201,7 +1201,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
12011201

12021202
LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block);
12031203
LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1204-
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1204+
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2,
1205+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, "");
12051206
LLVMBuildRetVoid(g->builder);
12061207

12071208
LLVMPositionBuilderAtEnd(g->builder, prev_block);
@@ -1370,13 +1371,13 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
13701371
err_val,
13711372
};
13721373
call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2,
1373-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1374+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
13741375
} else {
13751376
LLVMValueRef args[] = {
13761377
err_val,
13771378
};
13781379
call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1,
1379-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1380+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
13801381
}
13811382
if (!is_llvm_alloca) {
13821383
LLVMSetTailCall(call_instruction, true);
@@ -2216,7 +2217,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
22162217
LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
22172218
LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
22182219
LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
2219-
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
2220+
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, "");
22202221
LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
22212222
LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
22222223
LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
@@ -2253,7 +2254,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
22532254
LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope,
22542255
&is_llvm_alloca);
22552256
ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
2256-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2257+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
22572258

22582259
ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
22592260
if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
@@ -2297,7 +2298,7 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar
22972298
LLVMValueRef arg_val = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
22982299
LLVMConstInt(usize_type_ref, resume_id, false));
22992300
LLVMValueRef args[] = {target_frame_ptr, arg_val};
2300-
return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
2301+
return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_CallAttrAuto, "");
23012302
}
23022303

23032304
static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) {
@@ -2424,7 +2425,7 @@ static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) {
24242425
LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca);
24252426
LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val };
24262427
ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
2427-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2428+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
24282429
}
24292430
}
24302431

@@ -4142,16 +4143,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
41424143
fn_walk.data.call.gen_param_types = &gen_param_types;
41434144
walk_function_params(g, fn_type, &fn_walk);
41444145

4145-
ZigLLVM_FnInline fn_inline;
4146-
switch (instruction->fn_inline) {
4147-
case FnInlineAuto:
4148-
fn_inline = ZigLLVM_FnInlineAuto;
4146+
ZigLLVM_CallAttr call_attr;
4147+
switch (instruction->modifier) {
4148+
case CallModifierBuiltin:
4149+
case CallModifierCompileTime:
4150+
zig_unreachable();
4151+
case CallModifierNone:
4152+
case CallModifierNoAsync:
4153+
case CallModifierAsync:
4154+
call_attr = ZigLLVM_CallAttrAuto;
41494155
break;
4150-
case FnInlineAlways:
4151-
fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways;
4156+
case CallModifierNeverTail:
4157+
call_attr = ZigLLVM_CallAttrNeverTail;
41524158
break;
4153-
case FnInlineNever:
4154-
fn_inline = ZigLLVM_FnInlineNever;
4159+
case CallModifierNeverInline:
4160+
call_attr = ZigLLVM_CallAttrNeverInline;
4161+
break;
4162+
case CallModifierAlwaysTail:
4163+
call_attr = ZigLLVM_CallAttrAlwaysTail;
4164+
break;
4165+
case CallModifierAlwaysInline:
4166+
ir_assert(instruction->fn_entry != nullptr, &instruction->base);
4167+
call_attr = ZigLLVM_CallAttrAlwaysInline;
41554168
break;
41564169
}
41574170

@@ -4257,7 +4270,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
42574270

42584271
if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) {
42594272
result = ZigLLVMBuildCall(g->builder, fn_val,
4260-
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
4273+
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, "");
42614274
} else if (instruction->modifier == CallModifierAsync) {
42624275
zig_panic("TODO @asyncCall of non-async function");
42634276
} else {
@@ -4269,7 +4282,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
42694282
}
42704283
gen_set_stack_pointer(g, new_stack_addr);
42714284
result = ZigLLVMBuildCall(g->builder, fn_val,
4272-
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
4285+
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, "");
42734286
if (src_return_type->id != ZigTypeIdUnreachable) {
42744287
LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
42754288
LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
@@ -4947,7 +4960,7 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
49474960

49484961
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
49494962
return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
4950-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4963+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
49514964
}
49524965

49534966
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
@@ -5903,7 +5916,7 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_ins
59035916
LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca);
59045917
LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
59055918
ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5906-
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5919+
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
59075920
}
59085921
if (non_async && type_has_bits(result_type)) {
59095922
LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc;
@@ -6137,6 +6150,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
61376150
case IrInstructionIdLoadPtr:
61386151
case IrInstructionIdHasDecl:
61396152
case IrInstructionIdUndeclaredIdent:
6153+
case IrInstructionIdCallExtra:
61406154
case IrInstructionIdCallSrc:
61416155
case IrInstructionIdAllocaSrc:
61426156
case IrInstructionIdEndExpr:
@@ -8146,6 +8160,7 @@ static void define_builtin_fns(CodeGen *g) {
81468160
create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
81478161
create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
81488162
create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
8163+
create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
81498164
}
81508165

81518166
static const char *bool_to_str(bool b) {

0 commit comments

Comments
 (0)