call to foreign function dropped continuation

This commit is contained in:
Folkert 2021-02-10 22:04:59 +01:00
parent e247b573a6
commit 1f0a16ec57
3 changed files with 127 additions and 22 deletions

View file

@ -729,10 +729,9 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments) run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
} }
CallType::Foreign { CallType::Foreign { .. } => {
foreign_symbol: foreign, unreachable!("foreign symbols should always be invoked!")
ret_layout, }
} => build_foreign_symbol(env, scope, foreign, arguments, ret_layout),
} }
} }
@ -1846,8 +1845,6 @@ fn invoke_roc_function<'a, 'ctx, 'env>(
{ {
env.builder.position_at_end(pass_block); env.builder.position_at_end(pass_block);
// env.builder.build_store(alloca, call_result);
// scope.insert(symbol, (layout, alloca));
scope.insert(symbol, (layout, call_result)); scope.insert(symbol, (layout, call_result));
build_exp_stmt(env, layout_ids, scope, parent, pass); build_exp_stmt(env, layout_ids, scope, parent, pass);
@ -2010,7 +2007,18 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
CallType::Foreign { CallType::Foreign {
ref foreign_symbol, ref foreign_symbol,
ref ret_layout, ref ret_layout,
} => build_foreign_symbol(env, scope, foreign_symbol, call.arguments, ret_layout), } => build_foreign_symbol(
env,
layout_ids,
scope,
parent,
foreign_symbol,
call.arguments,
*symbol,
ret_layout,
pass,
fail,
),
CallType::LowLevel { .. } => { CallType::LowLevel { .. } => {
unreachable!("lowlevel itself never throws exceptions") unreachable!("lowlevel itself never throws exceptions")
@ -2114,12 +2122,6 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
context.i64_type().const_zero().into() context.i64_type().const_zero().into()
} }
/*
Inc(symbol1, 1, Dec(symbol2, cont)) if symbol1 == symbol2 => {
dbg!(symbol1);
build_exp_stmt(env, layout_ids, scope, parent, cont)
}
*/
Refcounting(modify, cont) => { Refcounting(modify, cont) => {
use ModifyRc::*; use ModifyRc::*;
@ -3484,7 +3486,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let inplace = get_inplace_from_layout(layout); let inplace = get_inplace_from_layout(layout);
str_concat(env, inplace, scope, args[0], args[1]) str_concat(env, layout_ids, inplace, scope, args[0], args[1])
} }
StrJoinWith => { StrJoinWith => {
// Str.joinWith : List Str, Str -> Str // Str.joinWith : List Str, Str -> Str
@ -3981,17 +3983,26 @@ fn run_low_level<'a, 'ctx, 'env>(
} }
} }
#[allow(clippy::too_many_arguments)]
fn build_foreign_symbol<'a, 'ctx, 'env>( fn build_foreign_symbol<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>, layout_ids: &mut LayoutIds<'a>,
scope: &mut Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
foreign: &roc_module::ident::ForeignSymbol, foreign: &roc_module::ident::ForeignSymbol,
arguments: &[Symbol], arguments: &[Symbol],
symbol: Symbol,
ret_layout: &Layout<'a>, ret_layout: &Layout<'a>,
pass: &'a roc_mono::ir::Stmt<'a>,
fail: &'a roc_mono::ir::Stmt<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(arguments.len(), env.arena); let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(arguments.len(), env.arena);
let mut arg_types = Vec::with_capacity_in(arguments.len() + 1, env.arena); let mut arg_types = Vec::with_capacity_in(arguments.len() + 1, env.arena);
let pass_block = env.context.append_basic_block(parent, "invoke_pass");
let fail_block = env.context.append_basic_block(parent, "invoke_fail");
// crude approximation of the C calling convention // crude approximation of the C calling convention
let pass_result_by_pointer = ret_layout.stack_size(env.ptr_bytes) > 2 * env.ptr_bytes; let pass_result_by_pointer = ret_layout.stack_size(env.ptr_bytes) > 2 * env.ptr_bytes;
@ -4017,14 +4028,51 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
let function_type = env.context.void_type().fn_type(&arg_types, false); let function_type = env.context.void_type().fn_type(&arg_types, false);
let function = get_foreign_symbol(env, foreign.clone(), function_type); let function = get_foreign_symbol(env, foreign.clone(), function_type);
let call = env.builder.build_call(function, arg_vals.as_slice(), "tmp"); let call =
env.builder
.build_invoke(function, arg_vals.as_slice(), pass_block, fail_block, "tmp");
// this is a foreign function, use c calling convention // this is a foreign function, use c calling convention
call.set_call_convention(C_CALL_CONV); call.set_call_convention(C_CALL_CONV);
call.try_as_basic_value(); call.try_as_basic_value();
env.builder.build_load(ret_ptr, "read_result") let call_result = env.builder.build_load(ret_ptr, "read_result");
{
env.builder.position_at_end(pass_block);
scope.insert(symbol, (ret_layout.clone(), call_result));
build_exp_stmt(env, layout_ids, scope, parent, pass);
scope.remove(&symbol);
}
{
env.builder.position_at_end(fail_block);
let landing_pad_type = {
let exception_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic).into();
let selector_value = env.context.i32_type().into();
env.context
.struct_type(&[exception_ptr, selector_value], false)
};
env.builder
.build_catch_all_landing_pad(
&landing_pad_type,
&BasicValueEnum::IntValue(env.context.i8_type().const_zero()),
env.context.i8_type().ptr_type(AddressSpace::Generic),
"invoke_landing_pad",
)
.into_struct_value();
build_exp_stmt(env, layout_ids, scope, parent, fail);
}
call_result
} else { } else {
for arg in arguments.iter() { for arg in arguments.iter() {
let (value, layout) = load_symbol_and_layout(scope, arg); let (value, layout) = load_symbol_and_layout(scope, arg);
@ -4037,14 +4085,52 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
let function_type = get_fn_type(&ret_type, &arg_types); let function_type = get_fn_type(&ret_type, &arg_types);
let function = get_foreign_symbol(env, foreign.clone(), function_type); let function = get_foreign_symbol(env, foreign.clone(), function_type);
let call = env.builder.build_call(function, arg_vals.as_slice(), "tmp"); let call =
env.builder
.build_invoke(function, arg_vals.as_slice(), pass_block, fail_block, "tmp");
// this is a foreign function, use c calling convention // this is a foreign function, use c calling convention
call.set_call_convention(C_CALL_CONV); call.set_call_convention(C_CALL_CONV);
call.try_as_basic_value() let call_result = call
.try_as_basic_value()
.left() .left()
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer.")) .unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."));
{
env.builder.position_at_end(pass_block);
scope.insert(symbol, (ret_layout.clone(), call_result));
build_exp_stmt(env, layout_ids, scope, parent, pass);
scope.remove(&symbol);
}
{
env.builder.position_at_end(fail_block);
let landing_pad_type = {
let exception_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic).into();
let selector_value = env.context.i32_type().into();
env.context
.struct_type(&[exception_ptr, selector_value], false)
};
env.builder
.build_catch_all_landing_pad(
&landing_pad_type,
&BasicValueEnum::IntValue(env.context.i8_type().const_zero()),
env.context.i8_type().ptr_type(AddressSpace::Generic),
"invoke_landing_pad",
)
.into_struct_value();
build_exp_stmt(env, layout_ids, scope, parent, fail);
}
call_result
} }
} }

