mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
gen_wasm: add support for non-recursive Tags
This commit is contained in:
parent
f6b6d91c56
commit
6a801ebc7e
@ -6,7 +6,7 @@ use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_mono::gen_refcount::{RefcountProcGenerator, REFCOUNT_MAX};
|
||||
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||
|
||||
use crate::layout::{CallConv, ReturnMethod, WasmLayout};
|
||||
use crate::low_level::{decode_low_level, LowlevelBuildResult};
|
||||
@ -24,8 +24,8 @@ use crate::wasm_module::{
|
||||
LinkingSubSection, LocalId, Signature, SymInfo, ValueType,
|
||||
};
|
||||
use crate::{
|
||||
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_SIZE,
|
||||
PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME,
|
||||
MEMORY_NAME, PTR_SIZE, PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME,
|
||||
};
|
||||
|
||||
/// The memory address where the constants data will be loaded during module instantiation.
|
||||
@ -633,7 +633,7 @@ impl<'a> WasmBackend<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Expr::Array { .. } => Err(format!("Expression is not yet implemented {:?}", 2)),
|
||||
Expr::Array { .. } => Err(format!("Expression is not yet implemented {:?}", expr)),
|
||||
|
||||
Expr::EmptyArray => {
|
||||
if let StoredValue::StackMemory { location, .. } = storage {
|
||||
@ -653,10 +653,68 @@ impl<'a> WasmBackend<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Tag {
|
||||
tag_layout,
|
||||
tag_id,
|
||||
arguments,
|
||||
..
|
||||
} => {
|
||||
self.build_tag(tag_layout, *tag_id, arguments, storage);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
x => Err(format!("Expression is not yet implemented {:?}", x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tag(
|
||||
&mut self,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
tag_id: TagIdIntType,
|
||||
arguments: &'a [Symbol],
|
||||
stored: &StoredValue,
|
||||
) {
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(tags) => {
|
||||
let (local_id, offset) = if let StoredValue::StackMemory { location, .. } = stored {
|
||||
location.local_and_offset(self.storage.stack_frame_pointer)
|
||||
} else {
|
||||
panic!("NonRecursive Tag should always be stored in StackMemory");
|
||||
};
|
||||
|
||||
let mut field_offset = offset;
|
||||
for field_symbol in arguments.iter() {
|
||||
field_offset += self.storage.copy_value_to_memory(
|
||||
&mut self.code_builder,
|
||||
local_id,
|
||||
field_offset,
|
||||
*field_symbol,
|
||||
);
|
||||
}
|
||||
|
||||
let tag_field_layouts = &tags[tag_id as usize];
|
||||
let alignment_bytes = Layout::Struct(tag_field_layouts).alignment_bytes(PTR_SIZE);
|
||||
let tag_id_offset =
|
||||
round_up_to_alignment(field_offset as i32, alignment_bytes as i32) as u32;
|
||||
let tag_id_align = Align::from(alignment_bytes);
|
||||
|
||||
match tag_id_align {
|
||||
Align::Bytes1 | Align::Bytes2 | Align::Bytes4 => {
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i32_const(tag_id as i32);
|
||||
self.code_builder.i32_store(tag_id_align, tag_id_offset);
|
||||
}
|
||||
_ => {
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i64_const(tag_id as i64);
|
||||
self.code_builder.i64_store(tag_id_align, tag_id_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("Tag with layout {:?}", union_layout),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_low_level(
|
||||
&mut self,
|
||||
lowlevel: LowLevel,
|
||||
|
@ -806,6 +806,24 @@ fn return_nested_record() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_record_load() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x = { a : { b : 0x5 } }
|
||||
|
||||
y = x.a
|
||||
|
||||
y.b
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn accessor_twice() {
|
||||
|
@ -1,16 +1,15 @@
|
||||
#![cfg(feature = "gen-llvm")]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
||||
// #[cfg(feature = "gen-dev")]
|
||||
// use crate::helpers::dev::assert_evals_to;
|
||||
|
||||
// #[cfg(feature = "gen-wasm")]
|
||||
// use crate::helpers::wasm::assert_evals_to;
|
||||
#[cfg(feature = "gen-wasm")]
|
||||
use crate::helpers::wasm::assert_evals_to;
|
||||
|
||||
// use crate::assert_wasm_evals_to as assert_evals_to;
|
||||
use indoc::indoc;
|
||||
#[allow(unused_imports)]
|
||||
use roc_std::{RocList, RocStr};
|
||||
|
||||
#[test]
|
||||
@ -71,7 +70,7 @@ fn applied_tag_nothing() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -90,7 +89,7 @@ fn applied_tag_just() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just_ir() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -109,7 +108,7 @@ fn applied_tag_just_ir() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn applied_tag_just_enum() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -133,7 +132,7 @@ fn applied_tag_just_enum() {
|
||||
}
|
||||
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn raw_result() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
@ -149,7 +148,7 @@ fn applied_tag_just_enum() {
|
||||
// );
|
||||
// }
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn true_is_true() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -166,7 +165,7 @@ fn true_is_true() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn false_is_false() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -205,7 +204,7 @@ fn basic_enum() {
|
||||
}
|
||||
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_empty() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
@ -224,7 +223,7 @@ fn basic_enum() {
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_singleton() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
@ -243,7 +242,7 @@ fn basic_enum() {
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// #[cfg(any(feature = "gen-llvm"))]
|
||||
// fn linked_list_is_empty() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
@ -264,7 +263,7 @@ fn basic_enum() {
|
||||
// );
|
||||
// }
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn even_odd() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -290,7 +289,7 @@ fn even_odd() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_literal_true() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -304,7 +303,7 @@ fn gen_literal_true() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_if_float() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -792,7 +791,7 @@ fn pattern_matching_unit() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn one_element_tag() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -809,7 +808,7 @@ fn one_element_tag() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn nested_tag_union() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -830,7 +829,7 @@ fn nested_tag_union() {
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn unit_type() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -848,24 +847,6 @@ fn unit_type() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn nested_record_load() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x = { a : { b : 0x5 } }
|
||||
|
||||
y = x.a
|
||||
|
||||
y.b
|
||||
"#
|
||||
),
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn join_point_if() {
|
||||
@ -949,7 +930,7 @@ fn join_point_with_cond_expr() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_single_tag_construction() {
|
||||
assert_evals_to!(indoc!("Three (1 == 1) 32"), (32i64, true), (i64, bool));
|
||||
|
||||
@ -993,7 +974,7 @@ fn alignment_in_single_tag_pattern_match() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_multi_tag_construction_two() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1011,7 +992,7 @@ fn alignment_in_multi_tag_construction_two() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn alignment_in_multi_tag_construction_three() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -27,7 +27,7 @@ macro_rules! from_wasm_memory_primitive_decode {
|
||||
let raw_ptr = ptr as *mut u8;
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) };
|
||||
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset as u32);
|
||||
let ptr: wasmer::WasmPtr<u8, wasmer::Array> = wasmer::WasmPtr::new(offset);
|
||||
let foobar = (ptr.deref(memory, 0, width as u32)).unwrap();
|
||||
let wasm_slice = unsafe { std::mem::transmute(foobar) };
|
||||
|
||||
|
@ -221,7 +221,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, expected: T) -> Result<T, String>
|
||||
pub fn assert_wasm_evals_to_help<T>(src: &str, phantom: T) -> Result<T, String>
|
||||
where
|
||||
T: FromWasm32Memory + Wasm32TestResult,
|
||||
{
|
||||
@ -230,7 +230,7 @@ where
|
||||
// NOTE the stdlib must be in the arena; just taking a reference will segfault
|
||||
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
|
||||
|
||||
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &expected);
|
||||
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &phantom);
|
||||
|
||||
let memory = instance.exports.get_memory(MEMORY_NAME).unwrap();
|
||||
|
||||
@ -254,7 +254,8 @@ where
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! assert_wasm_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||
match $crate::helpers::wasm::assert_wasm_evals_to_help::<$ty>($src, $expected) {
|
||||
let phantom = <$ty>::default();
|
||||
match $crate::helpers::wasm::assert_wasm_evals_to_help::<$ty>($src, phantom) {
|
||||
Err(msg) => panic!("{:?}", msg),
|
||||
Ok(actual) => {
|
||||
assert_eq!($transform(actual), $expected)
|
||||
|
Loading…
Reference in New Issue
Block a user