From 7ebee2ed36069fcfdd4b0b7f587a605ca12db88a Mon Sep 17 00:00:00 2001 From: l-m Date: Mon, 2 Oct 2023 11:42:02 +0000 Subject: [PATCH] examples: add a brainfuck->wasm compiler example (#19492) --- examples/wasm_codegen/bf_compiler.v | 132 ++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 examples/wasm_codegen/bf_compiler.v diff --git a/examples/wasm_codegen/bf_compiler.v b/examples/wasm_codegen/bf_compiler.v new file mode 100644 index 00000000000000..3a4b47f28a6bf4 --- /dev/null +++ b/examples/wasm_codegen/bf_compiler.v @@ -0,0 +1,132 @@ +import os +import wasm + +const runtime_page = 1024 * 64 // 64 KiBs + +fn generate_ciovec(mut start wasm.Function, sp wasm.LocalIndex) { + // construct struct __wasi_ciovec_t + // + // field, `const uint8_t *buf` + start.i32_const(runtime_page) + start.local_get(sp) + start.store(.i32_t, 2, 0) + // field, `__wasi_size_t buf_len` + start.i32_const(runtime_page) + start.i32_const(1) // len + start.store(.i32_t, 2, 4) +} + +fn generate_code(mut start wasm.Function, bf_expr string) { + // locals are initialised to zero, by spec + sp := start.new_local_named(.i32_t, 'sp') + + mut loop_labels := []wasm.LabelIndex{} + mut block_labels := []wasm.LabelIndex{} + + // our page, the second one + + for ch in bf_expr { + match ch { + `>` { + start.local_get(sp) + start.i32_const(1) + start.add(.i32_t) + start.local_set(sp) + } + `<` { + start.local_get(sp) + start.i32_const(1) + start.sub(.i32_t) + start.local_set(sp) + } + `+` { + start.local_get(sp) + { + start.local_get(sp) + start.load8(.i32_t, false, 0, 0) + start.i32_const(1) + start.add(.i32_t) + } + start.store8(.i32_t, 0, 0) + } + `-` { + start.local_get(sp) + { + start.local_get(sp) + start.load8(.i32_t, false, 0, 0) + start.i32_const(1) + start.sub(.i32_t) + } + start.store8(.i32_t, 0, 0) + } + `.` { + generate_ciovec(mut start, sp) + + start.i32_const(1) // stdout + start.i32_const(runtime_page) // *iovs + start.i32_const(1) // iovs_len + start.i32_const(runtime_page + 1024) // *nwritten + start.call_import('wasi_unstable', 'fd_write') + start.drop() // ignore errno + } + `,` { + generate_ciovec(mut start, sp) + + start.i32_const(0) // stdin + start.i32_const(runtime_page) // *iovs + start.i32_const(1) // iovs_len + start.i32_const(runtime_page + 1024) // *nwritten + start.call_import('wasi_unstable', 'fd_read') + start.drop() // ignore errno + } + `[` { + block_lbl := start.c_block([], []) + loop_lbl := start.c_loop([], []) + { + start.local_get(sp) + start.load8(.i32_t, false, 0, 0) + start.eqz(.i32_t) + start.c_br_if(block_lbl) + } + loop_labels << loop_lbl + block_labels << block_lbl + } + `]` { + loop_lbl := loop_labels.pop() + start.c_br(loop_lbl) // jump back to top + start.c_end(loop_lbl) + start.c_end(block_labels.pop()) + } + else {} + } + } +} + +@[noreturn] +fn usage() { + eprintln('Usage: bf ') + exit(1) +} + +fn main() { + bf_expr := os.args[1] or { usage() } + + outfile := os.args[2] or { usage() } + + mut m := wasm.Module{} + m.enable_debug('wasm bf') + m.new_function_import('wasi_unstable', 'fd_write', [.i32_t, .i32_t, .i32_t, .i32_t], + [.i32_t]) + m.new_function_import('wasi_unstable', 'fd_read', [.i32_t, .i32_t, .i32_t, .i32_t], + [.i32_t]) + m.assign_memory('memory', true, 2, none) + + mut start := m.new_function('_start', [], []) + { + generate_code(mut start, bf_expr) + } + m.commit(start, true) + + bytes := m.compile() + os.write_file_array(outfile, bytes)! +}