Skip to content

Commit e2dd340

Browse files
committed
Automatically inline a function if there is only a single call to that function from a decision block
1 parent b5f0c02 commit e2dd340

File tree

5 files changed

+147
-8
lines changed

5 files changed

+147
-8
lines changed

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ bench-langs:
221221
'chaos dev.kaos' \
222222
'python3 dev.py' \
223223
'ruby dev.rb' \
224-
'php dev.php'
224+
'php dev.php' \
225+
'lua dev.lua'
225226

226227
profile:
227228
./profile.sh

compiler/compiler.c

+136-7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ KaosIR* compile(ASTRoot* ast_root)
4848
// Declare functions in all parsed files
4949
declare_functions(ast_root, program);
5050

51+
// Determine whether the functions should be inlined or not
52+
determine_inline_functions(ast_root);
53+
5154
// Compile functions in all parsed files
5255
compile_functions(ast_root, program);
5356

@@ -652,6 +655,12 @@ unsigned short compileExpr(KaosIR* program, Expr* expr)
652655
enum ValueType value_type = compileExpr(program, expr) - 1;
653656
Symbol* parameter = function->parameters[i - 1];
654657

658+
if (function->should_inline) {
659+
Symbol* symbol_upper = getSymbol(expr_list->exprs[i - 1]->v.ident->name);
660+
Symbol* symbol_new = createCloneFromSymbol(parameter->name, symbol_upper->type, symbol_upper, symbol_upper->type);
661+
symbol_new->addr = symbol_upper->addr;
662+
}
663+
655664
strongly_type(parameter, NULL, function, expr, value_type);
656665

657666
enum Type type = parameter->type;
@@ -857,16 +866,23 @@ unsigned short compileExpr(KaosIR* program, Expr* expr)
857866
} else {
858867
}
859868

860-
push_inst_(program, PREPARE);
861-
for (size_t i = 0; i < putargr_stack_p; i++)
862-
push_inst_r(program, PUTARGR, putargr_stack[i]);
869+
if (function->should_inline) {
870+
Decl* decl = function->ast;
871+
compileStmt(program, decl->v.func_decl->body);
872+
if (decl->v.func_decl->decision != NULL)
873+
compileSpec(program, decl->v.func_decl->decision);
874+
} else {
875+
push_inst_(program, PREPARE);
876+
for (size_t i = 0; i < putargr_stack_p; i++)
877+
push_inst_r(program, PUTARGR, putargr_stack[i]);
863878

864-
push_inst_i_i(program, CALL, function->addr, op_counter++);
879+
push_inst_i_i(program, CALL, function->addr, op_counter++);
865880

866-
function->call_patches[function->call_patches_size++] = op_counter - 1;
881+
function->call_patches[function->call_patches_size++] = op_counter - 1;
867882

868-
push_inst_r(program, RETVAL, R1);
869-
push_inst_r_i(program, MOVI, R0, 1); // TODO: temp, set it according to function return type
883+
push_inst_r(program, RETVAL, R1);
884+
push_inst_r_i(program, MOVI, R0, 1); // TODO: temp, set it according to function return type
885+
}
870886

871887
return function->value_type + 1;
872888
break;
@@ -1042,6 +1058,14 @@ void compileDecl(KaosIR* program, Decl* decl)
10421058
}
10431059
case FuncDecl_kind: {
10441060
_Function* function = startFunctionNew(decl->v.func_decl->name->v.ident->name);
1061+
if (function->should_inline) {
1062+
function->ast = decl;
1063+
function_mode->is_compiled = true;
1064+
endFunction();
1065+
break;
1066+
}
1067+
1068+
function->ast = decl;
10451069

10461070
if (function->is_compiled)
10471071
break;
@@ -2145,6 +2169,111 @@ void compile_functions(ASTRoot* ast_root, KaosIR* program)
21452169
}
21462170
}
21472171

