mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
explicitly store and pass layout of a function passed to lowlevel
This commit is contained in:
parent
357f93a2ee
commit
3739f41cac
3 changed files with 103 additions and 87 deletions
|
@ -131,7 +131,6 @@ impl<'ctx> Iterator for FunctionIterator<'ctx> {
|
||||||
#[derive(Default, Debug, Clone, PartialEq)]
|
#[derive(Default, Debug, Clone, PartialEq)]
|
||||||
pub struct Scope<'a, 'ctx> {
|
pub struct Scope<'a, 'ctx> {
|
||||||
symbols: ImMap<Symbol, (Layout<'a>, BasicValueEnum<'ctx>)>,
|
symbols: ImMap<Symbol, (Layout<'a>, BasicValueEnum<'ctx>)>,
|
||||||
pub function_pointers: MutMap<Symbol, (Layout<'a>, FunctionValue<'ctx>)>,
|
|
||||||
pub top_level_thunks: ImMap<Symbol, (Layout<'a>, FunctionValue<'ctx>)>,
|
pub top_level_thunks: ImMap<Symbol, (Layout<'a>, FunctionValue<'ctx>)>,
|
||||||
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, &'a [PointerValue<'ctx>])>,
|
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, &'a [PointerValue<'ctx>])>,
|
||||||
}
|
}
|
||||||
|
@ -885,7 +884,16 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
|
||||||
CallType::LowLevel {
|
CallType::LowLevel {
|
||||||
op,
|
op,
|
||||||
opt_closure_layout,
|
opt_closure_layout,
|
||||||
} => run_low_level(env, layout_ids, scope, parent, layout, *op, arguments),
|
} => run_low_level(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
scope,
|
||||||
|
parent,
|
||||||
|
layout,
|
||||||
|
*op,
|
||||||
|
*opt_closure_layout,
|
||||||
|
arguments,
|
||||||
|
),
|
||||||
|
|
||||||
CallType::Foreign {
|
CallType::Foreign {
|
||||||
foreign_symbol,
|
foreign_symbol,
|
||||||
|
@ -1702,10 +1710,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
scope
|
|
||||||
.function_pointers
|
|
||||||
.insert(left_hand_side, (*layout, function_value));
|
|
||||||
|
|
||||||
let ptr = function_value.as_global_value().as_pointer_value();
|
let ptr = function_value.as_global_value().as_pointer_value();
|
||||||
|
|
||||||
BasicValueEnum::PointerValue(ptr)
|
BasicValueEnum::PointerValue(ptr)
|
||||||
|
@ -3609,10 +3613,65 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
op: LowLevel,
|
op: LowLevel,
|
||||||
|
opt_closure_layout: Option<Layout<'a>>,
|
||||||
args: &[Symbol],
|
args: &[Symbol],
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
use LowLevel::*;
|
use LowLevel::*;
|
||||||
|
|
||||||
|
// macros because functions cause lifetime issues related to the `env` or `layout_ids`
|
||||||
|
macro_rules! passed_function_at_index {
|
||||||
|
($function_layout:expr, $index:expr) => {{
|
||||||
|
let function_symbol = args[$index];
|
||||||
|
|
||||||
|
let fn_name = layout_ids
|
||||||
|
.get(function_symbol, &$function_layout)
|
||||||
|
.to_symbol_string(function_symbol, &env.interns);
|
||||||
|
|
||||||
|
env.module
|
||||||
|
.get_function(fn_name.as_str())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"Could not get pointer to unknown function {:?} {:?}",
|
||||||
|
fn_name, $function_layout
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! list_walk {
|
||||||
|
($variant:expr) => {{
|
||||||
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
|
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 2);
|
||||||
|
|
||||||
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
||||||
|
|
||||||
|
match list_layout {
|
||||||
|
Layout::Builtin(Builtin::EmptyList) => default,
|
||||||
|
Layout::Builtin(Builtin::List(_, element_layout)) => {
|
||||||
|
crate::llvm::build_list::list_walk_generic(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
parent,
|
||||||
|
list,
|
||||||
|
element_layout,
|
||||||
|
function,
|
||||||
|
function_layout,
|
||||||
|
closure,
|
||||||
|
*closure_layout,
|
||||||
|
default,
|
||||||
|
default_layout,
|
||||||
|
$variant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => unreachable!("invalid list layout"),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
StrConcat => {
|
StrConcat => {
|
||||||
// Str.concat : Str, Str -> Str
|
// Str.concat : Str, Str -> Str
|
||||||
|
@ -3759,7 +3818,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -3784,7 +3844,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let (list1, list1_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list1, list1_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[2]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 2);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
||||||
|
|
||||||
match (list1_layout, list2_layout) {
|
match (list1_layout, list2_layout) {
|
||||||
|
@ -3815,7 +3876,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
let (list3, list3_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (list3, list3_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[3]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 3);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[4]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[4]);
|
||||||
|
|
||||||
match (list1_layout, list2_layout, list3_layout) {
|
match (list1_layout, list2_layout, list3_layout) {
|
||||||
|
@ -3849,7 +3911,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -3874,7 +3937,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -3899,7 +3963,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -3931,7 +3996,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -3981,30 +4047,15 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_range(env, *builtin, low.into_int_value(), high.into_int_value())
|
list_range(env, *builtin, low.into_int_value(), high.into_int_value())
|
||||||
}
|
}
|
||||||
ListWalk => list_walk_help(
|
ListWalk => {
|
||||||
env,
|
list_walk!(crate::llvm::build_list::ListWalk::Walk)
|
||||||
layout_ids,
|
}
|
||||||
scope,
|
ListWalkUntil => {
|
||||||
parent,
|
list_walk!(crate::llvm::build_list::ListWalk::WalkUntil)
|
||||||
args,
|
}
|
||||||
crate::llvm::build_list::ListWalk::Walk,
|
ListWalkBackwards => {
|
||||||
),
|
list_walk!(crate::llvm::build_list::ListWalk::WalkBackwards)
|
||||||
ListWalkUntil => list_walk_help(
|
}
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
scope,
|
|
||||||
parent,
|
|
||||||
args,
|
|
||||||
crate::llvm::build_list::ListWalk::WalkUntil,
|
|
||||||
),
|
|
||||||
ListWalkBackwards => list_walk_help(
|
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
scope,
|
|
||||||
parent,
|
|
||||||
args,
|
|
||||||
crate::llvm::build_list::ListWalk::WalkBackwards,
|
|
||||||
),
|
|
||||||
ListAppend => {
|
ListAppend => {
|
||||||
// List.append : List elem, elem -> List elem
|
// List.append : List elem, elem -> List elem
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
@ -4043,7 +4094,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
let (_, function) = scope.function_pointers[&args[1]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
|
@ -4499,7 +4551,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
let (function_layout, function) = scope.function_pointers[&args[2]];
|
let function_layout = opt_closure_layout.unwrap();
|
||||||
|
let function = passed_function_at_index!(function_layout, 2);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
||||||
|
|
||||||
match dict_layout {
|
match dict_layout {
|
||||||
|
|
|
@ -446,11 +446,13 @@ pub enum ListWalk {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_walk_help<'a, 'ctx, 'env>(
|
pub fn list_walk_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &'ctx Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
scope: &crate::llvm::build::Scope<'a, 'ctx>,
|
scope: &crate::llvm::build::Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
args: &[roc_module::symbol::Symbol],
|
args: &[roc_module::symbol::Symbol],
|
||||||
|
function: FunctionValue<'a>,
|
||||||
|
function_layout: Layout<'a>,
|
||||||
variant: ListWalk,
|
variant: ListWalk,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
use crate::llvm::build::load_symbol_and_layout;
|
use crate::llvm::build::load_symbol_and_layout;
|
||||||
|
@ -461,8 +463,6 @@ pub fn list_walk_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
let (function_layout, function) = scope.function_pointers[&args[2]];
|
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
||||||
|
|
||||||
match list_layout {
|
match list_layout {
|
||||||
|
@ -485,7 +485,7 @@ pub fn list_walk_help<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_walk_generic<'a, 'ctx, 'env>(
|
pub fn list_walk_generic<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
_parent: FunctionValue<'ctx>,
|
_parent: FunctionValue<'ctx>,
|
||||||
|
|
|
@ -7691,26 +7691,16 @@ where
|
||||||
Layout::Struct(_) => {
|
Layout::Struct(_) => {
|
||||||
let function_symbol = lambda_set.set[0].0;
|
let function_symbol = lambda_set.set[0].0;
|
||||||
|
|
||||||
let bound = env.unique_symbol();
|
|
||||||
|
|
||||||
// build the call
|
// build the call
|
||||||
let stmt = Stmt::Let(
|
Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Call(to_lowlevel_call(
|
Expr::Call(to_lowlevel_call(
|
||||||
bound,
|
function_symbol,
|
||||||
closure_data_symbol,
|
closure_data_symbol,
|
||||||
function_layout,
|
function_layout,
|
||||||
)),
|
)),
|
||||||
return_layout,
|
return_layout,
|
||||||
env.arena.alloc(hole),
|
env.arena.alloc(hole),
|
||||||
);
|
|
||||||
|
|
||||||
// fix the layout; needs top-level signature
|
|
||||||
Stmt::Let(
|
|
||||||
bound,
|
|
||||||
Expr::FunctionPointer(function_symbol, function_layout),
|
|
||||||
function_layout,
|
|
||||||
env.arena.alloc(stmt),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Int1) => {
|
Layout::Builtin(Builtin::Int1) => {
|
||||||
|
@ -7775,13 +7765,11 @@ where
|
||||||
|
|
||||||
let hole = Stmt::Jump(join_point_id, env.arena.alloc([assigned]));
|
let hole = Stmt::Jump(join_point_id, env.arena.alloc([assigned]));
|
||||||
|
|
||||||
let bound = env.unique_symbol();
|
|
||||||
|
|
||||||
// build the call
|
// build the call
|
||||||
let stmt = Stmt::Let(
|
let stmt = Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Call(to_lowlevel_call(
|
Expr::Call(to_lowlevel_call(
|
||||||
bound,
|
*function_symbol,
|
||||||
closure_data_symbol,
|
closure_data_symbol,
|
||||||
function_layout,
|
function_layout,
|
||||||
)),
|
)),
|
||||||
|
@ -7789,13 +7777,6 @@ where
|
||||||
env.arena.alloc(hole),
|
env.arena.alloc(hole),
|
||||||
);
|
);
|
||||||
|
|
||||||
let stmt = Stmt::Let(
|
|
||||||
bound,
|
|
||||||
Expr::FunctionPointer(*function_symbol, function_layout),
|
|
||||||
function_layout,
|
|
||||||
env.arena.alloc(stmt),
|
|
||||||
);
|
|
||||||
|
|
||||||
branches.push((i as u64, BranchInfo::None, stmt));
|
branches.push((i as u64, BranchInfo::None, stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7844,25 +7825,16 @@ where
|
||||||
|
|
||||||
let hole = Stmt::Jump(join_point_id, env.arena.alloc([assigned]));
|
let hole = Stmt::Jump(join_point_id, env.arena.alloc([assigned]));
|
||||||
|
|
||||||
let bound = env.unique_symbol();
|
|
||||||
|
|
||||||
// build the call
|
// build the call
|
||||||
let stmt = Stmt::Let(
|
Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Call(to_lowlevel_call(
|
Expr::Call(to_lowlevel_call(
|
||||||
bound,
|
function_symbol,
|
||||||
closure_data_symbol,
|
closure_data_symbol,
|
||||||
function_layout,
|
function_layout,
|
||||||
)),
|
)),
|
||||||
return_layout,
|
return_layout,
|
||||||
env.arena.alloc(hole),
|
env.arena.alloc(hole),
|
||||||
);
|
|
||||||
|
|
||||||
Stmt::Let(
|
|
||||||
assigned,
|
|
||||||
Expr::FunctionPointer(function_symbol, function_layout),
|
|
||||||
function_layout,
|
|
||||||
env.arena.alloc(stmt),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8328,24 +8300,15 @@ where
|
||||||
|
|
||||||
let hole = Stmt::Jump(join_point_id, env.arena.alloc([result_symbol]));
|
let hole = Stmt::Jump(join_point_id, env.arena.alloc([result_symbol]));
|
||||||
|
|
||||||
let bound = env.unique_symbol();
|
|
||||||
|
|
||||||
// build the call
|
// build the call
|
||||||
let stmt = Stmt::Let(
|
Stmt::Let(
|
||||||
result_symbol,
|
result_symbol,
|
||||||
Expr::Call(to_lowlevel_call(
|
Expr::Call(to_lowlevel_call(
|
||||||
bound,
|
function_symbol,
|
||||||
closure_data_symbol,
|
closure_data_symbol,
|
||||||
function_layout,
|
function_layout,
|
||||||
)),
|
)),
|
||||||
return_layout,
|
return_layout,
|
||||||
env.arena.alloc(hole),
|
env.arena.alloc(hole),
|
||||||
);
|
|
||||||
|
|
||||||
Stmt::Let(
|
|
||||||
bound,
|
|
||||||
Expr::FunctionPointer(function_symbol, function_layout),
|
|
||||||
function_layout,
|
|
||||||
env.arena.alloc(stmt),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue