| author | |
| committer | |
| log | 41144a8566a6fbd779403f6b69424bb640c94a7f |
| tree | b4c5807dddca6d3eb66047aebccf6cc9d3fdd90c |
| parent | f043e0e85cac9330cf809bef177784c3cd133348 |
closes #30611 files changed, 213 insertions(+), 48 deletions(-)
doc/langref.md+6-3| ... | @@ -81,9 +81,9 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo | ... | @@ -81,9 +81,9 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo |
| 81 | 81 | ||
| 82 | SwitchItem = Expression | (Expression "..." Expression) | 82 | SwitchItem = Expression | (Expression "..." Expression) |
| 83 | 83 | ||
| 84 | WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body | 84 | WhileExpression(body) = "while" "(" Expression option(";" Expression) ")" body |
| 85 | 85 | ||
| 86 | ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body | 86 | ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body |
| 87 | 87 | ||
| 88 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression | 88 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression |
| 89 | 89 | ||
| ... | @@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | ... | @@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%" |
| 127 | 127 | ||
| 128 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression | 128 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression |
| 129 | 129 | ||
| 130 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | 130 | SuffixOpExpression = InlineExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) |
| 131 | |||
| 132 | InlineExpression = option("inline") PrimaryExpression | ||
| 131 | 133 | ||
| 132 | FieldAccessExpression = "." Symbol | 134 | FieldAccessExpression = "." Symbol |
| 133 | 135 | ||
| ... | @@ -161,6 +163,7 @@ ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" ma | ... | @@ -161,6 +163,7 @@ ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" ma |
| 161 | ## Operator Precedence | 163 | ## Operator Precedence |
| 162 | 164 | ||
| 163 | ``` | 165 | ``` |
| 166 | inline x | ||
| 164 | x() x[] x.y | 167 | x() x[] x.y |
| 165 | !x -x -%x ~x *x &x ?x %x %%x ??x | 168 | !x -x -%x ~x *x &x ?x %x %%x ??x |
| 166 | x{} | 169 | x{} |
src/all_types.hpp+21-1| ... | @@ -167,6 +167,7 @@ struct ConstErrValue { | ... | @@ -167,6 +167,7 @@ struct ConstErrValue { |
| 167 | struct ConstBoundFnValue { | 167 | struct ConstBoundFnValue { |
| 168 | FnTableEntry *fn; | 168 | FnTableEntry *fn; |
| 169 | IrInstruction *first_arg; | 169 | IrInstruction *first_arg; |
| 170 | bool is_inline; | ||
| 170 | }; | 171 | }; |
| 171 | 172 | ||
| 172 | struct ConstArgTuple { | 173 | struct ConstArgTuple { |
| ... | @@ -192,6 +193,11 @@ enum RuntimeHintMaybe { | ... | @@ -192,6 +193,11 @@ enum RuntimeHintMaybe { |
| 192 | RuntimeHintMaybeNonNull, | 193 | RuntimeHintMaybeNonNull, |
| 193 | }; | 194 | }; |
| 194 | 195 | ||
| 196 | struct ConstFn { | ||
| 197 | FnTableEntry *fn_entry; | ||
| 198 | bool is_inline; | ||
| 199 | }; | ||
| 200 | |||
| 195 | struct ConstExprValue { | 201 | struct ConstExprValue { |
| 196 | TypeTableEntry *type; | 202 | TypeTableEntry *type; |
| 197 | ConstValSpecial special; | 203 | ConstValSpecial special; |
| ... | @@ -202,7 +208,7 @@ struct ConstExprValue { | ... | @@ -202,7 +208,7 @@ struct ConstExprValue { |
| 202 | // populated if special == ConstValSpecialStatic | 208 | // populated if special == ConstValSpecialStatic |
| 203 | BigNum x_bignum; | 209 | BigNum x_bignum; |
| 204 | bool x_bool; | 210 | bool x_bool; |
| 205 | FnTableEntry *x_fn; | 211 | ConstFn x_fn; |
| 206 | ConstBoundFnValue x_bound_fn; | 212 | ConstBoundFnValue x_bound_fn; |
| 207 | TypeTableEntry *x_type; | 213 | TypeTableEntry *x_type; |
| 208 | ConstExprValue *x_maybe; | 214 | ConstExprValue *x_maybe; |
| ... | @@ -366,6 +372,7 @@ enum NodeType { | ... | @@ -366,6 +372,7 @@ enum NodeType { |
| 366 | NodeTypeTypeLiteral, | 372 | NodeTypeTypeLiteral, |
| 367 | NodeTypeVarLiteral, | 373 | NodeTypeVarLiteral, |
| 368 | NodeTypeTryExpr, | 374 | NodeTypeTryExpr, |
| 375 | NodeTypeInlineExpr, | ||
| 369 | }; | 376 | }; |
| 370 | 377 | ||
| 371 | struct AstNodeRoot { | 378 | struct AstNodeRoot { |
| ... | @@ -789,6 +796,10 @@ struct AstNodeTypeLiteral { | ... | @@ -789,6 +796,10 @@ struct AstNodeTypeLiteral { |
| 789 | struct AstNodeVarLiteral { | 796 | struct AstNodeVarLiteral { |
| 790 | }; | 797 | }; |
| 791 | 798 | ||
| 799 | struct AstNodeInlineExpr { | ||
| 800 | AstNode *body; | ||
| 801 | }; | ||
| 802 | |||
| 792 | struct AstNode { | 803 | struct AstNode { |
| 793 | enum NodeType type; | 804 | enum NodeType type; |
| 794 | size_t line; | 805 | size_t line; |
| ... | @@ -847,6 +858,7 @@ struct AstNode { | ... | @@ -847,6 +858,7 @@ struct AstNode { |
| 847 | AstNodeErrorType error_type; | 858 | AstNodeErrorType error_type; |
| 848 | AstNodeTypeLiteral type_literal; | 859 | AstNodeTypeLiteral type_literal; |
| 849 | AstNodeVarLiteral var_literal; | 860 | AstNodeVarLiteral var_literal; |
| 861 | AstNodeInlineExpr inline_expr; | ||
| 850 | } data; | 862 | } data; |
| 851 | }; | 863 | }; |
| 852 | 864 | ||
| ... | @@ -1748,6 +1760,7 @@ enum IrInstructionId { | ... | @@ -1748,6 +1760,7 @@ enum IrInstructionId { |
| 1748 | IrInstructionIdDeclRef, | 1760 | IrInstructionIdDeclRef, |
| 1749 | IrInstructionIdPanic, | 1761 | IrInstructionIdPanic, |
| 1750 | IrInstructionIdEnumTagName, | 1762 | IrInstructionIdEnumTagName, |
| 1763 | IrInstructionIdSetFnRefInline, | ||
| 1751 | }; | 1764 | }; |
| 1752 | 1765 | ||
| 1753 | struct IrInstruction { | 1766 | struct IrInstruction { |
| ... | @@ -1943,6 +1956,7 @@ struct IrInstructionCall { | ... | @@ -1943,6 +1956,7 @@ struct IrInstructionCall { |
| 1943 | IrInstruction **args; | 1956 | IrInstruction **args; |
| 1944 | bool is_comptime; | 1957 | bool is_comptime; |
| 1945 | LLVMValueRef tmp_ptr; | 1958 | LLVMValueRef tmp_ptr; |
| 1959 | bool is_inline; | ||
| 1946 | }; | 1960 | }; |
| 1947 | 1961 | ||
| 1948 | struct IrInstructionConst { | 1962 | struct IrInstructionConst { |
| ... | @@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName { | ... | @@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName { |
| 2493 | IrInstruction *target; | 2507 | IrInstruction *target; |
| 2494 | }; | 2508 | }; |
| 2495 | 2509 | ||
| 2510 | struct IrInstructionSetFnRefInline { | ||
| 2511 | IrInstruction base; | ||
| 2512 | |||
| 2513 | IrInstruction *fn_ref; | ||
| 2514 | }; | ||
| 2515 | |||
| 2496 | static const size_t slice_ptr_index = 0; | 2516 | static const size_t slice_ptr_index = 0; |
| 2497 | static const size_t slice_len_index = 1; | 2517 | static const size_t slice_len_index = 1; |
| 2498 | 2518 |
src/analyze.cpp+10-5| ... | @@ -2129,6 +2129,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -2129,6 +2129,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 2129 | case NodeTypeTypeLiteral: | 2129 | case NodeTypeTypeLiteral: |
| 2130 | case NodeTypeVarLiteral: | 2130 | case NodeTypeVarLiteral: |
| 2131 | case NodeTypeTryExpr: | 2131 | case NodeTypeTryExpr: |
| 2132 | case NodeTypeInlineExpr: | ||
| 2132 | zig_unreachable(); | 2133 | zig_unreachable(); |
| 2133 | } | 2134 | } |
| 2134 | } | 2135 | } |
| ... | @@ -3251,7 +3252,8 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { | ... | @@ -3251,7 +3252,8 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3251 | // TODO better hashing algorithm | 3252 | // TODO better hashing algorithm |
| 3252 | return 31643936; | 3253 | return 31643936; |
| 3253 | case TypeTableEntryIdFn: | 3254 | case TypeTableEntryIdFn: |
| 3254 | return hash_ptr(const_val->data.x_fn); | 3255 | return hash_ptr(const_val->data.x_fn.fn_entry) + |
| 3256 | (const_val->data.x_fn.is_inline ? 4133894920 : 3983484790); | ||
| 3255 | case TypeTableEntryIdTypeDecl: | 3257 | case TypeTableEntryIdTypeDecl: |
| 3256 | return hash_ptr(const_val->data.x_type); | 3258 | return hash_ptr(const_val->data.x_type); |
| 3257 | case TypeTableEntryIdNamespace: | 3259 | case TypeTableEntryIdNamespace: |
| ... | @@ -3697,7 +3699,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { | ... | @@ -3697,7 +3699,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3697 | case TypeTableEntryIdPureError: | 3699 | case TypeTableEntryIdPureError: |
| 3698 | return a->data.x_pure_err == b->data.x_pure_err; | 3700 | return a->data.x_pure_err == b->data.x_pure_err; |
| 3699 | case TypeTableEntryIdFn: | 3701 | case TypeTableEntryIdFn: |
| 3700 | return a->data.x_fn == b->data.x_fn; | 3702 | return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry && |
| 3703 | a->data.x_fn.is_inline == b->data.x_fn.is_inline; | ||
| 3701 | case TypeTableEntryIdBool: | 3704 | case TypeTableEntryIdBool: |
| 3702 | return a->data.x_bool == b->data.x_bool; | 3705 | return a->data.x_bool == b->data.x_bool; |
| 3703 | case TypeTableEntryIdInt: | 3706 | case TypeTableEntryIdInt: |
| ... | @@ -3933,8 +3936,9 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { | ... | @@ -3933,8 +3936,9 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 3933 | zig_unreachable(); | 3936 | zig_unreachable(); |
| 3934 | case TypeTableEntryIdFn: | 3937 | case TypeTableEntryIdFn: |
| 3935 | { | 3938 | { |
| 3936 | FnTableEntry *fn_entry = const_val->data.x_fn; | 3939 | FnTableEntry *fn_entry = const_val->data.x_fn.fn_entry; |
| 3937 | buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name)); | 3940 | const char *inline_str = const_val->data.x_fn.is_inline ? "inline " : ""; |
| 3941 | buf_appendf(buf, "%s%s", inline_str, buf_ptr(&fn_entry->symbol_name)); | ||
| 3938 | return; | 3942 | return; |
| 3939 | } | 3943 | } |
| 3940 | case TypeTableEntryIdBlock: | 3944 | case TypeTableEntryIdBlock: |
| ... | @@ -4011,7 +4015,8 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { | ... | @@ -4011,7 +4015,8 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 4011 | case TypeTableEntryIdBoundFn: | 4015 | case TypeTableEntryIdBoundFn: |
| 4012 | { | 4016 | { |
| 4013 | FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn; | 4017 | FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn; |
| 4014 | buf_appendf(buf, "(bound fn %s)", buf_ptr(&fn_entry->symbol_name)); | 4018 | const char *inline_str = const_val->data.x_bound_fn.is_inline ? "inline " : ""; |
| 4019 | buf_appendf(buf, "(%sbound fn %s)", inline_str, buf_ptr(&fn_entry->symbol_name)); | ||
| 4015 | return; | 4020 | return; |
| 4016 | } | 4021 | } |
| 4017 | case TypeTableEntryIdStruct: | 4022 | case TypeTableEntryIdStruct: |
src/ast_render.cpp+8| ... | @@ -240,6 +240,8 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -240,6 +240,8 @@ static const char *node_type_str(NodeType node_type) { |
| 240 | return "VarLiteral"; | 240 | return "VarLiteral"; |
| 241 | case NodeTypeTryExpr: | 241 | case NodeTypeTryExpr: |
| 242 | return "TryExpr"; | 242 | return "TryExpr"; |
| 243 | case NodeTypeInlineExpr: | ||
| 244 | return "InlineExpr"; | ||
| 243 | } | 245 | } |
| 244 | zig_unreachable(); | 246 | zig_unreachable(); |
| 245 | } | 247 | } |
| ... | @@ -921,6 +923,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -921,6 +923,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 921 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); | 923 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); |
| 922 | break; | 924 | break; |
| 923 | } | 925 | } |
| 926 | case NodeTypeInlineExpr: | ||
| 927 | { | ||
| 928 | fprintf(ar->f, "inline "); | ||
| 929 | render_node_grouped(ar, node->data.inline_expr.body); | ||
| 930 | break; | ||
| 931 | } | ||
| 924 | case NodeTypeFnDecl: | 932 | case NodeTypeFnDecl: |
| 925 | case NodeTypeParamDecl: | 933 | case NodeTypeParamDecl: |
| 926 | case NodeTypeErrorValueDecl: | 934 | case NodeTypeErrorValueDecl: |
src/codegen.cpp+8-3| ... | @@ -608,7 +608,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { | ... | @@ -608,7 +608,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { |
| 608 | LLVMBuildLoad(g->builder, ptr_ptr, ""), | 608 | LLVMBuildLoad(g->builder, ptr_ptr, ""), |
| 609 | LLVMBuildLoad(g->builder, len_ptr, ""), | 609 | LLVMBuildLoad(g->builder, len_ptr, ""), |
| 610 | }; | 610 | }; |
| 611 | ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, ""); | 611 | ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, ""); |
| 612 | LLVMBuildUnreachable(g->builder); | 612 | LLVMBuildUnreachable(g->builder); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| ... | @@ -1773,8 +1773,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -1773,8 +1773,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 1773 | } | 1773 | } |
| 1774 | } | 1774 | } |
| 1775 | 1775 | ||
| 1776 | bool want_always_inline = (instruction->fn_entry != nullptr && | ||
| 1777 | instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline; | ||
| 1778 | |||
| 1776 | LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, | 1779 | LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, |
| 1777 | gen_param_values, (unsigned)gen_param_index, fn_type->data.fn.calling_convention, ""); | 1780 | gen_param_values, (unsigned)gen_param_index, fn_type->data.fn.calling_convention, |
| 1781 | want_always_inline, ""); | ||
| 1778 | 1782 | ||
| 1779 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | 1783 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 1780 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; | 1784 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| ... | @@ -2749,6 +2753,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -2749,6 +2753,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2749 | case IrInstructionIdSetGlobalLinkage: | 2753 | case IrInstructionIdSetGlobalLinkage: |
| 2750 | case IrInstructionIdDeclRef: | 2754 | case IrInstructionIdDeclRef: |
| 2751 | case IrInstructionIdSwitchVar: | 2755 | case IrInstructionIdSwitchVar: |
| 2756 | case IrInstructionIdSetFnRefInline: | ||
| 2752 | zig_unreachable(); | 2757 | zig_unreachable(); |
| 2753 | case IrInstructionIdReturn: | 2758 | case IrInstructionIdReturn: |
| 2754 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); | 2759 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | @@ -3183,7 +3188,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3183,7 +3188,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3183 | } | 3188 | } |
| 3184 | } | 3189 | } |
| 3185 | case TypeTableEntryIdFn: | 3190 | case TypeTableEntryIdFn: |
| 3186 | return fn_llvm_value(g, const_val->data.x_fn); | 3191 | return fn_llvm_value(g, const_val->data.x_fn.fn_entry); |
| 3187 | case TypeTableEntryIdPointer: | 3192 | case TypeTableEntryIdPointer: |
| 3188 | { | 3193 | { |
| 3189 | render_const_val_global(g, const_val, ""); | 3194 | render_const_val_global(g, const_val, ""); |
src/ir.cpp+102-22| ... | @@ -545,6 +545,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) { | ... | @@ -545,6 +545,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) { |
| 545 | return IrInstructionIdEnumTagName; | 545 | return IrInstructionIdEnumTagName; |
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnRefInline *) { | ||
| 549 | return IrInstructionIdSetFnRefInline; | ||
| 550 | } | ||
| 551 | |||
| 548 | template<typename T> | 552 | template<typename T> |
| 549 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 553 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 550 | T *special_instruction = allocate<T>(1); | 554 | T *special_instruction = allocate<T>(1); |
| ... | @@ -701,7 +705,7 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -701,7 +705,7 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode * |
| 701 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node); | 705 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node); |
| 702 | const_instruction->base.value.type = fn_entry->type_entry; | 706 | const_instruction->base.value.type = fn_entry->type_entry; |
| 703 | const_instruction->base.value.special = ConstValSpecialStatic; | 707 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 704 | const_instruction->base.value.data.x_fn = fn_entry; | 708 | const_instruction->base.value.data.x_fn.fn_entry = fn_entry; |
| 705 | return &const_instruction->base; | 709 | return &const_instruction->base; |
| 706 | } | 710 | } |
| 707 | 711 | ||
| ... | @@ -882,12 +886,13 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction | ... | @@ -882,12 +886,13 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction |
| 882 | 886 | ||
| 883 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, | 887 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 884 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 888 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 885 | bool is_comptime) | 889 | bool is_comptime, bool is_inline) |
| 886 | { | 890 | { |
| 887 | IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node); | 891 | IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node); |
| 888 | call_instruction->fn_entry = fn_entry; | 892 | call_instruction->fn_entry = fn_entry; |
| 889 | call_instruction->fn_ref = fn_ref; | 893 | call_instruction->fn_ref = fn_ref; |
| 890 | call_instruction->is_comptime = is_comptime; | 894 | call_instruction->is_comptime = is_comptime; |
| 895 | call_instruction->is_inline = is_inline; | ||
| 891 | call_instruction->args = args; | 896 | call_instruction->args = args; |
| 892 | call_instruction->arg_count = arg_count; | 897 | call_instruction->arg_count = arg_count; |
| 893 | 898 | ||
| ... | @@ -901,10 +906,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc | ... | @@ -901,10 +906,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc |
| 901 | 906 | ||
| 902 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, | 907 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 903 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 908 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 904 | bool is_comptime) | 909 | bool is_comptime, bool is_inline) |
| 905 | { | 910 | { |
| 906 | IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, | 911 | IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, |
| 907 | old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime); | 912 | old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, is_inline); |
| 908 | ir_link_new_instruction(new_instruction, old_instruction); | 913 | ir_link_new_instruction(new_instruction, old_instruction); |
| 909 | return new_instruction; | 914 | return new_instruction; |
| 910 | } | 915 | } |
| ... | @@ -2145,6 +2150,18 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -2145,6 +2150,18 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo |
| 2145 | return &instruction->base; | 2150 | return &instruction->base; |
| 2146 | } | 2151 | } |
| 2147 | 2152 | ||
| 2153 | static IrInstruction *ir_build_set_fn_ref_inline(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2154 | IrInstruction *fn_ref) | ||
| 2155 | { | ||
| 2156 | IrInstructionSetFnRefInline *instruction = ir_build_instruction<IrInstructionSetFnRefInline>( | ||
| 2157 | irb, scope, source_node); | ||
| 2158 | instruction->fn_ref = fn_ref; | ||
| 2159 | |||
| 2160 | ir_ref_instruction(fn_ref, irb->current_basic_block); | ||
| 2161 | |||
| 2162 | return &instruction->base; | ||
| 2163 | } | ||
| 2164 | |||
| 2148 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { | 2165 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2149 | return nullptr; | 2166 | return nullptr; |
| 2150 | } | 2167 | } |
| ... | @@ -2809,6 +2826,14 @@ static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagNam | ... | @@ -2809,6 +2826,14 @@ static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagNam |
| 2809 | } | 2826 | } |
| 2810 | } | 2827 | } |
| 2811 | 2828 | ||
| 2829 | static IrInstruction *ir_instruction_setfnrefinline_get_dep(IrInstructionSetFnRefInline *instruction, size_t index) { | ||
| 2830 | switch (index) { | ||
| 2831 | case 0: return instruction->fn_ref; | ||
| 2832 | default: return nullptr; | ||
| 2833 | } | ||
| 2834 | } | ||
| 2835 | |||
| 2836 | |||
| 2812 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { | 2837 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2813 | switch (instruction->id) { | 2838 | switch (instruction->id) { |
| 2814 | case IrInstructionIdInvalid: | 2839 | case IrInstructionIdInvalid: |
| ... | @@ -2999,6 +3024,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -2999,6 +3024,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 2999 | return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); | 3024 | return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); |
| 3000 | case IrInstructionIdEnumTagName: | 3025 | case IrInstructionIdEnumTagName: |
| 3001 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); | 3026 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); |
| 3027 | case IrInstructionIdSetFnRefInline: | ||
| 3028 | return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index); | ||
| 3002 | } | 3029 | } |
| 3003 | zig_unreachable(); | 3030 | zig_unreachable(); |
| 3004 | } | 3031 | } |
| ... | @@ -4297,7 +4324,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -4297,7 +4324,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 4297 | return args[i]; | 4324 | return args[i]; |
| 4298 | } | 4325 | } |
| 4299 | 4326 | ||
| 4300 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false); | 4327 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, false); |
| 4301 | } | 4328 | } |
| 4302 | 4329 | ||
| 4303 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 4330 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | @@ -5490,6 +5517,19 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -5490,6 +5517,19 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5490 | return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type); | 5517 | return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type); |
| 5491 | } | 5518 | } |
| 5492 | 5519 | ||
| 5520 | static IrInstruction *ir_gen_inline_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | ||
| 5521 | assert(node->type == NodeTypeInlineExpr); | ||
| 5522 | |||
| 5523 | AstNode *body_node = node->data.inline_expr.body; | ||
| 5524 | |||
| 5525 | IrInstruction *fn_ptr = ir_gen_node(irb, body_node, parent_scope); | ||
| 5526 | if (fn_ptr == irb->codegen->invalid_instruction) | ||
| 5527 | return irb->codegen->invalid_instruction; | ||
| 5528 | |||
| 5529 | return ir_build_set_fn_ref_inline(irb, parent_scope, node, fn_ptr); | ||
| 5530 | } | ||
| 5531 | |||
| 5532 | |||
| 5493 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, | 5533 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| 5494 | LVal lval) | 5534 | LVal lval) |
| 5495 | { | 5535 | { |
| ... | @@ -5580,6 +5620,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -5580,6 +5620,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5580 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); | 5620 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 5581 | case NodeTypeFnProto: | 5621 | case NodeTypeFnProto: |
| 5582 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); | 5622 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); |
| 5623 | case NodeTypeInlineExpr: | ||
| 5624 | return ir_lval_wrap(irb, scope, ir_gen_inline_expr(irb, scope, node), lval); | ||
| 5583 | case NodeTypeFnDef: | 5625 | case NodeTypeFnDef: |
| 5584 | zig_panic("TODO IR gen NodeTypeFnDef"); | 5626 | zig_panic("TODO IR gen NodeTypeFnDef"); |
| 5585 | case NodeTypeFnDecl: | 5627 | case NodeTypeFnDecl: |
| ... | @@ -6435,7 +6477,7 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value | ... | @@ -6435,7 +6477,7 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value |
| 6435 | return const_val->data.x_type; | 6477 | return const_val->data.x_type; |
| 6436 | } | 6478 | } |
| 6437 | 6479 | ||
| 6438 | static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { | 6480 | static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value, bool *is_inline) { |
| 6439 | if (fn_value == ira->codegen->invalid_instruction) | 6481 | if (fn_value == ira->codegen->invalid_instruction) |
| 6440 | return nullptr; | 6482 | return nullptr; |
| 6441 | 6483 | ||
| ... | @@ -6452,7 +6494,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { | ... | @@ -6452,7 +6494,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 6452 | if (!const_val) | 6494 | if (!const_val) |
| 6453 | return nullptr; | 6495 | return nullptr; |
| 6454 | 6496 | ||
| 6455 | return const_val->data.x_fn; | 6497 | *is_inline = const_val->data.x_fn.is_inline; |
| 6498 | return const_val->data.x_fn.fn_entry; | ||
| 6456 | } | 6499 | } |
| 6457 | 6500 | ||
| 6458 | static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { | 6501 | static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { |
| ... | @@ -8245,7 +8288,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -8245,7 +8288,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 8245 | 8288 | ||
| 8246 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 8289 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 8247 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, | 8290 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, |
| 8248 | IrInstruction *first_arg_ptr, bool inline_fn_call) | 8291 | IrInstruction *first_arg_ptr, bool comptime_fn_call, bool inline_fn_call) |
| 8249 | { | 8292 | { |
| 8250 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 8293 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 8251 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; | 8294 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; |
| ... | @@ -8276,7 +8319,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -8276,7 +8319,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 8276 | return ira->codegen->builtin_types.entry_invalid; | 8319 | return ira->codegen->builtin_types.entry_invalid; |
| 8277 | } | 8320 | } |
| 8278 | 8321 | ||
| 8279 | if (inline_fn_call) { | 8322 | if (comptime_fn_call) { |
| 8280 | // No special handling is needed for compile time evaluation of generic functions. | 8323 | // No special handling is needed for compile time evaluation of generic functions. |
| 8281 | if (!fn_entry || fn_entry->type_entry->data.fn.fn_type_id.is_extern) { | 8324 | if (!fn_entry || fn_entry->type_entry->data.fn.fn_type_id.is_extern) { |
| 8282 | ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); | 8325 | ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); |
| ... | @@ -8472,8 +8515,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -8472,8 +8515,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 8472 | inst_fn_type_id.return_type = return_type; | 8515 | inst_fn_type_id.return_type = return_type; |
| 8473 | 8516 | ||
| 8474 | if (type_requires_comptime(return_type)) { | 8517 | if (type_requires_comptime(return_type)) { |
| 8475 | // Throw out our work and call the function as if it were inline. | 8518 | // Throw out our work and call the function as if it were comptime. |
| 8476 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true); | 8519 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, false); |
| 8477 | } | 8520 | } |
| 8478 | } | 8521 | } |
| 8479 | 8522 | ||
| ... | @@ -8498,7 +8541,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -8498,7 +8541,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 8498 | 8541 | ||
| 8499 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; | 8542 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; |
| 8500 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, | 8543 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, |
| 8501 | impl_fn, nullptr, impl_param_count, casted_args, false); | 8544 | impl_fn, nullptr, impl_param_count, casted_args, false, inline_fn_call); |
| 8502 | 8545 | ||
| 8503 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; | 8546 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 8504 | ir_add_alloca(ira, new_call_instruction, return_type); | 8547 | ir_add_alloca(ira, new_call_instruction, return_type); |
| ... | @@ -8557,7 +8600,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -8557,7 +8600,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 8557 | return ira->codegen->builtin_types.entry_invalid; | 8600 | return ira->codegen->builtin_types.entry_invalid; |
| 8558 | 8601 | ||
| 8559 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, | 8602 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, |
| 8560 | fn_entry, fn_ref, call_param_count, casted_args, false); | 8603 | fn_entry, fn_ref, call_param_count, casted_args, false, inline_fn_call); |
| 8561 | 8604 | ||
| 8562 | ir_add_alloca(ira, new_call_instruction, return_type); | 8605 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 8563 | return ir_finish_anal(ira, return_type); | 8606 | return ir_finish_anal(ira, return_type); |
| ... | @@ -8568,10 +8611,10 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -8568,10 +8611,10 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 8568 | if (type_is_invalid(fn_ref->value.type)) | 8611 | if (type_is_invalid(fn_ref->value.type)) |
| 8569 | return ira->codegen->builtin_types.entry_invalid; | 8612 | return ira->codegen->builtin_types.entry_invalid; |
| 8570 | 8613 | ||
| 8571 | bool is_inline = call_instruction->is_comptime || | 8614 | bool is_comptime = call_instruction->is_comptime || |
| 8572 | ir_should_inline(ira->new_irb.exec, call_instruction->base.scope); | 8615 | ir_should_inline(ira->new_irb.exec, call_instruction->base.scope); |
| 8573 | 8616 | ||
| 8574 | if (is_inline || instr_is_comptime(fn_ref)) { | 8617 | if (is_comptime || instr_is_comptime(fn_ref)) { |
| 8575 | if (fn_ref->value.type->id == TypeTableEntryIdMetaType) { | 8618 | if (fn_ref->value.type->id == TypeTableEntryIdMetaType) { |
| 8576 | TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); | 8619 | TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); |
| 8577 | if (type_is_invalid(dest_type)) | 8620 | if (type_is_invalid(dest_type)) |
| ... | @@ -8594,15 +8637,17 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -8594,15 +8637,17 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 8594 | ir_link_new_instruction(cast_instruction, &call_instruction->base); | 8637 | ir_link_new_instruction(cast_instruction, &call_instruction->base); |
| 8595 | return ir_finish_anal(ira, cast_instruction->value.type); | 8638 | return ir_finish_anal(ira, cast_instruction->value.type); |
| 8596 | } else if (fn_ref->value.type->id == TypeTableEntryIdFn) { | 8639 | } else if (fn_ref->value.type->id == TypeTableEntryIdFn) { |
| 8597 | FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref); | 8640 | bool is_inline; |
| 8641 | FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref, &is_inline); | ||
| 8598 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | 8642 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, |
| 8599 | fn_ref, nullptr, is_inline); | 8643 | fn_ref, nullptr, is_comptime, is_inline); |
| 8600 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { | 8644 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { |
| 8601 | assert(fn_ref->value.special == ConstValSpecialStatic); | 8645 | assert(fn_ref->value.special == ConstValSpecialStatic); |
| 8602 | FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn; | 8646 | FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn; |
| 8603 | IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg; | 8647 | IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg; |
| 8648 | bool is_inline = fn_ref->value.data.x_bound_fn.is_inline; | ||
| 8604 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | 8649 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, |
| 8605 | nullptr, first_arg_ptr, is_inline); | 8650 | nullptr, first_arg_ptr, is_comptime, is_inline); |
| 8606 | } else { | 8651 | } else { |
| 8607 | ir_add_error_node(ira, fn_ref->source_node, | 8652 | ir_add_error_node(ira, fn_ref->source_node, |
| 8608 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); | 8653 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); |
| ... | @@ -8612,7 +8657,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction | ... | @@ -8612,7 +8657,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 8612 | 8657 | ||
| 8613 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { | 8658 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { |
| 8614 | return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type, | 8659 | return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type, |
| 8615 | fn_ref, nullptr, false); | 8660 | fn_ref, nullptr, false, false); |
| 8616 | } else { | 8661 | } else { |
| 8617 | ir_add_error_node(ira, fn_ref->source_node, | 8662 | ir_add_error_node(ira, fn_ref->source_node, |
| 8618 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); | 8663 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name))); |
| ... | @@ -9354,7 +9399,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source | ... | @@ -9354,7 +9399,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 9354 | ConstExprValue *const_val = allocate<ConstExprValue>(1); | 9399 | ConstExprValue *const_val = allocate<ConstExprValue>(1); |
| 9355 | const_val->special = ConstValSpecialStatic; | 9400 | const_val->special = ConstValSpecialStatic; |
| 9356 | const_val->type = fn_entry->type_entry; | 9401 | const_val->type = fn_entry->type_entry; |
| 9357 | const_val->data.x_fn = fn_entry; | 9402 | const_val->data.x_fn.fn_entry = fn_entry; |
| 9358 | 9403 | ||
| 9359 | bool ptr_is_const = true; | 9404 | bool ptr_is_const = true; |
| 9360 | bool ptr_is_volatile = false; | 9405 | bool ptr_is_volatile = false; |
| ... | @@ -9891,7 +9936,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, | ... | @@ -9891,7 +9936,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, |
| 9891 | safety_off_ptr = &block_scope->safety_off; | 9936 | safety_off_ptr = &block_scope->safety_off; |
| 9892 | safety_set_node_ptr = &block_scope->safety_set_node; | 9937 | safety_set_node_ptr = &block_scope->safety_set_node; |
| 9893 | } else if (target_type->id == TypeTableEntryIdFn) { | 9938 | } else if (target_type->id == TypeTableEntryIdFn) { |
| 9894 | FnTableEntry *target_fn = target_val->data.x_fn; | 9939 | FnTableEntry *target_fn = target_val->data.x_fn.fn_entry; |
| 9895 | assert(target_fn->def_scope); | 9940 | assert(target_fn->def_scope); |
| 9896 | safety_off_ptr = &target_fn->def_scope->safety_off; | 9941 | safety_off_ptr = &target_fn->def_scope->safety_off; |
| 9897 | safety_set_node_ptr = &target_fn->def_scope->safety_set_node; | 9942 | safety_set_node_ptr = &target_fn->def_scope->safety_set_node; |
| ... | @@ -11164,6 +11209,38 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn | ... | @@ -11164,6 +11209,38 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn |
| 11164 | return result->value.type; | 11209 | return result->value.type; |
| 11165 | } | 11210 | } |
| 11166 | 11211 | ||
| 11212 | static TypeTableEntry *ir_analyze_instruction_set_fn_ref_inline(IrAnalyze *ira, | ||
| 11213 | IrInstructionSetFnRefInline *instruction) | ||
| 11214 | { | ||
| 11215 | IrInstruction *fn_ref = instruction->fn_ref->other; | ||
| 11216 | if (type_is_invalid(fn_ref->value.type)) | ||
| 11217 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11218 | |||
| 11219 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { | ||
| 11220 | ConstExprValue *fn_ref_val = ir_resolve_const(ira, fn_ref, UndefBad); | ||
| 11221 | if (!fn_ref_val) | ||
| 11222 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11223 | |||
| 11224 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 11225 | *out_val = *fn_ref_val; | ||
| 11226 | out_val->data.x_fn.is_inline = true; | ||
| 11227 | return out_val->type; | ||
| 11228 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { | ||
| 11229 | ConstExprValue *fn_ref_val = ir_resolve_const(ira, fn_ref, UndefBad); | ||
| 11230 | if (!fn_ref_val) | ||
| 11231 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11232 | |||
| 11233 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 11234 | *out_val = *fn_ref_val; | ||
| 11235 | out_val->data.x_bound_fn.is_inline = true; | ||
| 11236 | return out_val->type; | ||
| 11237 | } else { | ||
| 11238 | ir_add_error(ira, &instruction->base, | ||
| 11239 | buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_ref->value.type->name))); | ||
| 11240 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11241 | } | ||
| 11242 | } | ||
| 11243 | |||
| 11167 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { | 11244 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { |
| 11168 | IrInstruction *type_value = instruction->type_value->other; | 11245 | IrInstruction *type_value = instruction->type_value->other; |
| 11169 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | 11246 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| ... | @@ -12710,6 +12787,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -12710,6 +12787,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 12710 | return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); | 12787 | return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); |
| 12711 | case IrInstructionIdEnumTagName: | 12788 | case IrInstructionIdEnumTagName: |
| 12712 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); | 12789 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); |
| 12790 | case IrInstructionIdSetFnRefInline: | ||
| 12791 | return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction); | ||
| 12713 | case IrInstructionIdMaybeWrap: | 12792 | case IrInstructionIdMaybeWrap: |
| 12714 | case IrInstructionIdErrWrapCode: | 12793 | case IrInstructionIdErrWrapCode: |
| 12715 | case IrInstructionIdErrWrapPayload: | 12794 | case IrInstructionIdErrWrapPayload: |
| ... | @@ -12892,6 +12971,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -12892,6 +12971,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 12892 | case IrInstructionIdErrName: | 12971 | case IrInstructionIdErrName: |
| 12893 | case IrInstructionIdTypeName: | 12972 | case IrInstructionIdTypeName: |
| 12894 | case IrInstructionIdEnumTagName: | 12973 | case IrInstructionIdEnumTagName: |
| 12974 | case IrInstructionIdSetFnRefInline: | ||
| 12895 | return false; | 12975 | return false; |
| 12896 | case IrInstructionIdAsm: | 12976 | case IrInstructionIdAsm: |
| 12897 | { | 12977 | { |
| ... | @@ -12953,7 +13033,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE | ... | @@ -12953,7 +13033,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE |
| 12953 | } | 13033 | } |
| 12954 | 13034 | ||
| 12955 | IrInstruction *call_instruction = ir_build_call(irb, scope, source_node, nullptr, fn_ref_instruction, | 13035 | IrInstruction *call_instruction = ir_build_call(irb, scope, source_node, nullptr, fn_ref_instruction, |
| 12956 | arg_count, args, false); | 13036 | arg_count, args, false, false); |
| 12957 | ir_build_return(irb, scope, source_node, call_instruction); | 13037 | ir_build_return(irb, scope, source_node, call_instruction); |
| 12958 | 13038 | ||
| 12959 | if (codegen->verbose) { | 13039 | if (codegen->verbose) { |
src/ir_print.cpp+7| ... | @@ -870,6 +870,10 @@ static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) { | ... | @@ -870,6 +870,10 @@ static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) { |
| 870 | fprintf(irp->f, ")"); | 870 | fprintf(irp->f, ")"); |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | static void ir_print_set_fn_ref_inline(IrPrint *irp, IrInstructionSetFnRefInline *instruction) { | ||
| 874 | fprintf(irp->f, "inline "); | ||
| 875 | ir_print_other_instruction(irp, instruction->fn_ref); | ||
| 876 | } | ||
| 873 | 877 | ||
| 874 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 878 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 875 | ir_print_prefix(irp, instruction); | 879 | ir_print_prefix(irp, instruction); |
| ... | @@ -1155,6 +1159,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1155,6 +1159,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1155 | case IrInstructionIdPanic: | 1159 | case IrInstructionIdPanic: |
| 1156 | ir_print_panic(irp, (IrInstructionPanic *)instruction); | 1160 | ir_print_panic(irp, (IrInstructionPanic *)instruction); |
| 1157 | break; | 1161 | break; |
| 1162 | case IrInstructionIdSetFnRefInline: | ||
| 1163 | ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction); | ||
| 1164 | break; | ||
| 1158 | } | 1165 | } |
| 1159 | fprintf(irp->f, "\n"); | 1166 | fprintf(irp->f, "\n"); |
| 1160 | } | 1167 | } |
src/parser.cpp+39-12| ... | @@ -927,7 +927,32 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde | ... | @@ -927,7 +927,32 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde |
| 927 | } | 927 | } |
| 928 | 928 | ||
| 929 | /* | 929 | /* |
| 930 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | 930 | InlineExpression = option("inline") PrimaryExpression |
| 931 | */ | ||
| 932 | static AstNode *ast_parse_inline_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | ||
| 933 | Token *token = &pc->tokens->at(*token_index); | ||
| 934 | |||
| 935 | if (token->id == TokenIdKeywordInline) { | ||
| 936 | *token_index += 1; | ||
| 937 | AstNode *primary_expr_node = ast_parse_primary_expr(pc, token_index, true); | ||
| 938 | if (primary_expr_node->type == NodeTypeWhileExpr) { | ||
| 939 | primary_expr_node->data.while_expr.is_inline = true; | ||
| 940 | return primary_expr_node; | ||
| 941 | } else if (primary_expr_node->type == NodeTypeForExpr) { | ||
| 942 | primary_expr_node->data.for_expr.is_inline = true; | ||
| 943 | return primary_expr_node; | ||
| 944 | } else { | ||
| 945 | AstNode *node = ast_create_node(pc, NodeTypeInlineExpr, token); | ||
| 946 | node->data.inline_expr.body = primary_expr_node; | ||
| 947 | return node; | ||
| 948 | } | ||
| 949 | } else { | ||
| 950 | return ast_parse_primary_expr(pc, token_index, mandatory); | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 954 | /* | ||
| 955 | SuffixOpExpression = InlineExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | ||
| 931 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) | 956 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 932 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) | 957 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 933 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) | 958 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) |
| ... | @@ -935,8 +960,8 @@ FieldAccessExpression : token(Dot) token(Symbol) | ... | @@ -935,8 +960,8 @@ FieldAccessExpression : token(Dot) token(Symbol) |
| 935 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression | 960 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression |
| 936 | */ | 961 | */ |
| 937 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | 962 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 938 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); | 963 | AstNode *inline_expr = ast_parse_inline_expr(pc, token_index, mandatory); |
| 939 | if (!primary_expr) | 964 | if (!inline_expr) |
| 940 | return nullptr; | 965 | return nullptr; |
| 941 | 966 | ||
| 942 | while (true) { | 967 | while (true) { |
| ... | @@ -945,10 +970,10 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, | ... | @@ -945,10 +970,10 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 945 | *token_index += 1; | 970 | *token_index += 1; |
| 946 | 971 | ||
| 947 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token); | 972 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token); |
| 948 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | 973 | node->data.fn_call_expr.fn_ref_expr = inline_expr; |
| 949 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); | 974 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); |
| 950 | 975 | ||
| 951 | primary_expr = node; | 976 | inline_expr = node; |
| 952 | } else if (first_token->id == TokenIdLBracket) { | 977 | } else if (first_token->id == TokenIdLBracket) { |
| 953 | *token_index += 1; | 978 | *token_index += 1; |
| 954 | 979 | ||
| ... | @@ -960,7 +985,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, | ... | @@ -960,7 +985,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 960 | *token_index += 1; | 985 | *token_index += 1; |
| 961 | 986 | ||
| 962 | AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token); | 987 | AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token); |
| 963 | node->data.slice_expr.array_ref_expr = primary_expr; | 988 | node->data.slice_expr.array_ref_expr = inline_expr; |
| 964 | node->data.slice_expr.start = expr_node; | 989 | node->data.slice_expr.start = expr_node; |
| 965 | node->data.slice_expr.end = ast_parse_expression(pc, token_index, false); | 990 | node->data.slice_expr.end = ast_parse_expression(pc, token_index, false); |
| 966 | 991 | ||
| ... | @@ -972,15 +997,15 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, | ... | @@ -972,15 +997,15 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 972 | node->data.slice_expr.is_const = true; | 997 | node->data.slice_expr.is_const = true; |
| 973 | } | 998 | } |
| 974 | 999 | ||
| 975 | primary_expr = node; | 1000 | inline_expr = node; |
| 976 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { | 1001 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { |
| 977 | *token_index += 1; | 1002 | *token_index += 1; |
| 978 | 1003 | ||
| 979 | AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token); | 1004 | AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token); |
| 980 | node->data.array_access_expr.array_ref_expr = primary_expr; | 1005 | node->data.array_access_expr.array_ref_expr = inline_expr; |
| 981 | node->data.array_access_expr.subscript = expr_node; | 1006 | node->data.array_access_expr.subscript = expr_node; |
| 982 | 1007 | ||
| 983 | primary_expr = node; | 1008 | inline_expr = node; |
| 984 | } else { | 1009 | } else { |
| 985 | ast_invalid_token_error(pc, first_token); | 1010 | ast_invalid_token_error(pc, first_token); |
| 986 | } | 1011 | } |
| ... | @@ -990,12 +1015,12 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, | ... | @@ -990,12 +1015,12 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 990 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | 1015 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 991 | 1016 | ||
| 992 | AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token); | 1017 | AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token); |
| 993 | node->data.field_access_expr.struct_expr = primary_expr; | 1018 | node->data.field_access_expr.struct_expr = inline_expr; |
| 994 | node->data.field_access_expr.field_name = token_buf(name_token); | 1019 | node->data.field_access_expr.field_name = token_buf(name_token); |
| 995 | 1020 | ||
| 996 | primary_expr = node; | 1021 | inline_expr = node; |
| 997 | } else { | 1022 | } else { |
| 998 | return primary_expr; | 1023 | return inline_expr; |
| 999 | } | 1024 | } |
| 1000 | } | 1025 | } |
| 1001 | } | 1026 | } |
| ... | @@ -2807,5 +2832,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2807,5 +2832,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2807 | case NodeTypeVarLiteral: | 2832 | case NodeTypeVarLiteral: |
| 2808 | // none | 2833 | // none |
| 2809 | break; | 2834 | break; |
| 2835 | case NodeTypeInlineExpr: | ||
| 2836 | visit_field(&node->data.inline_expr.body, visit, context); | ||
| 2810 | } | 2837 | } |
| 2811 | } | 2838 | } |
src/zig_llvm.cpp+4-1| ... | @@ -176,10 +176,13 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -176,10 +176,13 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 176 | 176 | ||
| 177 | 177 | ||
| 178 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 178 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 179 | unsigned NumArgs, unsigned CC, const char *Name) | 179 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name) |
| 180 | { | 180 | { |
| 181 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); | 181 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); |
| 182 | call_inst->setCallingConv(CC); | 182 | call_inst->setCallingConv(CC); |
| 183 | if (always_inline) { | ||
| 184 | call_inst->addAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline); | ||
| 185 | } | ||
| 183 | return wrap(unwrap(B)->Insert(call_inst)); | 186 | return wrap(unwrap(B)->Insert(call_inst)); |
| 184 | } | 187 | } |
| 185 | 188 |
src/zig_llvm.hpp+1-1| ... | @@ -38,7 +38,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -38,7 +38,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 38 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); | 38 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); |
| 39 | 39 | ||
| 40 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 40 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 41 | unsigned NumArgs, unsigned CC, const char *Name); | 41 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name); |
| 42 | 42 | ||
| 43 | LLVMValueRef ZigLLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString, | 43 | LLVMValueRef ZigLLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString, |
| 44 | const char *Constraints, bool HasSideEffects, bool IsAlignStack, bool is_x86); | 44 | const char *Constraints, bool HasSideEffects, bool IsAlignStack, bool is_x86); |
test/cases/fn.zig+7| ... | @@ -87,3 +87,10 @@ fn fn1() -> u32 {5} | ... | @@ -87,3 +87,10 @@ fn fn1() -> u32 {5} |
| 87 | fn fn2() -> u32 {6} | 87 | fn fn2() -> u32 {6} |
| 88 | fn fn3() -> u32 {7} | 88 | fn fn3() -> u32 {7} |
| 89 | fn fn4() -> u32 {8} | 89 | fn fn4() -> u32 {8} |
| 90 | |||
| 91 | |||
| 92 | test "inline function call" { | ||
| 93 | assert((inline add(3, 9)) == 12); | ||
| 94 | } | ||
| 95 | |||
| 96 | fn add(a: i32, b: i32) -> i32 { a + b } |