mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
fleshing out invoke
This commit is contained in:
parent
f8a8c26d2d
commit
2a3bf72d60
1 changed files with 136 additions and 28 deletions
|
@ -1395,23 +1395,122 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
env.builder.build_store(alloca, val);
|
env.builder.build_store(alloca, val);
|
||||||
|
|
||||||
// Make a new scope which includes the binding we just encountered.
|
let arguments = call.arguments;
|
||||||
// This should be done *after* compiling the bound expr, since any
|
match call.call_type {
|
||||||
// recursive (in the LetRec sense) bindings should already have
|
CallType::ByName {
|
||||||
// been extracted as procedures. Nothing in here should need to
|
name,
|
||||||
// access itself!
|
ref full_layout,
|
||||||
// scope = scope.clone();
|
..
|
||||||
|
} => {
|
||||||
|
let function_value = function_value_by_name(env, layout_ids, full_layout, name);
|
||||||
|
|
||||||
|
let mut arg_vals: Vec<BasicValueEnum> =
|
||||||
|
Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
|
|
||||||
|
for arg in arguments.iter() {
|
||||||
|
arg_vals.push(load_symbol(env, scope, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let pass_block = context.append_basic_block(parent, "invoke_pass");
|
||||||
|
let fail_block = context.append_basic_block(parent, "invoke_fail");
|
||||||
|
|
||||||
|
{
|
||||||
|
env.builder.position_at_end(pass_block);
|
||||||
|
|
||||||
let pass_branch = {
|
|
||||||
scope.insert(*symbol, (layout.clone(), alloca));
|
scope.insert(*symbol, (layout.clone(), alloca));
|
||||||
|
|
||||||
let result = build_exp_stmt(env, layout_ids, scope, parent, pass);
|
build_exp_stmt(env, layout_ids, scope, parent, pass);
|
||||||
|
|
||||||
scope.remove(symbol);
|
scope.remove(symbol);
|
||||||
result
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
env.builder.position_at_end(fail_block);
|
||||||
|
|
||||||
|
build_exp_stmt(env, layout_ids, scope, parent, fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
let call = env.builder.build_invoke(
|
||||||
|
function_value,
|
||||||
|
arg_vals.as_slice(),
|
||||||
|
pass_block,
|
||||||
|
fail_block,
|
||||||
|
"tmp",
|
||||||
|
);
|
||||||
|
|
||||||
|
if env.exposed_to_host.contains(&name) {
|
||||||
|
// If this is an external-facing function, use the C calling convention.
|
||||||
|
call.set_call_convention(C_CALL_CONV);
|
||||||
|
} else {
|
||||||
|
// If it's an internal-only function, use the fast calling convention.
|
||||||
|
call.set_call_convention(FAST_CALL_CONV);
|
||||||
|
}
|
||||||
|
|
||||||
|
call.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
||||||
|
}
|
||||||
|
CallType::ByPointer { name, .. } => {
|
||||||
|
let sub_expr = load_symbol(env, scope, &name);
|
||||||
|
|
||||||
|
let mut arg_vals: Vec<BasicValueEnum> =
|
||||||
|
Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
|
|
||||||
|
for arg in arguments.iter() {
|
||||||
|
arg_vals.push(load_symbol(env, scope, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let pass_block = context.append_basic_block(parent, "invoke_pass");
|
||||||
|
let fail_block = context.append_basic_block(parent, "invoke_fail");
|
||||||
|
|
||||||
|
{
|
||||||
|
env.builder.position_at_end(pass_block);
|
||||||
|
|
||||||
|
scope.insert(*symbol, (layout.clone(), alloca));
|
||||||
|
|
||||||
|
build_exp_stmt(env, layout_ids, scope, parent, pass);
|
||||||
|
|
||||||
|
scope.remove(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
env.builder.position_at_end(fail_block);
|
||||||
|
|
||||||
|
build_exp_stmt(env, layout_ids, scope, parent, fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
let call = match sub_expr {
|
||||||
|
BasicValueEnum::PointerValue(ptr) => env.builder.build_invoke(
|
||||||
|
ptr,
|
||||||
|
arg_vals.as_slice(),
|
||||||
|
pass_block,
|
||||||
|
fail_block,
|
||||||
|
"tmp",
|
||||||
|
),
|
||||||
|
non_ptr => {
|
||||||
|
panic!(
|
||||||
|
"Tried to call by pointer, but encountered a non-pointer: {:?}",
|
||||||
|
non_ptr
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pass_branch
|
if env.exposed_to_host.contains(&name) {
|
||||||
|
// If this is an external-facing function, use the C calling convention.
|
||||||
|
call.set_call_convention(C_CALL_CONV);
|
||||||
|
} else {
|
||||||
|
// If it's an internal-only function, use the fast calling convention.
|
||||||
|
call.set_call_convention(FAST_CALL_CONV);
|
||||||
|
}
|
||||||
|
|
||||||
|
call.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => {
|
Unreachable => {
|
||||||
|
@ -2579,6 +2678,29 @@ pub fn verify_fn(fn_val: FunctionValue<'_>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn function_value_by_name<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
layout: &Layout<'a>,
|
||||||
|
symbol: Symbol,
|
||||||
|
) -> FunctionValue<'ctx> {
|
||||||
|
let fn_name = layout_ids
|
||||||
|
.get(symbol, layout)
|
||||||
|
.to_symbol_string(symbol, &env.interns);
|
||||||
|
let fn_name = fn_name.as_str();
|
||||||
|
|
||||||
|
env.module.get_function(fn_name).unwrap_or_else(|| {
|
||||||
|
if symbol.is_builtin() {
|
||||||
|
panic!("Unrecognized builtin function: {:?}", fn_name)
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Unrecognized non-builtin function: {:?} (symbol: {:?}, layout: {:?})",
|
||||||
|
fn_name, symbol, layout
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// #[allow(clippy::cognitive_complexity)]
|
// #[allow(clippy::cognitive_complexity)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call_with_args<'a, 'ctx, 'env>(
|
fn call_with_args<'a, 'ctx, 'env>(
|
||||||
|
@ -2589,21 +2711,7 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||||
_parent: FunctionValue<'ctx>,
|
_parent: FunctionValue<'ctx>,
|
||||||
args: &[BasicValueEnum<'ctx>],
|
args: &[BasicValueEnum<'ctx>],
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let fn_name = layout_ids
|
let fn_val = function_value_by_name(env, layout_ids, layout, symbol);
|
||||||
.get(symbol, layout)
|
|
||||||
.to_symbol_string(symbol, &env.interns);
|
|
||||||
let fn_name = fn_name.as_str();
|
|
||||||
|
|
||||||
let fn_val = env.module.get_function(fn_name).unwrap_or_else(|| {
|
|
||||||
if symbol.is_builtin() {
|
|
||||||
panic!("Unrecognized builtin function: {:?}", fn_name)
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized non-builtin function: {:?} (symbol: {:?}, layout: {:?})",
|
|
||||||
fn_name, symbol, layout
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let call = env.builder.build_call(fn_val, args, "call");
|
let call = env.builder.build_call(fn_val, args, "call");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue