update llvm wasm calling convention

This commit is contained in:
Brendan Hansknecht 2023-09-22 18:33:12 -07:00
parent 197b626497
commit 72a488e72e
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
2 changed files with 228 additions and 18 deletions

View file

@ -22,7 +22,7 @@ use roc_mono::layout::{
};
use super::build::{create_entry_block_alloca, BuilderExt};
use super::convert::zig_list_type;
use super::convert::{zig_list_type, zig_str_type};
use super::struct_::struct_from_fields;
pub fn call_bitcode_fn<'ctx>(
@ -732,6 +732,26 @@ impl<'ctx> BitcodeReturnValue<'ctx> {
BitcodeReturnValue::Basic => call_bitcode_fn(env, arguments, fn_name),
}
}
fn call_and_load_wasm<'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
.new_build_load(zig_list_type(env), *result, "load_list")
}
BitcodeReturnValue::Str(result) => {
call_void_bitcode_fn(env, arguments, fn_name);
env.builder
.new_build_load(zig_str_type(env), *result, "load_list")
}
BitcodeReturnValue::Basic => call_bitcode_fn(env, arguments, fn_name),
}
}
}
pub(crate) enum BitcodeReturns {
@ -789,6 +809,16 @@ impl BitcodeReturns {
}
}
fn return_value_wasm<'a, 'ctx>(
&self,
env: &Env<'a, 'ctx, '_>,
arguments: &mut bumpalo::collections::Vec<'a, BasicValueEnum<'ctx>>,
) -> BitcodeReturnValue<'ctx> {
// Wasm follows 64bit despite being 32bit.
// This wrapper is just for clarity at call sites.
self.return_value_64bit(env, arguments)
}
fn call_and_load_32bit<'ctx>(
&self,
env: &Env<'_, 'ctx, '_>,
@ -900,6 +930,42 @@ pub(crate) fn pass_list_to_zig_64bit<'ctx>(
list_alloca
}
pub(crate) fn pass_list_to_zig_wasm<'ctx>(
env: &Env<'_, 'ctx, '_>,
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.new_build_store(list_alloca, list);
list_alloca
}
pub(crate) fn pass_string_to_zig_wasm<'ctx>(
env: &Env<'_, 'ctx, '_>,
string: BasicValueEnum<'ctx>,
) -> PointerValue<'ctx> {
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let string_type = super::convert::zig_str_type(env);
let string_alloca = create_entry_block_alloca(env, parent, string_type.into(), "string_alloca");
env.builder.new_build_store(string_alloca, string);
string_alloca
}
fn pass_string_to_zig_64bit<'ctx>(
_env: &Env<'_, 'ctx, '_>,
string: BasicValueEnum<'ctx>,
@ -958,9 +1024,10 @@ pub(crate) fn call_str_bitcode_fn<'ctx>(
fn_name: &str,
) -> BasicValueEnum<'ctx> {
use bumpalo::collections::Vec;
use roc_target::Architecture::*;
match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
match env.target_info.architecture {
Aarch32 | X86_32 => {
let mut arguments: Vec<BasicValueEnum> =
Vec::with_capacity_in(other_arguments.len() + 2 * strings.len(), env.arena);
@ -974,7 +1041,7 @@ pub(crate) fn call_str_bitcode_fn<'ctx>(
returns.call_and_load_32bit(env, &arguments, fn_name)
}
roc_target::PtrWidth::Bytes8 => {
X86_64 | Aarch64 => {
let capacity = other_arguments.len() + strings.len() + returns.additional_arguments();
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
@ -988,6 +1055,20 @@ pub(crate) fn call_str_bitcode_fn<'ctx>(
return_value.call_and_load_64bit(env, &arguments, fn_name)
}
Wasm32 => {
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_wasm(env, &mut arguments);
for string in strings {
arguments.push(pass_string_to_zig_wasm(env, *string).into());
}
arguments.extend(other_arguments);
return_value.call_and_load_wasm(env, &arguments, fn_name)
}
}
}
@ -999,9 +1080,10 @@ pub(crate) fn call_list_bitcode_fn<'ctx>(
fn_name: &str,
) -> BasicValueEnum<'ctx> {
use bumpalo::collections::Vec;
use roc_target::Architecture::*;
match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
match env.target_info.architecture {
Aarch32 | X86_32 => {
let mut arguments: Vec<BasicValueEnum> =
Vec::with_capacity_in(other_arguments.len() + 2 * lists.len(), env.arena);
@ -1015,7 +1097,7 @@ pub(crate) fn call_list_bitcode_fn<'ctx>(
returns.call_and_load_32bit(env, &arguments, fn_name)
}
roc_target::PtrWidth::Bytes8 => {
X86_64 | Aarch64 => {
let capacity = other_arguments.len() + lists.len() + returns.additional_arguments();
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
@ -1029,5 +1111,19 @@ pub(crate) fn call_list_bitcode_fn<'ctx>(
return_value.call_and_load_64bit(env, &arguments, fn_name)
}
Wasm32 => {
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_wasm(env, &mut arguments);
for list in lists {
arguments.push(pass_list_to_zig_wasm(env, (*list).into()).into());
}
arguments.extend(other_arguments);
return_value.call_and_load_wasm(env, &arguments, fn_name)
}
}
}

