stage1: switch from inline fn to callconv(.Inline)

This commit is contained in:
Tadeo Kondrak 2021-01-11 07:59:11 -07:00
parent 5dfe0e7e8f
commit 1c15091bc8
No known key found for this signature in database
GPG Key ID: D41E092CA43F1D8B
7 changed files with 56 additions and 84 deletions

View File

@ -155,6 +155,7 @@ pub const CallingConvention = enum {
C, C,
Naked, Naked,
Async, Async,
Inline,
Interrupt, Interrupt,
Signal, Signal,
Stdcall, Stdcall,
@ -404,21 +405,13 @@ pub const TypeInfo = union(enum) {
/// therefore must be kept in sync with the compiler implementation. /// therefore must be kept in sync with the compiler implementation.
pub const FnDecl = struct { pub const FnDecl = struct {
fn_type: type, fn_type: type,
inline_type: Inline, is_noinline: bool,
is_var_args: bool, is_var_args: bool,
is_extern: bool, is_extern: bool,
is_export: bool, is_export: bool,
lib_name: ?[]const u8, lib_name: ?[]const u8,
return_type: type, return_type: type,
arg_names: []const []const u8, arg_names: []const []const u8,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Inline = enum {
Auto,
Always,
Never,
};
}; };
}; };
}; };

View File

@ -74,6 +74,7 @@ enum CallingConvention {
CallingConventionC, CallingConventionC,
CallingConventionNaked, CallingConventionNaked,
CallingConventionAsync, CallingConventionAsync,
CallingConventionInline,
CallingConventionInterrupt, CallingConventionInterrupt,
CallingConventionSignal, CallingConventionSignal,
CallingConventionStdcall, CallingConventionStdcall,
@ -703,12 +704,6 @@ enum NodeType {
NodeTypeAnyTypeField, NodeTypeAnyTypeField,
}; };
enum FnInline {
FnInlineAuto,
FnInlineAlways,
FnInlineNever,
};
struct AstNodeFnProto { struct AstNodeFnProto {
Buf *name; Buf *name;
ZigList<AstNode *> params; ZigList<AstNode *> params;
@ -725,13 +720,12 @@ struct AstNodeFnProto {
AstNode *callconv_expr; AstNode *callconv_expr;
Buf doc_comments; Buf doc_comments;
FnInline fn_inline;
VisibMod visib_mod; VisibMod visib_mod;
bool auto_err_set; bool auto_err_set;
bool is_var_args; bool is_var_args;
bool is_extern; bool is_extern;
bool is_export; bool is_export;
bool is_noinline;
}; };
struct AstNodeFnDef { struct AstNodeFnDef {
@ -1719,7 +1713,6 @@ struct ZigFn {
LLVMValueRef valgrind_client_request_array; LLVMValueRef valgrind_client_request_array;
FnInline fn_inline;
FnAnalState anal_state; FnAnalState anal_state;
uint32_t align_bytes; uint32_t align_bytes;
@ -1728,6 +1721,7 @@ struct ZigFn {
bool calls_or_awaits_errorable_fn; bool calls_or_awaits_errorable_fn;
bool is_cold; bool is_cold;
bool is_test; bool is_test;
bool is_noinline;
}; };
uint32_t fn_table_entry_hash(ZigFn*); uint32_t fn_table_entry_hash(ZigFn*);

View File

@ -973,6 +973,7 @@ const char *calling_convention_name(CallingConvention cc) {
case CallingConventionAPCS: return "APCS"; case CallingConventionAPCS: return "APCS";
case CallingConventionAAPCS: return "AAPCS"; case CallingConventionAAPCS: return "AAPCS";
case CallingConventionAAPCSVFP: return "AAPCSVFP"; case CallingConventionAAPCSVFP: return "AAPCSVFP";
case CallingConventionInline: return "Inline";
} }
zig_unreachable(); zig_unreachable();
} }
@ -981,6 +982,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
switch (cc) { switch (cc) {
case CallingConventionUnspecified: case CallingConventionUnspecified:
case CallingConventionAsync: case CallingConventionAsync:
case CallingConventionInline:
return true; return true;
case CallingConventionC: case CallingConventionC:
case CallingConventionNaked: case CallingConventionNaked:
@ -1007,7 +1009,8 @@ ZigType *get_stack_trace_type(CodeGen *g) {
} }
bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
if (fn_type_id->cc == CallingConventionUnspecified) { if (fn_type_id->cc == CallingConventionUnspecified
|| fn_type_id->cc == CallingConventionInline) {
return handle_is_ptr(g, fn_type_id->return_type); return handle_is_ptr(g, fn_type_id->return_type);
} }
if (fn_type_id->cc != CallingConventionC) { if (fn_type_id->cc != CallingConventionC) {
@ -1888,6 +1891,7 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_
case CallingConventionC: case CallingConventionC:
case CallingConventionNaked: case CallingConventionNaked:
case CallingConventionAsync: case CallingConventionAsync:
case CallingConventionInline:
break; break;
case CallingConventionInterrupt: case CallingConventionInterrupt:
if (g->zig_target->arch != ZigLLVM_x86 if (g->zig_target->arch != ZigLLVM_x86
@ -3587,7 +3591,7 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i
} }
} }
static ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { static ZigFn *create_fn_raw(CodeGen *g, bool is_noinline) {
ZigFn *fn_entry = heap::c_allocator.create<ZigFn>(); ZigFn *fn_entry = heap::c_allocator.create<ZigFn>();
fn_entry->ir_executable = heap::c_allocator.create<IrExecutableSrc>(); fn_entry->ir_executable = heap::c_allocator.create<IrExecutableSrc>();
@ -3597,7 +3601,7 @@ static ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->analyzed_executable.fn_entry = fn_entry;
fn_entry->ir_executable->fn_entry = fn_entry; fn_entry->ir_executable->fn_entry = fn_entry;
fn_entry->fn_inline = inline_value; fn_entry->is_noinline = is_noinline;
return fn_entry; return fn_entry;
} }
@ -3606,7 +3610,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
assert(proto_node->type == NodeTypeFnProto); assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline); ZigFn *fn_entry = create_fn_raw(g, fn_proto->is_noinline);
fn_entry->proto_node = proto_node; fn_entry->proto_node = proto_node;
fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr :
@ -3739,6 +3743,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
fn_table_entry->type_entry = g->builtin_types.entry_invalid; fn_table_entry->type_entry = g->builtin_types.entry_invalid;
tld_fn->base.resolution = TldResolutionInvalid; tld_fn->base.resolution = TldResolutionInvalid;
return; return;
case CallingConventionInline:
add_node_error(g, fn_def_node,
buf_sprintf("exported function cannot be inline"));
fn_table_entry->type_entry = g->builtin_types.entry_invalid;
tld_fn->base.resolution = TldResolutionInvalid;
return;
case CallingConventionC: case CallingConventionC:
case CallingConventionNaked: case CallingConventionNaked:
case CallingConventionInterrupt: case CallingConventionInterrupt:
@ -3774,7 +3784,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
fn_table_entry->inferred_async_node = fn_table_entry->proto_node; fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
} }
} else if (source_node->type == NodeTypeTestDecl) { } else if (source_node->type == NodeTypeTestDecl) {
ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto); ZigFn *fn_table_entry = create_fn_raw(g, false);
get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, true); get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, true);

