Skip to content

Commit

Permalink
implement @call
Browse files Browse the repository at this point in the history
closes #3732
  • Loading branch information
andrewrk committed Dec 5, 2019
1 parent 38791ac commit 1f602fe
Show file tree
Hide file tree
Showing 14 changed files with 529 additions and 188 deletions.
18 changes: 18 additions & 0 deletions lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,24 @@ pub const Version = struct {
patch: u32,
};

/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const CallOptions = struct {
modifier: Modifier = .auto,
stack: ?[]align(std.Target.stack_align) u8 = null,

pub const Modifier = enum {
auto,
no_async,
async_call,
never_tail,
never_inline,
always_tail,
always_inline,
compile_time,
};
};

/// This function type is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn;
Expand Down
10 changes: 6 additions & 4 deletions src-self-hosted/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,12 @@ pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv;
pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv;
pub const CallConv = c.LLVMCallConv;

pub const FnInline = extern enum {
pub const CallAttr = extern enum {
Auto,
Always,
Never,
NeverTail,
NeverInline,
AlwaysTail,
AlwaysInline,
};

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

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

pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
28 changes: 23 additions & 5 deletions src/all_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,10 +767,18 @@ struct AstNodeUnwrapOptional {
AstNode *expr;
};

// Must be synchronized with std.builtin.CallOptions.Modifier
enum CallModifier {
CallModifierNone,
CallModifierAsync,
CallModifierNoAsync,
CallModifierAsync,
CallModifierNeverTail,
CallModifierNeverInline,
CallModifierAlwaysTail,
CallModifierAlwaysInline,
CallModifierCompileTime,

// This is an additional tag in the compiler, but not exposed in the std lib.
CallModifierBuiltin,
};

Expand Down Expand Up @@ -1717,6 +1725,7 @@ enum BuiltinFnId {
BuiltinFnIdFrameHandle,
BuiltinFnIdFrameSize,
BuiltinFnIdAs,
BuiltinFnIdCall,
};

struct BuiltinFnEntry {
Expand Down Expand Up @@ -2479,6 +2488,7 @@ enum IrInstructionId {
IrInstructionIdVarPtr,
IrInstructionIdReturnPtr,
IrInstructionIdCallSrc,
IrInstructionIdCallExtra,
IrInstructionIdCallGen,
IrInstructionIdConst,
IrInstructionIdReturn,
Expand Down Expand Up @@ -2886,15 +2896,24 @@ struct IrInstructionCallSrc {
ZigFn *fn_entry;
size_t arg_count;
IrInstruction **args;
IrInstruction *ret_ptr;
ResultLoc *result_loc;

IrInstruction *new_stack;

FnInline fn_inline;
CallModifier modifier;

bool is_async_call_builtin;
bool is_comptime;
};

/// This is a pass1 instruction, used by @call.
/// `args` is expected to be either a struct or a tuple.
struct IrInstructionCallExtra {
IrInstruction base;

IrInstruction *options;
IrInstruction *fn_ref;
IrInstruction *args;
ResultLoc *result_loc;
};

struct IrInstructionCallGen {
Expand All @@ -2908,7 +2927,6 @@ struct IrInstructionCallGen {
IrInstruction *frame_result_loc;
IrInstruction *new_stack;

FnInline fn_inline;
CallModifier modifier;

bool is_async_call_builtin;
Expand Down
17 changes: 10 additions & 7 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,10 +956,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {

ZigType *get_stack_trace_type(CodeGen *g) {
if (g->stack_trace_type == nullptr) {
ZigValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);

g->stack_trace_type = stack_trace_type_val->data.x_type;
g->stack_trace_type = get_builtin_type(g, "StackTrace");
assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));
}
return g->stack_trace_type;
Expand Down Expand Up @@ -2717,10 +2714,10 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
src_assert(struct_type->data.structure.fields == nullptr, decl_node);
struct_type->data.structure.fields = alloc_type_struct_fields(field_count);
} else if (decl_node->type == NodeTypeContainerInitExpr) {
src_assert(struct_type->data.structure.is_inferred, decl_node);
src_assert(struct_type->data.structure.fields != nullptr, decl_node);

field_count = struct_type->data.structure.src_field_count;

src_assert(struct_type->data.structure.is_inferred, decl_node);
src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node);
} else zig_unreachable();

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

ZigType *get_builtin_type(CodeGen *codegen, const char *name) {
ZigValue *type_val = get_builtin_value(codegen, name);
assert(type_val->type->id == ZigTypeIdMetaType);
return type_val->data.x_type;
}

bool type_is_global_error_set(ZigType *err_set_type) {
assert(err_set_type->id == ZigTypeIdErrorSet);
assert(!err_set_type->data.error_set.incomplete);
Expand Down
1 change: 1 addition & 0 deletions src/analyze.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name,


ZigValue *get_builtin_value(CodeGen *codegen, const char *name);
ZigType *get_builtin_type(CodeGen *codegen, const char *name);
ZigType *get_stack_trace_type(CodeGen *g);
bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);

Expand Down
23 changes: 19 additions & 4 deletions src/ast_render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,14 +702,29 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
switch (node->data.fn_call_expr.modifier) {
case CallModifierNone:
break;
case CallModifierBuiltin:
fprintf(ar->f, "@");
case CallModifierNoAsync:
fprintf(ar->f, "noasync ");
break;
case CallModifierAsync:
fprintf(ar->f, "async ");
break;
case CallModifierNoAsync:
fprintf(ar->f, "noasync ");
case CallModifierNeverTail:
fprintf(ar->f, "notail ");
break;
case CallModifierNeverInline:
fprintf(ar->f, "noinline ");
break;
case CallModifierAlwaysTail:
fprintf(ar->f, "tail ");
break;
case CallModifierAlwaysInline:
fprintf(ar->f, "inline ");
break;
case CallModifierCompileTime:
fprintf(ar->f, "comptime ");
break;
case CallModifierBuiltin:
fprintf(ar->f, "@");
break;
}
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
Expand Down
55 changes: 35 additions & 20 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
msg_arg,
stack_trace_arg,
};
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_CallAttrAuto, "");
if (!stack_trace_is_llvm_alloca) {
// The stack trace argument is not in the stack of the caller, so
// we'd like to set tail call here, but because slices (the type of msg_arg) are
Expand Down Expand Up @@ -1201,7 +1201,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {

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

LLVMPositionBuilderAtEnd(g->builder, prev_block);
Expand Down Expand Up @@ -1370,13 +1371,13 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
err_val,
};
call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
} else {
LLVMValueRef args[] = {
err_val,
};
call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
}
if (!is_llvm_alloca) {
LLVMSetTailCall(call_instruction, true);
Expand Down Expand Up @@ -2216,7 +2217,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, "");
LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
Expand Down Expand Up @@ -2253,7 +2254,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope,
&is_llvm_alloca);
ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");

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

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

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

