Skip to content

Commit

Permalink
Procedure inlining on call site
Browse files Browse the repository at this point in the history
  • Loading branch information
gingerBill committed Sep 9, 2018
1 parent 76848e8 commit 4f3837f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 14 deletions.
46 changes: 46 additions & 0 deletions src/check_expr.cpp
Expand Up @@ -85,6 +85,17 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand *



Entity *entity_from_expr(Ast *expr) {
expr = unparen_expr(expr);
switch (expr->kind) {
case Ast_Ident:
return expr->Ident.entity;
case Ast_SelectorExpr:
return entity_from_expr(expr->SelectorExpr.selector);
}
return nullptr;
}

void error_operand_not_expression(Operand *o) {
if (o->mode == Addressing_Type) {
gbString err = expr_to_string(o->expr);
Expand Down Expand Up @@ -2862,6 +2873,10 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ

bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
ast_node(ce, CallExpr, call);
if (ce->inlining != ProcInlining_none) {
error(call, "Inlining operators are not allowed on built-in procedures");
}

BuiltinProc *bp = &builtin_procs[id];
{
char *err = nullptr;
Expand Down Expand Up @@ -4807,6 +4822,9 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
} else {
GB_PANIC("Unhandled #%.*s", LIT(name));
}
if (ce->inlining != ProcInlining_none) {
error(call, "Inlining operators are not allowed on built-in procedures");
}
} else {
check_expr_or_type(c, operand, ce->proc);
}
Expand Down Expand Up @@ -4964,6 +4982,25 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
}
}

switch (ce->inlining) {
case ProcInlining_inline: {
Entity *e = entity_from_expr(ce->proc);
if (e != nullptr && e->kind == Entity_Procedure) {
DeclInfo *decl = e->decl_info;
if (decl->proc_lit) {
ast_node(pl, ProcLit, decl->proc_lit);
if (pl->inlining == ProcInlining_no_inline) {
error(call, "'inline' cannot be applied to a procedure that has be marked as 'no_inline'");
}
}
}
break;
}

case ProcInlining_no_inline:
break;
}

operand->expr = call;
return Expr_Expr;
}
Expand Down Expand Up @@ -6511,6 +6548,15 @@ gbString write_expr_to_string(gbString str, Ast *node) {
case_end;

case_ast_node(ce, CallExpr, node);
switch (ce->inlining) {
case ProcInlining_inline:
str = gb_string_appendc(str, "inline ");
break;
case ProcInlining_no_inline:
str = gb_string_appendc(str, "no_inline ");
break;
}

str = write_expr_to_string(str, ce->proc);
str = gb_string_appendc(str, "(");

Expand Down
18 changes: 12 additions & 6 deletions src/ir.cpp
Expand Up @@ -250,6 +250,7 @@ gbAllocator ir_allocator(void) {
irValue * return_ptr; \
Array<irValue *> args; \
irValue * context_ptr; \
ProcInlining inlining; \
}) \
IR_INSTR_KIND(StartupRuntime, i32) \
IR_INSTR_KIND(DebugDeclare, struct { \
Expand Down Expand Up @@ -1075,13 +1076,14 @@ irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f)
return v;
}

irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, Array<irValue *> args, Type *result_type, irValue *context_ptr) {
irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, Array<irValue *> args, Type *result_type, irValue *context_ptr, ProcInlining inlining) {
irValue *v = ir_alloc_instr(p, irInstr_Call);
v->Instr.Call.value = value;
v->Instr.Call.return_ptr = return_ptr;
v->Instr.Call.args = args;
v->Instr.Call.type = result_type;
v->Instr.Call.context_ptr = context_ptr;
v->Instr.Call.inlining = inlining;
return v;
}

Expand Down Expand Up @@ -1684,7 +1686,7 @@ irValue *ir_find_or_generate_context_ptr(irProcedure *proc) {
}


irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args) {
irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, ProcInlining inlining = ProcInlining_none) {
Type *pt = base_type(ir_type(value));
GB_ASSERT(pt->kind == Type_Proc);
Type *results = pt->Proc.results;
Expand Down Expand Up @@ -1726,16 +1728,20 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args) {
}
}

if (inlining == ProcInlining_none) {
inlining = p->inlining;
}

