diff --git a/src/backend.rs b/src/backend.rs index a5345496f7..7313f2c05f 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -243,6 +243,20 @@ pub fn store_i32(ctx: &mut Context, local_idx: u32) { ctx.regs.release_scratch_gpr(gpr); } +pub fn relop_eq_i32(ctx: &mut Context) { + let right = pop_i32(ctx); + let left = pop_i32(ctx); + let result = ctx.regs.take_scratch_gpr(); + dynasm!(ctx.asm + ; xor Rq(result), Rq(result) + ; cmp Rd(left), Rd(right) + ; sete Rb(result) + ); + push_i32(ctx, result); + ctx.regs.release_scratch_gpr(left); + ctx.regs.release_scratch_gpr(right); +} + pub fn prepare_return_value(ctx: &mut Context) { let ret_gpr = pop_i32(ctx); if ret_gpr != RAX { diff --git a/src/function_body.rs b/src/function_body.rs index b9f365df33..e3030e492c 100644 --- a/src/function_body.rs +++ b/src/function_body.rs @@ -133,6 +133,9 @@ pub fn translate(session: &mut CodeGenSession, body: &FunctionBody) -> Result<() define_label(&mut ctx, control_frame.kind.br_destination()); } } + Operator::I32Eq => { + relop_eq_i32(&mut ctx); + } Operator::I32Add => { add_i32(&mut ctx); } diff --git a/src/tests.rs b/src/tests.rs index abed2a590e..fea82b12ba 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -31,4 +31,26 @@ fn adds() { } } +#[test] +fn relop_eq() { + const CASES: &[(usize, usize, usize)] = &[ + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + (1, 1, 1), + (1312, 1, 0), + (1312, 1312, 1), + ]; + + let code = r#" +(module + (func (param i32) (param i32) (result i32) (i32.eq (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.