2172+
void determine_inline_functions(ASTRoot* ast_root)
2173+
{
2174+
for (unsigned long i = 0; i < ast_root->file_count; i++) {
2175+
File* file = ast_root->files[i];
2176+
current_file_index = i;
2177+
StmtList* stmt_list = file->stmt_list;
2178+
pushModuleStack(file->module_path, file->module);
2179+
2180+
// Foreach function look for other functions' decision blocks for calls
2181+
for (unsigned long j = stmt_list->stmt_count; 0 < j; j--) {
2182+
Stmt* stmt = stmt_list->stmts[j - 1];
2183+
if (stmt->kind == DeclStmt_kind && stmt->v.decl_stmt->decl->kind == FuncDecl_kind) {
2184+
Decl* decl = stmt->v.decl_stmt->decl;
2185+
_Function* function = startFunctionNew(decl->v.func_decl->name->v.ident->name);
2186+
function->should_inline = determine_inline_function(ast_root, function);
2187+
endFunction();
2188+
}
2189+
}
2190+
2191+
popModuleStack();
2192+
}
2193+
}
2194+
2195+
bool determine_inline_function(ASTRoot* ast_root, _Function* function)
2196+
{
2197+
unsigned long call_counter = 0;
2198+
// Look for all functions' decision blocks for all the files compiled
2199+
for (unsigned long i = 0; i < ast_root->file_count; i++) {
2200+
File* file = ast_root->files[i];
2201+
current_file_index = i;
2202+
StmtList* stmt_list = file->stmt_list;
2203+
pushModuleStack(file->module_path, file->module);
2204+
2205+
for (unsigned long j = stmt_list->stmt_count; 0 < j; j--) {
2206+
Stmt* stmt = stmt_list->stmts[j - 1];
2207+
if (stmt->kind == DeclStmt_kind && stmt->v.decl_stmt->decl->kind == FuncDecl_kind) {
2208+
Decl* decl = stmt->v.decl_stmt->decl;
2209+
_Function* _function = startFunctionNew(decl->v.func_decl->name->v.ident->name);
2210+
if (function == _function)
2211+
continue;
2212+
if (decl->v.func_decl->decision != NULL) {
2213+
ExprList* expr_list = decl->v.func_decl->decision->v.decision_block->decisions;
2214+
for (unsigned long i = expr_list->expr_count; 0 < i; i--) {
2215+
Expr* expr = expr_list->exprs[i - 1];
2216+
if (does_decision_have_a_call(expr, function)) {
2217+
call_counter++;
2218+
}
2219+
}
2220+
}
2221+
endFunction();
2222+
}
2223+
}
2224+
2225+
popModuleStack();
2226+
}
2227+
2228+
if (call_counter == 1)
2229+
return true;
2230+
else
2231+
return false;
2232+
}
2233+
2234+
bool does_decision_have_a_call(Expr* expr, _Function* function)
2235+
{
2236+
Stmt* stmt = NULL;
2237+
switch (expr->kind) {
2238+
case DecisionExpr_kind:
2239+
stmt = expr->v.decision_expr->outcome;
2240+
break;
2241+
case DefaultExpr_kind:
2242+
stmt = expr->v.default_expr->outcome;
2243+
break;
2244+
default:
2245+
break;
2246+
}
2247+
2248+
return does_stmt_have_a_call(stmt, function);
2249+
}
2250+
2251+
bool does_stmt_have_a_call(Stmt* stmt, _Function* function)
2252+
{
2253+
if (stmt->kind == ExprStmt_kind && stmt->v.expr_stmt->x->kind == CallExpr_kind) {
2254+
Expr* expr = stmt->v.expr_stmt->x;
2255+
_Function* _function = NULL;
2256+
switch (expr->v.call_expr->fun->kind) {
2257+
case Ident_kind:
2258+
_function = getFunction(expr->v.call_expr->fun->v.ident->name, NULL);
2259+
break;
2260+
case SelectorExpr_kind:
2261+
_function = getFunction(
2262+
expr->v.call_expr->fun->v.selector_expr->sel->v.ident->name,
2263+
expr->v.call_expr->fun->v.selector_expr->x->v.ident->name
2264+
);
2265+
break;
2266+
default:
2267+
break;
2268+
}
2269+
2270+
if (function == _function)
2271+
return true;
2272+
}
2273+
2274+
return false;
2275+
}
2276+
21482277
void strongly_type(Symbol* symbol_x, Symbol* symbol_y, _Function* function, Expr* expr, enum ValueType value_type)
21492278
{
21502279
if (expr != NULL) {

compiler/compiler.h

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ char* compile_module_selector(Expr* module_selector);
7979
bool declare_function(Stmt* stmt, File* file, KaosIR* program);
8080
void declare_functions(ASTRoot* ast_root, KaosIR* program);
8181
void compile_functions(ASTRoot* ast_root, KaosIR* program);
82+
void determine_inline_functions(ASTRoot* ast_root);
83+
bool determine_inline_function(ASTRoot* ast_root, _Function* function);
84+
bool does_decision_have_a_call(Expr* expr, _Function* function);
85+
bool does_stmt_have_a_call(Stmt* stmt, _Function* function);
8286

8387
void strongly_type(Symbol* symbol_x, Symbol* symbol_y, _Function* function, Expr* expr, enum ValueType value_type);
8488
void strongly_type_basic_check(unsigned short code, char *str1, char *str2, enum Type type, enum ValueType value_type);

interpreter/function.c

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ _Function* declareFunction(char *name, char *module, char *module_path, char *co
179179

180180
function->call_patches = (int*)malloc(USHRT_MAX * 256 * sizeof(int));
181181
function->call_patches_size = 0;
182+
function->should_inline = false;
182183

183184
return function;
184185
}

interpreter/function.h

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ typedef struct FunctionCall FunctionCall;
4444
#include "../utilities/helpers.h"
4545
#include "module.h"
4646

47+
typedef struct Decl Decl;
48+
4749
extern enum Phase phase;
4850
enum BlockType { B_EXPRESSION, B_FUNCTION };
4951

@@ -72,6 +74,8 @@ typedef struct _Function {
7274
bool is_compiled;
7375
int *call_patches;
7476
int call_patches_size;
77+
Decl* ast;
78+
bool should_inline;
7579
} _Function;
7680

7781
_Function* function_cursor;

0 commit comments

Comments
 (0)