wasm: Work around Zig returning small structs as integers

This commit is contained in:
Brian Carroll 2022-04-11 08:54:16 +01:00
parent 2473b84ded
commit 249925cb23
4 changed files with 109 additions and 59 deletions

View file

@ -1,4 +1,3 @@
use bumpalo::collections::Vec;
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_error_macros::internal_error;
use roc_module::low_level::{LowLevel, LowLevel::*};
@ -126,7 +125,7 @@ impl<'a> LowLevelCall<'a> {
/// For numerical ops, this just pushes the arguments to the Wasm VM's value stack
/// It implements the calling convention used by Zig for both numbers and structs
/// Result is the type signature of the call
fn load_args(&self, backend: &mut WasmBackend<'a>) -> (Vec<'a, ValueType>, Option<ValueType>) {
fn load_args(&self, backend: &mut WasmBackend<'a>) -> (usize, bool, bool) {
backend.storage.load_symbols_for_call(
backend.env.arena,
&mut backend.code_builder,
@ -138,8 +137,29 @@ impl<'a> LowLevelCall<'a> {
}
fn load_args_and_call_zig(&self, backend: &mut WasmBackend<'a>, name: &'a str) {
let (param_types, ret_type) = self.load_args(backend);
backend.call_zig_builtin_after_loading_args(name, param_types.len(), ret_type.is_some());
let (num_wasm_args, has_return_val, ret_zig_packed_struct) = self.load_args(backend);
backend.call_zig_builtin_after_loading_args(name, num_wasm_args, has_return_val);
if ret_zig_packed_struct {
match self.ret_storage {
StoredValue::StackMemory {
size,
alignment_bytes,
..
} => {
// The address of the return value was already loaded before the call
let align = Align::from(alignment_bytes);
if size > 4 {
backend.code_builder.i64_store(align, 0);
} else {
backend.code_builder.i32_store(align, 0);
}
}
_ => {
internal_error!("Zig packed struct should always be stored to StackMemory")
}
}
}
}
/// Wrap an integer whose Wasm representation is i32