diff --git a/frontend-wasm/tests/rust_source/fib.rs b/frontend-wasm/tests/rust_source/fib.rs new file mode 100644 index 000000000..8c7b9b987 --- /dev/null +++ b/frontend-wasm/tests/rust_source/fib.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +#[panic_handler] +fn my_panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[inline(never)] +#[no_mangle] +pub fn fib(n: u32) -> u32 { + let mut a = 0; + let mut b = 1; + for _ in 0..n { + let c = a + b; + a = b; + b = c; + } + a +} + +#[no_mangle] +pub extern "C" fn __main() -> u32 { + fib(25) +} diff --git a/frontend-wasm/tests/test_rust_comp.rs b/frontend-wasm/tests/test_rust_comp.rs index bb7cde49e..0c646a084 100644 --- a/frontend-wasm/tests/test_rust_comp.rs +++ b/frontend-wasm/tests/test_rust_comp.rs @@ -12,10 +12,12 @@ use miden_diagnostics::Verbosity; use miden_frontend_wasm::translate_module; use miden_frontend_wasm::WasmTranslationConfig; -fn hash_string(input: &str) -> String { +fn hash_string(inputs: &[&str]) -> String { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); - hasher.update(input); + for input in inputs { + hasher.update(input); + } format!("{:x}", hasher.finalize()) } @@ -23,7 +25,16 @@ fn compile_wasm(rust_source: &str) -> Vec { use std::fs; use std::process::Command; - let file_name = hash_string(rust_source); + let rustc_opts = [ + "-C", + "opt-level=z", // optimize for size + "--target", + "wasm32-unknown-unknown", + ]; + + // include rustc_opts in the hash to ensure that the output file changes when options change + let file_name = hash_string(&[&rustc_opts.concat(), rust_source]); + let temp_dir = std::env::temp_dir(); let input_file = temp_dir.join(format!("{file_name}.rs")); let output_file = temp_dir.join(format!("{file_name}.wasm")); @@ -36,14 +47,10 @@ fn compile_wasm(rust_source: &str) -> Vec { fs::write(&input_file, rust_source).unwrap(); let output = Command::new("rustc") - .args(&[ - "--target", - "wasm32-unknown-unknown", - input_file.to_str().unwrap(), - "-o", - output_file.to_str().unwrap(), - "-O", - ]) + .args(&rustc_opts) + .arg(&input_file) + .arg("-o") + .arg(&output_file) .output() .expect("Failed to execute rustc."); @@ -88,7 +95,7 @@ fn default_emitter(verbosity: Verbosity, color: ColorChoice) -> Arc } #[test] -fn test_rust_add() { +fn rust_add() { check_ir( include_str!("rust_source/add.rs"), expect![[r#" @@ -140,3 +147,93 @@ fn test_rust_add() { "#]], ); } + +#[test] +fn rust_fib() { + check_ir( + include_str!("rust_source/fib.rs"), + expect![[r#" + (module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $fib (;0;) (type 0) (param i32) (result i32) + (local i32 i32 i32) + i32.const 0 + local.set 1 + i32.const 1 + local.set 2 + loop (result i32) ;; label = @1 + local.get 2 + local.set 3 + block ;; label = @2 + local.get 0 + br_if 0 (;@2;) + local.get 1 + return + end + local.get 0 + i32.const -1 + i32.add + local.set 0 + local.get 1 + local.get 3 + i32.add + local.set 2 + local.get 3 + local.set 1 + br 0 (;@1;) + end + ) + (func $__main (;1;) (type 1) (result i32) + i32.const 25 + call $fib + ) + (memory (;0;) 16) + (global $__stack_pointer (;0;) (mut i32) i32.const 1048576) + (global (;1;) i32 i32.const 1048576) + (global (;2;) i32 i32.const 1048576) + (export "memory" (memory 0)) + (export "fib" (func $fib)) + (export "__main" (func $__main)) + (export "__data_end" (global 1)) + (export "__heap_base" (global 2)) + )"#]], + expect![[r#" + module noname + + pub fn fib(i32) -> i32 { + block0(v0: i32): + v2 = const.int 0 : i32 + v3 = const.int 0 : i32 + v4 = const.int 1 : i32 + br block2(v4, v0, v3) + + block1(v1: i32): + + block2(v6: i32, v7: i32, v8: i32): + condbr v7, block4, block5 + + block3(v5: i32): + + block4: + v10 = const.int -1 : i32 + v11 = add v7, v10 : i32 + v12 = add v8, v6 : i32 + br block2(v12, v11, v6) + + block5: + v9 = ret v8 : () + } + + pub fn __main() -> i32 { + block0: + v1 = const.int 25 : i32 + v2 = call fib(v1) : i32 + br block1(v2) + + block1(v0: i32): + v3 = ret v0 : () + } + "#]], + ); +}