Fix lifetime errors due to interner

In the llvm backend, there are the lifetimes `'a` (lifetime of the
global arena) and `'ctx` (lifetime of constructed LLVM values). `'a`
lives longer than `'ctx`, but the compiler didn't enforce this until
the layout interner was introduced, for some reason. We have to make
sure that containers of lifetime `'a` have no `'ctx` references.
This commit is contained in:
Ayaz Hafiz 2022-12-29 11:38:34 -06:00
parent 512a1721ae
commit 759f8d86af
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 54 additions and 55 deletions

View file

@ -134,15 +134,15 @@ fn bytes_as_ascii(bytes: &[u8]) -> String {
buf
}
pub fn spec_program<'a, I>(
pub fn spec_program<'a, 'r, I>(
arena: &'a Bump,
interner: &mut STLayoutInterner<'a>,
interner: &'r mut STLayoutInterner<'a>,
opt_level: OptLevel,
entry_point: roc_mono::ir::EntryPoint<'a>,
procs: I,
) -> Result<morphic_lib::Solutions>
where
I: Iterator<Item = &'a Proc<'a>>,
I: Iterator<Item = &'r Proc<'a>>,
{
let main_module = {
let mut m = ModDefBuilder::new();

View file

@ -102,7 +102,7 @@ pub fn gen_from_mono_module<'a>(
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
fn gen_from_mono_module_llvm<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
mut loaded: MonomorphizedModule<'a>,
roc_file_path: &Path,
target: &target_lexicon::Triple,
code_gen_options: CodeGenOptions,
@ -168,7 +168,6 @@ fn gen_from_mono_module_llvm<'a>(
// Compile and add all the Procs before adding main
let env = roc_gen_llvm::llvm::build::Env {
arena,
layout_interner: &loaded.layout_interner,
builder: &builder,
dibuilder: &dibuilder,
compile_unit: &compile_unit,
@ -204,6 +203,7 @@ fn gen_from_mono_module_llvm<'a>(
roc_gen_llvm::llvm::build::build_procedures(
&env,
&mut loaded.layout_interner,
opt_level,
loaded.procedures,
entry_point,

View file

@ -166,7 +166,7 @@ macro_rules! debug_info_init {
pub struct Scope<'a, 'ctx> {
symbols: ImMap<Symbol, (Layout<'a>, BasicValueEnum<'ctx>)>,
pub top_level_thunks: ImMap<Symbol, (ProcLayout<'a>, FunctionValue<'ctx>)>,
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, &'a [PhiValue<'ctx>])>,
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, std::vec::Vec<PhiValue<'ctx>>)>,
}
impl<'a, 'ctx> Scope<'a, 'ctx> {
@ -179,11 +179,11 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
pub(crate) fn insert_top_level_thunk(
&mut self,
symbol: Symbol,
layout: &'a ProcLayout<'a>,
layout: ProcLayout<'a>,
function_value: FunctionValue<'ctx>,
) {
self.top_level_thunks
.insert(symbol, (*layout, function_value));
.insert(symbol, (layout, function_value));
}
fn remove(&mut self, symbol: &Symbol) {
self.symbols.remove(symbol);
@ -1575,27 +1575,27 @@ fn build_tag_field_value<'a, 'ctx, 'env>(
}
}
fn build_tag_fields<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
scope: &Scope<'a, 'ctx>,
fn build_tag_fields<'a, 'r, 'ctx, 'env>(
env: &'r Env<'a, 'ctx, 'env>,
layout_interner: &'r mut STLayoutInterner<'a>,
scope: &'r Scope<'a, 'ctx>,
fields: &[Layout<'a>],
arguments: &[Symbol],
) -> (
Vec<'a, BasicTypeEnum<'ctx>>,
Vec<'a, (Layout<'a>, BasicValueEnum<'ctx>)>,
std::vec::Vec<BasicTypeEnum<'ctx>>,
std::vec::Vec<(Layout<'a>, BasicValueEnum<'ctx>)>,
) {
debug_assert_eq!(fields.len(), arguments.len());
let capacity = fields.len();
let mut field_types = Vec::with_capacity_in(capacity, env.arena);
let mut field_values = Vec::with_capacity_in(capacity, env.arena);
let mut field_types = std::vec::Vec::with_capacity(capacity);
let mut field_values = std::vec::Vec::with_capacity(capacity);
for (field_symbol, tag_field_layout) in arguments.iter().zip(fields.iter()) {
let field_type = basic_type_from_layout(env, layout_interner, tag_field_layout);
field_types.push(field_type);
let raw_value = load_symbol(scope, field_symbol);
let raw_value: BasicValueEnum<'ctx> = load_symbol(scope, field_symbol);
let field_value = build_tag_field_value(env, layout_interner, raw_value, *tag_field_layout);
field_values.push((*tag_field_layout, field_value));
@ -1746,9 +1746,10 @@ fn build_tag<'a, 'ctx, 'env>(
&[fields],
);
let struct_type = env
.context
.struct_type(field_types.into_bump_slice(), false);
let struct_type = env.context.struct_type(
env.arena.alloc_slice_fill_iter(field_types.into_iter()),
false,
);
struct_pointer_from_fields(
env,
@ -2658,7 +2659,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
// create new block
let cont_block = context.append_basic_block(parent, "joinpointcont");
let mut joinpoint_args = Vec::with_capacity_in(parameters.len(), env.arena);
let mut joinpoint_args = std::vec::Vec::with_capacity(parameters.len());
{
let current = builder.get_insert_block().unwrap();
builder.position_at_end(cont_block);
@ -2683,7 +2684,6 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
}
// store this join point
let joinpoint_args = joinpoint_args.into_bump_slice();
scope.join_points.insert(*id, (cont_block, joinpoint_args));
// construct the blocks that may jump to this join point
@ -2703,9 +2703,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
builder.position_at_end(cont_block);
// bind the values
for (phi_value, param) in joinpoint_args.iter().zip(parameters.iter()) {
let ref_join_points = &scope.join_points.get(id).unwrap().1;
for (phi_value, param) in ref_join_points.iter().zip(parameters.iter()) {
let value = phi_value.as_basic_value();
scope.insert(param.symbol, (param.layout, value));
scope.symbols.insert(param.symbol, (param.layout, value));
}
// put the continuation in
@ -4542,23 +4543,20 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
wrapper_function
}
pub fn build_proc_headers<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
pub fn build_proc_headers<'a, 'r, 'ctx, 'env>(
env: &'r Env<'a, 'ctx, 'env>,
layout_interner: &'r mut STLayoutInterner<'a>,
mod_solutions: &'a ModSolutions,
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
scope: &mut Scope<'a, 'ctx>,
layout_ids: &mut LayoutIds<'a>,
// alias_analysis_solutions: AliasAnalysisSolutions,
) -> Vec<
'a,
(
roc_mono::ir::Proc<'a>,
&'a [(&'a FuncSpecSolutions, FunctionValue<'ctx>)],
),
> {
) -> std::vec::Vec<(
roc_mono::ir::Proc<'a>,
std::vec::Vec<(&'a FuncSpecSolutions, FunctionValue<'ctx>)>,
)> {
// Populate Procs further and get the low-level Expr from the canonical Expr
let mut headers = Vec::with_capacity_in(procedures.len(), env.arena);
let mut headers = std::vec::Vec::with_capacity(procedures.len());
for ((symbol, layout), proc) in procedures {
let name_bytes = roc_alias_analysis::func_name_bytes(&proc);
let func_name = FuncName(&name_bytes);
@ -4566,7 +4564,7 @@ pub fn build_proc_headers<'a, 'ctx, 'env>(
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
let it = func_solutions.specs();
let mut function_values = Vec::with_capacity_in(it.size_hint().0, env.arena);
let mut function_values = std::vec::Vec::with_capacity(it.size_hint().0);
for specialization in it {
let fn_val = build_proc_header(
env,
@ -4580,14 +4578,14 @@ pub fn build_proc_headers<'a, 'ctx, 'env>(
if proc.args.is_empty() {
// this is a 0-argument thunk, i.e. a top-level constant definition
// it must be in-scope everywhere in the module!
scope.insert_top_level_thunk(symbol, env.arena.alloc(layout), fn_val);
scope.insert_top_level_thunk(symbol, layout, fn_val);
}
let func_spec_solutions = func_solutions.spec(specialization).unwrap();
function_values.push((func_spec_solutions, fn_val));
}
headers.push((proc, function_values.into_bump_slice()));
headers.push((proc, function_values));
}
headers
@ -4665,7 +4663,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
opt_level: OptLevel,
expects: &[Symbol],
expects: &'a [Symbol],
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
) -> Vec<'a, &'a str> {
let entry_point = EntryPoint::Expects { symbols: expects };
@ -4796,17 +4794,17 @@ fn build_procedures_help<'a, 'ctx, 'env>(
layout_interner,
mod_solutions,
&mut layout_ids,
func_spec_solutions,
&func_spec_solutions,
scope.clone(),
&proc,
*fn_val,
fn_val,
);
// call finalize() before any code generation/verification
env.dibuilder.finalize();
if fn_val.verify(true) {
function_pass.run_on(fn_val);
function_pass.run_on(&fn_val);
} else {
let mode = "NON-OPTIMIZED";
@ -4932,7 +4930,7 @@ fn build_proc_header<'a, 'ctx, 'env>(
#[allow(clippy::too_many_arguments)]
fn expose_alias_to_host<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
mod_solutions: &'a ModSolutions,
proc_name: LambdaName,
@ -5019,7 +5017,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
#[allow(clippy::too_many_arguments)]
fn build_closure_caller<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
def_name: &str,
evaluator: FunctionValue<'ctx>,
@ -5160,9 +5158,9 @@ fn build_closure_caller<'a, 'ctx, 'env>(
);
}
fn build_host_exposed_alias_size<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
fn build_host_exposed_alias_size<'a, 'r, 'ctx, 'env>(
env: &'r Env<'a, 'ctx, 'env>,
layout_interner: &'r mut STLayoutInterner<'a>,
def_name: &str,
alias_symbol: Symbol,
layout: Layout<'a>,
@ -5222,7 +5220,7 @@ fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>(
}
pub fn build_proc<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
mod_solutions: &'a ModSolutions,
layout_ids: &mut LayoutIds<'a>,

View file

@ -100,7 +100,7 @@ fn create_llvm_module<'a>(
let MonomorphizedModule {
procedures,
interns,
layout_interner,
mut layout_interner,
..
} = loaded;
@ -217,7 +217,6 @@ fn create_llvm_module<'a>(
// Compile and add all the Procs before adding main
let env = roc_gen_llvm::llvm::build::Env {
arena,
layout_interner: &layout_interner,
builder: &builder,
dibuilder: &dibuilder,
compile_unit: &compile_unit,
@ -258,12 +257,14 @@ fn create_llvm_module<'a>(
LlvmBackendMode::CliTest => unreachable!(),
LlvmBackendMode::WasmGenTest => roc_gen_llvm::llvm::build::build_wasm_test_wrapper(
&env,
&mut layout_interner,
config.opt_level,
procedures,
entry_point,
),
LlvmBackendMode::GenTest => roc_gen_llvm::llvm::build::build_procedures_return_main(
&env,
&mut layout_interner,
config.opt_level,
procedures,
entry_point,

View file

@ -197,7 +197,7 @@ fn mono_module_to_dylib<'a>(
entry_point,
interns,
subs,
layout_interner,
mut layout_interner,
..
} = loaded;
@ -216,7 +216,6 @@ fn mono_module_to_dylib<'a>(
// Compile and add all the Procs before adding main
let env = roc_gen_llvm::llvm::build::Env {
arena,
layout_interner: &layout_interner,
builder: &builder,
dibuilder: &dibuilder,
compile_unit: &compile_unit,
@ -251,6 +250,7 @@ fn mono_module_to_dylib<'a>(
let (main_fn_name, main_fn) = roc_gen_llvm::llvm::build::build_procedures_return_main(
&env,
&mut layout_interner,
opt_level,
procedures,
entry_point,

View file

@ -716,7 +716,7 @@ pub fn expect_mono_module_to_dylib<'a>(
toplevel_expects,
procedures,
interns,
layout_interner,
mut layout_interner,
..
} = loaded;
@ -735,7 +735,6 @@ pub fn expect_mono_module_to_dylib<'a>(
// Compile and add all the Procs before adding main
let env = roc_gen_llvm::llvm::build::Env {
arena,
layout_interner: &layout_interner,
builder: &builder,
dibuilder: &dibuilder,
compile_unit: &compile_unit,
@ -760,8 +759,9 @@ pub fn expect_mono_module_to_dylib<'a>(
let expect_names = roc_gen_llvm::llvm::build::build_procedures_expose_expects(
&env,
&mut layout_interner,
opt_level,
&expect_symbols,
expect_symbols.into_bump_slice(),
procedures,
);