View file

@ -3,12 +3,13 @@ use crate::llvm::build::{
}; };
use crate::llvm::build_list::{allocate_list, store_list}; use crate::llvm::build_list::{allocate_list, store_list};
use crate::llvm::convert::collection; use crate::llvm::convert::collection;
use crate::llvm::refcounting::decrement_refcount_layout;
use inkwell::types::BasicTypeEnum; use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicValueEnum, IntValue, StructValue}; use inkwell::values::{BasicValueEnum, IntValue, StructValue};
use inkwell::AddressSpace; use inkwell::AddressSpace;
use roc_builtins::bitcode; use roc_builtins::bitcode;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout}; use roc_mono::layout::{Builtin, Layout, LayoutIds};
use super::build::load_symbol; use super::build::load_symbol;
@ -128,6 +129,7 @@ fn zig_str_to_struct<'a, 'ctx, 'env>(
/// Str.concat : Str, Str -> Str /// Str.concat : Str, Str -> Str
pub fn str_concat<'a, 'ctx, 'env>( pub fn str_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
inplace: InPlace, inplace: InPlace,
scope: &Scope<'a, 'ctx>, scope: &Scope<'a, 'ctx>,
str1_symbol: Symbol, str1_symbol: Symbol,
@ -151,6 +153,22 @@ pub fn str_concat<'a, 'ctx, 'env>(
) )
.into_struct_value(); .into_struct_value();
let parent = env
.builder
.get_insert_block()
.unwrap()
.get_parent()
.unwrap();
// fix refcounts; consume both arguments
let layout = Layout::Builtin(Builtin::Str);
let str1 = load_symbol(scope, &str1_symbol);
decrement_refcount_layout(env, parent, layout_ids, str1, &layout);
let str2 = load_symbol(scope, &str2_symbol);
decrement_refcount_layout(env, parent, layout_ids, str2, &layout);
zig_str_to_struct(env, zig_result).into() zig_str_to_struct(env, zig_result).into()
} }

View file

@ -489,9 +489,10 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
let field_ptr = env let field_ptr = env
.builder .builder
.build_extract_value(wrapper_struct, 1, "increment_closure_data") .build_extract_value(wrapper_struct, 1, "moddify_rc_closure_data")
.unwrap(); .unwrap();
// dbg!(&field_ptr, closure_layout.as_block_of_memory_layout());
modify_refcount_layout( modify_refcount_layout(
env, env,
parent, parent,