Record LLVM proc headers in a separate pass.

Turns out this was always necessary, and was
only working before by chance - because the
ordering in the one test we had for this
happened to work out.
This commit is contained in:
Richard Feldman 2020-02-25 01:25:29 -05:00
parent 80511e6381
commit 1fa411f593
3 changed files with 50 additions and 29 deletions

View File

@ -401,12 +401,11 @@ pub fn create_entry_block_alloca<'a, 'ctx>(
builder.build_alloca(basic_type, name)
}
pub fn build_proc<'a, 'ctx, 'env>(
pub fn build_proc_header<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
symbol: Symbol,
proc: Proc<'a>,
procs: &Procs<'a>,
) -> FunctionValue<'ctx> {
proc: &Proc<'a>,
) -> (FunctionValue<'ctx>, Vec<'a, BasicTypeEnum<'ctx>>) {
let args = proc.args;
let arena = env.arena;
let subs = &env.subs;
@ -434,6 +433,19 @@ pub fn build_proc<'a, 'ctx, 'env>(
Some(Linkage::Private),
);
(fn_val, arg_basic_types)
}
pub fn build_proc<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
proc: Proc<'a>,
procs: &Procs<'a>,
fn_val: FunctionValue<'ctx>,
arg_basic_types: Vec<'a, BasicTypeEnum<'ctx>>,
) {
let args = proc.args;
let context = &env.context;
// Add a basic block for the entry point
let entry = context.append_basic_block(fn_val, "entry");
let builder = env.builder;
@ -459,8 +471,6 @@ pub fn build_proc<'a, 'ctx, 'env>(
let body = build_expr(env, &scope, fn_val, &proc.body, procs);
builder.build_return(Some(&body));
fn_val
}
pub fn verify_fn(fn_val: FunctionValue<'_>) {

View File

@ -189,12 +189,12 @@ fn from_can<'a>(
Expr::Store(stored.into_bump_slice(), arena.alloc(ret))
}
Closure(_, _symbol, _, loc_args, boxed_body) => {
Closure(_, _, _, loc_args, boxed_body) => {
let (loc_body, ret_var) = *boxed_body;
let name =
let symbol =
name.unwrap_or_else(|| gen_closure_name(procs, &mut env.ident_ids, env.home));
add_closure(env, name, loc_body.value, ret_var, &loc_args, procs)
add_closure(env, symbol, loc_body.value, ret_var, &loc_args, procs)
}
Call(boxed, loc_args, _) => {
@ -293,7 +293,7 @@ fn from_can<'a>(
fn add_closure<'a>(
env: &mut Env<'a, '_>,
name: Symbol,
symbol: Symbol,
can_body: can::expr::Expr,
ret_var: Variable,
loc_args: &[(Variable, Located<Pattern>)],
@ -310,9 +310,9 @@ fn add_closure<'a>(
Ok(layout) => layout,
Err(()) => {
// Invalid closure!
procs.insert(name.clone(), None);
procs.insert(symbol, None);
return Expr::FunctionPointer(name);
return Expr::FunctionPointer(symbol);
}
};
@ -333,9 +333,9 @@ fn add_closure<'a>(
ret_var,
};
procs.insert(name.clone(), Some(proc));
procs.insert(symbol, Some(proc));
Expr::FunctionPointer(name)
Expr::FunctionPointer(symbol)
}
fn store_pattern<'a>(

View File

@ -29,7 +29,7 @@ mod test_gen {
use roc::crane::build::{declare_proc, define_proc_body, ScopeEntry};
use roc::crane::convert::type_from_layout;
use roc::infer::infer_expr;
use roc::llvm::build::build_proc;
use roc::llvm::build::{build_proc, build_proc_header};
use roc::llvm::convert::basic_type_from_layout;
use roc::mono::expr::Expr;
use roc::mono::layout::Layout;
@ -230,21 +230,32 @@ mod test_gen {
// Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids);
// Add all the Procs to the module
for (name, opt_proc) in procs.clone() {
if let Some(proc) = opt_proc {
// NOTE: This is here to be uncommented in case verification fails.
// (This approach means we don't have to defensively clone name here.)
//
// println!("\n\nBuilding and then verifying function {}\n\n", name);
let fn_val = build_proc(&env, name, proc, &procs);
let mut headers = Vec::with_capacity(procs.len());
if fn_val.verify(true) {
fpm.run_on(&fn_val);
} else {
// NOTE: If this fails, uncomment the above println to debug.
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
}
// Add all the Proc headers to the module.
// We have to do this in a separate pass first,
// because their bodies may reference each other.
for (symbol, opt_proc) in procs.clone().into_iter() {
if let Some(proc) = opt_proc {
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
headers.push((proc, fn_val, arg_basic_types));
}
}
// Build each proc using its header info.
for (proc, fn_val, arg_basic_types) in headers {
// NOTE: This is here to be uncommented in case verification fails.
// (This approach means we don't have to defensively clone name here.)
//
// println!("\n\nBuilding and then verifying function {}\n\n", name);
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
if fn_val.verify(true) {
fpm.run_on(&fn_val);
} else {
// NOTE: If this fails, uncomment the above println to debug.
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
}
}