mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-01 02:42:17 +00:00
add new 32/64-bit bitcode fn callers
This commit is contained in:
parent
f31bffab30
commit
dd35b44877
1 changed files with 332 additions and 2 deletions
|
@ -10,11 +10,14 @@ use crate::llvm::refcounting::{
|
|||
};
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
use inkwell::types::{BasicType, BasicTypeEnum};
|
||||
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue};
|
||||
use inkwell::values::{
|
||||
BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue,
|
||||
PointerValue, StructValue,
|
||||
};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{LambdaSet, Layout, LayoutIds, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
use super::build::create_entry_block_alloca;
|
||||
|
||||
|
@ -811,3 +814,330 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
function_value
|
||||
}
|
||||
|
||||
enum BitcodeReturnValue<'ctx> {
|
||||
List(PointerValue<'ctx>),
|
||||
Str(PointerValue<'ctx>),
|
||||
Basic,
|
||||
}
|
||||
|
||||
impl<'ctx> BitcodeReturnValue<'ctx> {
|
||||
fn call_and_load_64bit<'a, 'env>(
|
||||
&self,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arguments: &[BasicValueEnum<'ctx>],
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
match self {
|
||||
BitcodeReturnValue::List(result) => {
|
||||
call_void_bitcode_fn(env, arguments, fn_name);
|
||||
env.builder.build_load(*result, "load_list")
|
||||
}
|
||||
BitcodeReturnValue::Str(result) => {
|
||||
call_void_bitcode_fn(env, arguments, fn_name);
|
||||
|
||||
// we keep a string in the alloca
|
||||
(*result).into()
|
||||
}
|
||||
BitcodeReturnValue::Basic => call_bitcode_fn(env, arguments, fn_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum BitcodeReturns {
|
||||
List,
|
||||
Str,
|
||||
Basic,
|
||||
}
|
||||
|
||||
impl BitcodeReturns {
|
||||
fn additional_arguments(&self) -> usize {
|
||||
match self {
|
||||
BitcodeReturns::List | BitcodeReturns::Str => 1,
|
||||
BitcodeReturns::Basic => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn return_value_64bit<'a, 'ctx, 'env>(
|
||||
&self,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arguments: &mut bumpalo::collections::Vec<'a, BasicValueEnum<'ctx>>,
|
||||
) -> BitcodeReturnValue<'ctx> {
|
||||
match self {
|
||||
BitcodeReturns::List => {
|
||||
let list_type = super::convert::zig_list_type(env);
|
||||
|
||||
let parent = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.and_then(|b| b.get_parent())
|
||||
.unwrap();
|
||||
|
||||
let result =
|
||||
create_entry_block_alloca(env, parent, list_type.into(), "list_alloca");
|
||||
|
||||
arguments.push(result.into());
|
||||
|
||||
BitcodeReturnValue::List(result)
|
||||
}
|
||||
BitcodeReturns::Str => {
|
||||
let str_type = super::convert::zig_str_type(env);
|
||||
|
||||
let parent = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.and_then(|b| b.get_parent())
|
||||
.unwrap();
|
||||
|
||||
let result = create_entry_block_alloca(env, parent, str_type.into(), "str_alloca");
|
||||
|
||||
arguments.push(result.into());
|
||||
|
||||
BitcodeReturnValue::Str(result)
|
||||
}
|
||||
BitcodeReturns::Basic => BitcodeReturnValue::Basic,
|
||||
}
|
||||
}
|
||||
|
||||
fn call_and_load_32bit<'a, 'ctx, 'env>(
|
||||
&self,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arguments: &[BasicValueEnum<'ctx>],
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let value = call_bitcode_fn(env, arguments, fn_name);
|
||||
|
||||
match self {
|
||||
BitcodeReturns::List => {
|
||||
receive_zig_roc_list_32bit(env, value.into_struct_value()).into()
|
||||
}
|
||||
BitcodeReturns::Str => receive_zig_roc_str_32bit(env, value.into_struct_value()).into(),
|
||||
BitcodeReturns::Basic => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ptr_len_cap<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: StructValue<'ctx>,
|
||||
) -> (PointerValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>) {
|
||||
let ptr_and_len = env
|
||||
.builder
|
||||
.build_extract_value(value, 0, "get_list_cap")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let upper_word = {
|
||||
let shift = env.builder.build_right_shift(
|
||||
ptr_and_len,
|
||||
env.context.i64_type().const_int(32, false),
|
||||
false,
|
||||
"list_ptr_shift",
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_int_cast(shift, env.context.i32_type(), "list_ptr_int")
|
||||
};
|
||||
|
||||
let lower_word = env
|
||||
.builder
|
||||
.build_int_cast(ptr_and_len, env.context.i32_type(), "list_len");
|
||||
|
||||
let len = upper_word;
|
||||
|
||||
let ptr = env.builder.build_int_to_ptr(
|
||||
lower_word,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"list_ptr",
|
||||
);
|
||||
|
||||
let cap = env
|
||||
.builder
|
||||
.build_extract_value(value, 1, "get_list_cap")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
(ptr, len, cap)
|
||||
}
|
||||
|
||||
/// Converts the { i64, i32 } struct that zig returns into `list.RocList = type { i8*, i32, i32 }`
|
||||
fn receive_zig_roc_list_32bit<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: StructValue<'ctx>,
|
||||
) -> StructValue<'ctx> {
|
||||
let list_type = super::convert::zig_list_type(env);
|
||||
|
||||
let (ptr, len, cap) = ptr_len_cap(env, value);
|
||||
|
||||
struct_from_fields(
|
||||
env,
|
||||
list_type,
|
||||
[(0, ptr.into()), (1, len.into()), (2, cap.into())].into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts the { i64, i32 } struct that zig returns into `list.RocList = type { i8*, i32, i32 }`
|
||||
fn receive_zig_roc_str_32bit<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: StructValue<'ctx>,
|
||||
) -> StructValue<'ctx> {
|
||||
let str_type = super::convert::zig_str_type(env);
|
||||
|
||||
let (ptr, len, cap) = ptr_len_cap(env, value);
|
||||
|
||||
struct_from_fields(
|
||||
env,
|
||||
str_type,
|
||||
[(0, ptr.into()), (1, len.into()), (2, cap.into())].into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn pass_list_to_zig_64bit<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let parent = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.and_then(|b| b.get_parent())
|
||||
.unwrap();
|
||||
|
||||
let list_type = super::convert::zig_list_type(env);
|
||||
let list_alloca = create_entry_block_alloca(env, parent, list_type.into(), "list_alloca");
|
||||
|
||||
env.builder.build_store(list_alloca, list);
|
||||
|
||||
list_alloca
|
||||
}
|
||||
|
||||
fn pass_string_to_zig_64bit<'a, 'ctx, 'env>(
|
||||
_env: &Env<'a, 'ctx, 'env>,
|
||||
string: BasicValueEnum<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
// we must pass strings by-pointer, and that is already how they are stored
|
||||
string.into_pointer_value()
|
||||
}
|
||||
|
||||
pub(crate) fn pass_list_or_string_to_zig_32bit<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
list_or_string: StructValue<'ctx>,
|
||||
) -> (IntValue<'ctx>, IntValue<'ctx>) {
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_extract_value(list_or_string, Builtin::WRAPPER_PTR, "list_ptr")
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_ptr_to_int(ptr, env.context.i32_type(), "ptr_to_i32");
|
||||
|
||||
let len = env
|
||||
.builder
|
||||
.build_extract_value(list_or_string, Builtin::WRAPPER_LEN, "list_len")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let cap = env
|
||||
.builder
|
||||
.build_extract_value(list_or_string, Builtin::WRAPPER_CAPACITY, "list_cap")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let int_64_type = env.context.i64_type();
|
||||
let len = env
|
||||
.builder
|
||||
.build_int_z_extend(len, int_64_type, "list_len_64");
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_int_z_extend(ptr, int_64_type, "list_ptr_64");
|
||||
|
||||
let len_shift =
|
||||
env.builder
|
||||
.build_left_shift(len, int_64_type.const_int(32, false), "list_len_shift");
|
||||
let ptr_len = env.builder.build_or(len_shift, ptr, "list_ptr_len");
|
||||
|
||||
(ptr_len, cap)
|
||||
}
|
||||
|
||||
pub(crate) fn call_str_bitcode_fn_new<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
strings: &[BasicValueEnum<'ctx>],
|
||||
other_arguments: &[BasicValueEnum<'ctx>],
|
||||
returns: BitcodeReturns,
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
let mut arguments: Vec<BasicValueEnum> =
|
||||
Vec::with_capacity_in(other_arguments.len() + 2 * strings.len(), env.arena);
|
||||
|
||||
for string in strings {
|
||||
let (a, b) = pass_list_or_string_to_zig_32bit(env, string.into_struct_value());
|
||||
arguments.push(a.into());
|
||||
arguments.push(b.into());
|
||||
}
|
||||
|
||||
arguments.extend(other_arguments);
|
||||
|
||||
returns.call_and_load_32bit(env, &arguments, fn_name)
|
||||
}
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let capacity = other_arguments.len() + strings.len() + returns.additional_arguments();
|
||||
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
|
||||
|
||||
let return_value = returns.return_value_64bit(env, &mut arguments);
|
||||
|
||||
for string in strings {
|
||||
arguments.push(pass_string_to_zig_64bit(env, *string).into());
|
||||
}
|
||||
|
||||
arguments.extend(other_arguments);
|
||||
|
||||
return_value.call_and_load_64bit(env, &arguments, fn_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn call_list_bitcode_fn_new<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
lists: &[StructValue<'ctx>],
|
||||
other_arguments: &[BasicValueEnum<'ctx>],
|
||||
returns: BitcodeReturns,
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
let mut arguments: Vec<BasicValueEnum> =
|
||||
Vec::with_capacity_in(other_arguments.len() + 2 * lists.len(), env.arena);
|
||||
|
||||
for list in lists {
|
||||
let (a, b) = pass_list_or_string_to_zig_32bit(env, *list);
|
||||
arguments.push(a.into());
|
||||
arguments.push(b.into());
|
||||
}
|
||||
|
||||
arguments.extend(other_arguments);
|
||||
|
||||
returns.call_and_load_32bit(env, &arguments, fn_name)
|
||||
}
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let capacity = other_arguments.len() + lists.len() + returns.additional_arguments();
|
||||
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
|
||||
|
||||
let return_value = returns.return_value_64bit(env, &mut arguments);
|
||||
|
||||
for list in lists {
|
||||
arguments.push(pass_list_to_zig_64bit(env, (*list).into()).into());
|
||||
}
|
||||
|
||||
arguments.extend(other_arguments);
|
||||
|
||||
return_value.call_and_load_64bit(env, &arguments, fn_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue