Browse Source
* Implement basics. * Execute code * Add wasm2wat test cases. * abi_loc_for_arg for stack. * Assert that sp_depth is 0 at the epilogue * Do 32bit add. * Assert that RAX can be used as a scratch register * Reuse assembler. * Align stack slots.pull/397/head
Sergey Pepyakin
6 years ago
committed by
Dan Gohman
9 changed files with 334 additions and 68 deletions
@ -1,34 +1,48 @@ |
|||
use backend::*; |
|||
use disassemble::disassemble; |
|||
use error::Error; |
|||
use wasmparser::{FunctionBody, Operator}; |
|||
|
|||
pub fn translate(body: &FunctionBody) -> Result<(), Error> { |
|||
pub fn translate(session: &mut CodeGenSession, body: &FunctionBody) -> Result<(), Error> { |
|||
let locals = body.get_locals_reader()?; |
|||
|
|||
// Assume signature is (i32, i32) -> i32 for now.
|
|||
// TODO: Use a real signature
|
|||
const ARG_COUNT: u32 = 2; |
|||
|
|||
let mut framesize = ARG_COUNT; |
|||
for local in locals { |
|||
local?; // TODO
|
|||
let (count, _ty) = local?; |
|||
framesize += count; |
|||
} |
|||
|
|||
let mut ops = dynasmrt::x64::Assembler::new().unwrap(); |
|||
let mut ctx = session.new_context(); |
|||
let operators = body.get_operators_reader()?; |
|||
let mut regs = Registers::new(); |
|||
|
|||
prologue(&mut ctx, framesize); |
|||
|
|||
for arg_pos in 0..ARG_COUNT { |
|||
copy_incoming_arg(&mut ctx, arg_pos); |
|||
} |
|||
|
|||
for op in operators { |
|||
match op? { |
|||
Operator::I32Add => { |
|||
add_i32(&mut ops, &mut regs); |
|||
add_i32(&mut ctx); |
|||
} |
|||
Operator::GetLocal { local_index } => { |
|||
get_local_i32(&mut ctx, local_index); |
|||
} |
|||
Operator::End => { |
|||
// TODO: This is super naive and makes a lot of unfounded assumptions
|
|||
// but will do for the start.
|
|||
prepare_return_value(&mut ctx); |
|||
} |
|||
_ => { |
|||
unsupported_opcode(&mut ops); |
|||
unsupported_opcode(&mut ctx); |
|||
} |
|||
} |
|||
} |
|||
|
|||
let output = ops |
|||
.finalize() |
|||
.map_err(|_asm| Error::Assembler("assembler error".to_owned()))?; |
|||
|
|||
// TODO: Do something with the output.
|
|||
disassemble(&output)?; |
|||
epilogue(&mut ctx); |
|||
|
|||
Ok(()) |
|||
} |
|||
|
@ -0,0 +1,34 @@ |
|||
use super::{translate, TranslatedModule}; |
|||
use wabt; |
|||
|
|||
fn translate_wat(wat: &str) -> TranslatedModule { |
|||
let wasm = wabt::wat2wasm(wat).unwrap(); |
|||
let compiled = translate(&wasm).unwrap(); |
|||
compiled |
|||
} |
|||
|
|||
/// Execute the first function in the module.
|
|||
fn execute_wat(wat: &str, a: usize, b: usize) -> usize { |
|||
let translated = translate_wat(wat); |
|||
translated.execute_func(0, a, b) |
|||
} |
|||
|
|||
#[test] |
|||
fn adds() { |
|||
const CASES: &[(usize, usize, usize)] = &[ |
|||
(5, 3, 8), |
|||
(0, 228, 228), |
|||
(usize::max_value(), 1, 0), |
|||
]; |
|||
|
|||
let code = r#" |
|||
(module |
|||
(func (param i32) (param i32) (result i32) (i32.add (get_local 0) (get_local 1))) |
|||
) |
|||
"#; |
|||
for (a, b, expected) in CASES { |
|||
assert_eq!(execute_wat(code, *a, *b), *expected); |
|||
} |
|||
} |
|||
|
|||
// TODO: Add a test that checks argument passing via the stack.
|
Loading…
Reference in new issue