Type *abi_rt = pt->Proc.abi_compat_result_type;
Type *rt = reduce_tuple_to_single_type(results);
if (pt->Proc.return_by_pointer) {
irValue *return_ptr = ir_add_local_generated(p, rt);
GB_ASSERT(is_type_pointer(ir_type(return_ptr)));
ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr));
ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr, inlining));
return ir_emit_load(p, return_ptr);
}

irValue *result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr));
irValue *result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr, inlining));
if (abi_rt != results) {
result = ir_emit_transmute(p, result, rt);
}
Expand Down Expand Up @@ -5150,7 +5156,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
}
}
}
return ir_emit_call(proc, value, args);
return ir_emit_call(proc, value, args, ce->inlining);
}

isize arg_index = 0;
Expand Down Expand Up @@ -5344,7 +5350,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
}

auto call_args = array_slice(args, 0, final_count);
return ir_emit_call(proc, value, call_args);
return ir_emit_call(proc, value, call_args, ce->inlining);
case_end;

case_ast_node(se, SliceExpr, expr);
Expand Down
4 changes: 4 additions & 0 deletions src/ir_print.cpp
Expand Up @@ -1478,6 +1478,10 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (proc_type->Proc.diverging) {
ir_write_str_lit(f, " noreturn");
}
switch (call->inlining) {
case ProcInlining_inline: ir_write_str_lit(f, " alwaysinline"); break;
case ProcInlining_no_inline: ir_write_str_lit(f, " noinline"); break;
}
ir_print_debug_location(f, m, value, instr->block->proc);

break;
Expand Down
28 changes: 20 additions & 8 deletions src/parser.cpp
Expand Up @@ -1553,6 +1553,7 @@ Ast * parse_type (AstFile *f);
Ast * parse_call_expr (AstFile *f, Ast *operand);
Ast * parse_struct_field_list(AstFile *f, isize *name_count_);
Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_type_token);
Ast *parse_unary_expr(AstFile *f, bool lhs);


Ast *convert_stmt_to_expr(AstFile *f, Ast *statement, String kind) {
Expand Down Expand Up @@ -1673,9 +1674,10 @@ Ast *parse_operand(AstFile *f, bool lhs) {
case Token_no_inline:
{
Token token = advance_token(f);
Ast *expr = parse_operand(f, false);
if (expr->kind != Ast_ProcLit) {
syntax_error(expr, "%.*s must be followed by a procedure literal, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
Ast *expr = parse_unary_expr(f, false);
Ast *e = unparen_expr(expr);
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
return ast_bad_expr(f, token, f->curr_token);
}
ProcInlining pi = ProcInlining_none;
Expand All @@ -1685,11 +1687,19 @@ Ast *parse_operand(AstFile *f, bool lhs) {
pi = ProcInlining_no_inline;
}
if (pi != ProcInlining_none) {
if (expr->ProcLit.inlining != ProcInlining_none &&
expr->ProcLit.inlining != pi) {
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
if (e->kind == Ast_ProcLit) {
if (expr->ProcLit.inlining != ProcInlining_none &&
expr->ProcLit.inlining != pi) {
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
}
expr->ProcLit.inlining = pi;
} else if (e->kind == Ast_CallExpr) {
if (expr->CallExpr.inlining != ProcInlining_none &&
expr->CallExpr.inlining != pi) {
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
}
expr->CallExpr.inlining = pi;
}
expr->ProcLit.inlining = pi;
}

return expr;
Expand Down Expand Up @@ -3657,7 +3667,9 @@ Ast *parse_stmt(AstFile *f) {
Token token = f->curr_token;
switch (token.kind) {
// Operands
case Token_context: // Also allows for `context <-`
case Token_context: // Also allows for `context =`
case Token_inline:
case Token_no_inline:
case Token_Ident:
case Token_Integer:
case Token_Float:
Expand Down
1 change: 1 addition & 0 deletions src/parser.hpp
Expand Up @@ -252,6 +252,7 @@ AST_KIND(_ExprBegin, "", bool) \
Token open; \
Token close; \
Token ellipsis; \
ProcInlining inlining; \
}) \
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
Expand Down

0 comments on commit 4f3837f

Please sign in to comment.