Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix generation of invalid LLVM IR #4506

Merged
merged 7 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .release-notes/4506.md
ArthurPV marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Fix generation of invalid LLVM IR

Previously, this code failed at LLVM module verification. Now, with this change, it's fixed by stopping the generation of `ret` instructions after terminator instructions:

```pony
class Foo
new create(a: U32) ? =>
error

actor Main
new create(env: Env) =>
try
let f = Foo(1)?
end
```
4 changes: 2 additions & 2 deletions src/libponyc/codegen/gencontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,10 @@ LLVMValueRef gen_return(compile_t* c, ast_t* ast)
LLVMValueRef ret = gen_assign_cast(c, r_type, value, type);
ast_free_unattached(type);
codegen_scope_lifetime_end(c);
LLVMBuildRet(c->builder, ret);
genfun_build_ret(c, ret);
} else {
codegen_scope_lifetime_end(c);
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
}

codegen_debugloc(c, NULL);
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/gendesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static LLVMValueRef make_unbox_function(compile_t* c, reach_type_t* t,

LLVMValueRef result = codegen_call(c, LLVMGlobalGetValueType(c_m->func),
c_m->func, args, count, m->cap != TK_AT);
LLVMBuildRet(c->builder, result);
genfun_build_ret(c, result);
codegen_finishfun(c);

ponyint_pool_free_size(buf_size, params);
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/genexe.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ LLVMValueRef gen_main(compile_t* c, reach_type_t* t_main, reach_type_t* t_env)
rc = LLVMBuildSelect(c->builder, start_success, rc, minus_one, "");

// Return the runtime exit code.
LLVMBuildRet(c->builder, rc);
genfun_build_ret(c, rc);

codegen_finishfun(c);

Expand Down
60 changes: 46 additions & 14 deletions src/libponyc/codegen/genfun.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ static void add_dispatch_case(compile_t* c, reach_type_t* t,

// Call the handler.
codegen_call(c, LLVMGlobalGetValueType(handler), handler, args, count, true);
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
codegen_finishfun(c);
ponyint_pool_free_size(args_buf_size, args);
ponyint_pool_free_size(params_buf_size, param_types);
Expand Down Expand Up @@ -422,6 +422,36 @@ static void call_embed_finalisers(compile_t* c, reach_type_t* t,
}
}

static bool
genfun_has_terminator(compile_t* c)
{
LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder);

pony_assert(current_block);

return LLVMGetBasicBlockTerminator(current_block);
}

LLVMValueRef
genfun_build_ret(compile_t* c, LLVMValueRef v)
{
if (!genfun_has_terminator(c)) {
return LLVMBuildRet(c->builder, v);
}

return NULL;
}

LLVMValueRef
genfun_build_ret_void(compile_t* c)
{
if (!genfun_has_terminator(c)) {
return LLVMBuildRetVoid(c->builder);
}

return NULL;
}

static bool genfun_fun(compile_t* c, reach_type_t* t, reach_method_t* m)
{
compile_type_t* c_t = (compile_type_t*)t->c_type;
Expand Down Expand Up @@ -454,7 +484,8 @@ static bool genfun_fun(compile_t* c, reach_type_t* t, reach_method_t* m)
ast_free_unattached(r_result);
codegen_scope_lifetime_end(c);
codegen_debugloc(c, ast_childlast(body));
LLVMBuildRetVoid(c->builder);

genfun_build_ret_void(c);
} else {
LLVMTypeRef f_type = LLVMGlobalGetValueType(c_m->func);
LLVMTypeRef r_type = LLVMGetReturnType(f_type);
Expand All @@ -470,7 +501,8 @@ static bool genfun_fun(compile_t* c, reach_type_t* t, reach_method_t* m)

codegen_scope_lifetime_end(c);
codegen_debugloc(c, ast_childlast(body));
LLVMBuildRet(c->builder, ret);

genfun_build_ret(c, ret);
}

codegen_debugloc(c, NULL);
Expand Down Expand Up @@ -502,7 +534,7 @@ static bool genfun_be(compile_t* c, reach_type_t* t, reach_method_t* m)

codegen_scope_lifetime_end(c);
if(value != GEN_NOVALUE)
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);

codegen_finishfun(c);