View File

@ -123,13 +123,8 @@ static const char *export_string(bool is_export) {
// zig_unreachable(); // zig_unreachable();
//} //}
static const char *inline_string(FnInline fn_inline) { static const char *inline_string(bool is_inline) {
switch (fn_inline) { return is_inline ? "inline" : "";
case FnInlineAlways: return "inline ";
case FnInlineNever: return "noinline ";
case FnInlineAuto: return "";
}
zig_unreachable();
} }
static const char *const_or_var_string(bool is_const) { static const char *const_or_var_string(bool is_const) {
@ -446,7 +441,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *export_str = export_string(node->data.fn_proto.is_export); const char *export_str = export_string(node->data.fn_proto.is_export);
const char *inline_str = inline_string(node->data.fn_proto.fn_inline); const char *inline_str = inline_string(node->data.fn_proto.is_noinline);
fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);
if (node->data.fn_proto.name != nullptr) { if (node->data.fn_proto.name != nullptr) {
print_symbol(ar, node->data.fn_proto.name); print_symbol(ar, node->data.fn_proto.name);

View File

@ -159,6 +159,7 @@ static const char *get_mangled_name(CodeGen *g, const char *original_name) {
static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
switch (cc) { switch (cc) {
case CallingConventionUnspecified: case CallingConventionUnspecified:
case CallingConventionInline:
return ZigLLVM_Fast; return ZigLLVM_Fast;
case CallingConventionC: case CallingConventionC:
return ZigLLVM_C; return ZigLLVM_C;
@ -350,6 +351,7 @@ static bool cc_want_sret_attr(CallingConvention cc) {
return true; return true;
case CallingConventionAsync: case CallingConventionAsync:
case CallingConventionUnspecified: case CallingConventionUnspecified:
case CallingConventionInline:
return false; return false;
} }
zig_unreachable(); zig_unreachable();
@ -452,20 +454,11 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
} }
} }
switch (fn->fn_inline) { if (cc == CallingConventionInline)
case FnInlineAlways:
addLLVMFnAttr(llvm_fn, "alwaysinline"); addLLVMFnAttr(llvm_fn, "alwaysinline");
g->inline_fns.append(fn);
break; if (fn->is_noinline || (cc != CallingConventionInline && fn->alignstack_value != 0))
case FnInlineNever:
addLLVMFnAttr(llvm_fn, "noinline"); addLLVMFnAttr(llvm_fn, "noinline");
break;
case FnInlineAuto:
if (fn->alignstack_value != 0) {
addLLVMFnAttr(llvm_fn, "noinline");
}
break;
}
if (cc == CallingConventionNaked) { if (cc == CallingConventionNaked) {
addLLVMFnAttr(llvm_fn, "naked"); addLLVMFnAttr(llvm_fn, "naked");
@ -532,7 +525,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
addLLVMFnAttr(llvm_fn, "nounwind"); addLLVMFnAttr(llvm_fn, "nounwind");
add_uwtable_attr(g, llvm_fn); add_uwtable_attr(g, llvm_fn);
addLLVMFnAttr(llvm_fn, "nobuiltin"); addLLVMFnAttr(llvm_fn, "nobuiltin");
if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) { if (codegen_have_frame_pointer(g) && cc != CallingConventionInline) {
ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all"); ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all");
} }
if (fn->section_name) { if (fn->section_name) {
@ -9043,19 +9036,16 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
static_assert(CallingConventionC == 1, ""); static_assert(CallingConventionC == 1, "");
static_assert(CallingConventionNaked == 2, ""); static_assert(CallingConventionNaked == 2, "");
static_assert(CallingConventionAsync == 3, ""); static_assert(CallingConventionAsync == 3, "");
static_assert(CallingConventionInterrupt == 4, ""); static_assert(CallingConventionInline == 4, "");
static_assert(CallingConventionSignal == 5, ""); static_assert(CallingConventionInterrupt == 5, "");
static_assert(CallingConventionStdcall == 6, ""); static_assert(CallingConventionSignal == 6, "");
static_assert(CallingConventionFastcall == 7, ""); static_assert(CallingConventionStdcall == 7, "");
static_assert(CallingConventionVectorcall == 8, ""); static_assert(CallingConventionFastcall == 8, "");
static_assert(CallingConventionThiscall == 9, ""); static_assert(CallingConventionVectorcall == 9, "");
static_assert(CallingConventionAPCS == 10, ""); static_assert(CallingConventionThiscall == 10, "");
static_assert(CallingConventionAAPCS == 11, ""); static_assert(CallingConventionAPCS == 11, "");
static_assert(CallingConventionAAPCSVFP == 12, ""); static_assert(CallingConventionAAPCS == 12, "");
static_assert(CallingConventionAAPCSVFP == 13, "");
static_assert(FnInlineAuto == 0, "");
static_assert(FnInlineAlways == 1, "");
static_assert(FnInlineNever == 2, "");
static_assert(BuiltinPtrSizeOne == 0, ""); static_assert(BuiltinPtrSizeOne == 0, "");
static_assert(BuiltinPtrSizeMany == 1, ""); static_assert(BuiltinPtrSizeMany == 1, "");

View File

@ -19000,7 +19000,7 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV
} else if (init_val->type->id == ZigTypeIdFn && } else if (init_val->type->id == ZigTypeIdFn &&
init_val->special != ConstValSpecialUndef && init_val->special != ConstValSpecialUndef &&
init_val->data.x_ptr.special == ConstPtrSpecialFunction && init_val->data.x_ptr.special == ConstPtrSpecialFunction &&
init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) init_val->data.x_ptr.data.fn.fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline)
{ {
var_class_requires_const = true; var_class_requires_const = true;
if (!var->src_is_const && !is_comptime_var) { if (!var->src_is_const && !is_comptime_var) {
@ -19182,6 +19182,11 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
buf_sprintf("exported function cannot be async")); buf_sprintf("exported function cannot be async"));
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
} break; } break;
case CallingConventionInline: {
ErrorMsg *msg = ir_add_error(ira, &target->base,
buf_sprintf("exported function cannot be inline"));
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
} break;
case CallingConventionC: case CallingConventionC:
case CallingConventionNaked: case CallingConventionNaked:
case CallingConventionInterrupt: case CallingConventionInterrupt:
@ -21120,7 +21125,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
if (type_is_invalid(return_type)) if (type_is_invalid(return_type))
return ira->codegen->invalid_inst_gen; return ira->codegen->invalid_inst_gen;
if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && modifier == CallModifierNeverInline) { if (fn_entry != nullptr && fn_type_id->cc == CallingConventionInline && modifier == CallModifierNeverInline) {
ir_add_error(ira, source_instr, ir_add_error(ira, source_instr,
buf_sprintf("no-inline call of inline function")); buf_sprintf("no-inline call of inline function"));
return ira->codegen->invalid_inst_gen; return ira->codegen->invalid_inst_gen;
@ -25219,10 +25224,6 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown))) if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown)))
return err; return err;
ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type);
if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown)))
return err;
resolve_container_usingnamespace_decls(ira->codegen, decls_scope); resolve_container_usingnamespace_decls(ira->codegen, decls_scope);
// The unresolved declarations are collected in a separate queue to avoid // The unresolved declarations are collected in a separate queue to avoid
@ -25365,11 +25366,11 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa
fn_decl_fields[0]->special = ConstValSpecialStatic; fn_decl_fields[0]->special = ConstValSpecialStatic;
fn_decl_fields[0]->type = ira->codegen->builtin_types.entry_type; fn_decl_fields[0]->type = ira->codegen->builtin_types.entry_type;
fn_decl_fields[0]->data.x_type = fn_entry->type_entry; fn_decl_fields[0]->data.x_type = fn_entry->type_entry;
// inline_type: Data.FnDecl.Inline // is_noinline: bool
ensure_field_index(fn_decl_val->type, "inline_type", 1); ensure_field_index(fn_decl_val->type, "is_noinline", 1);
fn_decl_fields[1]->special = ConstValSpecialStatic; fn_decl_fields[1]->special = ConstValSpecialStatic;
fn_decl_fields[1]->type = type_info_fn_decl_inline_type; fn_decl_fields[1]->type = ira->codegen->builtin_types.entry_bool;
bigint_init_unsigned(&fn_decl_fields[1]->data.x_enum_tag, fn_entry->fn_inline); fn_decl_fields[1]->data.x_bool = fn_entry->is_noinline;
// is_var_args: bool // is_var_args: bool
ensure_field_index(fn_decl_val->type, "is_var_args", 2); ensure_field_index(fn_decl_val->type, "is_var_args", 2);
bool is_varargs = fn_node->is_var_args; bool is_varargs = fn_node->is_var_args;
@ -30957,7 +30958,7 @@ static IrInstGen *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstS
return ira->codegen->invalid_inst_gen; return ira->codegen->invalid_inst_gen;
} }
if (fn_entry->fn_inline == FnInlineAlways) { if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) {
ir_add_error(ira, &instruction->base.base, buf_sprintf("@setAlignStack in inline function")); ir_add_error(ira, &instruction->base.base, buf_sprintf("@setAlignStack in inline function"));
return ira->codegen->invalid_inst_gen; return ira->codegen->invalid_inst_gen;
} }

