implement factorial example

This commit is contained in:
Folkert 2021-09-08 20:05:05 +02:00
parent f40949c64e
commit e802da5f54
3 changed files with 51 additions and 14 deletions

View file

@ -23,7 +23,7 @@ struct LabelId(u32);
#[derive(Debug)] #[derive(Debug)]
struct SymbolStorage(LocalId, WasmLayout); struct SymbolStorage(LocalId, WasmLayout);
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
struct WasmLayout { struct WasmLayout {
value_type: ValueType, value_type: ValueType,
stack_memory: u32, stack_memory: u32,
@ -185,12 +185,12 @@ impl<'a> WasmBackend<'a> {
Ok(()) Ok(())
} }
fn start_loop(&mut self) { /// start a loop that leaves a value on the stack
fn start_loop_with_return(&mut self, value_type: ValueType) {
self.block_depth += 1; self.block_depth += 1;
// self.instructions.push(Loop(BlockType::NoResult)); // self.instructions.push(Loop(BlockType::NoResult));
self.instructions self.instructions.push(Loop(BlockType::Value(value_type)));
.push(Loop(BlockType::Value(ValueType::I64)));
} }
fn end_loop(&mut self) { fn end_loop(&mut self) {
@ -307,19 +307,21 @@ impl<'a> WasmBackend<'a> {
for parameter in parameters.iter() { for parameter in parameters.iter() {
let wasm_layout = WasmLayout::new(&parameter.layout)?; let wasm_layout = WasmLayout::new(&parameter.layout)?;
let local_id = self.insert_local(wasm_layout, parameter.symbol); let local_id = self.insert_local(wasm_layout, parameter.symbol);
local_ids.push(local_id); local_ids.push(local_id);
} }
self.start_block(); self.start_block();
self.joinpoint_label_map self.joinpoint_label_map
.insert(*id, (self.block_depth, local_ids.clone())); .insert(*id, (self.block_depth, local_ids));
self.build_stmt(remainder, ret_layout)?; self.build_stmt(remainder, ret_layout)?;
self.end_block(); self.end_block();
self.start_loop(); let return_wasm_layout = WasmLayout::new(ret_layout)?;
self.start_loop_with_return(return_wasm_layout.value_type);
self.build_stmt(body, ret_layout)?; self.build_stmt(body, ret_layout)?;
@ -358,7 +360,7 @@ impl<'a> WasmBackend<'a> {
layout: &Layout<'a>, layout: &Layout<'a>,
) -> Result<(), String> { ) -> Result<(), String> {
match expr { match expr {
Expr::Literal(lit) => self.load_literal(lit), Expr::Literal(lit) => self.load_literal(lit, layout),
Expr::Call(roc_mono::ir::Call { Expr::Call(roc_mono::ir::Call {
call_type, call_type,
@ -386,7 +388,7 @@ impl<'a> WasmBackend<'a> {
} }
} }
fn load_literal(&mut self, lit: &Literal<'a>) -> Result<(), String> { fn load_literal(&mut self, lit: &Literal<'a>, layout: &Layout<'a>) -> Result<(), String> {
match lit { match lit {
Literal::Bool(x) => { Literal::Bool(x) => {
self.instructions.push(I32Const(*x as i32)); self.instructions.push(I32Const(*x as i32));
@ -397,7 +399,15 @@ impl<'a> WasmBackend<'a> {
Ok(()) Ok(())
} }
Literal::Int(x) => { Literal::Int(x) => {
self.instructions.push(I64Const(*x as i64)); match layout {
Layout::Builtin(Builtin::Int32) => {
self.instructions.push(I32Const(*x as i32));
}
Layout::Builtin(Builtin::Int64) => {
self.instructions.push(I64Const(*x as i64));
}
x => panic!("loading literal, {:?}, is not yet implemented", x),
}
Ok(()) Ok(())
} }
Literal::Float(x) => { Literal::Float(x) => {
@ -441,6 +451,22 @@ impl<'a> WasmBackend<'a> {
ValueType::F32 => &[F32Add], ValueType::F32 => &[F32Add],
ValueType::F64 => &[F64Add], ValueType::F64 => &[F64Add],
}, },
LowLevel::NumSub => match return_value_type {
ValueType::I32 => &[I32Sub],
ValueType::I64 => &[I64Sub],
ValueType::F32 => &[F32Sub],
ValueType::F64 => &[F64Sub],
},
LowLevel::NumMul => match return_value_type {
ValueType::I32 => &[I32Mul],
ValueType::I64 => &[I64Mul],
ValueType::F32 => &[F32Mul],
ValueType::F64 => &[F64Mul],
},
LowLevel::NumGt => {
// needs layout of the argument to be implemented fully
&[I32GtS]
}
_ => { _ => {
return Err(format!("unsupported low-level op {:?}", lowlevel)); return Err(format!("unsupported low-level op {:?}", lowlevel));
} }

View file

@ -25,6 +25,9 @@ pub fn build_module<'a>(
let mut backend = WasmBackend::new(); let mut backend = WasmBackend::new();
let mut layout_ids = LayoutIds::default(); let mut layout_ids = LayoutIds::default();
let mut procedures: std::vec::Vec<_> = procedures.into_iter().collect();
procedures.sort_by(|a, b| b.0 .0.cmp(&a.0 .0));
for ((sym, layout), proc) in procedures { for ((sym, layout), proc) in procedures {
let function_index = backend.build_proc(proc, sym)?; let function_index = backend.build_proc(proc, sym)?;
if env.exposed_to_host.contains(&sym) { if env.exposed_to_host.contains(&sym) {

View file

@ -132,17 +132,25 @@ mod dev_num {
} }
#[test] #[test]
#[ignore]
fn factorial() { fn factorial() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
fac = \n -> app "test" provides [ main ] to "./platform"
if n
fac : I32, I32 -> I32
fac = \n, accum ->
if n > 1 then
fac (n - 1) (n * accum)
else
accum
main : I32
main = fac 8 1
"# "#
), ),
234, 40_320,
i64 i32
); );
} }