| 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 | 81 | |
| 82 | 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 | 88 | BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression |
| 89 | 89 | |
| ... | ... | @@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%" |
| 127 | 127 | |
| 128 | 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 | 134 | FieldAccessExpression = "." Symbol |
| 133 | 135 | |
| ... | ... | @@ -161,6 +163,7 @@ ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" ma |
| 161 | 163 | ## Operator Precedence |
| 162 | 164 | |
| 163 | 165 | ``` |
| 166 | inline x | |
| 164 | 167 | x() x[] x.y |
| 165 | 168 | !x -x -%x ~x *x &x ?x %x %%x ??x |
| 166 | 169 | x{} |
src/all_types.hpp+21-1| ... | ... | @@ -167,6 +167,7 @@ struct ConstErrValue { |
| 167 | 167 | struct ConstBoundFnValue { |
| 168 | 168 | FnTableEntry *fn; |
| 169 | 169 | IrInstruction *first_arg; |
| 170 | bool is_inline; | |
| 170 | 171 | }; |
| 171 | 172 | |
| 172 | 173 | struct ConstArgTuple { |
| ... | ... | @@ -192,6 +193,11 @@ enum RuntimeHintMaybe { |
| 192 | 193 | RuntimeHintMaybeNonNull, |
| 193 | 194 | }; |
| 194 | 195 | |
| 196 | struct ConstFn { | |
| 197 | FnTableEntry *fn_entry; | |
| 198 | bool is_inline; | |
| 199 | }; | |
| 200 | ||
| 195 | 201 | struct ConstExprValue { |
| 196 | 202 | TypeTableEntry *type; |
| 197 | 203 | ConstValSpecial special; |
| ... | ... | @@ -202,7 +208,7 @@ struct ConstExprValue { |
| 202 | 208 | // populated if special == ConstValSpecialStatic |
| 203 | 209 | BigNum x_bignum; |
| 204 | 210 | bool x_bool; |
| 205 | FnTableEntry *x_fn; | |
| 211 | ConstFn x_fn; | |
| 206 | 212 | ConstBoundFnValue x_bound_fn; |
| 207 | 213 | TypeTableEntry *x_type; |
| 208 | 214 | ConstExprValue *x_maybe; |
| ... | ... | @@ -366,6 +372,7 @@ enum NodeType { |
| 366 | 372 | NodeTypeTypeLiteral, |
| 367 | 373 | NodeTypeVarLiteral, |
| 368 | 374 | NodeTypeTryExpr, |
| 375 | NodeTypeInlineExpr, | |
| 369 | 376 | }; |
| 370 | 377 | |
| 371 | 378 | struct AstNodeRoot { |
| ... | ... | @@ -789,6 +796,10 @@ struct AstNodeTypeLiteral { |
| 789 | 796 | struct AstNodeVarLiteral { |
| 790 | 797 | }; |
| 791 | 798 | |
| 799 | struct AstNodeInlineExpr { | |
| 800 | AstNode *body; | |
| 801 | }; | |
| 802 | ||
| 792 | 803 | struct AstNode { |
| 793 | 804 | enum NodeType type; |
| 794 | 805 | size_t line; |
| ... | ... | @@ -847,6 +858,7 @@ struct AstNode { |
| 847 | 858 | AstNodeErrorType error_type; |
| 848 | 859 | AstNodeTypeLiteral type_literal; |
| 849 | 860 | AstNodeVarLiteral var_literal; |
| 861 | AstNodeInlineExpr inline_expr; | |
| 850 | 862 | } data; |
| 851 | 863 | }; |
| 852 | 864 | |
| ... | ... | @@ -1748,6 +1760,7 @@ enum IrInstructionId { |
| 1748 | 1760 | IrInstructionIdDeclRef, |
| 1749 | 1761 | IrInstructionIdPanic, |
| 1750 | 1762 | IrInstructionIdEnumTagName, |
| 1763 | IrInstructionIdSetFnRefInline, | |
| 1751 | 1764 | }; |
| 1752 | 1765 | |
| 1753 | 1766 | struct IrInstruction { |
| ... | ... | @@ -1943,6 +1956,7 @@ struct IrInstructionCall { |
| 1943 | 1956 | IrInstruction **args; |
| 1944 | 1957 | bool is_comptime; |
| 1945 | 1958 | LLVMValueRef tmp_ptr; |
| 1959 | bool is_inline; | |
| 1946 | 1960 | }; |
| 1947 | 1961 | |
| 1948 | 1962 | struct IrInstructionConst { |
| ... | ... | @@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName { |
| 2493 | 2507 | IrInstruction *target; |
| 2494 | 2508 | }; |
| 2495 | 2509 | |
| 2510 | struct IrInstructionSetFnRefInline { | |
| 2511 | IrInstruction base; | |
| 2512 | ||
| 2513 | IrInstruction *fn_ref; | |
| 2514 | }; | |
| 2515 | ||
| 2496 | 2516 | static const size_t slice_ptr_index = 0; |
| 2497 | 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 | 2129 | case NodeTypeTypeLiteral: |
| 2130 | 2130 | case NodeTypeVarLiteral: |
| 2131 | 2131 | case NodeTypeTryExpr: |
| 2132 | case NodeTypeInlineExpr: | |
| 2132 | 2133 | zig_unreachable(); |
| 2133 | 2134 | } |
| 2134 | 2135 | } |
| ... | ... | @@ -3251,7 +3252,8 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3251 | 3252 | // TODO better hashing algorithm |
| 3252 | 3253 | return 31643936; |
| 3253 | 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 | 3257 | case TypeTableEntryIdTypeDecl: |
| 3256 | 3258 | return hash_ptr(const_val->data.x_type); |
| 3257 | 3259 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -3697,7 +3699,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3697 | 3699 | case TypeTableEntryIdPureError: |
| 3698 | 3700 | return a->data.x_pure_err == b->data.x_pure_err; |
| 3699 | 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 | 3704 | case TypeTableEntryIdBool: |
| 3702 | 3705 | return a->data.x_bool == b->data.x_bool; |
| 3703 | 3706 | case TypeTableEntryIdInt: |
| ... | ... | @@ -3933,8 +3936,9 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 3933 | 3936 | zig_unreachable(); |
| 3934 | 3937 | case TypeTableEntryIdFn: |
| 3935 | 3938 | { |
| 3936 | FnTableEntry *fn_entry = const_val->data.x_fn; | |
| 3937 | buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name)); | |
| 3939 | FnTableEntry *fn_entry = const_val->data.x_fn.fn_entry; | |
| 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 | 3942 | return; |
| 3939 | 3943 | } |
| 3940 | 3944 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -4011,7 +4015,8 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 4011 | 4015 | case TypeTableEntryIdBoundFn: |
| 4012 | 4016 | { |
| 4013 | 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 | 4020 | return; |
| 4016 | 4021 | } |
| 4017 | 4022 | case TypeTableEntryIdStruct: |
src/ast_render.cpp+8| ... | ... | @@ -240,6 +240,8 @@ static const char *node_type_str(NodeType node_type) { |
| 240 | 240 | return "VarLiteral"; |
| 241 | 241 | case NodeTypeTryExpr: |
| 242 | 242 | return "TryExpr"; |
| 243 | case NodeTypeInlineExpr: | |
| 244 | return "InlineExpr"; | |
| 243 | 245 | } |
| 244 | 246 | zig_unreachable(); |
| 245 | 247 | } |
| ... | ... | @@ -921,6 +923,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 921 | 923 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); |
| 922 | 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 | 932 | case NodeTypeFnDecl: |
| 925 | 933 | case NodeTypeParamDecl: |
| 926 | 934 | case NodeTypeErrorValueDecl: |
src/codegen.cpp+8-3| ... | ... | @@ -608,7 +608,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { |
| 608 | 608 | LLVMBuildLoad(g->builder, ptr_ptr, ""), |
| 609 | 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 | 612 | LLVMBuildUnreachable(g->builder); |
| 613 | 613 | } |
| 614 | 614 | |
| ... | ... | @@ -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 | 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 | 1783 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 1780 | 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 | 2753 | case IrInstructionIdSetGlobalLinkage: |
| 2750 | 2754 | case IrInstructionIdDeclRef: |
| 2751 | 2755 | case IrInstructionIdSwitchVar: |
| 2756 | case IrInstructionIdSetFnRefInline: | |
| 2752 | 2757 | zig_unreachable(); |
| 2753 | 2758 | case IrInstructionIdReturn: |
| 2754 | 2759 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -3183,7 +3188,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3183 | 3188 | } |
| 3184 | 3189 | } |
| 3185 | 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 | 3192 | case TypeTableEntryIdPointer: |
| 3188 | 3193 | { |
| 3189 | 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 | 545 | return IrInstructionIdEnumTagName; |
| 546 | 546 | } |
| 547 | 547 | |
| 548 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnRefInline *) { | |
| 549 | return IrInstructionIdSetFnRefInline; | |
| 550 | } | |
| 551 | ||
| 548 | 552 | template<typename T> |
| 549 | 553 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 550 | 554 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -701,7 +705,7 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode * |
| 701 | 705 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node); |
| 702 | 706 | const_instruction->base.value.type = fn_entry->type_entry; |
| 703 | 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 | 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 | 886 | |
| 883 | 887 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 884 | 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 | 891 | IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node); |
| 888 | 892 | call_instruction->fn_entry = fn_entry; |
| 889 | 893 | call_instruction->fn_ref = fn_ref; |
| 890 | 894 | call_instruction->is_comptime = is_comptime; |
| 895 | call_instruction->is_inline = is_inline; | |
| 891 | 896 | call_instruction->args = args; |
| 892 | 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 | 906 | |
| 902 | 907 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 903 | 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 | 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 | 913 | ir_link_new_instruction(new_instruction, old_instruction); |
| 909 | 914 | return new_instruction; |
| 910 | 915 | } |
| ... | ... | @@ -2145,6 +2150,18 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo |
| 2145 | 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 | 2165 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2149 | 2166 | return nullptr; |
| 2150 | 2167 | } |
| ... | ... | @@ -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 | 2837 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2813 | 2838 | switch (instruction->id) { |
| 2814 | 2839 | case IrInstructionIdInvalid: |
| ... | ... | @@ -2999,6 +3024,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 2999 | 3024 | return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); |
| 3000 | 3025 | case IrInstructionIdEnumTagName: |
| 3001 | 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 | 3030 | zig_unreachable(); |
| 3004 | 3031 | } |
| ... | ... | @@ -4297,7 +4324,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 4297 | 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 | 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 | 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 | 5533 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| 5494 | 5534 | LVal lval) |
| 5495 | 5535 | { |
| ... | ... | @@ -5580,6 +5620,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5580 | 5620 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 5581 | 5621 | case NodeTypeFnProto: |
| 5582 | 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 | 5625 | case NodeTypeFnDef: |
| 5584 | 5626 | zig_panic("TODO IR gen NodeTypeFnDef"); |
| 5585 | 5627 | case NodeTypeFnDecl: |
| ... | ... | @@ -6435,7 +6477,7 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value |
| 6435 | 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 | 6481 | if (fn_value == ira->codegen->invalid_instruction) |
| 6440 | 6482 | return nullptr; |
| 6441 | 6483 | |
| ... | ... | @@ -6452,7 +6494,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { |
| 6452 | 6494 | if (!const_val) |
| 6453 | 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 | 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 | 8288 | |
| 8246 | 8289 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 8247 | 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 | 8293 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 8251 | 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 | 8319 | return ira->codegen->builtin_types.entry_invalid; |
| 8277 | 8320 | } |
| 8278 | 8321 | |
| 8279 | if (inline_fn_call) { | |
| 8322 | if (comptime_fn_call) { | |
| 8280 | 8323 | // No special handling is needed for compile time evaluation of generic functions. |
| 8281 | 8324 | if (!fn_entry || fn_entry->type_entry->data.fn.fn_type_id.is_extern) { |
| 8282 | 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 | 8515 | inst_fn_type_id.return_type = return_type; |
| 8473 | 8516 | |
| 8474 | 8517 | if (type_requires_comptime(return_type)) { |
| 8475 | // Throw out our work and call the function as if it were inline. | |
| 8476 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true); | |
| 8518 | // Throw out our work and call the function as if it were comptime. | |
| 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 | 8541 | |
| 8499 | 8542 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; |
| 8500 | 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 | 8546 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 8504 | 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 | 8600 | return ira->codegen->builtin_types.entry_invalid; |
| 8558 | 8601 | |
| 8559 | 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 | 8605 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 8563 | 8606 | return ir_finish_anal(ira, return_type); |
| ... | ... | @@ -8568,10 +8611,10 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 8568 | 8611 | if (type_is_invalid(fn_ref->value.type)) |
| 8569 | 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 | 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 | 8618 | if (fn_ref->value.type->id == TypeTableEntryIdMetaType) { |
| 8576 | 8619 | TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); |
| 8577 | 8620 | if (type_is_invalid(dest_type)) |
| ... | ... | @@ -8594,15 +8637,17 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 8594 | 8637 | ir_link_new_instruction(cast_instruction, &call_instruction->base); |
| 8595 | 8638 | return ir_finish_anal(ira, cast_instruction->value.type); |
| 8596 | 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 | 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 | 8644 | } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) { |
| 8601 | 8645 | assert(fn_ref->value.special == ConstValSpecialStatic); |
| 8602 | 8646 | FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn; |
| 8603 | 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 | 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 | 8651 | } else { |
| 8607 | 8652 | ir_add_error_node(ira, fn_ref->source_node, |
| 8608 | 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 | 8657 | |
| 8613 | 8658 | if (fn_ref->value.type->id == TypeTableEntryIdFn) { |
| 8614 | 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 | 8661 | } else { |
| 8617 | 8662 | ir_add_error_node(ira, fn_ref->source_node, |
| 8618 | 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 | 9399 | ConstExprValue *const_val = allocate<ConstExprValue>(1); |
| 9355 | 9400 | const_val->special = ConstValSpecialStatic; |
| 9356 | 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 | 9404 | bool ptr_is_const = true; |
| 9360 | 9405 | bool ptr_is_volatile = false; |
| ... | ... | @@ -9891,7 +9936,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, |
| 9891 | 9936 | safety_off_ptr = &block_scope->safety_off; |
| 9892 | 9937 | safety_set_node_ptr = &block_scope->safety_set_node; |
| 9893 | 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 | 9940 | assert(target_fn->def_scope); |
| 9896 | 9941 | safety_off_ptr = &target_fn->def_scope->safety_off; |
| 9897 | 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 | 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 | 11244 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { |
| 11168 | 11245 | IrInstruction *type_value = instruction->type_value->other; |
| 11169 | 11246 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| ... | ... | @@ -12710,6 +12787,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 12710 | 12787 | return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); |
| 12711 | 12788 | case IrInstructionIdEnumTagName: |
| 12712 | 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 | 12792 | case IrInstructionIdMaybeWrap: |
| 12714 | 12793 | case IrInstructionIdErrWrapCode: |
| 12715 | 12794 | case IrInstructionIdErrWrapPayload: |
| ... | ... | @@ -12892,6 +12971,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 12892 | 12971 | case IrInstructionIdErrName: |
| 12893 | 12972 | case IrInstructionIdTypeName: |
| 12894 | 12973 | case IrInstructionIdEnumTagName: |
| 12974 | case IrInstructionIdSetFnRefInline: | |
| 12895 | 12975 | return false; |
| 12896 | 12976 | case IrInstructionIdAsm: |
| 12897 | 12977 | { |
| ... | ... | @@ -12953,7 +13033,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE |
| 12953 | 13033 | } |
| 12954 | 13034 | |
| 12955 | 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 | 13037 | ir_build_return(irb, scope, source_node, call_instruction); |
| 12958 | 13038 | |
| 12959 | 13039 | if (codegen->verbose) { |
src/ir_print.cpp+7| ... | ... | @@ -870,6 +870,10 @@ static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) { |
| 870 | 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 | 878 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 875 | 879 | ir_print_prefix(irp, instruction); |
| ... | ... | @@ -1155,6 +1159,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1155 | 1159 | case IrInstructionIdPanic: |
| 1156 | 1160 | ir_print_panic(irp, (IrInstructionPanic *)instruction); |
| 1157 | 1161 | break; |
| 1162 | case IrInstructionIdSetFnRefInline: | |
| 1163 | ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction); | |
| 1164 | break; | |
| 1158 | 1165 | } |
| 1159 | 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 | 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 | 956 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 932 | 957 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 933 | 958 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) |
| ... | ... | @@ -935,8 +960,8 @@ FieldAccessExpression : token(Dot) token(Symbol) |
| 935 | 960 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression |
| 936 | 961 | */ |
| 937 | 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); | |
| 939 | if (!primary_expr) | |
| 963 | AstNode *inline_expr = ast_parse_inline_expr(pc, token_index, mandatory); | |
| 964 | if (!inline_expr) | |
| 940 | 965 | return nullptr; |
| 941 | 966 | |
| 942 | 967 | while (true) { |
| ... | ... | @@ -945,10 +970,10 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 945 | 970 | *token_index += 1; |
| 946 | 971 | |
| 947 | 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 | 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 | 977 | } else if (first_token->id == TokenIdLBracket) { |
| 953 | 978 | *token_index += 1; |
| 954 | 979 | |
| ... | ... | @@ -960,7 +985,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 960 | 985 | *token_index += 1; |
| 961 | 986 | |
| 962 | 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 | 989 | node->data.slice_expr.start = expr_node; |
| 965 | 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 | 997 | node->data.slice_expr.is_const = true; |
| 973 | 998 | } |
| 974 | 999 | |
| 975 | primary_expr = node; | |
| 1000 | inline_expr = node; | |
| 976 | 1001 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { |
| 977 | 1002 | *token_index += 1; |
| 978 | 1003 | |
| 979 | 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 | 1006 | node->data.array_access_expr.subscript = expr_node; |
| 982 | 1007 | |
| 983 | primary_expr = node; | |
| 1008 | inline_expr = node; | |
| 984 | 1009 | } else { |
| 985 | 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 | 1015 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 991 | 1016 | |
| 992 | 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 | 1019 | node->data.field_access_expr.field_name = token_buf(name_token); |
| 995 | 1020 | |
| 996 | primary_expr = node; | |
| 1021 | inline_expr = node; | |
| 997 | 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 | 2832 | case NodeTypeVarLiteral: |
| 2808 | 2833 | // none |
| 2809 | 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 | 176 | |
| 177 | 177 | |
| 178 | 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 | 181 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); |
| 182 | 182 | call_inst->setCallingConv(CC); |
| 183 | if (always_inline) { | |
| 184 | call_inst->addAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline); | |
| 185 | } | |
| 183 | 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 | 38 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); |
| 39 | 39 | |
| 40 | 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 | 43 | LLVMValueRef ZigLLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString, |
| 44 | 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 | 87 | fn fn2() -> u32 {6} |
| 88 | 88 | fn fn3() -> u32 {7} |
| 89 | 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 } |