authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-13 00:13:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-13 00:13:54-04:00
log41144a8566a6fbd779403f6b69424bb640c94a7f
treeb4c5807dddca6d3eb66047aebccf6cc9d3fdd90c
parentf043e0e85cac9330cf809bef177784c3cd133348

ability to inline at function callsite

closes #306

11 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
8181
82SwitchItem = Expression | (Expression "..." Expression)82SwitchItem = Expression | (Expression "..." Expression)
8383
84WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body84WhileExpression(body) = "while" "(" Expression option(";" Expression) ")" body
8585
86ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body86ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
8787
88BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression88BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
8989
...@@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%"...@@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
127127
128PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression128PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
129129
130SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)130SuffixOpExpression = InlineExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
131
132InlineExpression = option("inline") PrimaryExpression
131133
132FieldAccessExpression = "." Symbol134FieldAccessExpression = "." Symbol
133135
...@@ -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 Precedence163## Operator Precedence
162164
163```165```
166inline x
164x() x[] x.y167x() x[] x.y
165!x -x -%x ~x *x &x ?x %x %%x ??x168!x -x -%x ~x *x &x ?x %x %%x ??x
166x{}169x{}
src/all_types.hpp+21-1
...@@ -167,6 +167,7 @@ struct ConstErrValue {...@@ -167,6 +167,7 @@ struct ConstErrValue {
167struct ConstBoundFnValue {167struct ConstBoundFnValue {
168 FnTableEntry *fn;168 FnTableEntry *fn;
169 IrInstruction *first_arg;169 IrInstruction *first_arg;
170 bool is_inline;
170};171};
171172
172struct ConstArgTuple {173struct ConstArgTuple {
...@@ -192,6 +193,11 @@ enum RuntimeHintMaybe {...@@ -192,6 +193,11 @@ enum RuntimeHintMaybe {
192 RuntimeHintMaybeNonNull,193 RuntimeHintMaybeNonNull,
193};194};
194195
196struct ConstFn {
197 FnTableEntry *fn_entry;
198 bool is_inline;
199};
200
195struct ConstExprValue {201struct 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 == ConstValSpecialStatic208 // 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};
370377
371struct AstNodeRoot {378struct AstNodeRoot {
...@@ -789,6 +796,10 @@ struct AstNodeTypeLiteral {...@@ -789,6 +796,10 @@ struct AstNodeTypeLiteral {
789struct AstNodeVarLiteral {796struct AstNodeVarLiteral {
790};797};
791798
799struct AstNodeInlineExpr {
800 AstNode *body;
801};
802
792struct AstNode {803struct 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};
852864
...@@ -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};
17521765
1753struct IrInstruction {1766struct 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};
19471961
1948struct IrInstructionConst {1962struct IrInstructionConst {
...@@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName {...@@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName {
2493 IrInstruction *target;2507 IrInstruction *target;
2494};2508};
24952509
2510struct IrInstructionSetFnRefInline {
2511 IrInstruction base;
2512
2513 IrInstruction *fn_ref;
2514};
2515
2496static const size_t slice_ptr_index = 0;2516static const size_t slice_ptr_index = 0;
2497static const size_t slice_len_index = 1;2517static const size_t slice_len_index = 1;
24982518
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 algorithm3252 // 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}
614614
...@@ -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 }
17751775
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, "");
17781782
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}
547547
548static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnRefInline *) {
549 return IrInstructionIdSetFnRefInline;
550}
551
548template<typename T>552template<typename T>
549static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {553static 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}
707711
...@@ -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
882886
883static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,887static 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;
893898
...@@ -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
901906
902static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,907static 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}
21472152
2153static 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
2148static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {2165static 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}
28112828
2829static 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
2812static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {2837static 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 }
42994326
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}
43024329
4303static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {4330static 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}
54925519
5520static 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
5493static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,5533static 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}
64376479
6438static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {6480static 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;
64416483
...@@ -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;
64546496
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}
64576500
6458static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {6501static 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,
82458288
8246static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,8289static 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 }
82788321
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;
84738516
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 }
84798522
...@@ -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
84988541
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);
85028545
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;
85588601
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);
85618604
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;
85708613
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);
85738616
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
86128657
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;
93589403
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}
1116611211
11212static 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
11167static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {11244static 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 }
1295413034
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);
1295813038
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}
872872
873static 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}
873877
874static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {878static 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}
928928
929/*929/*
930SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)930InlineExpression = option("inline") PrimaryExpression
931*/
932static 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/*
955SuffixOpExpression = InlineExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
931FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)956FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
932ArrayAccessExpression : token(LBracket) Expression token(RBracket)957ArrayAccessExpression : token(LBracket) Expression token(RBracket)
933SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))958SliceExpression : 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)
935StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression960StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
936*/961*/
937static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {962static 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;
941966
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;
946971
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);
950975
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;
954979
...@@ -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;
961986
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);
966991
...@@ -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 }
974999
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;
9781003
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;
9821007
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);
9911016
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);
9951020
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 // none2833 // 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
176176
177177
178LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,178LLVMValueRef 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}
185188
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);
3939
40LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,40LLVMValueRef 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);
4242
43LLVMValueRef ZigLLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString,43LLVMValueRef 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}
87fn fn2() -> u32 {6}87fn fn2() -> u32 {6}
88fn fn3() -> u32 {7}88fn fn3() -> u32 {7}
89fn fn4() -> u32 {8}89fn fn4() -> u32 {8}
90
91
92test "inline function call" {
93 assert((inline add(3, 9)) == 12);
94}
95
96fn add(a: i32, b: i32) -> i32 { a + b }