make fastcc wrapper return by pointer if return type is large

This commit is contained in:
Folkert 2022-01-11 21:03:57 +01:00
parent 430a82810b
commit b2e05b92d1

View file

@ -6212,6 +6212,7 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
// - a FAST_CALL_CONV wrapper that we make here, e.g. `roc_fx_putLine_fastcc_wrapper` // - a FAST_CALL_CONV wrapper that we make here, e.g. `roc_fx_putLine_fastcc_wrapper`
let return_type = basic_type_from_layout(env, ret_layout); let return_type = basic_type_from_layout(env, ret_layout);
let roc_return = RocReturn::from_layout(env, ret_layout);
let cc_return = to_cc_return(env, ret_layout); let cc_return = to_cc_return(env, ret_layout);
let mut cc_argument_types = let mut cc_argument_types =
@ -6249,8 +6250,17 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
let cc_function = get_foreign_symbol(env, foreign.clone(), cc_type); let cc_function = get_foreign_symbol(env, foreign.clone(), cc_type);
let fastcc_type = let fastcc_type = match roc_return {
return_type.fn_type(&function_arguments(env, &fastcc_argument_types), false); RocReturn::Return => {
return_type.fn_type(&function_arguments(env, &fastcc_argument_types), false)
}
RocReturn::ByPointer => {
fastcc_argument_types.push(return_type.ptr_type(AddressSpace::Generic).into());
env.context
.void_type()
.fn_type(&function_arguments(env, &fastcc_argument_types), false)
}
};
let fastcc_function = add_func( let fastcc_function = add_func(
env.module, env.module,
@ -6265,12 +6275,16 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
let entry = context.append_basic_block(fastcc_function, "entry"); let entry = context.append_basic_block(fastcc_function, "entry");
{ {
builder.position_at_end(entry); builder.position_at_end(entry);
let return_pointer = env.builder.build_alloca(return_type, "return_value");
let fastcc_parameters = fastcc_function.get_params(); let mut fastcc_parameters = fastcc_function.get_params();
let mut cc_arguments = let mut cc_arguments =
Vec::with_capacity_in(fastcc_parameters.len() + 1, env.arena); Vec::with_capacity_in(fastcc_parameters.len() + 1, env.arena);
let return_pointer = match roc_return {
RocReturn::Return => env.builder.build_alloca(return_type, "return_value"),
RocReturn::ByPointer => fastcc_parameters.pop().unwrap().into_pointer_value(),
};
let it = fastcc_parameters.into_iter().zip(cc_argument_types.iter()); let it = fastcc_parameters.into_iter().zip(cc_argument_types.iter());
for (param, cc_type) in it { for (param, cc_type) in it {
if param.get_type() == *cc_type { if param.get_type() == *cc_type {
@ -6289,14 +6303,25 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
let call = env.builder.build_call(cc_function, &cc_arguments, "tmp"); let call = env.builder.build_call(cc_function, &cc_arguments, "tmp");
call.set_call_convention(C_CALL_CONV); call.set_call_convention(C_CALL_CONV);
let return_value = match cc_return { match roc_return {
CCReturn::Return => call.try_as_basic_value().left().unwrap(), RocReturn::Return => {
let return_value = match cc_return {
CCReturn::Return => call.try_as_basic_value().left().unwrap(),
CCReturn::ByPointer => env.builder.build_load(return_pointer, "read_result"), CCReturn::ByPointer => {
CCReturn::Void => return_type.const_zero(), env.builder.build_load(return_pointer, "read_result")
}; }
CCReturn::Void => return_type.const_zero(),
};
builder.build_return(Some(&return_value)); builder.build_return(Some(&return_value));
}
RocReturn::ByPointer => {
debug_assert!(matches!(cc_return, CCReturn::ByPointer));
builder.build_return(None);
}
}
} }
builder.position_at_end(old); builder.position_at_end(old);