Skip to content

Commit

Permalink
Use deferred reification during reachability analysis (#2449)
Browse files Browse the repository at this point in the history
This change is a followup to abdcf2e. Instead of fully reifying
functions during reachability analysis, the pass now uses deferred
reification as needed.

Functions are now fully reified one at a time during code generation,
instead of all at once during reachability analysis. In the future,
code generation will use deferred reification as well.

This change results in a huge improvement in the memory usage of the
compiler.
  • Loading branch information
Benoit Vey committed Jan 9, 2018
1 parent 28b67dd commit 884c62d
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 205 deletions.
17 changes: 6 additions & 11 deletions src/libponyc/codegen/gencall.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[],
for(size_t i = 0; i < m->param_count; i++)
{
cast_args[i+1] = gen_assign_cast(c, param_types[i+3], args[i+1],
ast_type(arg_ast));
ast_type(arg_ast));
arg_ast = ast_sibling(arg_ast);
}

Expand All @@ -556,20 +556,17 @@ void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[],
}

// Trace while populating the message contents.
ast_t* params = ast_childidx(m->r_fun, 3);
ast_t* param = ast_child(params);
arg_ast = ast_child(args_ast);
bool need_trace = false;

while(param != NULL)
for(size_t i = 0; i < m->param_count; i++)
{
if(gentrace_needed(c, ast_type(arg_ast), ast_type(param)))
if(gentrace_needed(c, ast_type(arg_ast), m->params[i].ast))
{
need_trace = true;
break;
}

param = ast_sibling(param);
arg_ast = ast_sibling(arg_ast);
}

Expand All @@ -579,14 +576,12 @@ void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[],
{
LLVMValueRef gc = gencall_runtime(c, "pony_gc_send", &ctx, 1, "");
LLVMSetMetadataStr(gc, "pony.msgsend", md);
param = ast_child(params);
arg_ast = ast_child(args_ast);

for(size_t i = 0; i < m->param_count; i++)
{
gentrace(c, ctx, args[i+1], cast_args[i+1], ast_type(arg_ast),
ast_type(param));
param = ast_sibling(param);
m->params[i].ast);
arg_ast = ast_sibling(arg_ast);
}

Expand All @@ -602,7 +597,7 @@ void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[],
msg_args[4] = LLVMConstInt(c->i1, 1, false);
LLVMValueRef send;