Expand All @@ -516,7 +548,7 @@ static bool genfun_be(compile_t* c, reach_type_t* t, reach_method_t* m)
gen_send_message(c, m, param_vals, params);

// Return None.
LLVMBuildRet(c->builder, c->none_instance);
genfun_build_ret(c, c->none_instance);
codegen_finishfun(c);

ponyint_pool_free_size(buf_size, param_vals);
Expand Down Expand Up @@ -552,9 +584,9 @@ static bool genfun_new(compile_t* c, reach_type_t* t, reach_method_t* m)
codegen_scope_lifetime_end(c);
codegen_debugloc(c, ast_childlast(body));
if(t->underlying == TK_CLASS)
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
else
LLVMBuildRet(c->builder, value);
genfun_build_ret(c, value);
codegen_debugloc(c, NULL);

codegen_finishfun(c);
Expand Down Expand Up @@ -582,7 +614,7 @@ static bool genfun_newbe(compile_t* c, reach_type_t* t, reach_method_t* m)
return false;

codegen_scope_lifetime_end(c);
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
codegen_finishfun(c);

// Generate the sender.
Expand All @@ -595,7 +627,7 @@ static bool genfun_newbe(compile_t* c, reach_type_t* t, reach_method_t* m)
gen_send_message(c, m, param_vals, params);

// Return 'this'.
LLVMBuildRet(c->builder, param_vals[0]);
genfun_build_ret(c, param_vals[0]);
codegen_finishfun(c);

ponyint_pool_free_size(buf_size, param_vals);
Expand Down Expand Up @@ -642,7 +674,7 @@ static bool genfun_implicit_final(compile_t* c, reach_type_t* t,

codegen_startfun(c, c_m->func, NULL, NULL, NULL, false);
call_embed_finalisers(c, t, NULL, gen_this(c, NULL));
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
codegen_finishfun(c);

return true;
Expand Down Expand Up @@ -708,7 +740,7 @@ static bool genfun_allocator(compile_t* c, reach_type_t* t)
return false;
}

LLVMBuildRet(c->builder, result);
genfun_build_ret(c, result);
codegen_finishfun(c);
return true;
}
Expand Down Expand Up @@ -747,7 +779,7 @@ static bool genfun_forward(compile_t* c, reach_type_t* t,
codegen_debugloc(c, NULL);
ret = gen_assign_cast(c, ((compile_type_t*)m->result->c_type)->use_type, ret,
m2->result->ast_cap);
LLVMBuildRet(c->builder, ret);
genfun_build_ret(c, ret);
codegen_finishfun(c);
ponyint_pool_free_size(buf_size, args);
return true;
Expand Down Expand Up @@ -1033,7 +1065,7 @@ void genfun_primitive_calls(compile_t* c)

codegen_startfun(c, c->primitives_init, NULL, NULL, NULL, false);
primitive_call(c, c->str__init);
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
codegen_finishfun(c);
}

Expand All @@ -1046,7 +1078,7 @@ void genfun_primitive_calls(compile_t* c)

codegen_startfun(c, c->primitives_final, NULL, NULL, NULL, false);
primitive_call(c, c->str__final);
LLVMBuildRetVoid(c->builder);
genfun_build_ret_void(c);
codegen_finishfun(c);
}
}
8 changes: 8 additions & 0 deletions src/libponyc/codegen/genfun.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ bool genfun_method_bodies(compile_t* c, reach_type_t* t);

void genfun_primitive_calls(compile_t* c);

bool genfun_last_inst_is_terminator(compile_t* c);

LLVMValueRef
genfun_build_ret(compile_t* c, LLVMValueRef v);

LLVMValueRef
genfun_build_ret_void(compile_t* c);

PONY_EXTERN_C_END

#endif
2 changes: 1 addition & 1 deletion src/libponyc/codegen/genident.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ void gen_is_tuple_fun(compile_t* c, reach_type_t* t)
// box_is_box(). Don't recheck it in tuple_is_box().
LLVMValueRef same_identity = tuple_is_box(c, t->ast_cap, NULL, l_value,
r_value, r_desc, true, false);
LLVMBuildRet(c->builder, same_identity);
genfun_build_ret(c, same_identity);

codegen_finishfun(c);
}
Expand Down
Loading
Loading