View file

@ -26,7 +26,7 @@ use crate::llvm::{
bitcode::{
call_bitcode_fn, call_bitcode_fn_fixing_for_convention, call_list_bitcode_fn,
call_str_bitcode_fn, call_void_bitcode_fn, pass_list_or_string_to_zig_32bit,
BitcodeReturns,
pass_string_to_zig_wasm, BitcodeReturns,
},
build::{
cast_basic_basic, complex_bitcast_check_size, create_entry_block_alloca,
@ -220,8 +220,9 @@ pub(crate) fn run_low_level<'a, 'ctx>(
_ => unreachable!(),
};
let result = match env.target_info.ptr_width() {
PtrWidth::Bytes4 => {
use roc_target::Architecture::*;
let result = match env.target_info.architecture {
Aarch32 | X86_32 => {
let zig_function = env.module.get_function(intrinsic).unwrap();
let zig_function_type = zig_function.get_type();
@ -286,7 +287,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
}
}
}
PtrWidth::Bytes8 => {
Aarch64 | X86_64 => {
let (type_name, width) = {
match layout_interner.get_repr(number_layout) {
LayoutRepr::Builtin(Builtin::Int(int_width)) => {
@ -332,6 +333,52 @@ pub(crate) fn run_low_level<'a, 'ctx>(
call_bitcode_fn(env, &[string], intrinsic)
}
}
Wasm32 => {
let return_type_name = match layout_interner.get_repr(number_layout) {
LayoutRepr::Builtin(Builtin::Float(float_width)) => float_width.type_name(),
LayoutRepr::Builtin(Builtin::Int(int_width)) => int_width.type_name(),
LayoutRepr::Builtin(Builtin::Decimal) => {
// zig picks 128 for dec.RocDec
"i128"
}
_ => unreachable!(),
};
let return_type = zig_num_parse_result_type(env, return_type_name);
let zig_return_alloca =
create_entry_block_alloca(env, parent, return_type.into(), "str_to_num");
call_void_bitcode_fn(
env,
&[
zig_return_alloca.into(),
pass_string_to_zig_wasm(env, string).into(),
],
intrinsic,
);
let roc_return_type = basic_type_from_layout(
env,
layout_interner,
layout_interner.get_repr(layout),
)
.ptr_type(AddressSpace::default());
let roc_return_alloca = env.builder.new_build_pointer_cast(
zig_return_alloca,
roc_return_type,
"cast_to_roc",
);
load_roc_value(
env,
layout_interner,
layout_interner.get_repr(layout),
roc_return_alloca,
"str_to_num_result",
)
}
};
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast if needed.
@ -391,8 +438,9 @@ pub(crate) fn run_low_level<'a, 'ctx>(
.builder
.new_build_alloca(result_type, "alloca_utf8_validate_bytes_result");
match env.target_info.ptr_width() {
PtrWidth::Bytes4 => {
use roc_target::Architecture::*;
match env.target_info.architecture {
Aarch32 | X86_32 => {
arguments!(list, start, count);
let (a, b) = pass_list_or_string_to_zig_32bit(env, list.into_struct_value());
@ -409,7 +457,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
bitcode::STR_FROM_UTF8_RANGE,
);
}
PtrWidth::Bytes8 => {
Aarch64 | X86_64 | Wasm32 => {
arguments!(_list, start, count);
// we use the symbol here instead
@ -516,9 +564,13 @@ pub(crate) fn run_low_level<'a, 'ctx>(
let roc_return_type =
basic_type_from_layout(env, layout_interner, layout_interner.get_repr(layout));
use roc_target::Architecture::*;
use roc_target::OperatingSystem::*;
match env.target_info.operating_system {
Windows => {
match env.target_info {
TargetInfo {
operating_system: Windows,
..
} => {
let result = env.builder.new_build_alloca(
BasicTypeEnum::try_from(roc_return_type).unwrap(),
"result",
@ -539,7 +591,38 @@ pub(crate) fn run_low_level<'a, 'ctx>(
env.builder
.new_build_load(roc_return_type, cast_result, "load_result")
}
Unix => {
TargetInfo {
architecture: Wasm32,
..
} => {
let result = env.builder.new_build_alloca(
BasicTypeEnum::try_from(roc_return_type).unwrap(),
"result",
);
call_void_bitcode_fn(
env,
&[
result.into(),
pass_string_to_zig_wasm(env, string).into(),
index,
],
bitcode::STR_GET_SCALAR_UNSAFE,
);
let cast_result = env.builder.new_build_pointer_cast(
result,
roc_return_type.ptr_type(AddressSpace::default()),
"cast",
);
env.builder
.new_build_load(roc_return_type, cast_result, "load_result")
}
TargetInfo {
operating_system: Unix,
..
} => {
let result = call_str_bitcode_fn(
env,
&[string],
@ -558,7 +641,10 @@ pub(crate) fn run_low_level<'a, 'ctx>(
env.builder
.new_build_load(roc_return_type, alloca, "to_roc_record")
}
Wasi => unimplemented!(),
TargetInfo {
operating_system: Wasi,
..
} => unimplemented!(),
}
}
StrCountUtf8Bytes => {
@ -2046,6 +2132,16 @@ fn dec_to_str<'ctx>(env: &Env<'_, 'ctx, '_>, dec: BasicValueEnum<'ctx>) -> Basic
bitcode::DEC_TO_STR,
)
}
TargetInfo {
architecture: Wasm32,
operating_system: Unix,
} => call_str_bitcode_fn(
env,
&[],
&[dec.into()],
BitcodeReturns::Str,
bitcode::DEC_TO_STR,
),
_ => call_str_bitcode_fn(
env,
&[],
@ -2073,6 +2169,10 @@ fn dec_unary_op<'ctx>(
let (low, high) = dec_split_into_words(env, dec);
call_bitcode_fn(env, &[low.into(), high.into()], fn_name)
}
TargetInfo {
architecture: Wasm32,
operating_system: Unix,
} => call_bitcode_fn(env, &[dec.into()], fn_name),
_ => call_bitcode_fn(env, &[dec_alloca(env, dec).into()], fn_name),
}
}
@ -2111,6 +2211,16 @@ fn dec_binop_with_overflow<'ctx>(
fn_name,
);
}
TargetInfo {
architecture: Wasm32,
operating_system: Unix,
} => {
call_void_bitcode_fn(
env,
&[return_alloca.into(), lhs.into(), rhs.into()],
fn_name,
);
}
_ => {
call_void_bitcode_fn(
env,
@ -2159,6 +2269,10 @@ pub(crate) fn dec_binop_with_unchecked<'ctx>(
fn_name,
)
}
TargetInfo {
architecture: Wasm32,
operating_system: Unix,
} => call_bitcode_fn(env, &[lhs.into(), rhs.into()], fn_name),
_ => call_bitcode_fn(
env,
&[dec_alloca(env, lhs).into(), dec_alloca(env, rhs).into()],