mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00: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) {
|
void error_operand_not_expression(Operand *o) {
|
||||||
if (o->mode == Addressing_Type) {
|
if (o->mode == Addressing_Type) {
|
||||||
gbString err = expr_to_string(o->expr);
|
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) {
|
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
|
||||||
ast_node(ce, CallExpr, call);
|
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];
|
BuiltinProc *bp = &builtin_procs[id];
|
||||||
{
|
{
|
||||||
char *err = nullptr;
|
char *err = nullptr;
|
||||||
@@ -4807,6 +4822,9 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
|
|||||||
} else {
|
} else {
|
||||||
GB_PANIC("Unhandled #%.*s", LIT(name));
|
GB_PANIC("Unhandled #%.*s", LIT(name));
|
||||||
}
|
}
|
||||||
|
if (ce->inlining != ProcInlining_none) {
|
||||||
|
error(call, "Inlining operators are not allowed on built-in procedures");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
check_expr_or_type(c, operand, ce->proc);
|
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;
|
operand->expr = call;
|
||||||
return Expr_Expr;
|
return Expr_Expr;
|
||||||
}
|
}
|
||||||
@@ -6511,6 +6548,15 @@ gbString write_expr_to_string(gbString str, Ast *node) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ce, CallExpr, node);
|
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 = write_expr_to_string(str, ce->proc);
|
||||||
str = gb_string_appendc(str, "(");
|
str = gb_string_appendc(str, "(");
|
||||||
|
|
||||||
|
|||||||
+12
-6
@@ -250,6 +250,7 @@ gbAllocator ir_allocator(void) {
|
|||||||
irValue * return_ptr; \
|
irValue * return_ptr; \
|
||||||
Array<irValue *> args; \
|
Array<irValue *> args; \
|
||||||
irValue * context_ptr; \
|
irValue * context_ptr; \
|
||||||
|
ProcInlining inlining; \
|
||||||
}) \
|
}) \
|
||||||
IR_INSTR_KIND(StartupRuntime, i32) \
|
IR_INSTR_KIND(StartupRuntime, i32) \
|
||||||
IR_INSTR_KIND(DebugDeclare, struct { \
|
IR_INSTR_KIND(DebugDeclare, struct { \
|
||||||
@@ -1075,13 +1076,14 @@ irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f)
|
|||||||
return v;
|
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);
|
irValue *v = ir_alloc_instr(p, irInstr_Call);
|
||||||
v->Instr.Call.value = value;
|
v->Instr.Call.value = value;
|
||||||
v->Instr.Call.return_ptr = return_ptr;
|
v->Instr.Call.return_ptr = return_ptr;
|
||||||
v->Instr.Call.args = args;
|
v->Instr.Call.args = args;
|
||||||
v->Instr.Call.type = result_type;
|
v->Instr.Call.type = result_type;
|
||||||
v->Instr.Call.context_ptr = context_ptr;
|
v->Instr.Call.context_ptr = context_ptr;
|
||||||
|
v->Instr.Call.inlining = inlining;
|
||||||
return v;
|
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));
|
Type *pt = base_type(ir_type(value));
|
||||||
GB_ASSERT(pt->kind == Type_Proc);
|
GB_ASSERT(pt->kind == Type_Proc);
|
||||||
Type *results = pt->Proc.results;
|
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 *abi_rt = pt->Proc.abi_compat_result_type;
|
||||||
Type *rt = reduce_tuple_to_single_type(results);
|
Type *rt = reduce_tuple_to_single_type(results);
|
||||||
if (pt->Proc.return_by_pointer) {
|
if (pt->Proc.return_by_pointer) {
|
||||||
irValue *return_ptr = ir_add_local_generated(p, rt);
|
irValue *return_ptr = ir_add_local_generated(p, rt);
|
||||||
GB_ASSERT(is_type_pointer(ir_type(return_ptr)));
|
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);
|
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) {
|
if (abi_rt != results) {
|
||||||
result = ir_emit_transmute(p, result, rt);
|
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;
|
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);
|
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_end;
|
||||||
|
|
||||||
case_ast_node(se, SliceExpr, expr);
|
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) {
|
if (proc_type->Proc.diverging) {
|
||||||
ir_write_str_lit(f, " noreturn");
|
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);
|
ir_print_debug_location(f, m, value, instr->block->proc);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
+20
-8
@@ -1553,6 +1553,7 @@ Ast * parse_type (AstFile *f);
|
|||||||
Ast * parse_call_expr (AstFile *f, Ast *operand);
|
Ast * parse_call_expr (AstFile *f, Ast *operand);
|
||||||
Ast * parse_struct_field_list(AstFile *f, isize *name_count_);
|
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_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) {
|
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:
|
case Token_no_inline:
|
||||||
{
|
{
|
||||||
Token token = advance_token(f);
|
Token token = advance_token(f);
|
||||||
Ast *expr = parse_operand(f, false);
|
Ast *expr = parse_unary_expr(f, false);
|
||||||
if (expr->kind != Ast_ProcLit) {
|
Ast *e = unparen_expr(expr);
|
||||||
syntax_error(expr, "%.*s must be followed by a procedure literal, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
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);
|
return ast_bad_expr(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
ProcInlining pi = ProcInlining_none;
|
ProcInlining pi = ProcInlining_none;
|
||||||
@@ -1685,11 +1687,19 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
pi = ProcInlining_no_inline;
|
pi = ProcInlining_no_inline;
|
||||||
}
|
}
|
||||||
if (pi != ProcInlining_none) {
|
if (pi != ProcInlining_none) {
|
||||||
if (expr->ProcLit.inlining != ProcInlining_none &&
|
if (e->kind == Ast_ProcLit) {
|
||||||
expr->ProcLit.inlining != pi) {
|
if (expr->ProcLit.inlining != ProcInlining_none &&
|
||||||
syntax_error(expr, "You cannot apply both 'inline' and 'no_inline' to a procedure literal");
|
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;
|
return expr;
|
||||||
@@ -3657,7 +3667,9 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
// Operands
|
// 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_Ident:
|
||||||
case Token_Integer:
|
case Token_Integer:
|
||||||
case Token_Float:
|
case Token_Float:
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
Token open; \
|
Token open; \
|
||||||
Token close; \
|
Token close; \
|
||||||
Token ellipsis; \
|
Token ellipsis; \
|
||||||
|
ProcInlining inlining; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||||
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
|
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
|
||||||
|
|||||||
Reference in New Issue
Block a user