if(ast_id(m->r_fun) == TK_NEW)
if(ast_id(m->fun->ast) == TK_NEW)
send = gencall_runtime(c, "pony_sendv_single", msg_args, 5, "");
else
send = gencall_runtime(c, "pony_sendv", msg_args, 5, "");
Expand Down Expand Up @@ -676,7 +671,7 @@ static bool can_inline_message_send(reach_type_t* t, reach_method_t* m,
return false;

case TK_ACTOR:
if(ast_id(m_sub->r_fun) == TK_FUN)
if(ast_id(m_sub->fun->ast) == TK_FUN)
return false;
break;

Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/codegen/gendesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static LLVMValueRef make_unbox_function(compile_t* c, reach_type_t* t,
const char* unbox_name = genname_unbox(m->full_name);
compile_type_t* c_t = (compile_type_t*)t->c_type;

if(ast_id(m->r_fun) != TK_NEW)
if(ast_id(m->fun->ast) != TK_NEW)
{
// It's the same type, but it takes the boxed type instead of the primitive
// type as the receiver.
Expand Down Expand Up @@ -82,7 +82,7 @@ static LLVMValueRef make_unbox_function(compile_t* c, reach_type_t* t,

LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);

if(ast_id(m->r_fun) != TK_NEW)
if(ast_id(m->fun->ast) != TK_NEW)
{
// If it's not a constructor, pass the extracted primitive as the receiver.
args[0] = primitive;
Expand Down
71 changes: 46 additions & 25 deletions src/libponyc/codegen/genfun.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ static void name_param(compile_t* c, reach_type_t* t, reach_method_t* m,
{
info = LLVMDIBuilderCreateArtificialVariable(c->di,
c_m->di_method, name, index + 1, c_m->di_file,
(unsigned)ast_line(m->r_fun), c_t->di_type);
(unsigned)ast_line(m->fun->ast), c_t->di_type);
} else {
info = LLVMDIBuilderCreateParameterVariable(c->di,
c_m->di_method, name, index + 1, c_m->di_file,
(unsigned)ast_line(m->r_fun), c_t->di_type);
(unsigned)ast_line(m->fun->ast), c_t->di_type);
}

LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0);
Expand All @@ -56,24 +56,28 @@ static void name_param(compile_t* c, reach_type_t* t, reach_method_t* m,
}

static void name_params(compile_t* c, reach_type_t* t, reach_method_t* m,
ast_t* params, LLVMValueRef func)
LLVMValueRef func)
{
unsigned offset = 0;

if(m->cap != TK_AT)
{
// Name the receiver 'this'.
name_param(c, t, m, func, c->str_this, 0, ast_line(params), ast_pos(params));
name_param(c, t, m, func, c->str_this, 0, ast_line(m->fun->ast),
ast_pos(m->fun->ast));
offset = 1;
}

// Name each parameter.
ast_t* params = ast_childidx(m->fun->ast, 3);
ast_t* param = ast_child(params);

// Name each parameter.
for(size_t i = 0; i < m->param_count; i++)
{
name_param(c, m->params[i].type, m, func, ast_name(ast_child(param)),
(unsigned)i + offset, ast_line(param), ast_pos(param));
reach_param_t* r_param = &m->params[i];
name_param(c, r_param->type, m, func, r_param->name, (unsigned)i + offset,
ast_line(param), ast_pos(param));

param = ast_sibling(param);
}
}
Expand Down Expand Up @@ -127,7 +131,7 @@ static void make_signature(compile_t* c, reach_type_t* t,
// Bare methods returning None return void to maintain compatibility with C.
// Class constructors return void to avoid clobbering nocapture information.
if(bare_void || (n->name == c->str__final) ||
((ast_id(m->r_fun) == TK_NEW) && (t->underlying == TK_CLASS)))
((ast_id(m->fun->ast) == TK_NEW) && (t->underlying == TK_CLASS)))
c_m->func_type = LLVMFunctionType(c->void_type, tparams, (int)count, false);
else
c_m->func_type = LLVMFunctionType(
Expand All @@ -150,9 +154,6 @@ static void make_signature(compile_t* c, reach_type_t* t,
static void make_function_debug(compile_t* c, reach_type_t* t,
reach_method_t* m, LLVMValueRef func)
{
AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
body);

// Count the parameters, including the receiver and the result.
size_t count = m->param_count + 1;
size_t offset = 1;
Expand Down Expand Up @@ -198,9 +199,11 @@ static void make_function_debug(compile_t* c, reach_type_t* t,
}
#endif

ast_t* id = ast_childidx(m->fun->ast, 1);

c_m->di_method = LLVMDIBuilderCreateMethod(c->di, scope, ast_name(id),
m->full_name, c_m->di_file, (unsigned)ast_line(m->r_fun), subroutine, func,
c->opt->release);
m->full_name, c_m->di_file, (unsigned)ast_line(m->fun->ast), subroutine,
func, c->opt->release);

ponyint_pool_free_size(md_size, md);
}
Expand All @@ -215,7 +218,7 @@ static void make_prototype(compile_t* c, reach_type_t* t,
bool handler = false;
bool is_trait = false;

switch(ast_id(m->r_fun))
switch(ast_id(m->fun->ast))
{
case TK_NEW:
handler = t->underlying == TK_ACTOR;
Expand Down Expand Up @@ -434,12 +437,14 @@ static bool genfun_fun(compile_t* c, reach_type_t* t, reach_method_t* m)
compile_method_t* c_m = (compile_method_t*)m->c_method;
pony_assert(c_m->func != NULL);

AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
ast_t* r_fun = deferred_reify(m->fun, m->fun->ast, c->opt);

AST_GET_CHILDREN(r_fun, cap, id, typeparams, params, result, can_error,
body);

codegen_startfun(c, c_m->func, c_m->di_file, c_m->di_method,
ast_id(cap) == TK_AT);
name_params(c, t, m, params, c_m->func);
name_params(c, t, m, c_m->func);

bool finaliser = c_m->func == c_t->final_fn;

Expand Down Expand Up @@ -483,6 +488,9 @@ static bool genfun_fun(compile_t* c, reach_type_t* t, reach_method_t* m)
}

codegen_finishfun(c);

ast_free_unattached(r_fun);

return true;
}

Expand All @@ -492,12 +500,14 @@ static bool genfun_be(compile_t* c, reach_type_t* t, reach_method_t* m)
pony_assert(c_m->func != NULL);
pony_assert(c_m->func_handler != NULL);

AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
ast_t* r_fun = deferred_reify(m->fun, m->fun->ast, c->opt);

AST_GET_CHILDREN(r_fun, cap, id, typeparams, params, result, can_error,
body);

// Generate the handler.
codegen_startfun(c, c_m->func_handler, c_m->di_file, c_m->di_method, false);
name_params(c, t, m, params, c_m->func_handler);
name_params(c, t, m, c_m->func_handler);

LLVMValueRef value = gen_expr(c, body);

Expand Down Expand Up @@ -530,6 +540,8 @@ static bool genfun_be(compile_t* c, reach_type_t* t, reach_method_t* m)
add_dispatch_case(c, t, params, m->vtable_index, c_m->func_handler,
c_m->func_type, msg_type_ptr);

ast_free_unattached(r_fun);

return true;
}

