Skip to content

Commit

Permalink
Fix {f32,f64}.cmp codegen bug (#881)
Browse files Browse the repository at this point in the history
* add regression tests found via fuzzing

* adjust existing tests to correct codegen

* fix {f32,f64}.cmp codegen bug
  • Loading branch information
Robbepop authored Jan 11, 2024
1 parent ab32d75 commit 548edc8
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 44 deletions.
11 changes: 8 additions & 3 deletions crates/wasmi/src/engine/translator/tests/op/cmp/f32_ge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F32, "ge");
#[test]
#[cfg_attr(miri, ignore)]
fn same_reg() {
let expected = [Instruction::ReturnImm32 {
value: AnyConst32::from(true),
}];
let expected = [
Instruction::f32_ge(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_reg(1),
];
test_binary_same_reg(WASM_OP, expected)
}

Expand Down
11 changes: 8 additions & 3 deletions crates/wasmi/src/engine/translator/tests/op/cmp/f32_le.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F32, "le");
#[test]
#[cfg_attr(miri, ignore)]
fn same_reg() {
let expected = [Instruction::ReturnImm32 {
value: AnyConst32::from(true),
}];
let expected = [
Instruction::f32_le(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_reg(1),
];
test_binary_same_reg(WASM_OP, expected)
}

Expand Down
11 changes: 8 additions & 3 deletions crates/wasmi/src/engine/translator/tests/op/cmp/f64_ge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F64, "ge");
#[test]
#[cfg_attr(miri, ignore)]
fn same_reg() {
let expected = [Instruction::ReturnImm32 {
value: AnyConst32::from(true),
}];
let expected = [
Instruction::f64_ge(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_reg(1),
];
test_binary_same_reg(WASM_OP, expected)
}

Expand Down
11 changes: 8 additions & 3 deletions crates/wasmi/src/engine/translator/tests/op/cmp/f64_le.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F64, "le");
#[test]
#[cfg_attr(miri, ignore)]
fn same_reg() {
let expected = [Instruction::ReturnImm32 {
value: AnyConst32::from(true),
}];
let expected = [
Instruction::f64_le(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_reg(1),
];
test_binary_same_reg(WASM_OP, expected)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(module
(func (param f32)
f32.const -nan:0x7fffff (;=NaN;)
local.tee 0
local.get 0
local.get 0
f32.le
br_if 0
unreachable
)
(func (param f32)
f32.const -nan:0x7fffff (;=NaN;)
local.tee 0
local.get 0
local.get 0
f32.ge
br_if 0
unreachable
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(module
(func (param f64)
f64.const -nan:0xfffffffffffff (;=NaN;)
local.tee 0
local.get 0
local.get 0
f64.le
br_if 0
unreachable
)
(func (param f64)
f64.const -nan:0xfffffffffffff (;=NaN;)
local.tee 0
local.get 0
local.get 0
f64.ge
br_if 0
unreachable
)
)
64 changes: 64 additions & 0 deletions crates/wasmi/src/engine/translator/tests/regression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,67 @@ fn fuzz_regression_11() {
])
.run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn fuzz_regression_12_f32() {
let wat = include_str!("fuzz_12_f32.wat");
let wasm = wat2wasm(wat);
TranslationTest::new(wasm)
.expect_func(ExpectedFunc::new([
Instruction::copy_imm32(Register::from_i16(0), u32::MAX),
Instruction::f32_le(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_nez(1),
Instruction::Trap(TrapCode::UnreachableCodeReached),
]))
.expect_func(ExpectedFunc::new([
Instruction::copy_imm32(Register::from_i16(0), u32::MAX),
Instruction::f32_ge(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_nez(1),
Instruction::Trap(TrapCode::UnreachableCodeReached),
]))
.run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn fuzz_regression_12_f64() {
let wat = include_str!("fuzz_12_f64.wat");
let wasm = wat2wasm(wat);
TranslationTest::new(wasm)
.expect_func(
ExpectedFunc::new([
Instruction::copy(0, -1),
Instruction::f64_le(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_nez(1),
Instruction::Trap(TrapCode::UnreachableCodeReached),
])
.consts([u64::MAX]),
)
.expect_func(
ExpectedFunc::new([
Instruction::copy(0, -1),
Instruction::f64_ge(
Register::from_i16(1),
Register::from_i16(0),
Register::from_i16(0),
),
Instruction::return_nez(1),
Instruction::Trap(TrapCode::UnreachableCodeReached),
])
.consts([u64::MAX]),
)
.run()
}
36 changes: 4 additions & 32 deletions crates/wasmi/src/engine/translator/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1950,14 +1950,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator {
self.translate_fbinary(
Instruction::f32_le,
TypedValue::f32_le,
|this, lhs: Register, rhs: Register| {
if lhs == rhs {
// Optimization: `x < x` is always `true`
this.alloc.stack.push_const(true);
return Ok(true);
}
Ok(false)
},
Self::no_custom_opt,
|this, _lhs: Register, rhs: f32| {
if rhs.is_nan() {
// Optimization: `x <= NAN` is always `false`
Expand All @@ -1981,14 +1974,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator {
self.translate_fbinary(
Instruction::f32_ge,
TypedValue::f32_ge,
|this, lhs: Register, rhs: Register| {
if lhs == rhs {
// Optimization: `x >= x` is always `true`
this.alloc.stack.push_const(true);
return Ok(true);
}
Ok(false)
},
Self::no_custom_opt,
|this, _lhs: Register, rhs: f32| {
if rhs.is_nan() {
// Optimization: `x >= NAN` is always `false`
Expand Down Expand Up @@ -2126,14 +2112,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator {
self.translate_fbinary(
Instruction::f64_le,
TypedValue::f64_le,
|this, lhs: Register, rhs: Register| {
if lhs == rhs {
// Optimization: `x < x` is always `true`
this.alloc.stack.push_const(true);
return Ok(true);
}
Ok(false)
},
Self::no_custom_opt,
|this, _lhs: Register, rhs: f64| {
if rhs.is_nan() {
// Optimization: `x <= NAN` is always `false`
Expand All @@ -2157,14 +2136,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator {
self.translate_fbinary(
Instruction::f64_ge,
TypedValue::f64_ge,
|this, lhs: Register, rhs: Register| {
if lhs == rhs {
// Optimization: `x >= x` is always `true`
this.alloc.stack.push_const(true);
return Ok(true);
}
Ok(false)
},
Self::no_custom_opt,
|this, _lhs: Register, rhs: f64| {
if rhs.is_nan() {
// Optimization: `x >= NAN` is always `false`
Expand Down

0 comments on commit 548edc8

Please sign in to comment.