mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
Merge pull request #1678 from rtfeldman/gen_wasm_switch
implement switch for the gen wasm backend
This commit is contained in:
commit
282c9d8f17
@ -1,6 +1,8 @@
|
||||
use parity_wasm::builder;
|
||||
use parity_wasm::builder::{CodeLocation, ModuleBuilder};
|
||||
use parity_wasm::elements::{Instruction, Instruction::*, Instructions, Local, ValueType};
|
||||
use parity_wasm::elements::{
|
||||
BlockType, Instruction, Instruction::*, Instructions, Local, ValueType,
|
||||
};
|
||||
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::low_level::LowLevel;
|
||||
@ -30,6 +32,12 @@ struct WasmLayout {
|
||||
impl WasmLayout {
|
||||
fn new(layout: &Layout) -> Result<Self, String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int1 | Builtin::Int8 | Builtin::Int16 | Builtin::Int32) => {
|
||||
Ok(Self {
|
||||
value_type: ValueType::I32,
|
||||
stack_memory: 0,
|
||||
})
|
||||
}
|
||||
Layout::Builtin(Builtin::Int64) => Ok(Self {
|
||||
value_type: ValueType::I64,
|
||||
stack_memory: 0,
|
||||
@ -207,6 +215,60 @@ impl<'a> WasmBackend<'a> {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
cond_layout: _,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout: _,
|
||||
} => {
|
||||
// NOTE currently implemented as a series of conditional jumps
|
||||
// We may be able to improve this in the future with `Select`
|
||||
// or `BrTable`
|
||||
|
||||
// create (number_of_branches - 1) new blocks.
|
||||
//
|
||||
// Every branch ends in a `return`,
|
||||
// so the block leaves no values on the stack
|
||||
for _ in 0..branches.len() {
|
||||
self.instructions.push(Block(BlockType::NoResult));
|
||||
}
|
||||
|
||||
// the LocalId of the symbol that we match on
|
||||
let matched_on = match self.symbol_storage_map.get(cond_symbol) {
|
||||
Some(SymbolStorage(local_id, _)) => local_id.0,
|
||||
None => unreachable!("symbol not defined: {:?}", cond_symbol),
|
||||
};
|
||||
|
||||
// then, we jump whenever the value under scrutiny is equal to the value of a branch
|
||||
for (i, (value, _, _)) in branches.iter().enumerate() {
|
||||
// put the cond_symbol on the top of the stack
|
||||
self.instructions.push(GetLocal(matched_on));
|
||||
|
||||
self.instructions.push(I32Const(*value as i32));
|
||||
|
||||
// compare the 2 topmost values
|
||||
self.instructions.push(I32Eq);
|
||||
|
||||
// "break" out of `i` surrounding blocks
|
||||
self.instructions.push(BrIf(i as u32));
|
||||
}
|
||||
|
||||
// if we never jumped because a value matched, we're in the default case
|
||||
self.build_stmt(default_branch.1, ret_layout)?;
|
||||
|
||||
// now put in the actual body of each branch in order
|
||||
// (the first branch would have broken out of 1 block,
|
||||
// hence we must generate its code first)
|
||||
for (_, _, branch) in branches.iter() {
|
||||
self.instructions.push(End);
|
||||
|
||||
self.build_stmt(branch, ret_layout)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
x => Err(format!("statement not yet implemented: {:?}", x)),
|
||||
}
|
||||
}
|
||||
@ -248,6 +310,14 @@ impl<'a> WasmBackend<'a> {
|
||||
|
||||
fn load_literal(&mut self, lit: &Literal<'a>) -> Result<(), String> {
|
||||
match lit {
|
||||
Literal::Bool(x) => {
|
||||
self.instructions.push(I32Const(*x as i32));
|
||||
Ok(())
|
||||
}
|
||||
Literal::Byte(x) => {
|
||||
self.instructions.push(I32Const(*x as i32));
|
||||
Ok(())
|
||||
}
|
||||
Literal::Int(x) => {
|
||||
self.instructions.push(I64Const(*x as i64));
|
||||
Ok(())
|
||||
|
@ -147,6 +147,7 @@ where
|
||||
Err(e) => Err(format!("{:?}", e)),
|
||||
Ok(result) => {
|
||||
let integer = match result[0] {
|
||||
wasmer::Value::I32(a) => a as i64,
|
||||
wasmer::Value::I64(a) => a,
|
||||
wasmer::Value::F64(a) => a.to_bits() as i64,
|
||||
_ => panic!(),
|
||||
|
@ -49,6 +49,73 @@ mod dev_num {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_then_else() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
cond : Bool
|
||||
cond = True
|
||||
|
||||
if cond then
|
||||
0
|
||||
else
|
||||
1
|
||||
"#
|
||||
),
|
||||
0,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rgb_red() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Red is
|
||||
Red -> 111
|
||||
Green -> 222
|
||||
Blue -> 333
|
||||
"#
|
||||
),
|
||||
111,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rgb_green() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Green is
|
||||
Red -> 111
|
||||
Green -> 222
|
||||
Blue -> 333
|
||||
"#
|
||||
),
|
||||
222,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rgb_blue() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Blue is
|
||||
Red -> 111
|
||||
Green -> 222
|
||||
Blue -> 333
|
||||
"#
|
||||
),
|
||||
333,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn gen_add_f64() {
|
||||
// assert_evals_to!(
|
||||
|
Loading…
Reference in New Issue
Block a user