Expand All @@ -539,11 +551,13 @@ static bool genfun_new(compile_t* c, reach_type_t* t, reach_method_t* m)
compile_method_t* c_m = (compile_method_t*)m->c_method;
pony_assert(c_m->func != NULL);

AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
ast_t* r_fun = deferred_reify(m->fun, m->fun->ast, c->opt);

AST_GET_CHILDREN(r_fun, cap, id, typeparams, params, result, can_error,
body);

codegen_startfun(c, c_m->func, c_m->di_file, c_m->di_method, false);
name_params(c, t, m, params, c_m->func);
name_params(c, t, m, c_m->func);

LLVMValueRef value = gen_expr(c, body);

Expand All @@ -563,6 +577,9 @@ static bool genfun_new(compile_t* c, reach_type_t* t, reach_method_t* m)
codegen_debugloc(c, NULL);

codegen_finishfun(c);

ast_free_unattached(r_fun);

return true;
}

Expand All @@ -572,12 +589,14 @@ static bool genfun_newbe(compile_t* c, reach_type_t* t, reach_method_t* m)
pony_assert(c_m->func != NULL);
pony_assert(c_m->func_handler != NULL);

AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
ast_t* r_fun = deferred_reify(m->fun, m->fun->ast, c->opt);

AST_GET_CHILDREN(r_fun, cap, id, typeparams, params, result, can_error,
body);

// Generate the handler.
codegen_startfun(c, c_m->func_handler, c_m->di_file, c_m->di_method, false);
name_params(c, t, m, params, c_m->func_handler);
name_params(c, t, m, c_m->func_handler);

LLVMValueRef value = gen_expr(c, body);

Expand Down Expand Up @@ -608,6 +627,8 @@ static bool genfun_newbe(compile_t* c, reach_type_t* t, reach_method_t* m)
add_dispatch_case(c, t, params, m->vtable_index, c_m->func_handler,
c_m->func_type, msg_type_ptr);

ast_free_unattached(r_fun);

return true;
}

Expand Down Expand Up @@ -747,7 +768,7 @@ static bool genfun_forward(compile_t* c, reach_type_t* t,
m->params[i - 1].type->ast_cap);
}

codegen_debugloc(c, m2->r_fun);
codegen_debugloc(c, m2->fun->ast);
LLVMValueRef ret = codegen_call(c, c_m2->func, args, count, m->cap != TK_AT);
codegen_debugloc(c, NULL);
ret = gen_assign_cast(c, ((compile_type_t*)m->result->c_type)->use_type, ret,
Expand Down Expand Up @@ -788,7 +809,7 @@ void genfun_param_attrs(compile_t* c, reach_type_t* t, reach_method_t* m,
{
type = m->params[i-1].type;
cap = m->params[i-1].cap;
} else if(ast_id(m->r_fun) == TK_NEW) {
} else if(ast_id(m->fun->ast) == TK_NEW) {
param = LLVMGetNextParam(param);
++i;
continue;
Expand Down Expand Up @@ -920,7 +941,7 @@ bool genfun_method_bodies(compile_t* c, reach_type_t* t)
if(!genfun_forward(c, t, n, m))
return false;
} else {
switch(ast_id(m->r_fun))
switch(ast_id(m->fun->ast))
{
case TK_NEW:
if(t->underlying == TK_ACTOR)
Expand Down
Loading

0 comments on commit 884c62d

Please sign in to comment.