mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-26 15:34:59 -07:00
Procedure inlining on call site
This commit is contained in:
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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, "(");
|
||||
|
||||
|
||||
+12
-6
@@ -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 { \
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+20
-8
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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:
|
||||
|
||||
@@ -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; }) \
|
||||
|
||||
Reference in New Issue
Block a user