Skip to content

Commit 41144a8

Browse files
committedApr 13, 2017
ability to inline at function callsite
closes #306
1 parent f043e0e commit 41144a8

11 files changed

+213
-48
lines changed
 

‎doc/langref.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo
8181
8282
SwitchItem = Expression | (Expression "..." Expression)
8383
84-
WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body
84+
WhileExpression(body) = "while" "(" Expression option(";" Expression) ")" body
8585
86-
ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
86+
ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
8787
8888
BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
8989
@@ -127,7 +127,9 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
127127
128128
PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
129129
130-
SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
130+
SuffixOpExpression = InlineExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
131+
132+
InlineExpression = option("inline") PrimaryExpression
131133
132134
FieldAccessExpression = "." Symbol
133135
@@ -161,6 +163,7 @@ ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" ma
161163
## Operator Precedence
162164

163165
```
166+
inline x
164167
x() x[] x.y
165168
!x -x -%x ~x *x &x ?x %x %%x ??x
166169
x{}

‎src/all_types.hpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ struct ConstErrValue {
167167
struct ConstBoundFnValue {
168168
FnTableEntry *fn;
169169
IrInstruction *first_arg;
170+
bool is_inline;
170171
};
171172

172173
struct ConstArgTuple {
@@ -192,6 +193,11 @@ enum RuntimeHintMaybe {
192193
RuntimeHintMaybeNonNull,
193194
};
194195

196+
struct ConstFn {
197+
FnTableEntry *fn_entry;
198+
bool is_inline;
199+
};
200+
195201
struct ConstExprValue {
196202
TypeTableEntry *type;
197203
ConstValSpecial special;
@@ -202,7 +208,7 @@ struct ConstExprValue {
202208
// populated if special == ConstValSpecialStatic
203209
BigNum x_bignum;
204210
bool x_bool;
205-
FnTableEntry *x_fn;
211+
ConstFn x_fn;
206212
ConstBoundFnValue x_bound_fn;
207213
TypeTableEntry *x_type;
208214
ConstExprValue *x_maybe;
@@ -366,6 +372,7 @@ enum NodeType {
366372
NodeTypeTypeLiteral,
367373
NodeTypeVarLiteral,
368374
NodeTypeTryExpr,
375+
NodeTypeInlineExpr,
369376
};
370377

371378
struct AstNodeRoot {
@@ -789,6 +796,10 @@ struct AstNodeTypeLiteral {
789796
struct AstNodeVarLiteral {
790797
};
791798

799+
struct AstNodeInlineExpr {
800+
AstNode *body;
801+
};
802+
792803
struct AstNode {
793804
enum NodeType type;
794805
size_t line;
@@ -847,6 +858,7 @@ struct AstNode {
847858
AstNodeErrorType error_type;
848859
AstNodeTypeLiteral type_literal;
849860
AstNodeVarLiteral var_literal;
861+
AstNodeInlineExpr inline_expr;
850862
} data;
851863
};
852864

@@ -1748,6 +1760,7 @@ enum IrInstructionId {
17481760
IrInstructionIdDeclRef,
17491761
IrInstructionIdPanic,
17501762
IrInstructionIdEnumTagName,
1763+
IrInstructionIdSetFnRefInline,
17511764
};
17521765

17531766
struct IrInstruction {
@@ -1943,6 +1956,7 @@ struct IrInstructionCall {
19431956
IrInstruction **args;
19441957
bool is_comptime;
19451958
LLVMValueRef tmp_ptr;
1959+
bool is_inline;
19461960
};
19471961

19481962
struct IrInstructionConst {
@@ -2493,6 +2507,12 @@ struct IrInstructionEnumTagName {
24932507
IrInstruction *target;
24942508
};
24952509

2510+
struct IrInstructionSetFnRefInline {
2511+
IrInstruction base;
2512+
2513+
IrInstruction *fn_ref;
2514+
};
2515+
24962516
static const size_t slice_ptr_index = 0;
24972517
static const size_t slice_len_index = 1;
24982518

‎src/analyze.cpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
21292129
case NodeTypeTypeLiteral:
21302130
case NodeTypeVarLiteral:
21312131
case NodeTypeTryExpr:
2132+
case NodeTypeInlineExpr:
21322133
zig_unreachable();
21332134
}
21342135
}
@@ -3251,7 +3252,8 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
32513252
// TODO better hashing algorithm
32523253
return 31643936;
32533254
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);
32553257
case TypeTableEntryIdTypeDecl:
32563258
return hash_ptr(const_val->data.x_type);
32573259
case TypeTableEntryIdNamespace:
@@ -3697,7 +3699,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
36973699
case TypeTableEntryIdPureError:
36983700
return a->data.x_pure_err == b->data.x_pure_err;
36993701
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;
37013704
case TypeTableEntryIdBool:
37023705
return a->data.x_bool == b->data.x_bool;
37033706
case TypeTableEntryIdInt:
@@ -3933,8 +3936,9 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
39333936
zig_unreachable();
39343937
case TypeTableEntryIdFn:
39353938
{
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));
39383942
return;
39393943
}
39403944
case TypeTableEntryIdBlock:
@@ -4011,7 +4015,8 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
40114015
case TypeTableEntryIdBoundFn:
40124016
{
40134017
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));
40154020
return;
40164021
}
40174022
case TypeTableEntryIdStruct:

‎src/ast_render.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ static const char *node_type_str(NodeType node_type) {
240240
return "VarLiteral";
241241
case NodeTypeTryExpr:
242242
return "TryExpr";
243+
case NodeTypeInlineExpr:
244+
return "InlineExpr";
243245
}
244246
zig_unreachable();
245247
}
@@ -921,6 +923,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
921923
render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
922924
break;
923925
}
926+
case NodeTypeInlineExpr:
927+
{
928+
fprintf(ar->f, "inline ");
929+
render_node_grouped(ar, node->data.inline_expr.body);
930+
break;
931+
}
924932
case NodeTypeFnDecl:
925933
case NodeTypeParamDecl:
926934
case NodeTypeErrorValueDecl:

‎src/codegen.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
608608
LLVMBuildLoad(g->builder, ptr_ptr, ""),
609609
LLVMBuildLoad(g->builder, len_ptr, ""),
610610
};
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, "");
612612
LLVMBuildUnreachable(g->builder);
613613
}
614614

@@ -1773,8 +1773,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
17731773
}
17741774
}
17751775

1776+
bool want_always_inline = (instruction->fn_entry != nullptr &&
1777+
instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
1778+
17761779
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

17791783
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
17801784
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,
27492753
case IrInstructionIdSetGlobalLinkage:
27502754
case IrInstructionIdDeclRef:
27512755
case IrInstructionIdSwitchVar:
2756+
case IrInstructionIdSetFnRefInline:
27522757
zig_unreachable();
27532758
case IrInstructionIdReturn:
27542759
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3183,7 +3188,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
31833188
}
31843189
}
31853190
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);
31873192
case TypeTableEntryIdPointer:
31883193
{
31893194
render_const_val_global(g, const_val, "");

‎src/ir.cpp

+102-22
Large diffs are not rendered by default.

‎src/ir_print.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,10 @@ static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) {
870870
fprintf(irp->f, ")");
871871
}
872872

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+
}
873877

874878
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
875879
ir_print_prefix(irp, instruction);
@@ -1155,6 +1159,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11551159
case IrInstructionIdPanic:
11561160
ir_print_panic(irp, (IrInstructionPanic *)instruction);
11571161
break;
1162+
case IrInstructionIdSetFnRefInline:
1163+
ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction);
1164+
break;
11581165
}
11591166
fprintf(irp->f, "\n");
11601167
}

‎src/parser.cpp

+39-12
Original file line numberDiff line numberDiff line change
@@ -927,16 +927,41 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
927927
}
928928

929929
/*
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)
931956
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
932957
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
933958
SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
934959
FieldAccessExpression : token(Dot) token(Symbol)
935960
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
936961
*/
937962
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)
940965
return nullptr;
941966

942967
while (true) {
@@ -945,10 +970,10 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
945970
*token_index += 1;
946971

947972
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;
949974
ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
950975

951-
primary_expr = node;
976+
inline_expr = node;
952977
} else if (first_token->id == TokenIdLBracket) {
953978
*token_index += 1;
954979

@@ -960,7 +985,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
960985
*token_index += 1;
961986

962987
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;
964989
node->data.slice_expr.start = expr_node;
965990
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,
972997
node->data.slice_expr.is_const = true;
973998
}
974999

975-
primary_expr = node;
1000+
inline_expr = node;
9761001
} else if (ellipsis_or_r_bracket->id == TokenIdRBracket) {
9771002
*token_index += 1;
9781003

9791004
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;
9811006
node->data.array_access_expr.subscript = expr_node;
9821007

983-
primary_expr = node;
1008+
inline_expr = node;
9841009
} else {
9851010
ast_invalid_token_error(pc, first_token);
9861011
}
@@ -990,12 +1015,12 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
9901015
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
9911016

9921017
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;
9941019
node->data.field_access_expr.field_name = token_buf(name_token);
9951020

996-
primary_expr = node;
1021+
inline_expr = node;
9971022
} else {
998-
return primary_expr;
1023+
return inline_expr;
9991024
}
10001025
}
10011026
}
@@ -2807,5 +2832,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
28072832
case NodeTypeVarLiteral:
28082833
// none
28092834
break;
2835+
case NodeTypeInlineExpr:
2836+
visit_field(&node->data.inline_expr.body, visit, context);
28102837
}
28112838
}

‎src/zig_llvm.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,13 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
176176

177177

178178
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)
180180
{
181181
CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
182182
call_inst->setCallingConv(CC);
183+
if (always_inline) {
184+
call_inst->addAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline);
185+
}
183186
return wrap(unwrap(B)->Insert(call_inst));
184187
}
185188

‎src/zig_llvm.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
3838
const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug);
3939

4040
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);
4242

4343
LLVMValueRef ZigLLVMConstInlineAsm(LLVMTypeRef Ty, const char *AsmString,
4444
const char *Constraints, bool HasSideEffects, bool IsAlignStack, bool is_x86);

‎test/cases/fn.zig

+7
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ fn fn1() -> u32 {5}
8787
fn fn2() -> u32 {6}
8888
fn fn3() -> u32 {7}
8989
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 }

0 commit comments

Comments
 (0)
Please sign in to comment.