View File

@ -693,8 +693,6 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
Token *first = eat_token_if(pc, TokenIdKeywordExport); Token *first = eat_token_if(pc, TokenIdKeywordExport);
if (first == nullptr) if (first == nullptr)
first = eat_token_if(pc, TokenIdKeywordExtern); first = eat_token_if(pc, TokenIdKeywordExtern);
if (first == nullptr)
first = eat_token_if(pc, TokenIdKeywordInline);
if (first == nullptr) if (first == nullptr)
first = eat_token_if(pc, TokenIdKeywordNoInline); first = eat_token_if(pc, TokenIdKeywordNoInline);
if (first != nullptr) { if (first != nullptr) {
@ -702,7 +700,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
if (first->id == TokenIdKeywordExtern) if (first->id == TokenIdKeywordExtern)
lib_name = eat_token_if(pc, TokenIdStringLiteral); lib_name = eat_token_if(pc, TokenIdStringLiteral);
if (first->id != TokenIdKeywordInline && first->id != TokenIdKeywordNoInline) { if (first->id != TokenIdKeywordNoInline) {
Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
AstNode *var_decl = ast_parse_var_decl(pc); AstNode *var_decl = ast_parse_var_decl(pc);
if (var_decl != nullptr) { if (var_decl != nullptr) {
@ -739,17 +737,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
if (!fn_proto->data.fn_proto.is_extern) if (!fn_proto->data.fn_proto.is_extern)
fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern;
fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport;
switch (first->id) { if (first->id == TokenIdKeywordNoInline)
case TokenIdKeywordInline: fn_proto->data.fn_proto.is_noinline = true;
fn_proto->data.fn_proto.fn_inline = FnInlineAlways;
break;
case TokenIdKeywordNoInline:
fn_proto->data.fn_proto.fn_inline = FnInlineNever;
break;
default:
fn_proto->data.fn_proto.fn_inline = FnInlineAuto;
break;
}
fn_proto->data.fn_proto.lib_name = token_buf(lib_name); fn_proto->data.fn_proto.lib_name = token_buf(lib_name);
AstNode *res = fn_proto; AstNode *res = fn_proto;