ZigLLVM_FnInline fn_inline;
switch (instruction->fn_inline) {
case FnInlineAuto:
fn_inline = ZigLLVM_FnInlineAuto;
ZigLLVM_CallAttr call_attr;
switch (instruction->modifier) {
case CallModifierBuiltin:
case CallModifierCompileTime:
zig_unreachable();
case CallModifierNone:
case CallModifierNoAsync:
case CallModifierAsync:
call_attr = ZigLLVM_CallAttrAuto;
break;
case FnInlineAlways:
fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways;
case CallModifierNeverTail:
call_attr = ZigLLVM_CallAttrNeverTail;
break;
case FnInlineNever:
fn_inline = ZigLLVM_FnInlineNever;
case CallModifierNeverInline:
call_attr = ZigLLVM_CallAttrNeverInline;
break;
case CallModifierAlwaysTail:
call_attr = ZigLLVM_CallAttrAlwaysTail;
break;
case CallModifierAlwaysInline:
ir_assert(instruction->fn_entry != nullptr, &instruction->base);
call_attr = ZigLLVM_CallAttrAlwaysInline;
break;
}

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

if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) {
result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, "");
} else if (instruction->modifier == CallModifierAsync) {
zig_panic("TODO @asyncCall of non-async function");
} else {
Expand All @@ -4269,7 +4282,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
gen_set_stack_pointer(g, new_stack_addr);
result = ZigLLVMBuildCall(g->builder, fn_val,
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, "");
if (src_return_type->id != ZigTypeIdUnreachable) {
LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
Expand Down Expand Up @@ -4947,7 +4960,7 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable

LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
}

static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
Expand Down Expand Up @@ -5903,7 +5916,7 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_ins
LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca);
LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, "");
}
if (non_async && type_has_bits(result_type)) {
LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc;
Expand Down Expand Up @@ -6137,6 +6150,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdLoadPtr:
case IrInstructionIdHasDecl:
case IrInstructionIdUndeclaredIdent:
case IrInstructionIdCallExtra:
case IrInstructionIdCallSrc:
case IrInstructionIdAllocaSrc:
case IrInstructionIdEndExpr:
Expand Down Expand Up @@ -8146,6 +8160,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
}

static const char *bool_to_str(bool b) {
Expand Down
Loading

0 comments on commit 1f602fe

Please sign in to comment.