diff --git a/crates/ir/src/enum.rs b/crates/ir/src/enum.rs index 15e225c021..bd44f4b959 100644 --- a/crates/ir/src/enum.rs +++ b/crates/ir/src/enum.rs @@ -79,6 +79,63 @@ macro_rules! define_enum { } for_each_op::for_each_op!(define_enum); +/// Helper trait for [`Instruction::result`] method implementation. +trait IntoReg: Sized { + /// Converts `self` into a [`Reg`] if possible. + fn into_reg(self) -> Option { + None + } +} + +impl IntoReg for Reg { + fn into_reg(self) -> Option { + Some(self) + } +} +impl IntoReg for RegSpan {} +impl IntoReg for FixedRegSpan {} +impl IntoReg for () {} + +macro_rules! define_result { + ( + $( + $( #[doc = $doc:literal] )* + #[snake_name($snake_name:ident)] + $name:ident + $( + { + $( + @ $result_name:ident: $result_ty:ty, + )? + $( + $( #[$field_docs:meta] )* + $field_name:ident: $field_ty:ty + ),* + $(,)? + } + )? + ),* $(,)? + ) => { + impl Instruction { + /// Returns the result [`Reg`] for `self`. + /// + /// Returns `None` if `self` does not statically return a single [`Reg`]. + pub fn result(&self) -> Option<$crate::Reg> { + match *self { + $( + Self::$name { $( $( $result_name, )? )* .. } => { + IntoReg::into_reg(( + $( $( $result_name )? )* + )) + } + )* + } + } + } + }; +} +for_each_op::for_each_op!(define_result); + impl Instruction { /// Creates a new [`Instruction::ReturnReg2`] for the given [`Reg`] indices. pub fn return_reg2_ext(reg0: impl Into, reg1: impl Into) -> Self { diff --git a/crates/ir/src/for_each_op.rs b/crates/ir/src/for_each_op.rs index 346e2109be..f1870de819 100644 --- a/crates/ir/src/for_each_op.rs +++ b/crates/ir/src/for_each_op.rs @@ -442,6 +442,16 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, + /// A fused `i32.lt_s` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i32_lt_s_imm16_lhs)] + BranchI32LtSImm16Lhs { + /// The right-hand side operand to the conditional operator. + lhs: Const16, + /// The left-hand side operand to the conditional operator. + rhs: Reg, + /// The 16-bit encoded branch offset. + offset: BranchOffset16, + }, /// A fused `i32.lt_s` and branch instruction with 16-bit immediate `rhs` value. #[snake_name(branch_i32_lt_s_imm16_rhs)] BranchI32LtSImm16Rhs { @@ -462,6 +472,16 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, + /// A fused `i32.lt_u` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i32_lt_u_imm16_lhs)] + BranchI32LtUImm16Lhs { + /// The right-hand side operand to the conditional operator. + lhs: Const16, + /// The left-hand side operand to the conditional operator. + rhs: Reg, + /// The 16-bit encoded branch offset. + offset: BranchOffset16, + }, /// A fused `i32.lt_u` and branch instruction with 16-bit immediate `rhs` value. #[snake_name(branch_i32_lt_u_imm16_rhs)] BranchI32LtUImm16Rhs { @@ -482,49 +502,19 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i32.le_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_le_s_imm16_rhs)] - BranchI32LeSImm16Rhs { - /// The left-hand side operand to the conditional operator. - lhs: Reg, + /// A fused `i32.le_s` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i32_le_s_imm16_lhs)] + BranchI32LeSImm16Lhs { /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.le_u` and branch instruction. - #[snake_name(branch_i32_le_u)] - BranchI32LeU { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.le_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_le_u_imm16_rhs)] - BranchI32LeUImm16Rhs { + lhs: Const16, /// The left-hand side operand to the conditional operator. - lhs: Reg, - /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.gt_s` and branch instruction. - #[snake_name(branch_i32_gt_s)] - BranchI32GtS { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. rhs: Reg, /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i32.gt_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_gt_s_imm16_rhs)] - BranchI32GtSImm16Rhs { + /// A fused `i32.le_s` and branch instruction with 16-bit immediate `rhs` value. + #[snake_name(branch_i32_le_s_imm16_rhs)] + BranchI32LeSImm16Rhs { /// The left-hand side operand to the conditional operator. lhs: Reg, /// The right-hand side operand to the conditional operator. @@ -532,9 +522,9 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i32.gt_u` and branch instruction. - #[snake_name(branch_i32_gt_u)] - BranchI32GtU { + /// A fused `i32.le_u` and branch instruction. + #[snake_name(branch_i32_le_u)] + BranchI32LeU { /// The left-hand side operand to the branch conditional. lhs: Reg, /// The right-hand side operand to the branch conditional. @@ -542,49 +532,19 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i32.gt_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_gt_u_imm16_rhs)] - BranchI32GtUImm16Rhs { - /// The left-hand side operand to the conditional operator. - lhs: Reg, + /// A fused `i32.le_u` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i32_le_u_imm16_lhs)] + BranchI32LeUImm16Lhs { /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.ge_s` and branch instruction. - #[snake_name(branch_i32_ge_s)] - BranchI32GeS { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.ge_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_ge_s_imm16_rhs)] - BranchI32GeSImm16Rhs { + lhs: Const16, /// The left-hand side operand to the conditional operator. - lhs: Reg, - /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i32.ge_u` and branch instruction. - #[snake_name(branch_i32_ge_u)] - BranchI32GeU { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. rhs: Reg, /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i32.ge_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i32_ge_u_imm16_rhs)] - BranchI32GeUImm16Rhs { + /// A fused `i32.le_u` and branch instruction with 16-bit immediate `rhs` value. + #[snake_name(branch_i32_le_u_imm16_rhs)] + BranchI32LeUImm16Rhs { /// The left-hand side operand to the conditional operator. lhs: Reg, /// The right-hand side operand to the conditional operator. @@ -644,6 +604,16 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, + /// A fused `i64.lt_s` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i64_lt_s_imm16_lhs)] + BranchI64LtSImm16Lhs { + /// The right-hand side operand to the conditional operator. + lhs: Const16, + /// The left-hand side operand to the conditional operator. + rhs: Reg, + /// The 16-bit encoded branch offset. + offset: BranchOffset16, + }, /// A fused `i64.lt_s` and branch instruction with 16-bit immediate `rhs` value. #[snake_name(branch_i64_lt_s_imm16_rhs)] BranchI64LtSImm16Rhs { @@ -664,6 +634,16 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, + /// A fused `i64.lt_u` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i64_lt_u_imm16_lhs)] + BranchI64LtUImm16Lhs { + /// The right-hand side operand to the conditional operator. + lhs: Const16, + /// The left-hand side operand to the conditional operator. + rhs: Reg, + /// The 16-bit encoded branch offset. + offset: BranchOffset16, + }, /// A fused `i64.lt_u` and branch instruction with 16-bit immediate `rhs` value. #[snake_name(branch_i64_lt_u_imm16_rhs)] BranchI64LtUImm16Rhs { @@ -684,49 +664,19 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i64.le_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_le_s_imm16_rhs)] - BranchI64LeSImm16Rhs { - /// The left-hand side operand to the conditional operator. - lhs: Reg, + /// A fused `i64.le_s` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i64_le_s_imm16_lhs)] + BranchI64LeSImm16Lhs { /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.le_u` and branch instruction. - #[snake_name(branch_i64_le_u)] - BranchI64LeU { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.le_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_le_u_imm16_rhs)] - BranchI64LeUImm16Rhs { + lhs: Const16, /// The left-hand side operand to the conditional operator. - lhs: Reg, - /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.gt_s` and branch instruction. - #[snake_name(branch_i64_gt_s)] - BranchI64GtS { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. rhs: Reg, /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i64.gt_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_gt_s_imm16_rhs)] - BranchI64GtSImm16Rhs { + /// A fused `i64.le_s` and branch instruction with 16-bit immediate `rhs` value. + #[snake_name(branch_i64_le_s_imm16_rhs)] + BranchI64LeSImm16Rhs { /// The left-hand side operand to the conditional operator. lhs: Reg, /// The right-hand side operand to the conditional operator. @@ -734,9 +684,9 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i64.gt_u` and branch instruction. - #[snake_name(branch_i64_gt_u)] - BranchI64GtU { + /// A fused `i64.le_u` and branch instruction. + #[snake_name(branch_i64_le_u)] + BranchI64LeU { /// The left-hand side operand to the branch conditional. lhs: Reg, /// The right-hand side operand to the branch conditional. @@ -744,49 +694,19 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i64.gt_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_gt_u_imm16_rhs)] - BranchI64GtUImm16Rhs { - /// The left-hand side operand to the conditional operator. - lhs: Reg, + /// A fused `i64.le_u` and branch instruction with 16-bit immediate `lhs` value. + #[snake_name(branch_i64_le_u_imm16_lhs)] + BranchI64LeUImm16Lhs { /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.ge_s` and branch instruction. - #[snake_name(branch_i64_ge_s)] - BranchI64GeS { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.ge_s` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_ge_s_imm16_rhs)] - BranchI64GeSImm16Rhs { + lhs: Const16, /// The left-hand side operand to the conditional operator. - lhs: Reg, - /// The right-hand side operand to the conditional operator. - rhs: Const16, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `i64.ge_u` and branch instruction. - #[snake_name(branch_i64_ge_u)] - BranchI64GeU { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. rhs: Reg, /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `i64.ge_u` and branch instruction with 16-bit immediate `rhs` value. - #[snake_name(branch_i64_ge_u_imm16_rhs)] - BranchI64GeUImm16Rhs { + /// A fused `i64.le_u` and branch instruction with 16-bit immediate `rhs` value. + #[snake_name(branch_i64_le_u_imm16_rhs)] + BranchI64LeUImm16Rhs { /// The left-hand side operand to the conditional operator. lhs: Reg, /// The right-hand side operand to the conditional operator. @@ -836,26 +756,6 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `f32.gt` and branch instruction. - #[snake_name(branch_f32_gt)] - BranchF32Gt { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `f32.ge` and branch instruction. - #[snake_name(branch_f32_ge)] - BranchF32Ge { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, /// A fused `f64.eq` and branch instruction. #[snake_name(branch_f64_eq)] @@ -898,26 +798,6 @@ macro_rules! for_each_op { /// The 16-bit encoded branch offset. offset: BranchOffset16, }, - /// A fused `f64.gt` and branch instruction. - #[snake_name(branch_f64_gt)] - BranchF64Gt { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, - /// A fused `f64.ge` and branch instruction. - #[snake_name(branch_f64_ge)] - BranchF64Ge { - /// The left-hand side operand to the branch conditional. - lhs: Reg, - /// The right-hand side operand to the branch conditional. - rhs: Reg, - /// The 16-bit encoded branch offset. - offset: BranchOffset16, - }, /// A Wasm `br_table` equivalent Wasmi instruction. /// @@ -2991,6 +2871,15 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, + /// Wasm `i32.lt_s` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i32_lt_s_imm16_lhs)] + I32LtSImm16Lhs{ + @result: Reg, + /// The 16-bit immediate value. + lhs: Const16, + /// The register holding one of the operands. + rhs: Reg, + }, /// Wasm `i32.lt_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. #[snake_name(i32_lt_s_imm16_rhs)] I32LtSImm16Rhs{ @@ -3009,46 +2898,18 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i32.lt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_lt_u_imm16_rhs)] - I32LtUImm16Rhs{ + /// Wasm `i32.lt_u` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i32_lt_u_imm16_lhs)] + I32LtUImm16Lhs{ @result: Reg, - /// The register holding one of the operands. - lhs: Reg, /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i32.gt_s` equivalent Wasmi instruction. - #[snake_name(i32_gt_s)] - I32GtS{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `i32.gt_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_gt_s_imm16_rhs)] - I32GtSImm16Rhs{ - @result: Reg, + lhs: Const16, /// The register holding one of the operands. - lhs: Reg, - /// The 16-bit immediate value. - rhs: Const16, - }, - /// Wasm `i32.gt_u` equivalent Wasmi instruction. - #[snake_name(i32_gt_u)] - I32GtU{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i32.gt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_gt_u_imm16_rhs)] - I32GtUImm16Rhs{ + /// Wasm `i32.lt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. + #[snake_name(i32_lt_u_imm16_rhs)] + I32LtUImm16Rhs{ @result: Reg, /// The register holding one of the operands. lhs: Reg, @@ -3065,6 +2926,15 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, + /// Wasm `i32.le_s` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i32_le_s_imm16_lhs)] + I32LeSImm16Lhs{ + @result: Reg, + /// The 16-bit immediate value. + lhs: Const16, + /// The register holding one of the operands. + rhs: Reg, + }, /// Wasm `i32.le_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. #[snake_name(i32_le_s_imm16_rhs)] I32LeSImm16Rhs{ @@ -3083,46 +2953,18 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i32.le_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_le_u_imm16_rhs)] - I32LeUImm16Rhs{ + /// Wasm `i32.le_u` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i32_le_u_imm16_lhs)] + I32LeUImm16Lhs{ @result: Reg, - /// The register holding one of the operands. - lhs: Reg, /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i32.ge_s` equivalent Wasmi instruction. - #[snake_name(i32_ge_s)] - I32GeS{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `i32.ge_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_ge_s_imm16_rhs)] - I32GeSImm16Rhs{ - @result: Reg, + lhs: Const16, /// The register holding one of the operands. - lhs: Reg, - /// The 16-bit immediate value. - rhs: Const16, - }, - /// Wasm `i32.ge_u` equivalent Wasmi instruction. - #[snake_name(i32_ge_u)] - I32GeU{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i32.ge_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i32_ge_u_imm16_rhs)] - I32GeUImm16Rhs{ + /// Wasm `i32.le_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. + #[snake_name(i32_le_u_imm16_rhs)] + I32LeUImm16Rhs{ @result: Reg, /// The register holding one of the operands. lhs: Reg, @@ -3177,6 +3019,15 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, + /// Wasm `i64.lt_s` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i64_lt_s_imm16_lhs)] + I64LtSImm16Lhs{ + @result: Reg, + /// The 16-bit immediate value. + lhs: Const16, + /// The register holding one of the operands. + rhs: Reg, + }, /// Wasm `i64.lt_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. #[snake_name(i64_lt_s_imm16_rhs)] I64LtSImm16Rhs{ @@ -3187,7 +3038,7 @@ macro_rules! for_each_op { rhs: Const16, }, - /// Wasm `i64.lt_s` equivalent Wasmi instruction. + /// Wasm `i64.lt_u` equivalent Wasmi instruction. #[snake_name(i64_lt_u)] I64LtU{ @result: Reg, @@ -3196,47 +3047,18 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i64.lt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_lt_u_imm16_rhs)] - I64LtUImm16Rhs{ + /// Wasm `i64.lt_u` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i64_lt_u_imm16_lhs)] + I64LtUImm16Lhs{ @result: Reg, - /// The register holding one of the operands. - lhs: Reg, /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i64.gt_s` equivalent Wasmi instruction. - #[snake_name(i64_gt_s)] - I64GtS{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `i64.gt_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_gt_s_imm16_rhs)] - I64GtSImm16Rhs{ - @result: Reg, + lhs: Const16, /// The register holding one of the operands. - lhs: Reg, - /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i64.gt_u` equivalent Wasmi instruction. - #[snake_name(i64_gt_u)] - I64GtU{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i64.gt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_gt_u_imm16_rhs)] - I64GtUImm16Rhs{ + /// Wasm `i64.lt_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. + #[snake_name(i64_lt_u_imm16_rhs)] + I64LtUImm16Rhs{ @result: Reg, /// The register holding one of the operands. lhs: Reg, @@ -3253,6 +3075,15 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, + /// Wasm `i64.le_s` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i64_le_s_imm16_lhs)] + I64LeSImm16Lhs{ + @result: Reg, + /// The 16-bit immediate value. + lhs: Const16, + /// The register holding one of the operands. + rhs: Reg, + }, /// Wasm `i64.le_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. #[snake_name(i64_le_s_imm16_rhs)] I64LeSImm16Rhs{ @@ -3272,47 +3103,18 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i64.le_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_le_u_imm16_rhs)] - I64LeUImm16Rhs{ + /// Wasm `i64.le_u` equivalent Wasmi instruction with 16-bit immediate `lhs` value. + #[snake_name(i64_le_u_imm16_lhs)] + I64LeUImm16Lhs{ @result: Reg, - /// The register holding one of the operands. - lhs: Reg, /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i64.ge_s` equivalent Wasmi instruction. - #[snake_name(i64_ge_s)] - I64GeS{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `i64.ge_s` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_ge_s_imm16_rhs)] - I64GeSImm16Rhs{ - @result: Reg, + lhs: Const16, /// The register holding one of the operands. - lhs: Reg, - /// The 16-bit immediate value. - rhs: Const16, - }, - - /// Wasm `i64.ge_u` equivalent Wasmi instruction. - #[snake_name(i64_ge_u)] - I64GeU{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `i64.ge_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. - #[snake_name(i64_ge_u_imm16_rhs)] - I64GeUImm16Rhs{ + /// Wasm `i64.le_u` equivalent Wasmi instruction with 16-bit immediate `rhs` value. + #[snake_name(i64_le_u_imm16_rhs)] + I64LeUImm16Rhs{ @result: Reg, /// The register holding one of the operands. lhs: Reg, @@ -3356,24 +3158,6 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `f32.gt` equivalent Wasmi instruction. - #[snake_name(f32_gt)] - F32Gt{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `f32.ge` equivalent Wasmi instruction. - #[snake_name(f32_ge)] - F32Ge{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, /// Wasm `f64.eq` equivalent Wasmi instruction. #[snake_name(f64_eq)] @@ -3411,24 +3195,6 @@ macro_rules! for_each_op { /// The register holding the right-hand side value. rhs: Reg, }, - /// Wasm `f64.gt` equivalent Wasmi instruction. - #[snake_name(f64_gt)] - F64Gt{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, - /// Wasm `f64.ge` equivalent Wasmi instruction. - #[snake_name(f64_ge)] - F64Ge{ - @result: Reg, - /// The register holding the left-hand side value. - lhs: Reg, - /// The register holding the right-hand side value. - rhs: Reg, - }, /// `i32` count-leading-zeros (clz) instruction. #[snake_name(i32_clz)] diff --git a/crates/ir/src/primitive.rs b/crates/ir/src/primitive.rs index 1972ea5a05..30b74397fd 100644 --- a/crates/ir/src/primitive.rs +++ b/crates/ir/src/primitive.rs @@ -244,10 +244,6 @@ macro_rules! for_each_comparator { I32LtU, I32LeS, I32LeU, - I32GtS, - I32GtU, - I32GeS, - I32GeU, I32And, I32Or, @@ -262,23 +258,16 @@ macro_rules! for_each_comparator { I64LtU, I64LeS, I64LeU, - I64GtS, - I64GtU, - I64GeS, - I64GeU, F32Eq, F32Ne, F32Lt, F32Le, - F32Gt, - F32Ge, + F64Eq, F64Ne, F64Lt, F64Le, - F64Gt, - F64Ge, } }; } diff --git a/crates/wasmi/src/engine/executor/instrs.rs b/crates/wasmi/src/engine/executor/instrs.rs index 67efe92938..4efebedfe3 100644 --- a/crates/wasmi/src/engine/executor/instrs.rs +++ b/crates/wasmi/src/engine/executor/instrs.rs @@ -265,51 +265,39 @@ impl<'engine> Executor<'engine> { Instr::BranchI32LtS { lhs, rhs, offset } => { self.execute_branch_i32_lt_s(lhs, rhs, offset) } + Instr::BranchI32LtSImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i32_lt_s_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI32LtSImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i32_lt_s_imm16_rhs(lhs, rhs, offset) } Instr::BranchI32LtU { lhs, rhs, offset } => { self.execute_branch_i32_lt_u(lhs, rhs, offset) } + Instr::BranchI32LtUImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i32_lt_u_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI32LtUImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i32_lt_u_imm16_rhs(lhs, rhs, offset) } Instr::BranchI32LeS { lhs, rhs, offset } => { self.execute_branch_i32_le_s(lhs, rhs, offset) } + Instr::BranchI32LeSImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i32_le_s_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI32LeSImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i32_le_s_imm16_rhs(lhs, rhs, offset) } Instr::BranchI32LeU { lhs, rhs, offset } => { self.execute_branch_i32_le_u(lhs, rhs, offset) } + Instr::BranchI32LeUImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i32_le_u_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI32LeUImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i32_le_u_imm16_rhs(lhs, rhs, offset) } - Instr::BranchI32GtS { lhs, rhs, offset } => { - self.execute_branch_i32_gt_s(lhs, rhs, offset) - } - Instr::BranchI32GtSImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i32_gt_s_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI32GtU { lhs, rhs, offset } => { - self.execute_branch_i32_gt_u(lhs, rhs, offset) - } - Instr::BranchI32GtUImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i32_gt_u_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI32GeS { lhs, rhs, offset } => { - self.execute_branch_i32_ge_s(lhs, rhs, offset) - } - Instr::BranchI32GeSImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i32_ge_s_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI32GeU { lhs, rhs, offset } => { - self.execute_branch_i32_ge_u(lhs, rhs, offset) - } - Instr::BranchI32GeUImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i32_ge_u_imm16_rhs(lhs, rhs, offset) - } Instr::BranchI64Eq { lhs, rhs, offset } => { self.execute_branch_i64_eq(lhs, rhs, offset) } @@ -325,51 +313,39 @@ impl<'engine> Executor<'engine> { Instr::BranchI64LtS { lhs, rhs, offset } => { self.execute_branch_i64_lt_s(lhs, rhs, offset) } + Instr::BranchI64LtSImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i64_lt_s_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI64LtSImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i64_lt_s_imm16_rhs(lhs, rhs, offset) } Instr::BranchI64LtU { lhs, rhs, offset } => { self.execute_branch_i64_lt_u(lhs, rhs, offset) } + Instr::BranchI64LtUImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i64_lt_u_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI64LtUImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i64_lt_u_imm16_rhs(lhs, rhs, offset) } Instr::BranchI64LeS { lhs, rhs, offset } => { self.execute_branch_i64_le_s(lhs, rhs, offset) } + Instr::BranchI64LeSImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i64_le_s_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI64LeSImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i64_le_s_imm16_rhs(lhs, rhs, offset) } Instr::BranchI64LeU { lhs, rhs, offset } => { self.execute_branch_i64_le_u(lhs, rhs, offset) } + Instr::BranchI64LeUImm16Lhs { lhs, rhs, offset } => { + self.execute_branch_i64_le_u_imm16_lhs(lhs, rhs, offset) + } Instr::BranchI64LeUImm16Rhs { lhs, rhs, offset } => { self.execute_branch_i64_le_u_imm16_rhs(lhs, rhs, offset) } - Instr::BranchI64GtS { lhs, rhs, offset } => { - self.execute_branch_i64_gt_s(lhs, rhs, offset) - } - Instr::BranchI64GtSImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i64_gt_s_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI64GtU { lhs, rhs, offset } => { - self.execute_branch_i64_gt_u(lhs, rhs, offset) - } - Instr::BranchI64GtUImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i64_gt_u_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI64GeS { lhs, rhs, offset } => { - self.execute_branch_i64_ge_s(lhs, rhs, offset) - } - Instr::BranchI64GeSImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i64_ge_s_imm16_rhs(lhs, rhs, offset) - } - Instr::BranchI64GeU { lhs, rhs, offset } => { - self.execute_branch_i64_ge_u(lhs, rhs, offset) - } - Instr::BranchI64GeUImm16Rhs { lhs, rhs, offset } => { - self.execute_branch_i64_ge_u_imm16_rhs(lhs, rhs, offset) - } Instr::BranchF32Eq { lhs, rhs, offset } => { self.execute_branch_f32_eq(lhs, rhs, offset) } @@ -382,12 +358,6 @@ impl<'engine> Executor<'engine> { Instr::BranchF32Le { lhs, rhs, offset } => { self.execute_branch_f32_le(lhs, rhs, offset) } - Instr::BranchF32Gt { lhs, rhs, offset } => { - self.execute_branch_f32_gt(lhs, rhs, offset) - } - Instr::BranchF32Ge { lhs, rhs, offset } => { - self.execute_branch_f32_ge(lhs, rhs, offset) - } Instr::BranchF64Eq { lhs, rhs, offset } => { self.execute_branch_f64_eq(lhs, rhs, offset) } @@ -400,12 +370,6 @@ impl<'engine> Executor<'engine> { Instr::BranchF64Le { lhs, rhs, offset } => { self.execute_branch_f64_le(lhs, rhs, offset) } - Instr::BranchF64Gt { lhs, rhs, offset } => { - self.execute_branch_f64_gt(lhs, rhs, offset) - } - Instr::BranchF64Ge { lhs, rhs, offset } => { - self.execute_branch_f64_ge(lhs, rhs, offset) - } Instr::Copy { result, value } => self.execute_copy(result, value), Instr::Copy2 { results, values } => self.execute_copy_2(results, values), Instr::CopyImm32 { result, value } => self.execute_copy_imm32(result, value), @@ -811,36 +775,32 @@ impl<'engine> Executor<'engine> { self.execute_i32_ne_imm16(result, lhs, rhs) } Instr::I32LtS { result, lhs, rhs } => self.execute_i32_lt_s(result, lhs, rhs), + Instr::I32LtSImm16Lhs { result, lhs, rhs } => { + self.execute_i32_lt_s_imm16_lhs(result, lhs, rhs) + } Instr::I32LtSImm16Rhs { result, lhs, rhs } => { - self.execute_i32_lt_s_imm16(result, lhs, rhs) + self.execute_i32_lt_s_imm16_rhs(result, lhs, rhs) } Instr::I32LtU { result, lhs, rhs } => self.execute_i32_lt_u(result, lhs, rhs), + Instr::I32LtUImm16Lhs { result, lhs, rhs } => { + self.execute_i32_lt_u_imm16_lhs(result, lhs, rhs) + } Instr::I32LtUImm16Rhs { result, lhs, rhs } => { - self.execute_i32_lt_u_imm16(result, lhs, rhs) + self.execute_i32_lt_u_imm16_rhs(result, lhs, rhs) } Instr::I32LeS { result, lhs, rhs } => self.execute_i32_le_s(result, lhs, rhs), + Instr::I32LeSImm16Lhs { result, lhs, rhs } => { + self.execute_i32_le_s_imm16_lhs(result, lhs, rhs) + } Instr::I32LeSImm16Rhs { result, lhs, rhs } => { - self.execute_i32_le_s_imm16(result, lhs, rhs) + self.execute_i32_le_s_imm16_rhs(result, lhs, rhs) } Instr::I32LeU { result, lhs, rhs } => self.execute_i32_le_u(result, lhs, rhs), - Instr::I32LeUImm16Rhs { result, lhs, rhs } => { - self.execute_i32_le_u_imm16(result, lhs, rhs) - } - Instr::I32GtS { result, lhs, rhs } => self.execute_i32_gt_s(result, lhs, rhs), - Instr::I32GtSImm16Rhs { result, lhs, rhs } => { - self.execute_i32_gt_s_imm16(result, lhs, rhs) + Instr::I32LeUImm16Lhs { result, lhs, rhs } => { + self.execute_i32_le_u_imm16_lhs(result, lhs, rhs) } - Instr::I32GtU { result, lhs, rhs } => self.execute_i32_gt_u(result, lhs, rhs), - Instr::I32GtUImm16Rhs { result, lhs, rhs } => { - self.execute_i32_gt_u_imm16(result, lhs, rhs) - } - Instr::I32GeS { result, lhs, rhs } => self.execute_i32_ge_s(result, lhs, rhs), - Instr::I32GeSImm16Rhs { result, lhs, rhs } => { - self.execute_i32_ge_s_imm16(result, lhs, rhs) - } - Instr::I32GeU { result, lhs, rhs } => self.execute_i32_ge_u(result, lhs, rhs), - Instr::I32GeUImm16Rhs { result, lhs, rhs } => { - self.execute_i32_ge_u_imm16(result, lhs, rhs) + Instr::I32LeUImm16Rhs { result, lhs, rhs } => { + self.execute_i32_le_u_imm16_rhs(result, lhs, rhs) } Instr::I64Eq { result, lhs, rhs } => self.execute_i64_eq(result, lhs, rhs), Instr::I64EqImm16 { result, lhs, rhs } => { @@ -851,49 +811,41 @@ impl<'engine> Executor<'engine> { self.execute_i64_ne_imm16(result, lhs, rhs) } Instr::I64LtS { result, lhs, rhs } => self.execute_i64_lt_s(result, lhs, rhs), + Instr::I64LtSImm16Lhs { result, lhs, rhs } => { + self.execute_i64_lt_s_imm16_lhs(result, lhs, rhs) + } Instr::I64LtSImm16Rhs { result, lhs, rhs } => { - self.execute_i64_lt_s_imm16(result, lhs, rhs) + self.execute_i64_lt_s_imm16_rhs(result, lhs, rhs) } Instr::I64LtU { result, lhs, rhs } => self.execute_i64_lt_u(result, lhs, rhs), + Instr::I64LtUImm16Lhs { result, lhs, rhs } => { + self.execute_i64_lt_u_imm16_lhs(result, lhs, rhs) + } Instr::I64LtUImm16Rhs { result, lhs, rhs } => { - self.execute_i64_lt_u_imm16(result, lhs, rhs) + self.execute_i64_lt_u_imm16_rhs(result, lhs, rhs) } Instr::I64LeS { result, lhs, rhs } => self.execute_i64_le_s(result, lhs, rhs), + Instr::I64LeSImm16Lhs { result, lhs, rhs } => { + self.execute_i64_le_s_imm16_lhs(result, lhs, rhs) + } Instr::I64LeSImm16Rhs { result, lhs, rhs } => { - self.execute_i64_le_s_imm16(result, lhs, rhs) + self.execute_i64_le_s_imm16_rhs(result, lhs, rhs) } Instr::I64LeU { result, lhs, rhs } => self.execute_i64_le_u(result, lhs, rhs), - Instr::I64LeUImm16Rhs { result, lhs, rhs } => { - self.execute_i64_le_u_imm16(result, lhs, rhs) - } - Instr::I64GtS { result, lhs, rhs } => self.execute_i64_gt_s(result, lhs, rhs), - Instr::I64GtSImm16Rhs { result, lhs, rhs } => { - self.execute_i64_gt_s_imm16(result, lhs, rhs) - } - Instr::I64GtU { result, lhs, rhs } => self.execute_i64_gt_u(result, lhs, rhs), - Instr::I64GtUImm16Rhs { result, lhs, rhs } => { - self.execute_i64_gt_u_imm16(result, lhs, rhs) + Instr::I64LeUImm16Lhs { result, lhs, rhs } => { + self.execute_i64_le_u_imm16_lhs(result, lhs, rhs) } - Instr::I64GeS { result, lhs, rhs } => self.execute_i64_ge_s(result, lhs, rhs), - Instr::I64GeSImm16Rhs { result, lhs, rhs } => { - self.execute_i64_ge_s_imm16(result, lhs, rhs) - } - Instr::I64GeU { result, lhs, rhs } => self.execute_i64_ge_u(result, lhs, rhs), - Instr::I64GeUImm16Rhs { result, lhs, rhs } => { - self.execute_i64_ge_u_imm16(result, lhs, rhs) + Instr::I64LeUImm16Rhs { result, lhs, rhs } => { + self.execute_i64_le_u_imm16_rhs(result, lhs, rhs) } Instr::F32Eq { result, lhs, rhs } => self.execute_f32_eq(result, lhs, rhs), Instr::F32Ne { result, lhs, rhs } => self.execute_f32_ne(result, lhs, rhs), Instr::F32Lt { result, lhs, rhs } => self.execute_f32_lt(result, lhs, rhs), Instr::F32Le { result, lhs, rhs } => self.execute_f32_le(result, lhs, rhs), - Instr::F32Gt { result, lhs, rhs } => self.execute_f32_gt(result, lhs, rhs), - Instr::F32Ge { result, lhs, rhs } => self.execute_f32_ge(result, lhs, rhs), Instr::F64Eq { result, lhs, rhs } => self.execute_f64_eq(result, lhs, rhs), Instr::F64Ne { result, lhs, rhs } => self.execute_f64_ne(result, lhs, rhs), Instr::F64Lt { result, lhs, rhs } => self.execute_f64_lt(result, lhs, rhs), Instr::F64Le { result, lhs, rhs } => self.execute_f64_le(result, lhs, rhs), - Instr::F64Gt { result, lhs, rhs } => self.execute_f64_gt(result, lhs, rhs), - Instr::F64Ge { result, lhs, rhs } => self.execute_f64_ge(result, lhs, rhs), Instr::I32Clz { result, input } => self.execute_i32_clz(result, input), Instr::I32Ctz { result, input } => self.execute_i32_ctz(result, input), Instr::I32Popcnt { result, input } => self.execute_i32_popcnt(result, input), @@ -1573,7 +1525,7 @@ impl Executor<'_> { /// Executes a generic binary [`Instruction`]. #[inline(always)] - fn execute_binary_imm16( + fn execute_binary_imm16_rhs( &mut self, result: Reg, lhs: Reg, diff --git a/crates/wasmi/src/engine/executor/instrs/binary.rs b/crates/wasmi/src/engine/executor/instrs/binary.rs index 9a48d55fe1..e37450ee6c 100644 --- a/crates/wasmi/src/engine/executor/instrs/binary.rs +++ b/crates/wasmi/src/engine/executor/instrs/binary.rs @@ -73,7 +73,7 @@ macro_rules! impl_binary_imm16 { $( #[doc = concat!("Executes an [`Instruction::", stringify!($var_name), "`].")] pub fn $fn_name(&mut self, result: Reg, lhs: Reg, rhs: Const16<$ty>) { - self.execute_binary_imm16(result, lhs, rhs, $op) + self.execute_binary_imm16_rhs(result, lhs, rhs, $op) } )* }; diff --git a/crates/wasmi/src/engine/executor/instrs/branch.rs b/crates/wasmi/src/engine/executor/instrs/branch.rs index fe39234f5f..1b9c61e737 100644 --- a/crates/wasmi/src/engine/executor/instrs/branch.rs +++ b/crates/wasmi/src/engine/executor/instrs/branch.rs @@ -214,7 +214,7 @@ impl Executor<'_> { } /// Executes a generic fused compare and branch instruction with immediate `rhs` operand. - fn execute_branch_binop_imm( + fn execute_branch_binop_imm16_rhs( &mut self, lhs: Reg, rhs: Const16, @@ -230,6 +230,24 @@ impl Executor<'_> { } self.next_instr() } + + /// Executes a generic fused compare and branch instruction with immediate `rhs` operand. + fn execute_branch_binop_imm16_lhs( + &mut self, + lhs: Const16, + rhs: Reg, + offset: BranchOffset16, + f: fn(T, T) -> bool, + ) where + T: From + From>, + { + let lhs = T::from(lhs); + let rhs: T = self.get_register_as(rhs); + if f(lhs, rhs) { + return self.branch_to16(offset); + } + self.next_instr() + } } fn cmp_eq(a: T, b: T) -> bool @@ -260,20 +278,6 @@ where a <= b } -fn cmp_gt(a: T, b: T) -> bool -where - T: PartialOrd, -{ - a > b -} - -fn cmp_ge(a: T, b: T) -> bool -where - T: PartialOrd, -{ - a >= b -} - fn cmp_i32_and(a: i32, b: i32) -> bool { (a & b) != 0 } @@ -323,10 +327,6 @@ impl_execute_branch_binop! { (u32, Instruction::BranchI32LtU, execute_branch_i32_lt_u, cmp_lt), (i32, Instruction::BranchI32LeS, execute_branch_i32_le_s, cmp_le), (u32, Instruction::BranchI32LeU, execute_branch_i32_le_u, cmp_le), - (i32, Instruction::BranchI32GtS, execute_branch_i32_gt_s, cmp_gt), - (u32, Instruction::BranchI32GtU, execute_branch_i32_gt_u, cmp_gt), - (i32, Instruction::BranchI32GeS, execute_branch_i32_ge_s, cmp_ge), - (u32, Instruction::BranchI32GeU, execute_branch_i32_ge_u, cmp_ge), (i64, Instruction::BranchI64Eq, execute_branch_i64_eq, cmp_eq), (i64, Instruction::BranchI64Ne, execute_branch_i64_ne, cmp_ne), @@ -334,39 +334,31 @@ impl_execute_branch_binop! { (u64, Instruction::BranchI64LtU, execute_branch_i64_lt_u, cmp_lt), (i64, Instruction::BranchI64LeS, execute_branch_i64_le_s, cmp_le), (u64, Instruction::BranchI64LeU, execute_branch_i64_le_u, cmp_le), - (i64, Instruction::BranchI64GtS, execute_branch_i64_gt_s, cmp_gt), - (u64, Instruction::BranchI64GtU, execute_branch_i64_gt_u, cmp_gt), - (i64, Instruction::BranchI64GeS, execute_branch_i64_ge_s, cmp_ge), - (u64, Instruction::BranchI64GeU, execute_branch_i64_ge_u, cmp_ge), (f32, Instruction::BranchF32Eq, execute_branch_f32_eq, cmp_eq), (f32, Instruction::BranchF32Ne, execute_branch_f32_ne, cmp_ne), (f32, Instruction::BranchF32Lt, execute_branch_f32_lt, cmp_lt), (f32, Instruction::BranchF32Le, execute_branch_f32_le, cmp_le), - (f32, Instruction::BranchF32Gt, execute_branch_f32_gt, cmp_gt), - (f32, Instruction::BranchF32Ge, execute_branch_f32_ge, cmp_ge), (f64, Instruction::BranchF64Eq, execute_branch_f64_eq, cmp_eq), (f64, Instruction::BranchF64Ne, execute_branch_f64_ne, cmp_ne), (f64, Instruction::BranchF64Lt, execute_branch_f64_lt, cmp_lt), (f64, Instruction::BranchF64Le, execute_branch_f64_le, cmp_le), - (f64, Instruction::BranchF64Gt, execute_branch_f64_gt, cmp_gt), - (f64, Instruction::BranchF64Ge, execute_branch_f64_ge, cmp_ge), } -macro_rules! impl_execute_branch_binop_imm { +macro_rules! impl_execute_branch_binop_imm16_rhs { ( $( ($ty:ty, Instruction::$op_name:ident, $fn_name:ident, $op:expr) ),* $(,)? ) => { impl<'engine> Executor<'engine> { $( #[doc = concat!("Executes an [`Instruction::", stringify!($op_name), "`].")] pub fn $fn_name(&mut self, lhs: Reg, rhs: Const16<$ty>, offset: BranchOffset16) { - self.execute_branch_binop_imm::<$ty>(lhs, rhs, offset, $op) + self.execute_branch_binop_imm16_rhs::<$ty>(lhs, rhs, offset, $op) } )* } } } -impl_execute_branch_binop_imm! { +impl_execute_branch_binop_imm16_rhs! { (i32, Instruction::BranchI32AndImm16, execute_branch_i32_and_imm16, cmp_i32_and), (i32, Instruction::BranchI32OrImm16, execute_branch_i32_or_imm16, cmp_i32_or), (i32, Instruction::BranchI32XorImm16, execute_branch_i32_xor_imm16, cmp_i32_xor), @@ -379,10 +371,6 @@ impl_execute_branch_binop_imm! { (u32, Instruction::BranchI32LtUImm16Rhs, execute_branch_i32_lt_u_imm16_rhs, cmp_lt), (i32, Instruction::BranchI32LeSImm16Rhs, execute_branch_i32_le_s_imm16_rhs, cmp_le), (u32, Instruction::BranchI32LeUImm16Rhs, execute_branch_i32_le_u_imm16_rhs, cmp_le), - (i32, Instruction::BranchI32GtSImm16Rhs, execute_branch_i32_gt_s_imm16_rhs, cmp_gt), - (u32, Instruction::BranchI32GtUImm16Rhs, execute_branch_i32_gt_u_imm16_rhs, cmp_gt), - (i32, Instruction::BranchI32GeSImm16Rhs, execute_branch_i32_ge_s_imm16_rhs, cmp_ge), - (u32, Instruction::BranchI32GeUImm16Rhs, execute_branch_i32_ge_u_imm16_rhs, cmp_ge), (i64, Instruction::BranchI64EqImm16, execute_branch_i64_eq_imm16, cmp_eq), (i64, Instruction::BranchI64NeImm16, execute_branch_i64_ne_imm16, cmp_ne), @@ -390,10 +378,30 @@ impl_execute_branch_binop_imm! { (u64, Instruction::BranchI64LtUImm16Rhs, execute_branch_i64_lt_u_imm16_rhs, cmp_lt), (i64, Instruction::BranchI64LeSImm16Rhs, execute_branch_i64_le_s_imm16_rhs, cmp_le), (u64, Instruction::BranchI64LeUImm16Rhs, execute_branch_i64_le_u_imm16_rhs, cmp_le), - (i64, Instruction::BranchI64GtSImm16Rhs, execute_branch_i64_gt_s_imm16_rhs, cmp_gt), - (u64, Instruction::BranchI64GtUImm16Rhs, execute_branch_i64_gt_u_imm16_rhs, cmp_gt), - (i64, Instruction::BranchI64GeSImm16Rhs, execute_branch_i64_ge_s_imm16_rhs, cmp_ge), - (u64, Instruction::BranchI64GeUImm16Rhs, execute_branch_i64_ge_u_imm16_rhs, cmp_ge), +} + +macro_rules! impl_execute_branch_binop_imm16_lhs { + ( $( ($ty:ty, Instruction::$op_name:ident, $fn_name:ident, $op:expr) ),* $(,)? ) => { + impl<'engine> Executor<'engine> { + $( + #[doc = concat!("Executes an [`Instruction::", stringify!($op_name), "`].")] + pub fn $fn_name(&mut self, lhs: Const16<$ty>, rhs: Reg, offset: BranchOffset16) { + self.execute_branch_binop_imm16_lhs::<$ty>(lhs, rhs, offset, $op) + } + )* + } + } +} +impl_execute_branch_binop_imm16_lhs! { + (i32, Instruction::BranchI32LtSImm16Lhs, execute_branch_i32_lt_s_imm16_lhs, cmp_lt), + (u32, Instruction::BranchI32LtUImm16Lhs, execute_branch_i32_lt_u_imm16_lhs, cmp_lt), + (i32, Instruction::BranchI32LeSImm16Lhs, execute_branch_i32_le_s_imm16_lhs, cmp_le), + (u32, Instruction::BranchI32LeUImm16Lhs, execute_branch_i32_le_u_imm16_lhs, cmp_le), + + (i64, Instruction::BranchI64LtSImm16Lhs, execute_branch_i64_lt_s_imm16_lhs, cmp_lt), + (u64, Instruction::BranchI64LtUImm16Lhs, execute_branch_i64_lt_u_imm16_lhs, cmp_lt), + (i64, Instruction::BranchI64LeSImm16Lhs, execute_branch_i64_le_s_imm16_lhs, cmp_le), + (u64, Instruction::BranchI64LeUImm16Lhs, execute_branch_i64_le_u_imm16_lhs, cmp_le), } impl Executor<'_> { @@ -412,10 +420,6 @@ impl Executor<'_> { C::I32LtU => self.execute_branch_binop::(lhs, rhs, offset, cmp_lt), C::I32LeS => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), C::I32LeU => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), - C::I32GtS => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::I32GtU => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::I32GeS => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), - C::I32GeU => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), C::I32And => self.execute_branch_binop::(lhs, rhs, offset, cmp_i32_and), C::I32Or => self.execute_branch_binop::(lhs, rhs, offset, cmp_i32_or), C::I32Xor => self.execute_branch_binop::(lhs, rhs, offset, cmp_i32_xor), @@ -428,22 +432,14 @@ impl Executor<'_> { C::I64LtU => self.execute_branch_binop::(lhs, rhs, offset, cmp_lt), C::I64LeS => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), C::I64LeU => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), - C::I64GtS => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::I64GtU => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::I64GeS => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), - C::I64GeU => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), C::F32Eq => self.execute_branch_binop::(lhs, rhs, offset, cmp_eq), C::F32Ne => self.execute_branch_binop::(lhs, rhs, offset, cmp_ne), C::F32Lt => self.execute_branch_binop::(lhs, rhs, offset, cmp_lt), C::F32Le => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), - C::F32Gt => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::F32Ge => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), C::F64Eq => self.execute_branch_binop::(lhs, rhs, offset, cmp_eq), C::F64Ne => self.execute_branch_binop::(lhs, rhs, offset, cmp_ne), C::F64Lt => self.execute_branch_binop::(lhs, rhs, offset, cmp_lt), C::F64Le => self.execute_branch_binop::(lhs, rhs, offset, cmp_le), - C::F64Gt => self.execute_branch_binop::(lhs, rhs, offset, cmp_gt), - C::F64Ge => self.execute_branch_binop::(lhs, rhs, offset, cmp_ge), }; } } diff --git a/crates/wasmi/src/engine/executor/instrs/comparison.rs b/crates/wasmi/src/engine/executor/instrs/comparison.rs index ff0609f56f..676bf2d6d1 100644 --- a/crates/wasmi/src/engine/executor/instrs/comparison.rs +++ b/crates/wasmi/src/engine/executor/instrs/comparison.rs @@ -26,10 +26,6 @@ impl Executor<'_> { (Instruction::I32LtU, execute_i32_lt_u, UntypedVal::i32_lt_u), (Instruction::I32LeS, execute_i32_le_s, UntypedVal::i32_le_s), (Instruction::I32LeU, execute_i32_le_u, UntypedVal::i32_le_u), - (Instruction::I32GtS, execute_i32_gt_s, UntypedVal::i32_gt_s), - (Instruction::I32GtU, execute_i32_gt_u, UntypedVal::i32_gt_u), - (Instruction::I32GeS, execute_i32_ge_s, UntypedVal::i32_ge_s), - (Instruction::I32GeU, execute_i32_ge_u, UntypedVal::i32_ge_u), (Instruction::I64Eq, execute_i64_eq, UntypedVal::i64_eq), (Instruction::I64Ne, execute_i64_ne, UntypedVal::i64_ne), @@ -37,60 +33,69 @@ impl Executor<'_> { (Instruction::I64LtU, execute_i64_lt_u, UntypedVal::i64_lt_u), (Instruction::I64LeS, execute_i64_le_s, UntypedVal::i64_le_s), (Instruction::I64LeU, execute_i64_le_u, UntypedVal::i64_le_u), - (Instruction::I64GtS, execute_i64_gt_s, UntypedVal::i64_gt_s), - (Instruction::I64GtU, execute_i64_gt_u, UntypedVal::i64_gt_u), - (Instruction::I64GeS, execute_i64_ge_s, UntypedVal::i64_ge_s), - (Instruction::I64GeU, execute_i64_ge_u, UntypedVal::i64_ge_u), (Instruction::F32Eq, execute_f32_eq, UntypedVal::f32_eq), (Instruction::F32Ne, execute_f32_ne, UntypedVal::f32_ne), (Instruction::F32Lt, execute_f32_lt, UntypedVal::f32_lt), (Instruction::F32Le, execute_f32_le, UntypedVal::f32_le), - (Instruction::F32Gt, execute_f32_gt, UntypedVal::f32_gt), - (Instruction::F32Ge, execute_f32_ge, UntypedVal::f32_ge), (Instruction::F64Eq, execute_f64_eq, UntypedVal::f64_eq), (Instruction::F64Ne, execute_f64_ne, UntypedVal::f64_ne), (Instruction::F64Lt, execute_f64_lt, UntypedVal::f64_lt), (Instruction::F64Le, execute_f64_le, UntypedVal::f64_le), - (Instruction::F64Gt, execute_f64_gt, UntypedVal::f64_gt), - (Instruction::F64Ge, execute_f64_ge, UntypedVal::f64_ge), } } -macro_rules! impl_comparison_imm16 { +macro_rules! impl_comparison_imm16_rhs { ( $( ($ty:ty, Instruction::$var_name:ident, $fn_name:ident, $op:expr) ),* $(,)? ) => { $( #[doc = concat!("Executes an [`Instruction::", stringify!($var_name), "`].")] pub fn $fn_name(&mut self, result: Reg, lhs: Reg, rhs: Const16<$ty>) { - self.execute_binary_imm16(result, lhs, rhs, $op) + self.execute_binary_imm16_rhs(result, lhs, rhs, $op) } )* }; } impl Executor<'_> { - impl_comparison_imm16! { + impl_comparison_imm16_rhs! { (i32, Instruction::I32EqImm16, execute_i32_eq_imm16, UntypedVal::i32_eq), (i32, Instruction::I32NeImm16, execute_i32_ne_imm16, UntypedVal::i32_ne), - (i32, Instruction::I32LtSImm16Rhs, execute_i32_lt_s_imm16, UntypedVal::i32_lt_s), - (u32, Instruction::I32LtUImm16Rhs, execute_i32_lt_u_imm16, UntypedVal::i32_lt_u), - (i32, Instruction::I32LeSImm16Rhs, execute_i32_le_s_imm16, UntypedVal::i32_le_s), - (u32, Instruction::I32LeUImm16Rhs, execute_i32_le_u_imm16, UntypedVal::i32_le_u), - (i32, Instruction::I32GtSImm16Rhs, execute_i32_gt_s_imm16, UntypedVal::i32_gt_s), - (u32, Instruction::I32GtUImm16Rhs, execute_i32_gt_u_imm16, UntypedVal::i32_gt_u), - (i32, Instruction::I32GeSImm16Rhs, execute_i32_ge_s_imm16, UntypedVal::i32_ge_s), - (u32, Instruction::I32GeUImm16Rhs, execute_i32_ge_u_imm16, UntypedVal::i32_ge_u), + (i32, Instruction::I32LtSImm16Rhs, execute_i32_lt_s_imm16_rhs, UntypedVal::i32_lt_s), + (u32, Instruction::I32LtUImm16Rhs, execute_i32_lt_u_imm16_rhs, UntypedVal::i32_lt_u), + (i32, Instruction::I32LeSImm16Rhs, execute_i32_le_s_imm16_rhs, UntypedVal::i32_le_s), + (u32, Instruction::I32LeUImm16Rhs, execute_i32_le_u_imm16_rhs, UntypedVal::i32_le_u), (i64, Instruction::I64EqImm16, execute_i64_eq_imm16, UntypedVal::i64_eq), (i64, Instruction::I64NeImm16, execute_i64_ne_imm16, UntypedVal::i64_ne), - (i64, Instruction::I64LtSImm16Rhs, execute_i64_lt_s_imm16, UntypedVal::i64_lt_s), - (u64, Instruction::I64LtUImm16Rhs, execute_i64_lt_u_imm16, UntypedVal::i64_lt_u), - (i64, Instruction::I64LeSImm16Rhs, execute_i64_le_s_imm16, UntypedVal::i64_le_s), - (u64, Instruction::I64LeUImm16Rhs, execute_i64_le_u_imm16, UntypedVal::i64_le_u), - (i64, Instruction::I64GtSImm16Rhs, execute_i64_gt_s_imm16, UntypedVal::i64_gt_s), - (u64, Instruction::I64GtUImm16Rhs, execute_i64_gt_u_imm16, UntypedVal::i64_gt_u), - (i64, Instruction::I64GeSImm16Rhs, execute_i64_ge_s_imm16, UntypedVal::i64_ge_s), - (u64, Instruction::I64GeUImm16Rhs, execute_i64_ge_u_imm16, UntypedVal::i64_ge_u), + (i64, Instruction::I64LtSImm16Rhs, execute_i64_lt_s_imm16_rhs, UntypedVal::i64_lt_s), + (u64, Instruction::I64LtUImm16Rhs, execute_i64_lt_u_imm16_rhs, UntypedVal::i64_lt_u), + (i64, Instruction::I64LeSImm16Rhs, execute_i64_le_s_imm16_rhs, UntypedVal::i64_le_s), + (u64, Instruction::I64LeUImm16Rhs, execute_i64_le_u_imm16_rhs, UntypedVal::i64_le_u), + } +} + +macro_rules! impl_comparison_imm16_lhs { + ( $( ($ty:ty, Instruction::$var_name:ident, $fn_name:ident, $op:expr) ),* $(,)? ) => { + $( + #[doc = concat!("Executes an [`Instruction::", stringify!($var_name), "`].")] + pub fn $fn_name(&mut self, result: Reg, lhs: Const16<$ty>, rhs: Reg) { + self.execute_binary_imm16_lhs(result, lhs, rhs, $op) + } + )* + }; +} + +impl Executor<'_> { + impl_comparison_imm16_lhs! { + (i32, Instruction::I32LtSImm16Lhs, execute_i32_lt_s_imm16_lhs, UntypedVal::i32_lt_s), + (u32, Instruction::I32LtUImm16Lhs, execute_i32_lt_u_imm16_lhs, UntypedVal::i32_lt_u), + (i32, Instruction::I32LeSImm16Lhs, execute_i32_le_s_imm16_lhs, UntypedVal::i32_le_s), + (u32, Instruction::I32LeUImm16Lhs, execute_i32_le_u_imm16_lhs, UntypedVal::i32_le_u), + + (i64, Instruction::I64LtSImm16Lhs, execute_i64_lt_s_imm16_lhs, UntypedVal::i64_lt_s), + (u64, Instruction::I64LtUImm16Lhs, execute_i64_lt_u_imm16_lhs, UntypedVal::i64_lt_u), + (i64, Instruction::I64LeSImm16Lhs, execute_i64_le_s_imm16_lhs, UntypedVal::i64_le_s), + (u64, Instruction::I64LeUImm16Lhs, execute_i64_le_u_imm16_lhs, UntypedVal::i64_le_u), } } diff --git a/crates/wasmi/src/engine/translator/comparator.rs b/crates/wasmi/src/engine/translator/comparator.rs index fc027d76dd..d9b4d588c6 100644 --- a/crates/wasmi/src/engine/translator/comparator.rs +++ b/crates/wasmi/src/engine/translator/comparator.rs @@ -1,273 +1,322 @@ -use crate::ir::{self, BranchOffset16, Comparator, Const16, Instruction, Reg}; +use super::ValueStack; +use crate::{ + ir::{BranchOffset, BranchOffset16, Comparator, ComparatorAndOffset, Instruction}, + Error, +}; -/// Extensional functionality for [`Comparator`]. -pub trait ComparatorExt: Sized { - /// Creates a [`Comparator`] from a comparison [`Instruction`]. - fn from_cmp_instruction(instr: Instruction) -> Option; - - /// Creates a [`Comparator`] from a fused compare+branch [`Instruction`]. - fn from_cmp_branch_instruction(instr: Instruction) -> Option; - - /// Returns the negated version of `self` if possible. - /// - /// # Note - /// - /// Comparators for `f32` and `f64` that are not symmetric (`Eq` and `Ne`) - /// cannot be negated since NaN value handling would not preserve semantics. - fn negate(self) -> Option; - - /// Returns the [`Instruction`] constructor for `self` without immediate value. - fn branch_cmp_instr(self) -> fn(lhs: Reg, rhs: Reg, offset: BranchOffset16) -> ir::Instruction; +pub trait NegateCmpInstr: Sized { + fn negate_cmp_instr(&self) -> Option; } -impl ComparatorExt for Comparator { - fn from_cmp_instruction(instr: Instruction) -> Option { - use Instruction as I; - let cmp = match instr { - I::I32And { .. } | I::I32AndImm16 { .. } => Self::I32And, - I::I32Or { .. } | I::I32OrImm16 { .. } => Self::I32Or, - I::I32Xor { .. } | I::I32XorImm16 { .. } => Self::I32Xor, - I::I32AndEqz { .. } | I::I32AndEqzImm16 { .. } => Self::I32AndEqz, - I::I32OrEqz { .. } | I::I32OrEqzImm16 { .. } => Self::I32OrEqz, - I::I32XorEqz { .. } | I::I32XorEqzImm16 { .. } => Self::I32XorEqz, - I::I32Eq { .. } | I::I32EqImm16 { .. } => Self::I32Eq, - I::I32Ne { .. } | I::I32NeImm16 { .. } => Self::I32Ne, - I::I32LtS { .. } | I::I32LtSImm16Rhs { .. } => Self::I32LtS, - I::I32LtU { .. } | I::I32LtUImm16Rhs { .. } => Self::I32LtU, - I::I32LeS { .. } | I::I32LeSImm16Rhs { .. } => Self::I32LeS, - I::I32LeU { .. } | I::I32LeUImm16Rhs { .. } => Self::I32LeU, - I::I32GtS { .. } | I::I32GtSImm16Rhs { .. } => Self::I32GtS, - I::I32GtU { .. } | I::I32GtUImm16Rhs { .. } => Self::I32GtU, - I::I32GeS { .. } | I::I32GeSImm16Rhs { .. } => Self::I32GeS, - I::I32GeU { .. } | I::I32GeUImm16Rhs { .. } => Self::I32GeU, - I::I64Eq { .. } | I::I64EqImm16 { .. } => Self::I64Eq, - I::I64Ne { .. } | I::I64NeImm16 { .. } => Self::I64Ne, - I::I64LtS { .. } | I::I64LtSImm16Rhs { .. } => Self::I64LtS, - I::I64LtU { .. } | I::I64LtUImm16Rhs { .. } => Self::I64LtU, - I::I64LeS { .. } | I::I64LeSImm16Rhs { .. } => Self::I64LeS, - I::I64LeU { .. } | I::I64LeUImm16Rhs { .. } => Self::I64LeU, - I::I64GtS { .. } | I::I64GtSImm16Rhs { .. } => Self::I64GtS, - I::I64GtU { .. } | I::I64GtUImm16Rhs { .. } => Self::I64GtU, - I::I64GeS { .. } | I::I64GeSImm16Rhs { .. } => Self::I64GeS, - I::I64GeU { .. } | I::I64GeUImm16Rhs { .. } => Self::I64GeU, - I::F32Eq { .. } => Self::F32Eq, - I::F32Ne { .. } => Self::F32Ne, - I::F32Lt { .. } => Self::F32Lt, - I::F32Le { .. } => Self::F32Le, - I::F32Gt { .. } => Self::F32Gt, - I::F32Ge { .. } => Self::F32Ge, - I::F64Eq { .. } => Self::F64Eq, - I::F64Ne { .. } => Self::F64Ne, - I::F64Lt { .. } => Self::F64Lt, - I::F64Le { .. } => Self::F64Le, - I::F64Gt { .. } => Self::F64Gt, - I::F64Ge { .. } => Self::F64Ge, - _ => return None, - }; - Some(cmp) - } - - fn from_cmp_branch_instruction(instr: Instruction) -> Option { +impl NegateCmpInstr for Instruction { + fn negate_cmp_instr(&self) -> Option { use Instruction as I; - let cmp = match instr { - I::BranchI32And { .. } | I::BranchI32AndImm16 { .. } => Self::I32And, - I::BranchI32Or { .. } | I::BranchI32OrImm16 { .. } => Self::I32Or, - I::BranchI32Xor { .. } | I::BranchI32XorImm16 { .. } => Self::I32Xor, - I::BranchI32AndEqz { .. } | I::BranchI32AndEqzImm16 { .. } => Self::I32AndEqz, - I::BranchI32OrEqz { .. } | I::BranchI32OrEqzImm16 { .. } => Self::I32OrEqz, - I::BranchI32XorEqz { .. } | I::BranchI32XorEqzImm16 { .. } => Self::I32XorEqz, - I::BranchI32Eq { .. } | I::BranchI32EqImm16 { .. } => Self::I32Eq, - I::BranchI32Ne { .. } | I::BranchI32NeImm16 { .. } => Self::I32Ne, - I::BranchI32LtS { .. } | I::BranchI32LtSImm16Rhs { .. } => Self::I32LtS, - I::BranchI32LtU { .. } | I::BranchI32LtUImm16Rhs { .. } => Self::I32LtU, - I::BranchI32LeS { .. } | I::BranchI32LeSImm16Rhs { .. } => Self::I32LeS, - I::BranchI32LeU { .. } | I::BranchI32LeUImm16Rhs { .. } => Self::I32LeU, - I::BranchI32GtS { .. } | I::BranchI32GtSImm16Rhs { .. } => Self::I32GtS, - I::BranchI32GtU { .. } | I::BranchI32GtUImm16Rhs { .. } => Self::I32GtU, - I::BranchI32GeS { .. } | I::BranchI32GeSImm16Rhs { .. } => Self::I32GeS, - I::BranchI32GeU { .. } | I::BranchI32GeUImm16Rhs { .. } => Self::I32GeU, - I::BranchI64Eq { .. } | I::BranchI64EqImm16 { .. } => Self::I64Eq, - I::BranchI64Ne { .. } | I::BranchI64NeImm16 { .. } => Self::I64Ne, - I::BranchI64LtS { .. } | I::BranchI64LtSImm16Rhs { .. } => Self::I64LtS, - I::BranchI64LtU { .. } | I::BranchI64LtUImm16Rhs { .. } => Self::I64LtU, - I::BranchI64LeS { .. } | I::BranchI64LeSImm16Rhs { .. } => Self::I64LeS, - I::BranchI64LeU { .. } | I::BranchI64LeUImm16Rhs { .. } => Self::I64LeU, - I::BranchI64GtS { .. } | I::BranchI64GtSImm16Rhs { .. } => Self::I64GtS, - I::BranchI64GtU { .. } | I::BranchI64GtUImm16Rhs { .. } => Self::I64GtU, - I::BranchI64GeS { .. } | I::BranchI64GeSImm16Rhs { .. } => Self::I64GeS, - I::BranchI64GeU { .. } | I::BranchI64GeUImm16Rhs { .. } => Self::I64GeU, - I::BranchF32Eq { .. } => Self::F32Eq, - I::BranchF32Ne { .. } => Self::F32Ne, - I::BranchF32Lt { .. } => Self::F32Lt, - I::BranchF32Le { .. } => Self::F32Le, - I::BranchF32Gt { .. } => Self::F32Gt, - I::BranchF32Ge { .. } => Self::F32Ge, - I::BranchF64Eq { .. } => Self::F64Eq, - I::BranchF64Ne { .. } => Self::F64Ne, - I::BranchF64Lt { .. } => Self::F64Lt, - I::BranchF64Le { .. } => Self::F64Le, - I::BranchF64Gt { .. } => Self::F64Gt, - I::BranchF64Ge { .. } => Self::F64Ge, - _ => return None, - }; - Some(cmp) - } - - fn negate(self) -> Option { - let negated = match self { - Self::I32And => Self::I32AndEqz, - Self::I32Or => Self::I32OrEqz, - Self::I32Xor => Self::I32XorEqz, - Self::I32AndEqz => Self::I32And, - Self::I32OrEqz => Self::I32Or, - Self::I32XorEqz => Self::I32Xor, - Self::I32Eq => Self::I32Ne, - Self::I32Ne => Self::I32Eq, - Self::I32LtS => Self::I32GeS, - Self::I32LtU => Self::I32GeU, - Self::I32LeS => Self::I32GtS, - Self::I32LeU => Self::I32GtU, - Self::I32GtS => Self::I32LeS, - Self::I32GtU => Self::I32LeU, - Self::I32GeS => Self::I32LtS, - Self::I32GeU => Self::I32LtU, - Self::I64Eq => Self::I64Ne, - Self::I64Ne => Self::I64Eq, - Self::I64LtS => Self::I64GeS, - Self::I64LtU => Self::I64GeU, - Self::I64LeS => Self::I64GtS, - Self::I64LeU => Self::I64GtU, - Self::I64GtS => Self::I64LeS, - Self::I64GtU => Self::I64LeU, - Self::I64GeS => Self::I64LtS, - Self::I64GeU => Self::I64LtU, - Self::F32Eq => Self::F32Ne, - Self::F32Ne => Self::F32Eq, - Self::F64Eq => Self::F64Ne, - Self::F64Ne => Self::F64Eq, - // Note: Due to non-semantics preserving NaN handling we cannot - // negate `F{32,64}{Lt,Le,Gt,Ge}` comparators. + #[rustfmt::skip] + let negated = match *self { + // i32 + I::I32Eq { result, lhs, rhs } => I::i32_ne(result, lhs, rhs), + I::I32Ne { result, lhs, rhs } => I::i32_eq(result, lhs, rhs), + I::I32LeS { result, lhs, rhs } => I::i32_lt_s(result, rhs, lhs), + I::I32LeU { result, lhs, rhs } => I::i32_lt_u(result, rhs, lhs), + I::I32LtS { result, lhs, rhs } => I::i32_le_s(result, rhs, lhs), + I::I32LtU { result, lhs, rhs } => I::i32_le_u(result, rhs, lhs), + I::I32EqImm16 { result, lhs, rhs } => I::i32_ne_imm16(result, lhs, rhs), + I::I32NeImm16 { result, lhs, rhs } => I::i32_eq_imm16(result, lhs, rhs), + I::I32LeSImm16Rhs { result, lhs, rhs } => I::i32_lt_s_imm16_lhs(result, rhs, lhs), + I::I32LeUImm16Rhs { result, lhs, rhs } => I::i32_lt_u_imm16_lhs(result, rhs, lhs), + I::I32LtSImm16Rhs { result, lhs, rhs } => I::i32_le_s_imm16_lhs(result, rhs, lhs), + I::I32LtUImm16Rhs { result, lhs, rhs } => I::i32_le_u_imm16_lhs(result, rhs, lhs), + I::I32LeSImm16Lhs { result, lhs, rhs } => I::i32_lt_s_imm16_rhs(result, rhs, lhs), + I::I32LeUImm16Lhs { result, lhs, rhs } => I::i32_lt_u_imm16_rhs(result, rhs, lhs), + I::I32LtSImm16Lhs { result, lhs, rhs } => I::i32_le_s_imm16_rhs(result, rhs, lhs), + I::I32LtUImm16Lhs { result, lhs, rhs } => I::i32_le_u_imm16_rhs(result, rhs, lhs), + // i32 (special) + I::I32And { result, lhs, rhs } => I::i32_and_eqz(result, lhs, rhs), + I::I32Or { result, lhs, rhs } => I::i32_or_eqz(result, lhs, rhs), + I::I32Xor { result, lhs, rhs } => I::i32_xor_eqz(result, lhs, rhs), + I::I32AndEqz { result, lhs, rhs } => I::i32_and(result, lhs, rhs), + I::I32OrEqz { result, lhs, rhs } => I::i32_or(result, lhs, rhs), + I::I32XorEqz { result, lhs, rhs } => I::i32_xor(result, lhs, rhs), + I::I32AndImm16 { result, lhs, rhs } => I::i32_and_eqz_imm16(result, lhs, rhs), + I::I32OrImm16 { result, lhs, rhs } => I::i32_or_eqz_imm16(result, lhs, rhs), + I::I32XorImm16 { result, lhs, rhs } => I::i32_xor_eqz_imm16(result, lhs, rhs), + I::I32AndEqzImm16 { result, lhs, rhs } => I::i32_and_imm16(result, lhs, rhs), + I::I32OrEqzImm16 { result, lhs, rhs } => I::i32_or_imm16(result, lhs, rhs), + I::I32XorEqzImm16 { result, lhs, rhs } => I::i32_xor_imm16(result, lhs, rhs), + // i64 + I::I64Eq { result, lhs, rhs } => I::i64_ne(result, lhs, rhs), + I::I64Ne { result, lhs, rhs } => I::i64_eq(result, lhs, rhs), + I::I64LeS { result, lhs, rhs } => I::i64_lt_s(result, rhs, lhs), + I::I64LeU { result, lhs, rhs } => I::i64_lt_u(result, rhs, lhs), + I::I64LtS { result, lhs, rhs } => I::i64_le_s(result, rhs, lhs), + I::I64LtU { result, lhs, rhs } => I::i64_le_u(result, rhs, lhs), + I::I64EqImm16 { result, lhs, rhs } => I::i64_ne_imm16(result, lhs, rhs), + I::I64NeImm16 { result, lhs, rhs } => I::i64_eq_imm16(result, lhs, rhs), + I::I64LeSImm16Rhs { result, lhs, rhs } => I::i64_lt_s_imm16_lhs(result, rhs, lhs), + I::I64LeUImm16Rhs { result, lhs, rhs } => I::i64_lt_u_imm16_lhs(result, rhs, lhs), + I::I64LtSImm16Rhs { result, lhs, rhs } => I::i64_le_s_imm16_lhs(result, rhs, lhs), + I::I64LtUImm16Rhs { result, lhs, rhs } => I::i64_le_u_imm16_lhs(result, rhs, lhs), + I::I64LeSImm16Lhs { result, lhs, rhs } => I::i64_lt_s_imm16_rhs(result, rhs, lhs), + I::I64LeUImm16Lhs { result, lhs, rhs } => I::i64_lt_u_imm16_rhs(result, rhs, lhs), + I::I64LtSImm16Lhs { result, lhs, rhs } => I::i64_le_s_imm16_rhs(result, rhs, lhs), + I::I64LtUImm16Lhs { result, lhs, rhs } => I::i64_le_u_imm16_rhs(result, rhs, lhs), + // f32 + // + // Note: due to NaN values always comparing as `false` we unfortunately + // cannot negate `f32.{lt,le}` comparison instructions. + I::F32Eq { result, lhs, rhs } => I::f32_ne(result, lhs, rhs), + I::F32Ne { result, lhs, rhs } => I::f32_eq(result, lhs, rhs), + // f64 + // + // Note: due to NaN values always comparing as `false` we unfortunately + // cannot negate `f64.{lt,le}` comparison instructions. + I::F64Eq { result, lhs, rhs } => I::f64_ne(result, lhs, rhs), + I::F64Ne { result, lhs, rhs } => I::f64_eq(result, lhs, rhs), _ => return None, }; Some(negated) } - - fn branch_cmp_instr(self) -> fn(lhs: Reg, rhs: Reg, offset: BranchOffset16) -> ir::Instruction { - match self { - Self::I32And => Instruction::branch_i32_and, - Self::I32Or => Instruction::branch_i32_or, - Self::I32Xor => Instruction::branch_i32_xor, - Self::I32AndEqz => Instruction::branch_i32_and_eqz, - Self::I32OrEqz => Instruction::branch_i32_or_eqz, - Self::I32XorEqz => Instruction::branch_i32_xor_eqz, - Self::I32Eq => Instruction::branch_i32_eq, - Self::I32Ne => Instruction::branch_i32_ne, - Self::I32LtS => Instruction::branch_i32_lt_s, - Self::I32LtU => Instruction::branch_i32_lt_u, - Self::I32LeS => Instruction::branch_i32_le_s, - Self::I32LeU => Instruction::branch_i32_le_u, - Self::I32GtS => Instruction::branch_i32_gt_s, - Self::I32GtU => Instruction::branch_i32_gt_u, - Self::I32GeS => Instruction::branch_i32_ge_s, - Self::I32GeU => Instruction::branch_i32_ge_u, - Self::I64Eq => Instruction::branch_i64_eq, - Self::I64Ne => Instruction::branch_i64_ne, - Self::I64LtS => Instruction::branch_i64_lt_s, - Self::I64LtU => Instruction::branch_i64_lt_u, - Self::I64LeS => Instruction::branch_i64_le_s, - Self::I64LeU => Instruction::branch_i64_le_u, - Self::I64GtS => Instruction::branch_i64_gt_s, - Self::I64GtU => Instruction::branch_i64_gt_u, - Self::I64GeS => Instruction::branch_i64_ge_s, - Self::I64GeU => Instruction::branch_i64_ge_u, - Self::F32Eq => Instruction::branch_f32_eq, - Self::F32Ne => Instruction::branch_f32_ne, - Self::F32Lt => Instruction::branch_f32_lt, - Self::F32Le => Instruction::branch_f32_le, - Self::F32Gt => Instruction::branch_f32_gt, - Self::F32Ge => Instruction::branch_f32_ge, - Self::F64Eq => Instruction::branch_f64_eq, - Self::F64Ne => Instruction::branch_f64_ne, - Self::F64Lt => Instruction::branch_f64_lt, - Self::F64Le => Instruction::branch_f64_le, - Self::F64Gt => Instruction::branch_f64_gt, - Self::F64Ge => Instruction::branch_f64_ge, - } - } } -/// Extensional functionality for [`Comparator`] with immediate value [`Instruction`]. -pub trait ComparatorExtImm { - /// Returns the [`Instruction`] constructor for `self` without immediate value of type `T` if any. - fn branch_cmp_instr_imm(self) -> Option>; +pub trait TryIntoCmpBranchInstr: Sized { + fn try_into_cmp_branch_instr( + &self, + offset: BranchOffset, + stack: &mut ValueStack, + ) -> Result, Error>; } -/// Constructor for branch+cmp [`Instruction`] with an immediate value of type `T`. -type MakeBranchCmpInstrImm = - fn(lhs: Reg, rhs: Const16, offset: BranchOffset16) -> ir::Instruction; - -impl ComparatorExtImm for Comparator { - fn branch_cmp_instr_imm(self) -> Option> { +impl TryIntoCmpBranchInstr for Instruction { + fn try_into_cmp_branch_instr( + &self, + offset: BranchOffset, + stack: &mut ValueStack, + ) -> Result, Error> { use Instruction as I; - let make_instr = match self { - Self::I32And => I::branch_i32_and_imm16, - Self::I32Or => I::branch_i32_or_imm16, - Self::I32Xor => I::branch_i32_xor_imm16, - Self::I32AndEqz => I::branch_i32_and_eqz_imm16, - Self::I32OrEqz => I::branch_i32_or_eqz_imm16, - Self::I32XorEqz => I::branch_i32_xor_eqz_imm16, - Self::I32Eq => I::branch_i32_eq_imm16, - Self::I32Ne => I::branch_i32_ne_imm16, - Self::I32LtS => I::branch_i32_lt_s_imm16_rhs, - Self::I32LeS => I::branch_i32_le_s_imm16_rhs, - Self::I32GtS => I::branch_i32_gt_s_imm16_rhs, - Self::I32GeS => I::branch_i32_ge_s_imm16_rhs, - _ => return None, + let Ok(offset) = BranchOffset16::try_from(offset) else { + return self.try_into_cmp_branch_fallback_instr(offset, stack); }; - Some(make_instr) + #[rustfmt::skip] + let cmp_branch_instr = match *self { + // i32 + I::I32Eq { lhs, rhs, .. } => I::branch_i32_eq(lhs, rhs, offset), + I::I32Ne { lhs, rhs, .. } => I::branch_i32_ne(lhs, rhs, offset), + I::I32LeS { lhs, rhs, .. } => I::branch_i32_le_s(lhs, rhs, offset), + I::I32LeU { lhs, rhs, .. } => I::branch_i32_le_u(lhs, rhs, offset), + I::I32LtS { lhs, rhs, .. } => I::branch_i32_lt_s(lhs, rhs, offset), + I::I32LtU { lhs, rhs, .. } => I::branch_i32_lt_u(lhs, rhs, offset), + I::I32EqImm16 { lhs, rhs, .. } => I::branch_i32_eq_imm16(lhs, rhs, offset), + I::I32NeImm16 { lhs, rhs, .. } => I::branch_i32_ne_imm16(lhs, rhs, offset), + I::I32LeSImm16Lhs { lhs, rhs, .. } => I::branch_i32_le_s_imm16_lhs(lhs, rhs, offset), + I::I32LeUImm16Lhs { lhs, rhs, .. } => I::branch_i32_le_u_imm16_lhs(lhs, rhs, offset), + I::I32LtSImm16Lhs { lhs, rhs, .. } => I::branch_i32_lt_s_imm16_lhs(lhs, rhs, offset), + I::I32LtUImm16Lhs { lhs, rhs, .. } => I::branch_i32_lt_u_imm16_lhs(lhs, rhs, offset), + I::I32LeSImm16Rhs { lhs, rhs, .. } => I::branch_i32_le_s_imm16_rhs(lhs, rhs, offset), + I::I32LeUImm16Rhs { lhs, rhs, .. } => I::branch_i32_le_u_imm16_rhs(lhs, rhs, offset), + I::I32LtSImm16Rhs { lhs, rhs, .. } => I::branch_i32_lt_s_imm16_rhs(lhs, rhs, offset), + I::I32LtUImm16Rhs { lhs, rhs, .. } => I::branch_i32_lt_u_imm16_rhs(lhs, rhs, offset), + // i32 (special) + I::I32And { lhs, rhs, .. } => I::branch_i32_and(lhs, rhs, offset), + I::I32Or { lhs, rhs, .. } => I::branch_i32_or(lhs, rhs, offset), + I::I32Xor { lhs, rhs, .. } => I::branch_i32_xor(lhs, rhs, offset), + I::I32AndEqz { lhs, rhs, .. } => I::branch_i32_and_eqz(lhs, rhs, offset), + I::I32OrEqz { lhs, rhs, .. } => I::branch_i32_or_eqz(lhs, rhs, offset), + I::I32XorEqz { lhs, rhs, .. } => I::branch_i32_xor_eqz(lhs, rhs, offset), + I::I32AndImm16 { lhs, rhs, .. } => I::branch_i32_and_imm16(lhs, rhs, offset), + I::I32OrImm16 { lhs, rhs, .. } => I::branch_i32_or_imm16(lhs, rhs, offset), + I::I32XorImm16 { lhs, rhs, .. } => I::branch_i32_xor_imm16(lhs, rhs, offset), + I::I32AndEqzImm16 { lhs, rhs, .. } => I::branch_i32_and_eqz_imm16(lhs, rhs, offset), + I::I32OrEqzImm16 { lhs, rhs, .. } => I::branch_i32_or_eqz_imm16(lhs, rhs, offset), + I::I32XorEqzImm16 { lhs, rhs, .. } => I::branch_i32_xor_eqz_imm16(lhs, rhs, offset), + // i64 + I::I64Eq { lhs, rhs, .. } => I::branch_i64_eq(lhs, rhs, offset), + I::I64Ne { lhs, rhs, .. } => I::branch_i64_ne(lhs, rhs, offset), + I::I64LeS { lhs, rhs, .. } => I::branch_i64_le_s(lhs, rhs, offset), + I::I64LeU { lhs, rhs, .. } => I::branch_i64_le_u(lhs, rhs, offset), + I::I64LtS { lhs, rhs, .. } => I::branch_i64_lt_s(lhs, rhs, offset), + I::I64LtU { lhs, rhs, .. } => I::branch_i64_lt_u(lhs, rhs, offset), + I::I64EqImm16 { lhs, rhs, .. } => I::branch_i64_eq_imm16(lhs, rhs, offset), + I::I64NeImm16 { lhs, rhs, .. } => I::branch_i64_ne_imm16(lhs, rhs, offset), + I::I64LeSImm16Lhs { lhs, rhs, .. } => I::branch_i64_le_s_imm16_lhs(lhs, rhs, offset), + I::I64LeUImm16Lhs { lhs, rhs, .. } => I::branch_i64_le_u_imm16_lhs(lhs, rhs, offset), + I::I64LtSImm16Lhs { lhs, rhs, .. } => I::branch_i64_lt_s_imm16_lhs(lhs, rhs, offset), + I::I64LtUImm16Lhs { lhs, rhs, .. } => I::branch_i64_lt_u_imm16_lhs(lhs, rhs, offset), + I::I64LeSImm16Rhs { lhs, rhs, .. } => I::branch_i64_le_s_imm16_rhs(lhs, rhs, offset), + I::I64LeUImm16Rhs { lhs, rhs, .. } => I::branch_i64_le_u_imm16_rhs(lhs, rhs, offset), + I::I64LtSImm16Rhs { lhs, rhs, .. } => I::branch_i64_lt_s_imm16_rhs(lhs, rhs, offset), + I::I64LtUImm16Rhs { lhs, rhs, .. } => I::branch_i64_lt_u_imm16_rhs(lhs, rhs, offset), + // f32 + I::F32Eq { lhs, rhs, .. } => I::branch_f32_eq(lhs, rhs, offset), + I::F32Ne { lhs, rhs, .. } => I::branch_f32_ne(lhs, rhs, offset), + I::F32Lt { lhs, rhs, .. } => I::branch_f32_lt(lhs, rhs, offset), + I::F32Le { lhs, rhs, .. } => I::branch_f32_le(lhs, rhs, offset), + // f64 + I::F64Eq { lhs, rhs, .. } => I::branch_f64_eq(lhs, rhs, offset), + I::F64Ne { lhs, rhs, .. } => I::branch_f64_ne(lhs, rhs, offset), + I::F64Lt { lhs, rhs, .. } => I::branch_f64_lt(lhs, rhs, offset), + I::F64Le { lhs, rhs, .. } => I::branch_f64_le(lhs, rhs, offset), + _ => return Ok(None), + }; + Ok(Some(cmp_branch_instr)) } } -impl ComparatorExtImm for Comparator { - fn branch_cmp_instr_imm(self) -> Option> { - use Instruction as I; - let make_instr = match self { - Self::I32LtU => I::branch_i32_lt_u_imm16_rhs, - Self::I32LeU => I::branch_i32_le_u_imm16_rhs, - Self::I32GtU => I::branch_i32_gt_u_imm16_rhs, - Self::I32GeU => I::branch_i32_ge_u_imm16_rhs, - _ => return None, - }; - Some(make_instr) - } +pub trait TryIntoCmpBranchFallbackInstr { + fn try_into_cmp_branch_fallback_instr( + &self, + offset: BranchOffset, + stack: &mut ValueStack, + ) -> Result, Error>; } -impl ComparatorExtImm for Comparator { - fn branch_cmp_instr_imm(self) -> Option> { +impl TryIntoCmpBranchFallbackInstr for Instruction { + fn try_into_cmp_branch_fallback_instr( + &self, + offset: BranchOffset, + stack: &mut ValueStack, + ) -> Result, Error> { use Instruction as I; - let make_instr = match self { - Self::I64Eq => I::branch_i64_eq_imm16, - Self::I64Ne => I::branch_i64_ne_imm16, - Self::I64LtS => I::branch_i64_lt_s_imm16_rhs, - Self::I64LeS => I::branch_i64_le_s_imm16_rhs, - Self::I64GtS => I::branch_i64_gt_s_imm16_rhs, - Self::I64GeS => I::branch_i64_ge_s_imm16_rhs, - _ => return None, + debug_assert!(BranchOffset16::try_from(offset).is_err()); + let Some(comparator) = try_into_cmp_br_comparator(self) else { + return Ok(None); + }; + #[rustfmt::skip] + let (lhs, rhs) = match *self { + | I::BranchI32And { lhs, rhs, .. } + | I::BranchI32Or { lhs, rhs, .. } + | I::BranchI32Xor { lhs, rhs, .. } + | I::BranchI32AndEqz { lhs, rhs, .. } + | I::BranchI32OrEqz { lhs, rhs, .. } + | I::BranchI32XorEqz { lhs, rhs, .. } + | I::BranchI32Eq { lhs, rhs, .. } + | I::BranchI32Ne { lhs, rhs, .. } + | I::BranchI32LtS { lhs, rhs, .. } + | I::BranchI32LtU { lhs, rhs, .. } + | I::BranchI32LeS { lhs, rhs, .. } + | I::BranchI32LeU { lhs, rhs, .. } + | I::BranchI64Eq { lhs, rhs, .. } + | I::BranchI64Ne { lhs, rhs, .. } + | I::BranchI64LtS { lhs, rhs, .. } + | I::BranchI64LtU { lhs, rhs, .. } + | I::BranchI64LeS { lhs, rhs, .. } + | I::BranchI64LeU { lhs, rhs, .. } + | I::BranchF32Eq { lhs, rhs, .. } + | I::BranchF32Ne { lhs, rhs, .. } + | I::BranchF32Lt { lhs, rhs, .. } + | I::BranchF32Le { lhs, rhs, .. } + | I::BranchF64Eq { lhs, rhs, .. } + | I::BranchF64Ne { lhs, rhs, .. } + | I::BranchF64Lt { lhs, rhs, .. } + | I::BranchF64Le { lhs, rhs, .. } => (lhs, rhs), + | I::BranchI32AndImm16 { lhs, rhs, .. } + | I::BranchI32OrImm16 { lhs, rhs, .. } + | I::BranchI32XorImm16 { lhs, rhs, .. } + | I::BranchI32AndEqzImm16 { lhs, rhs, .. } + | I::BranchI32OrEqzImm16 { lhs, rhs, .. } + | I::BranchI32XorEqzImm16 { lhs, rhs, .. } + | I::BranchI32EqImm16 { lhs, rhs, .. } + | I::BranchI32NeImm16 { lhs, rhs, .. } + | I::BranchI32LtSImm16Rhs { lhs, rhs, .. } + | I::BranchI32LeSImm16Rhs { lhs, rhs, .. } => { + let rhs = stack.alloc_const(i32::from(rhs))?; + (lhs, rhs) + } + | I::BranchI32LtSImm16Lhs { lhs, rhs, .. } + | I::BranchI32LeSImm16Lhs { lhs, rhs, .. } => { + let lhs = stack.alloc_const(i32::from(lhs))?; + (lhs, rhs) + } + | I::BranchI32LtUImm16Rhs { lhs, rhs, .. } + | I::BranchI32LeUImm16Rhs { lhs, rhs, .. } => { + let rhs = stack.alloc_const(u32::from(rhs))?; + (lhs, rhs) + } + | I::BranchI32LtUImm16Lhs { lhs, rhs, .. } + | I::BranchI32LeUImm16Lhs { lhs, rhs, .. } => { + let lhs = stack.alloc_const(u32::from(lhs))?; + (lhs, rhs) + } + | I::BranchI64EqImm16 { lhs, rhs, .. } + | I::BranchI64NeImm16 { lhs, rhs, .. } + | I::BranchI64LtSImm16Rhs { lhs, rhs, .. } + | I::BranchI64LeSImm16Rhs { lhs, rhs, .. } => { + let rhs = stack.alloc_const(i64::from(rhs))?; + (lhs, rhs) + } + | I::BranchI64LtSImm16Lhs { lhs, rhs, .. } + | I::BranchI64LeSImm16Lhs { lhs, rhs, .. } => { + let lhs = stack.alloc_const(i64::from(lhs))?; + (lhs, rhs) + } + | I::BranchI64LtUImm16Rhs { lhs, rhs, .. } + | I::BranchI64LeUImm16Rhs { lhs, rhs, .. } => { + let rhs = stack.alloc_const(u64::from(rhs))?; + (lhs, rhs) + } + | I::BranchI64LtUImm16Lhs { lhs, rhs, .. } + | I::BranchI64LeUImm16Lhs { lhs, rhs, .. } => { + let lhs = stack.alloc_const(u64::from(lhs))?; + (lhs, rhs) + } + _ => return Ok(None), }; - Some(make_instr) + let params = stack.alloc_const(ComparatorAndOffset::new(comparator, offset))?; + Ok(Some(Instruction::branch_cmp_fallback(lhs, rhs, params))) } } -impl ComparatorExtImm for Comparator { - fn branch_cmp_instr_imm(self) -> Option> { - use Instruction as I; - let make_instr = match self { - Self::I64LtU => I::branch_i64_lt_u_imm16_rhs, - Self::I64LeU => I::branch_i64_le_u_imm16_rhs, - Self::I64GtU => I::branch_i64_gt_u_imm16_rhs, - Self::I64GeU => I::branch_i64_ge_u_imm16_rhs, - _ => return None, - }; - Some(make_instr) - } +fn try_into_cmp_br_comparator(instr: &Instruction) -> Option { + use Instruction as I; + #[rustfmt::skip] + let comparator = match *instr { + // i32 + | I::BranchI32Eq { .. } | I::BranchI32EqImm16 { .. } => Comparator::I32Eq, + | I::BranchI32Ne { .. } | I::BranchI32NeImm16 { .. } => Comparator::I32Ne, + | I::BranchI32LtS { .. } + | I::BranchI32LtSImm16Lhs { .. } + | I::BranchI32LtSImm16Rhs { .. } => Comparator::I32LtS, + | I::BranchI32LtU { .. } + | I::BranchI32LtUImm16Lhs { .. } + | I::BranchI32LtUImm16Rhs { .. } => Comparator::I32LtU, + | I::BranchI32LeS { .. } + | I::BranchI32LeSImm16Lhs { .. } + | I::BranchI32LeSImm16Rhs { .. } => Comparator::I32LeS, + | I::BranchI32LeU { .. } + | I::BranchI32LeUImm16Lhs { .. } + | I::BranchI32LeUImm16Rhs { .. } => Comparator::I32LeU, + // i32 (special) + | I::BranchI32And { .. } => Comparator::I32And, + | I::BranchI32Or { .. } => Comparator::I32Or, + | I::BranchI32Xor { .. } => Comparator::I32Xor, + | I::BranchI32AndEqz { .. } => Comparator::I32AndEqz, + | I::BranchI32OrEqz { .. } => Comparator::I32OrEqz, + | I::BranchI32XorEqz { .. } => Comparator::I32XorEqz, + // i64 + | I::BranchI64Eq { .. } | I::BranchI64EqImm16 { .. } => Comparator::I64Eq, + | I::BranchI64Ne { .. } | I::BranchI64NeImm16 { .. } => Comparator::I64Ne, + | I::BranchI64LtS { .. } + | I::BranchI64LtSImm16Lhs { .. } + | I::BranchI64LtSImm16Rhs { .. } => Comparator::I64LtS, + | I::BranchI64LtU { .. } + | I::BranchI64LtUImm16Lhs { .. } + | I::BranchI64LtUImm16Rhs { .. } => Comparator::I64LtU, + | I::BranchI64LeS { .. } + | I::BranchI64LeSImm16Lhs { .. } + | I::BranchI64LeSImm16Rhs { .. } => Comparator::I64LeS, + | I::BranchI64LeU { .. } + | I::BranchI64LeUImm16Lhs { .. } + | I::BranchI64LeUImm16Rhs { .. } => Comparator::I64LeU, + // f32 + | I::BranchF32Eq { .. } => Comparator::F32Eq, + | I::BranchF32Ne { .. } => Comparator::F32Ne, + | I::BranchF32Lt { .. } => Comparator::F32Lt, + | I::BranchF32Le { .. } => Comparator::F32Le, + // f64 + | I::BranchF64Eq { .. } => Comparator::F64Eq, + | I::BranchF64Ne { .. } => Comparator::F64Ne, + | I::BranchF64Lt { .. } => Comparator::F64Lt, + | I::BranchF64Le { .. } => Comparator::F64Le, + _ => return None, + }; + Some(comparator) } diff --git a/crates/wasmi/src/engine/translator/instr_encoder.rs b/crates/wasmi/src/engine/translator/instr_encoder.rs index 99143c0dc7..6aea272193 100644 --- a/crates/wasmi/src/engine/translator/instr_encoder.rs +++ b/crates/wasmi/src/engine/translator/instr_encoder.rs @@ -3,12 +3,13 @@ use super::{ utils::FromProviders as _, visit_register::VisitInputRegisters as _, BumpFuelConsumption as _, - ComparatorExt as _, - ComparatorExtImm, FuelInfo, LabelRef, LabelRegistry, + NegateCmpInstr, Provider, + TryIntoCmpBranchFallbackInstr, + TryIntoCmpBranchInstr, TypedProvider, }; use crate::{ @@ -24,7 +25,6 @@ use crate::{ BranchOffset16, Comparator, ComparatorAndOffset, - Const16, Const32, Instruction, Reg, @@ -921,89 +921,35 @@ impl InstrEncoder { /// Tries to fuse `i32.eqz` with a previous `i32.{and,or,xor}` instruction if possible. /// Returns `true` if it was possible to fuse the `i32.eqz` instruction. pub fn fuse_i32_eqz(&mut self, stack: &mut ValueStack) -> bool { - /// Fuse a `i32.{and,or,xor}` instruction with `i32.eqz`. - macro_rules! fuse { - ($result:expr, $lhs:expr, $rhs:expr, $stack:ident, $input:ident, $make_fuse:expr) => {{ - if matches!($stack.get_register_space($result), RegisterSpace::Local) { - // The instruction stores its result into a local variable which - // is an observable side effect which we are not allowed to mutate. - return false; - } - if $result != $input { - // The result of the instruction and the current input are not equal - // thus indicating that we cannot fuse the instructions. - return false; - } - $make_fuse($result, $lhs, $rhs) - }}; - } - - /// Fuse a `i32.{and,or,xor}` instruction with 16-bit encoded immediate parameter with `i32.eqz`. - macro_rules! fuse_imm16 { - ($result:expr, $lhs:expr, $rhs:expr, $stack:ident, $input:ident, $make_fuse:expr) => {{ - if matches!($stack.get_register_space($result), RegisterSpace::Local) { - // The instruction stores its result into a local variable which - // is an observable side effect which we are not allowed to mutate. - return false; - } - if $result != $input { - // The result of the instruction and the current input are not equal - // thus indicating that we cannot fuse the instructions. - return false; - } - $make_fuse($result, $lhs, $rhs) - }}; - } - let Provider::Register(input) = stack.peek() else { + // Only register inputs can be negated. + // Constant inputs are resolved via constant propagation. return false; }; let Some(last_instr) = self.last_instr else { + // If there is no last instruction there is no comparison instruction to negate. return false; }; - let fused_instr = match *self.instrs.get(last_instr) { - Instruction::I32And { result, lhs, rhs } => { - fuse!(result, lhs, rhs, stack, input, Instruction::i32_and_eqz) - } - Instruction::I32AndImm16 { result, lhs, rhs } => { - fuse_imm16!( - result, - lhs, - rhs, - stack, - input, - Instruction::i32_and_eqz_imm16 - ) - } - Instruction::I32Or { result, lhs, rhs } => { - fuse!(result, lhs, rhs, stack, input, Instruction::i32_or_eqz) - } - Instruction::I32OrImm16 { result, lhs, rhs } => { - fuse_imm16!( - result, - lhs, - rhs, - stack, - input, - Instruction::i32_or_eqz_imm16 - ) - } - Instruction::I32Xor { result, lhs, rhs } => { - fuse!(result, lhs, rhs, stack, input, Instruction::i32_xor_eqz) - } - Instruction::I32XorImm16 { result, lhs, rhs } => { - fuse_imm16!( - result, - lhs, - rhs, - stack, - input, - Instruction::i32_xor_eqz_imm16 - ) - } - _ => return false, + let last_instruction = *self.instrs.get(last_instr); + let Some(result) = last_instruction.result() else { + // All negatable instructions have a single result register. + return false; }; - _ = mem::replace(self.instrs.get_mut(last_instr), fused_instr); + if matches!(stack.get_register_space(result), RegisterSpace::Local) { + // The instruction stores its result into a local variable which + // is an observable side effect which we are not allowed to mutate. + return false; + } + if result != input { + // The result of the instruction and the current input are not equal + // thus indicating that we cannot fuse the instructions. + return false; + } + let Some(negated) = last_instruction.negate_cmp_instr() else { + // Last instruction is unable to be negated. + return false; + }; + _ = mem::replace(self.instrs.get_mut(last_instr), negated); true } @@ -1019,84 +965,6 @@ impl InstrEncoder { Ok(Instruction::branch_cmp_fallback(lhs, rhs, params)) } - /// Try to create a fused cmp+branch instruction. - /// - /// Returns `Some` `Instruction` if the cmp+branch instruction fusion was successful. - #[allow(clippy::too_many_arguments)] - fn try_fuse_branch_cmp( - &mut self, - stack: &mut ValueStack, - last_instr: Instr, - condition: Reg, - result: Reg, - lhs: Reg, - rhs: Reg, - label: LabelRef, - cmp: Comparator, - ) -> Result, Error> { - if matches!(stack.get_register_space(result), RegisterSpace::Local) { - // We need to filter out instructions that store their result - // into a local register slot because they introduce observable behavior - // which a fused cmp+branch instruction would remove. - return Ok(None); - } - if result != condition { - // We cannot fuse the instructions since the result of the compare instruction - // does not match the input of the conditional branch instruction. - return Ok(None); - } - let offset = self.try_resolve_label_for(label, last_instr)?; - let instr = match BranchOffset16::try_from(offset) { - Ok(offset) => (cmp.branch_cmp_instr())(lhs, rhs, offset), - Err(_) => InstrEncoder::make_branch_cmp_fallback(stack, cmp, lhs, rhs, offset)?, - }; - Ok(Some(instr)) - } - - /// Try to create a fused cmp+branch instruction with 16-bit immediate value. - /// - /// Returns `Some` `Instruction` if the cmp+branch instruction fusion was successful. - #[allow(clippy::too_many_arguments)] - fn try_fuse_branch_cmp_imm( - &mut self, - stack: &mut ValueStack, - last_instr: Instr, - condition: Reg, - result: Reg, - lhs: Reg, - rhs: Const16, - label: LabelRef, - cmp: Comparator, - ) -> Result, Error> - where - T: From> + Into, - Comparator: ComparatorExtImm, - { - if matches!(stack.get_register_space(result), RegisterSpace::Local) { - // We need to filter out instructions that store their result - // into a local register slot because they introduce observable behavior - // which a fused cmp+branch instruction would remove. - return Ok(None); - } - if result != condition { - // We cannot fuse the instructions since the result of the compare instruction - // does not match the input of the conditional branch instruction. - return Ok(None); - } - let Some(make_instr) = cmp.branch_cmp_instr_imm() else { - unreachable!("expected valid `Instruction` constructor for `T` for {cmp:?}") - }; - let offset = self.try_resolve_label_for(label, last_instr)?; - let instr = match BranchOffset16::try_from(offset) { - Ok(offset) => make_instr(lhs, rhs, offset), - Err(_) => { - let rhs = stack.alloc_const(T::from(rhs))?; - InstrEncoder::make_branch_cmp_fallback(stack, cmp, lhs, rhs, offset)? - } - }; - Ok(Some(instr)) - } - /// Encodes a `branch_eqz` instruction and tries to fuse it with a previous comparison instruction. pub fn encode_branch_eqz( &mut self, @@ -1107,15 +975,8 @@ impl InstrEncoder { let Some(last_instr) = self.last_instr else { return self.encode_branch_eqz_unopt(stack, condition, label); }; - let last_instruction = *self.instrs.get(last_instr); - let Some(comparator) = Comparator::from_cmp_instruction(last_instruction) else { - return self.encode_branch_eqz_unopt(stack, condition, label); - }; - let Some(comparator) = comparator.negate() else { - return self.encode_branch_eqz_unopt(stack, condition, label); - }; let fused_instr = - self.try_fuse_branch_cmp_for_instr(stack, last_instr, condition, label, comparator)?; + self.try_fuse_branch_cmp_for_instr(stack, last_instr, condition, label, true)?; if let Some(fused_instr) = fused_instr { _ = mem::replace(self.instrs.get_mut(last_instr), fused_instr); return Ok(()); @@ -1160,12 +1021,8 @@ impl InstrEncoder { let Some(last_instr) = self.last_instr else { return self.encode_branch_nez_unopt(stack, condition, label); }; - let last_instruction = *self.instrs.get(last_instr); - let Some(comparator) = Comparator::from_cmp_instruction(last_instruction) else { - return self.encode_branch_nez_unopt(stack, condition, label); - }; let fused_instr = - self.try_fuse_branch_cmp_for_instr(stack, last_instr, condition, label, comparator)?; + self.try_fuse_branch_cmp_for_instr(stack, last_instr, condition, label, false)?; if let Some(fused_instr) = fused_instr { _ = mem::replace(self.instrs.get_mut(last_instr), fused_instr); return Ok(()); @@ -1176,93 +1033,66 @@ impl InstrEncoder { /// Try to fuse [`Instruction`] at `instr` into a branch+cmp instruction. /// /// Returns `Ok(Some)` if successful. + #[rustfmt::skip] fn try_fuse_branch_cmp_for_instr( &mut self, stack: &mut ValueStack, - instr: Instr, + last_instr: Instr, condition: Reg, label: LabelRef, - comparator: Comparator, + negate: bool, ) -> Result, Error> { use Instruction as I; - let fused_instr = match *self.instrs.get(instr) { - | I::I32And { result, lhs, rhs } - | I::I32Or { result, lhs, rhs } - | I::I32Xor { result, lhs, rhs } - | I::I32AndEqz { result, lhs, rhs } - | I::I32OrEqz { result, lhs, rhs } - | I::I32XorEqz { result, lhs, rhs } - | I::I32Eq { result, lhs, rhs } - | I::I32Ne { result, lhs, rhs } - | I::I32LtS { result, lhs, rhs } - | I::I32LtU { result, lhs, rhs } - | I::I32LeS { result, lhs, rhs } - | I::I32LeU { result, lhs, rhs } - | I::I32GtS { result, lhs, rhs } - | I::I32GtU { result, lhs, rhs } - | I::I32GeS { result, lhs, rhs } - | I::I32GeU { result, lhs, rhs } - | I::I64Eq { result, lhs, rhs } - | I::I64Ne { result, lhs, rhs } - | I::I64LtS { result, lhs, rhs } - | I::I64LtU { result, lhs, rhs } - | I::I64LeS { result, lhs, rhs } - | I::I64LeU { result, lhs, rhs } - | I::I64GtS { result, lhs, rhs } - | I::I64GtU { result, lhs, rhs } - | I::I64GeS { result, lhs, rhs } - | I::I64GeU { result, lhs, rhs } - | I::F32Eq { result, lhs, rhs } - | I::F32Ne { result, lhs, rhs } - | I::F32Lt { result, lhs, rhs } - | I::F32Le { result, lhs, rhs } - | I::F32Gt { result, lhs, rhs } - | I::F32Ge { result, lhs, rhs } - | I::F64Eq { result, lhs, rhs } - | I::F64Ne { result, lhs, rhs } - | I::F64Lt { result, lhs, rhs } - | I::F64Le { result, lhs, rhs } - | I::F64Gt { result, lhs, rhs } - | I::F64Ge { result, lhs, rhs } => self.try_fuse_branch_cmp( - stack, instr, condition, result, lhs, rhs, label, comparator, - )?, - | I::I32AndImm16 { result, lhs, rhs } - | I::I32OrImm16 { result, lhs, rhs } - | I::I32XorImm16 { result, lhs, rhs } - | I::I32AndEqzImm16 { result, lhs, rhs } - | I::I32OrEqzImm16 { result, lhs, rhs } - | I::I32XorEqzImm16 { result, lhs, rhs } - | I::I32EqImm16 { result, lhs, rhs } - | I::I32NeImm16 { result, lhs, rhs } - | I::I32LtSImm16Rhs { result, lhs, rhs } - | I::I32LeSImm16Rhs { result, lhs, rhs } - | I::I32GtSImm16Rhs { result, lhs, rhs } - | I::I32GeSImm16Rhs { result, lhs, rhs } => self.try_fuse_branch_cmp_imm::( - stack, instr, condition, result, lhs, rhs, label, comparator, - )?, - | I::I32LtUImm16Rhs { result, lhs, rhs } - | I::I32LeUImm16Rhs { result, lhs, rhs } - | I::I32GtUImm16Rhs { result, lhs, rhs } - | I::I32GeUImm16Rhs { result, lhs, rhs } => self.try_fuse_branch_cmp_imm::( - stack, instr, condition, result, lhs, rhs, label, comparator, - )?, - | I::I64EqImm16 { result, lhs, rhs } - | I::I64NeImm16 { result, lhs, rhs } - | I::I64LtSImm16Rhs { result, lhs, rhs } - | I::I64LeSImm16Rhs { result, lhs, rhs } - | I::I64GtSImm16Rhs { result, lhs, rhs } - | I::I64GeSImm16Rhs { result, lhs, rhs } => self.try_fuse_branch_cmp_imm::( - stack, instr, condition, result, lhs, rhs, label, comparator, - )?, - | I::I64LtUImm16Rhs { result, lhs, rhs } - | I::I64LeUImm16Rhs { result, lhs, rhs } - | I::I64GtUImm16Rhs { result, lhs, rhs } - | I::I64GeUImm16Rhs { result, lhs, rhs } => self.try_fuse_branch_cmp_imm::( - stack, instr, condition, result, lhs, rhs, label, comparator, - )?, - _ => None, + let last_instruction = *self.instrs.get(last_instr); + let result = match last_instruction { + | I::I32And { result, .. } | I::I32AndImm16 { result, .. } + | I::I32Or { result, .. } | I::I32OrImm16 { result, .. } + | I::I32Xor { result, .. } | I::I32XorImm16 { result, .. } + | I::I32AndEqz { result, .. } | I::I32AndEqzImm16 { result, .. } + | I::I32OrEqz { result, .. } | I::I32OrEqzImm16 { result, .. } + | I::I32XorEqz { result, .. } | I::I32XorEqzImm16 { result, .. } + | I::I32Eq { result, .. } | I::I32EqImm16 { result, .. } + | I::I32Ne { result, .. } | I::I32NeImm16 { result, .. } + | I::I32LtS { result, .. } | I::I32LtSImm16Lhs { result, .. } | I::I32LtSImm16Rhs { result, .. } + | I::I32LtU { result, .. } | I::I32LtUImm16Lhs { result, .. } | I::I32LtUImm16Rhs { result, .. } + | I::I32LeS { result, .. } | I::I32LeSImm16Lhs { result, .. } | I::I32LeSImm16Rhs { result, .. } + | I::I32LeU { result, .. } | I::I32LeUImm16Lhs { result, .. } | I::I32LeUImm16Rhs { result, .. } + | I::I64Eq { result, .. } | I::I64EqImm16 { result, .. } + | I::I64Ne { result, .. } | I::I64NeImm16 { result, .. } + | I::I64LtS { result, .. } | I::I64LtSImm16Lhs { result, .. } | I::I64LtSImm16Rhs { result, .. } + | I::I64LtU { result, .. } | I::I64LtUImm16Lhs { result, .. } | I::I64LtUImm16Rhs { result, .. } + | I::I64LeS { result, .. } | I::I64LeSImm16Lhs { result, .. } | I::I64LeSImm16Rhs { result, .. } + | I::I64LeU { result, .. } | I::I64LeUImm16Lhs { result, .. } | I::I64LeUImm16Rhs { result, .. } + | I::F32Eq { result, .. } + | I::F32Ne { result, .. } + | I::F32Lt { result, .. } + | I::F32Le { result, .. } + | I::F64Eq { result, .. } + | I::F64Ne { result, .. } + | I::F64Lt { result, .. } + | I::F64Le { result, .. } => result, + _ => return Ok(None), }; - Ok(fused_instr) + if matches!(stack.get_register_space(result), RegisterSpace::Local) { + // We need to filter out instructions that store their result + // into a local register slot because they introduce observable behavior + // which a fused cmp+branch instruction would remove. + return Ok(None); + } + if result != condition { + // We cannot fuse the instructions since the result of the compare instruction + // does not match the input of the conditional branch instruction. + return Ok(None); + } + let last_instruction = match negate { + true => match last_instruction.negate_cmp_instr() { + Some(negated) => negated, + None => return Ok(None), + }, + false => last_instruction, + }; + let offset = self.try_resolve_label_for(label, last_instr)?; + last_instruction.try_into_cmp_branch_instr(offset, stack) } /// Encode an unoptimized `branch_nez` instruction. @@ -1310,30 +1140,6 @@ trait UpdateBranchOffset { impl UpdateBranchOffset for Instruction { #[rustfmt::skip] fn update_branch_offset(&mut self, stack: &mut ValueStack, new_offset: BranchOffset) -> Result<(), Error> { - /// Updates the [`BranchOffset16`] to `new_offset` if possible. - /// - /// Otherwise returns `Some` fallback `Instruction` that replaces the outer `self`. - fn init_offset_imm( - stack: &mut ValueStack, - lhs: Reg, - rhs: Const16, - offset: &mut BranchOffset16, - new_offset: BranchOffset, - cmp: Comparator, - ) -> Result, Error> - where - T: From> + Into, - { - match offset.init(new_offset) { - Ok(_) => Ok(None), - Err(_) => { - let rhs = stack.alloc_const(::from(rhs))?; - let params = stack.alloc_const(ComparatorAndOffset::new(cmp, new_offset))?; - Ok(Some(Instruction::branch_cmp_fallback(lhs, rhs, params))) - } - } - } - use Instruction as I; match self { Instruction::Branch { offset } | @@ -1344,94 +1150,69 @@ impl UpdateBranchOffset for Instruction { } _ => {} }; - let Some(comparator) = Comparator::from_cmp_branch_instruction(*self) else { - panic!("expected a Wasmi branch+cmp instruction but found: {:?}", *self) - }; - let update = match self { - I::BranchI32And { lhs, rhs, offset } | - I::BranchI32Or { lhs, rhs, offset } | - I::BranchI32Xor { lhs, rhs, offset } | - I::BranchI32AndEqz { lhs, rhs, offset } | - I::BranchI32OrEqz { lhs, rhs, offset } | - I::BranchI32XorEqz { lhs, rhs, offset } | - I::BranchI32Eq { lhs, rhs, offset } | - I::BranchI32Ne { lhs, rhs, offset } | - I::BranchI32LtS { lhs, rhs, offset } | - I::BranchI32LtU { lhs, rhs, offset } | - I::BranchI32LeS { lhs, rhs, offset } | - I::BranchI32LeU { lhs, rhs, offset } | - I::BranchI32GtS { lhs, rhs, offset } | - I::BranchI32GtU { lhs, rhs, offset } | - I::BranchI32GeS { lhs, rhs, offset } | - I::BranchI32GeU { lhs, rhs, offset } | - I::BranchI64Eq { lhs, rhs, offset } | - I::BranchI64Ne { lhs, rhs, offset } | - I::BranchI64LtS { lhs, rhs, offset } | - I::BranchI64LtU { lhs, rhs, offset } | - I::BranchI64LeS { lhs, rhs, offset } | - I::BranchI64LeU { lhs, rhs, offset } | - I::BranchI64GtS { lhs, rhs, offset } | - I::BranchI64GtU { lhs, rhs, offset } | - I::BranchI64GeS { lhs, rhs, offset } | - I::BranchI64GeU { lhs, rhs, offset } | - I::BranchF32Eq { lhs, rhs, offset } | - I::BranchF32Ne { lhs, rhs, offset } | - I::BranchF32Lt { lhs, rhs, offset } | - I::BranchF32Le { lhs, rhs, offset } | - I::BranchF32Gt { lhs, rhs, offset } | - I::BranchF32Ge { lhs, rhs, offset } | - I::BranchF64Eq { lhs, rhs, offset } | - I::BranchF64Ne { lhs, rhs, offset } | - I::BranchF64Lt { lhs, rhs, offset } | - I::BranchF64Le { lhs, rhs, offset } | - I::BranchF64Gt { lhs, rhs, offset } | - I::BranchF64Ge { lhs, rhs, offset } => { - match offset.init(new_offset) { - Ok(_) => None, - Err(_) => { - let params = stack.alloc_const(ComparatorAndOffset::new(comparator, new_offset))?; - Some(Instruction::branch_cmp_fallback(*lhs, *rhs, params)) - } - } - } - I::BranchI32AndImm16 { lhs, rhs, offset } | - I::BranchI32OrImm16 { lhs, rhs, offset } | - I::BranchI32XorImm16 { lhs, rhs, offset } | - I::BranchI32AndEqzImm16 { lhs, rhs, offset } | - I::BranchI32OrEqzImm16 { lhs, rhs, offset } | - I::BranchI32XorEqzImm16 { lhs, rhs, offset } | - I::BranchI32EqImm16 { lhs, rhs, offset } | - I::BranchI32NeImm16 { lhs, rhs, offset } | - I::BranchI32LtSImm16Rhs { lhs, rhs, offset } | - I::BranchI32LeSImm16Rhs { lhs, rhs, offset } | - I::BranchI32GtSImm16Rhs { lhs, rhs, offset } | - I::BranchI32GeSImm16Rhs { lhs, rhs, offset } => { - init_offset_imm::(stack, *lhs, *rhs, offset, new_offset, comparator)? + let update_status = match self { + I::BranchI32And { offset, .. } | + I::BranchI32Or { offset, .. } | + I::BranchI32Xor { offset, .. } | + I::BranchI32AndEqz { offset, .. } | + I::BranchI32OrEqz { offset, .. } | + I::BranchI32XorEqz { offset, .. } | + I::BranchI32Eq { offset, .. } | + I::BranchI32Ne { offset, .. } | + I::BranchI32LtS { offset, .. } | + I::BranchI32LtU { offset, .. } | + I::BranchI32LeS { offset, .. } | + I::BranchI32LeU { offset, .. } | + I::BranchI64Eq { offset, .. } | + I::BranchI64Ne { offset, .. } | + I::BranchI64LtS { offset, .. } | + I::BranchI64LtU { offset, .. } | + I::BranchI64LeS { offset, .. } | + I::BranchI64LeU { offset, .. } | + I::BranchF32Eq { offset, .. } | + I::BranchF32Ne { offset, .. } | + I::BranchF32Lt { offset, .. } | + I::BranchF32Le { offset, .. } | + I::BranchF64Eq { offset, .. } | + I::BranchF64Ne { offset, .. } | + I::BranchF64Lt { offset, .. } | + I::BranchF64Le { offset, .. } | + I::BranchI32AndImm16 { offset, .. } | + I::BranchI32OrImm16 { offset, .. } | + I::BranchI32XorImm16 { offset, .. } | + I::BranchI32AndEqzImm16 { offset, .. } | + I::BranchI32OrEqzImm16 { offset, .. } | + I::BranchI32XorEqzImm16 { offset, .. } | + I::BranchI32EqImm16 { offset, .. } | + I::BranchI32NeImm16 { offset, .. } | + I::BranchI32LtSImm16Lhs { offset, .. } | + I::BranchI32LtSImm16Rhs { offset, .. } | + I::BranchI32LeSImm16Lhs { offset, .. } | + I::BranchI32LeSImm16Rhs { offset, .. } | + I::BranchI32LtUImm16Lhs { offset, .. } | + I::BranchI32LtUImm16Rhs { offset, .. } | + I::BranchI32LeUImm16Lhs { offset, .. } | + I::BranchI32LeUImm16Rhs { offset, .. } | + I::BranchI64EqImm16 { offset, .. } | + I::BranchI64NeImm16 { offset, .. } | + I::BranchI64LtSImm16Lhs { offset, .. } | + I::BranchI64LtSImm16Rhs { offset, .. } | + I::BranchI64LeSImm16Lhs { offset, .. } | + I::BranchI64LeSImm16Rhs { offset, .. } | + I::BranchI64LtUImm16Lhs { offset, .. } | + I::BranchI64LtUImm16Rhs { offset, .. } | + I::BranchI64LeUImm16Lhs { offset, .. } | + I::BranchI64LeUImm16Rhs { offset, .. } => { + offset.init(new_offset) } - I::BranchI32LtUImm16Rhs { lhs, rhs, offset } | - I::BranchI32LeUImm16Rhs { lhs, rhs, offset } | - I::BranchI32GtUImm16Rhs { lhs, rhs, offset } | - I::BranchI32GeUImm16Rhs { lhs, rhs, offset } => { - init_offset_imm::(stack, *lhs, *rhs, offset, new_offset, comparator)? + unexpected => { + panic!("expected a Wasmi branch+cmp instruction but found: {unexpected:?}") } - I::BranchI64EqImm16 { lhs, rhs, offset } | - I::BranchI64NeImm16 { lhs, rhs, offset } | - I::BranchI64LtSImm16Rhs { lhs, rhs, offset } | - I::BranchI64LeSImm16Rhs { lhs, rhs, offset } | - I::BranchI64GtSImm16Rhs { lhs, rhs, offset } | - I::BranchI64GeSImm16Rhs { lhs, rhs, offset } => { - init_offset_imm::(stack, *lhs, *rhs, offset, new_offset, comparator)? - } - I::BranchI64LtUImm16Rhs { lhs, rhs, offset } | - I::BranchI64LeUImm16Rhs { lhs, rhs, offset } | - I::BranchI64GtUImm16Rhs { lhs, rhs, offset } | - I::BranchI64GeUImm16Rhs { lhs, rhs, offset } => { - init_offset_imm::(stack, *lhs, *rhs, offset, new_offset, comparator)? - } - _ => panic!("expected a Wasmi branch+cmp instruction but found: {:?}", *self), }; - if let Some(update) = update { - *self = update; + if update_status.is_err() { + if let Some(fallback) = self.try_into_cmp_branch_fallback_instr(new_offset, stack)? { + *self = fallback; + } } Ok(()) } diff --git a/crates/wasmi/src/engine/translator/mod.rs b/crates/wasmi/src/engine/translator/mod.rs index d046c9f620..9ee5bcb0d8 100644 --- a/crates/wasmi/src/engine/translator/mod.rs +++ b/crates/wasmi/src/engine/translator/mod.rs @@ -18,7 +18,7 @@ mod visit_register; mod tests; use self::{ - comparator::{ComparatorExt, ComparatorExtImm}, + comparator::{NegateCmpInstr, TryIntoCmpBranchFallbackInstr, TryIntoCmpBranchInstr}, control_frame::{ BlockControlFrame, BlockHeight, @@ -1363,8 +1363,8 @@ impl FuncTranslator { fn translate_binary( &mut self, make_instr: fn(result: Reg, lhs: Reg, rhs: Reg) -> Instruction, - make_instr_imm16: fn(result: Reg, lhs: Reg, rhs: Const16) -> Instruction, - make_instr_imm16_rev: fn(result: Reg, lhs: Const16, rhs: Reg) -> Instruction, + make_instr_imm16_rhs: fn(result: Reg, lhs: Reg, rhs: Const16) -> Instruction, + make_instr_imm16_lhs: fn(result: Reg, lhs: Const16, rhs: Reg) -> Instruction, consteval: fn(TypedVal, TypedVal) -> TypedVal, make_instr_opt: fn(&mut Self, lhs: Reg, rhs: Reg) -> Result, make_instr_reg_imm_opt: fn(&mut Self, lhs: Reg, rhs: T) -> Result, @@ -1387,7 +1387,7 @@ impl FuncTranslator { // Case: the custom logic applied its optimization and we can return. return Ok(()); } - if self.try_push_binary_instr_imm16(lhs, T::from(rhs), make_instr_imm16)? { + if self.try_push_binary_instr_imm16(lhs, T::from(rhs), make_instr_imm16_rhs)? { // Optimization was applied: return early. return Ok(()); } @@ -1398,7 +1398,7 @@ impl FuncTranslator { // Case: the custom logic applied its optimization and we can return. return Ok(()); } - if self.try_push_binary_instr_imm16_rev(T::from(lhs), rhs, make_instr_imm16_rev)? { + if self.try_push_binary_instr_imm16_rev(T::from(lhs), rhs, make_instr_imm16_lhs)? { // Optimization was applied: return early. return Ok(()); } diff --git a/crates/wasmi/src/engine/translator/tests/fuzz/mod.rs b/crates/wasmi/src/engine/translator/tests/fuzz/mod.rs index 6708c4dd1d..1be418f84f 100644 --- a/crates/wasmi/src/engine/translator/tests/fuzz/mod.rs +++ b/crates/wasmi/src/engine/translator/tests/fuzz/mod.rs @@ -205,7 +205,7 @@ fn fuzz_regression_12_f32() { ])) .expect_func(ExpectedFunc::new([ Instruction::copy_imm32(Reg::from(0), u32::MAX), - Instruction::f32_ge(Reg::from(1), Reg::from(0), Reg::from(0)), + Instruction::f32_le(Reg::from(1), Reg::from(0), Reg::from(0)), Instruction::return_nez(1), Instruction::trap(TrapCode::UnreachableCodeReached), ])) @@ -229,7 +229,7 @@ fn fuzz_regression_12_f64() { .expect_func( ExpectedFunc::new([ Instruction::copy(0, -1), - Instruction::f64_ge(Reg::from(1), Reg::from(0), Reg::from(0)), + Instruction::f64_le(Reg::from(1), Reg::from(0), Reg::from(0)), Instruction::return_nez(1), Instruction::trap(TrapCode::UnreachableCodeReached), ]) diff --git a/crates/wasmi/src/engine/translator/tests/mod.rs b/crates/wasmi/src/engine/translator/tests/mod.rs index 7605cd9e49..b68ee8589e 100644 --- a/crates/wasmi/src/engine/translator/tests/mod.rs +++ b/crates/wasmi/src/engine/translator/tests/mod.rs @@ -32,11 +32,19 @@ fn create_module(config: &Config, bytes: &[u8]) -> Module { /// Used to swap operands of a `rev` variant [`Instruction`] constructor. macro_rules! swap_ops { ($fn_name:path) => { - |result: Reg, lhs: Const16<_>, rhs: Reg| -> Instruction { $fn_name(result, rhs, lhs) } + |result: Reg, lhs, rhs| -> Instruction { $fn_name(result, rhs, lhs) } }; } use swap_ops; +/// Used to swap `lhs` and `rhs` operands of a fused `cmp+branch` instruction. +macro_rules! swap_cmp_br_ops { + ($fn_name:path) => { + |lhs, rhs, offset: BranchOffset16| -> Instruction { $fn_name(rhs, lhs, offset) } + }; +} +use swap_cmp_br_ops; + /// Asserts that the given `wasm` bytes yield functions with expected instructions. /// /// Uses the given [`Config`] to configure the [`Engine`] that the tests are run on. diff --git a/crates/wasmi/src/engine/translator/tests/op/br_if.rs b/crates/wasmi/src/engine/translator/tests/op/br_if.rs index 71ab5b8d7a..a61144e52d 100644 --- a/crates/wasmi/src/engine/translator/tests/op/br_if.rs +++ b/crates/wasmi/src/engine/translator/tests/op/br_if.rs @@ -989,3 +989,46 @@ fn branch_if_results_4_mixed_2() { ]) .run() } + +#[test] +#[cfg_attr(miri, ignore)] +fn branch_if_i32_eqz() { + let wasm = r" + (module + (func (param i32) + (block $exit + (i32.eqz (local.get 0)) ;; br_if condition + (br_if $exit) + (drop (i32.add (local.get 0) (i32.const 1))) + ) + ) + )"; + TranslationTest::from_wat(wasm) + .expect_func_instrs([ + Instruction::branch_i32_eq_imm16(0, 0_i16, BranchOffset16::from(2)), + Instruction::i32_add_imm16(1, 0, 1), + Instruction::r#return(), + ]) + .run() +} + +#[test] +#[cfg_attr(miri, ignore)] +fn return_if_i32_eqz() { + let wasm = r" + (module + (func (param i32) + (i32.eqz (local.get 0)) ;; br_if condition + (br_if 0) + (drop (i32.add (local.get 0) (i32.const 1))) + ) + )"; + TranslationTest::from_wat(wasm) + .expect_func_instrs([ + Instruction::i32_eq_imm16(1, 0, 0), + Instruction::return_nez(1), + Instruction::i32_add_imm16(1, 0, 1), + Instruction::r#return(), + ]) + .run() +} diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/f32_ge.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/f32_ge.rs index 08d700361d..6dbc89604d 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/f32_ge.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/f32_ge.rs @@ -6,7 +6,7 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F32, "ge"); #[cfg_attr(miri, ignore)] fn same_reg() { let expected = [ - Instruction::f32_ge(Reg::from(1), Reg::from(0), Reg::from(0)), + Instruction::f32_le(Reg::from(1), Reg::from(0), Reg::from(0)), Instruction::return_reg(1), ]; test_binary_same_reg(WASM_OP, expected) @@ -15,19 +15,19 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::f32_ge) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::f32_le)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 1.0_f32, Instruction::f32_ge) + test_binary_reg_imm32(WASM_OP, 1.0_f32, swap_ops!(Instruction::f32_le)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 1.0_f32, Instruction::f32_ge) + test_binary_reg_imm32_lhs(WASM_OP, 1.0_f32, swap_ops!(Instruction::f32_le)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/f32_gt.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/f32_gt.rs index 14da7e15b0..7e6b757a32 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/f32_gt.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/f32_gt.rs @@ -14,19 +14,19 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::f32_gt) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::f32_lt)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 1.0_f32, Instruction::f32_gt) + test_binary_reg_imm32(WASM_OP, 1.0_f32, swap_ops!(Instruction::f32_lt)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 1.0_f32, Instruction::f32_gt) + test_binary_reg_imm32_lhs(WASM_OP, 1.0_f32, swap_ops!(Instruction::f32_lt)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/f64_ge.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/f64_ge.rs index eecc59802c..1196398760 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/f64_ge.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/f64_ge.rs @@ -6,7 +6,7 @@ const WASM_OP: WasmOp = WasmOp::cmp(WasmType::F64, "ge"); #[cfg_attr(miri, ignore)] fn same_reg() { let expected = [ - Instruction::f64_ge(Reg::from(1), Reg::from(0), Reg::from(0)), + Instruction::f64_le(Reg::from(1), Reg::from(0), Reg::from(0)), Instruction::return_reg(1), ]; test_binary_same_reg(WASM_OP, expected) @@ -15,19 +15,19 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::f64_ge) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::f64_le)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 1.0, Instruction::f64_ge) + test_binary_reg_imm32(WASM_OP, 1.0, swap_ops!(Instruction::f64_le)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 1.0, Instruction::f64_ge) + test_binary_reg_imm32_lhs(WASM_OP, 1.0, swap_ops!(Instruction::f64_le)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/f64_gt.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/f64_gt.rs index 41cf72cdbf..67feaa49c6 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/f64_gt.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/f64_gt.rs @@ -14,19 +14,19 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::f64_gt) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::f64_lt)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 1.0, Instruction::f64_gt) + test_binary_reg_imm32(WASM_OP, 1.0, swap_ops!(Instruction::f64_lt)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 1.0, Instruction::f64_gt) + test_binary_reg_imm32_lhs(WASM_OP, 1.0, swap_ops!(Instruction::f64_lt)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_s.rs index 8c4e94188c..25a7719840 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_s.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i32_ge_s) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i32_le_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i32_ge_s_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i32_le_s_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i32_ge_s) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i32_le_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i32_ge_s) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i32_le_s)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_u.rs index 5fe3781b71..dfa5860242 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_ge_u.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i32_ge_u) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i32_le_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i32_ge_u_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i32_le_u_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i32_ge_u) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i32_le_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i32_ge_u) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i32_le_u)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_s.rs index 3b8777c491..d4caa00a57 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_s.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i32_gt_s) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i32_lt_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i32_gt_s_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i32_lt_s_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i32_gt_s) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i32_lt_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i32_gt_s) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i32_lt_s)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_u.rs index b98f6a8291..a1fb91c4be 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_gt_u.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i32_gt_u) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i32_lt_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i32_gt_u_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i32_lt_u_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i32_gt_u) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i32_lt_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i32_gt_u) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i32_lt_u)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_s.rs index fd6c2f6ce0..776993e270 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_s.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i32_ge_s_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i32_le_s_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_u.rs index c474acc5a3..6463681b87 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_le_u.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i32_ge_u_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i32_le_u_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_s.rs index 613f670f44..3ad868ae76 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_s.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i32_gt_s_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i32_lt_s_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_u.rs index 0b25b21139..e691cd4638 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i32_lt_u.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i32_gt_u_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i32_lt_u_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_s.rs index ae5295dba1..bc8b93582c 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_s.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i64_ge_s) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i64_le_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i64_ge_s_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i64_le_s_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i64_ge_s) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i64_le_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i64_ge_s) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i64_le_s)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_u.rs index ddc57e5938..512cffaf8a 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_ge_u.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i64_ge_u) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i64_le_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i64_ge_u_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i64_le_u_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i64_ge_u) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i64_le_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i64_ge_u) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i64_le_u)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_s.rs index 7d4d3edd4c..b1aaf6c5a9 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_s.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i64_gt_s) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i64_lt_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i64_gt_s_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i64_lt_s_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i64_gt_s) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i64_lt_s)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i64_gt_s) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i64_lt_s)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_u.rs index 381f9ffb45..ce58a1043f 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_gt_u.rs @@ -14,13 +14,13 @@ fn same_reg() { #[test] #[cfg_attr(miri, ignore)] fn reg_reg() { - test_binary_reg_reg(WASM_OP, Instruction::i64_gt_u) + test_binary_reg_reg(WASM_OP, swap_ops!(Instruction::i64_lt_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm16() { - test_binary_reg_imm16_rhs::(WASM_OP, 100, Instruction::i64_gt_u_imm16_rhs) + test_binary_reg_imm16_rhs::(WASM_OP, 100, swap_ops!(Instruction::i64_lt_u_imm16_lhs)) } #[test] @@ -32,13 +32,13 @@ fn reg_imm16_lhs() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm() { - test_binary_reg_imm32(WASM_OP, 100_000, Instruction::i64_gt_u) + test_binary_reg_imm32(WASM_OP, 100_000, swap_ops!(Instruction::i64_lt_u)) } #[test] #[cfg_attr(miri, ignore)] fn reg_imm_lhs() { - test_binary_reg_imm32_lhs(WASM_OP, 100_000, Instruction::i64_gt_u) + test_binary_reg_imm32_lhs(WASM_OP, 100_000, swap_ops!(Instruction::i64_lt_u)) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_s.rs index ded595815f..141b03f73a 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_s.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i64_ge_s_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i64_le_s_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_u.rs index 1e7b648462..d9f7089569 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_le_u.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i64_ge_u_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i64_le_u_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_s.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_s.rs index a488ce9fd6..c54d2bc532 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_s.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_s.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i64_gt_s_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i64_lt_s_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_u.rs b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_u.rs index ff230da2d6..7eb235f3bb 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_u.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp/i64_lt_u.rs @@ -26,7 +26,7 @@ fn reg_imm16() { #[test] #[cfg_attr(miri, ignore)] fn reg_imm16_lhs() { - test_binary_reg_imm16_lhs::(WASM_OP, 100, swap_ops!(Instruction::i64_gt_u_imm16_rhs)) + test_binary_reg_imm16_lhs::(WASM_OP, 100, Instruction::i64_lt_u_imm16_lhs) } #[test] diff --git a/crates/wasmi/src/engine/translator/tests/op/cmp_br.rs b/crates/wasmi/src/engine/translator/tests/op/cmp_br.rs index 6af038d34a..606a2b0137 100644 --- a/crates/wasmi/src/engine/translator/tests/op/cmp_br.rs +++ b/crates/wasmi/src/engine/translator/tests/op/cmp_br.rs @@ -40,10 +40,26 @@ fn loop_backward() { test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u); test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s); test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u); - test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s); - test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u); - test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s); - test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u); + test_for( + ValType::I32, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i32_lt_s), + ); + test_for( + ValType::I32, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i32_lt_u), + ); + test_for( + ValType::I32, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i32_le_s), + ); + test_for( + ValType::I32, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i32_le_u), + ); test_for(ValType::I64, "eq", Instruction::branch_i64_eq); test_for(ValType::I64, "ne", Instruction::branch_i64_ne); @@ -51,24 +67,56 @@ fn loop_backward() { test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u); test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s); test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u); - test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s); - test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u); - test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s); - test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u); + test_for( + ValType::I64, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i64_lt_s), + ); + test_for( + ValType::I64, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i64_lt_u), + ); + test_for( + ValType::I64, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i64_le_s), + ); + test_for( + ValType::I64, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i64_le_u), + ); test_for(ValType::F32, "eq", Instruction::branch_f32_eq); test_for(ValType::F32, "ne", Instruction::branch_f32_ne); test_for(ValType::F32, "lt", Instruction::branch_f32_lt); test_for(ValType::F32, "le", Instruction::branch_f32_le); - test_for(ValType::F32, "gt", Instruction::branch_f32_gt); - test_for(ValType::F32, "ge", Instruction::branch_f32_ge); + test_for( + ValType::F32, + "gt", + swap_cmp_br_ops!(Instruction::branch_f32_lt), + ); + test_for( + ValType::F32, + "ge", + swap_cmp_br_ops!(Instruction::branch_f32_le), + ); test_for(ValType::F64, "eq", Instruction::branch_f64_eq); test_for(ValType::F64, "ne", Instruction::branch_f64_ne); test_for(ValType::F64, "lt", Instruction::branch_f64_lt); test_for(ValType::F64, "le", Instruction::branch_f64_le); - test_for(ValType::F64, "gt", Instruction::branch_f64_gt); - test_for(ValType::F64, "ge", Instruction::branch_f64_ge); + test_for( + ValType::F64, + "gt", + swap_cmp_br_ops!(Instruction::branch_f64_lt), + ); + test_for( + ValType::F64, + "ge", + swap_cmp_br_ops!(Instruction::branch_f64_le), + ); } #[test] @@ -119,10 +167,26 @@ fn loop_backward_imm() { test_for::("lt_u", 1, Instruction::branch_i32_lt_u_imm16_rhs); test_for::("le_s", 1, Instruction::branch_i32_le_s_imm16_rhs); test_for::("le_u", 1, Instruction::branch_i32_le_u_imm16_rhs); - test_for::("gt_s", 1, Instruction::branch_i32_gt_s_imm16_rhs); - test_for::("gt_u", 1, Instruction::branch_i32_gt_u_imm16_rhs); - test_for::("ge_s", 1, Instruction::branch_i32_ge_s_imm16_rhs); - test_for::("ge_u", 1, Instruction::branch_i32_ge_u_imm16_rhs); + test_for::( + "gt_s", + 1, + swap_cmp_br_ops!(Instruction::branch_i32_lt_s_imm16_lhs), + ); + test_for::( + "gt_u", + 1, + swap_cmp_br_ops!(Instruction::branch_i32_lt_u_imm16_lhs), + ); + test_for::( + "ge_s", + 1, + swap_cmp_br_ops!(Instruction::branch_i32_le_s_imm16_lhs), + ); + test_for::( + "ge_u", + 1, + swap_cmp_br_ops!(Instruction::branch_i32_le_u_imm16_lhs), + ); test_for::("eq", 1, Instruction::branch_i64_eq_imm16); test_for::("ne", 1, Instruction::branch_i64_ne_imm16); @@ -130,10 +194,26 @@ fn loop_backward_imm() { test_for::("lt_u", 1, Instruction::branch_i64_lt_u_imm16_rhs); test_for::("le_s", 1, Instruction::branch_i64_le_s_imm16_rhs); test_for::("le_u", 1, Instruction::branch_i64_le_u_imm16_rhs); - test_for::("gt_s", 1, Instruction::branch_i64_gt_s_imm16_rhs); - test_for::("gt_u", 1, Instruction::branch_i64_gt_u_imm16_rhs); - test_for::("ge_s", 1, Instruction::branch_i64_ge_s_imm16_rhs); - test_for::("ge_u", 1, Instruction::branch_i64_ge_u_imm16_rhs); + test_for::( + "gt_s", + 1, + swap_cmp_br_ops!(Instruction::branch_i64_lt_s_imm16_lhs), + ); + test_for::( + "gt_u", + 1, + swap_cmp_br_ops!(Instruction::branch_i64_lt_u_imm16_lhs), + ); + test_for::( + "ge_s", + 1, + swap_cmp_br_ops!(Instruction::branch_i64_le_s_imm16_lhs), + ); + test_for::( + "ge_u", + 1, + swap_cmp_br_ops!(Instruction::branch_i64_le_u_imm16_lhs), + ); } #[test] @@ -199,10 +279,26 @@ fn block_forward() { test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u); test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s); test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u); - test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s); - test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u); - test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s); - test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u); + test_for( + ValType::I32, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i32_lt_s), + ); + test_for( + ValType::I32, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i32_lt_u), + ); + test_for( + ValType::I32, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i32_le_s), + ); + test_for( + ValType::I32, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i32_le_u), + ); test_for(ValType::I64, "eq", Instruction::branch_i64_eq); test_for(ValType::I64, "ne", Instruction::branch_i64_ne); @@ -210,24 +306,56 @@ fn block_forward() { test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u); test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s); test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u); - test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s); - test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u); - test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s); - test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u); + test_for( + ValType::I64, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i64_lt_s), + ); + test_for( + ValType::I64, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i64_lt_u), + ); + test_for( + ValType::I64, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i64_le_s), + ); + test_for( + ValType::I64, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i64_le_u), + ); test_for(ValType::F32, "eq", Instruction::branch_f32_eq); test_for(ValType::F32, "ne", Instruction::branch_f32_ne); test_for(ValType::F32, "lt", Instruction::branch_f32_lt); test_for(ValType::F32, "le", Instruction::branch_f32_le); - test_for(ValType::F32, "gt", Instruction::branch_f32_gt); - test_for(ValType::F32, "ge", Instruction::branch_f32_ge); + test_for( + ValType::F32, + "gt", + swap_cmp_br_ops!(Instruction::branch_f32_lt), + ); + test_for( + ValType::F32, + "ge", + swap_cmp_br_ops!(Instruction::branch_f32_le), + ); test_for(ValType::F64, "eq", Instruction::branch_f64_eq); test_for(ValType::F64, "ne", Instruction::branch_f64_ne); test_for(ValType::F64, "lt", Instruction::branch_f64_lt); test_for(ValType::F64, "le", Instruction::branch_f64_le); - test_for(ValType::F64, "gt", Instruction::branch_f64_gt); - test_for(ValType::F64, "ge", Instruction::branch_f64_ge); + test_for( + ValType::F64, + "gt", + swap_cmp_br_ops!(Instruction::branch_f64_lt), + ); + test_for( + ValType::F64, + "ge", + swap_cmp_br_ops!(Instruction::branch_f64_le), + ); } #[test] @@ -271,10 +399,26 @@ fn block_forward_nop_copy() { test_for(ValType::I32, "lt_u", Instruction::branch_i32_lt_u); test_for(ValType::I32, "le_s", Instruction::branch_i32_le_s); test_for(ValType::I32, "le_u", Instruction::branch_i32_le_u); - test_for(ValType::I32, "gt_s", Instruction::branch_i32_gt_s); - test_for(ValType::I32, "gt_u", Instruction::branch_i32_gt_u); - test_for(ValType::I32, "ge_s", Instruction::branch_i32_ge_s); - test_for(ValType::I32, "ge_u", Instruction::branch_i32_ge_u); + test_for( + ValType::I32, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i32_lt_s), + ); + test_for( + ValType::I32, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i32_lt_u), + ); + test_for( + ValType::I32, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i32_le_s), + ); + test_for( + ValType::I32, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i32_le_u), + ); test_for(ValType::I64, "eq", Instruction::branch_i64_eq); test_for(ValType::I64, "ne", Instruction::branch_i64_ne); @@ -282,24 +426,56 @@ fn block_forward_nop_copy() { test_for(ValType::I64, "lt_u", Instruction::branch_i64_lt_u); test_for(ValType::I64, "le_s", Instruction::branch_i64_le_s); test_for(ValType::I64, "le_u", Instruction::branch_i64_le_u); - test_for(ValType::I64, "gt_s", Instruction::branch_i64_gt_s); - test_for(ValType::I64, "gt_u", Instruction::branch_i64_gt_u); - test_for(ValType::I64, "ge_s", Instruction::branch_i64_ge_s); - test_for(ValType::I64, "ge_u", Instruction::branch_i64_ge_u); + test_for( + ValType::I64, + "gt_s", + swap_cmp_br_ops!(Instruction::branch_i64_lt_s), + ); + test_for( + ValType::I64, + "gt_u", + swap_cmp_br_ops!(Instruction::branch_i64_lt_u), + ); + test_for( + ValType::I64, + "ge_s", + swap_cmp_br_ops!(Instruction::branch_i64_le_s), + ); + test_for( + ValType::I64, + "ge_u", + swap_cmp_br_ops!(Instruction::branch_i64_le_u), + ); test_for(ValType::F32, "eq", Instruction::branch_f32_eq); test_for(ValType::F32, "ne", Instruction::branch_f32_ne); test_for(ValType::F32, "lt", Instruction::branch_f32_lt); test_for(ValType::F32, "le", Instruction::branch_f32_le); - test_for(ValType::F32, "gt", Instruction::branch_f32_gt); - test_for(ValType::F32, "ge", Instruction::branch_f32_ge); + test_for( + ValType::F32, + "gt", + swap_cmp_br_ops!(Instruction::branch_f32_lt), + ); + test_for( + ValType::F32, + "ge", + swap_cmp_br_ops!(Instruction::branch_f32_le), + ); test_for(ValType::F64, "eq", Instruction::branch_f64_eq); test_for(ValType::F64, "ne", Instruction::branch_f64_ne); test_for(ValType::F64, "lt", Instruction::branch_f64_lt); test_for(ValType::F64, "le", Instruction::branch_f64_le); - test_for(ValType::F64, "gt", Instruction::branch_f64_gt); - test_for(ValType::F64, "ge", Instruction::branch_f64_ge); + test_for( + ValType::F64, + "gt", + swap_cmp_br_ops!(Instruction::branch_f64_lt), + ); + test_for( + ValType::F64, + "ge", + swap_cmp_br_ops!(Instruction::branch_f64_le), + ); } #[test] @@ -339,10 +515,26 @@ fn if_forward_multi_value() { test_for(ValType::I32, "xor", Instruction::branch_i32_xor_eqz); test_for(ValType::I32, "eq", Instruction::branch_i32_ne); test_for(ValType::I32, "ne", Instruction::branch_i32_eq); - test_for(ValType::I32, "lt_s", Instruction::branch_i32_ge_s); - test_for(ValType::I32, "lt_u", Instruction::branch_i32_ge_u); - test_for(ValType::I32, "le_s", Instruction::branch_i32_gt_s); - test_for(ValType::I32, "le_u", Instruction::branch_i32_gt_u); + test_for( + ValType::I32, + "lt_s", + swap_cmp_br_ops!(Instruction::branch_i32_le_s), + ); + test_for( + ValType::I32, + "lt_u", + swap_cmp_br_ops!(Instruction::branch_i32_le_u), + ); + test_for( + ValType::I32, + "le_s", + swap_cmp_br_ops!(Instruction::branch_i32_lt_s), + ); + test_for( + ValType::I32, + "le_u", + swap_cmp_br_ops!(Instruction::branch_i32_lt_u), + ); test_for(ValType::I32, "gt_s", Instruction::branch_i32_le_s); test_for(ValType::I32, "gt_u", Instruction::branch_i32_le_u); test_for(ValType::I32, "ge_s", Instruction::branch_i32_lt_s); @@ -350,10 +542,26 @@ fn if_forward_multi_value() { test_for(ValType::I64, "eq", Instruction::branch_i64_ne); test_for(ValType::I64, "ne", Instruction::branch_i64_eq); - test_for(ValType::I64, "lt_s", Instruction::branch_i64_ge_s); - test_for(ValType::I64, "lt_u", Instruction::branch_i64_ge_u); - test_for(ValType::I64, "le_s", Instruction::branch_i64_gt_s); - test_for(ValType::I64, "le_u", Instruction::branch_i64_gt_u); + test_for( + ValType::I64, + "lt_s", + swap_cmp_br_ops!(Instruction::branch_i64_le_s), + ); + test_for( + ValType::I64, + "lt_u", + swap_cmp_br_ops!(Instruction::branch_i64_le_u), + ); + test_for( + ValType::I64, + "le_s", + swap_cmp_br_ops!(Instruction::branch_i64_lt_s), + ); + test_for( + ValType::I64, + "le_u", + swap_cmp_br_ops!(Instruction::branch_i64_lt_u), + ); test_for(ValType::I64, "gt_s", Instruction::branch_i64_le_s); test_for(ValType::I64, "gt_u", Instruction::branch_i64_le_u); test_for(ValType::I64, "ge_s", Instruction::branch_i64_lt_s); @@ -392,10 +600,26 @@ fn if_forward() { test_for(ValType::I32, "xor", Instruction::branch_i32_xor_eqz); test_for(ValType::I32, "eq", Instruction::branch_i32_ne); test_for(ValType::I32, "ne", Instruction::branch_i32_eq); - test_for(ValType::I32, "lt_s", Instruction::branch_i32_ge_s); - test_for(ValType::I32, "lt_u", Instruction::branch_i32_ge_u); - test_for(ValType::I32, "le_s", Instruction::branch_i32_gt_s); - test_for(ValType::I32, "le_u", Instruction::branch_i32_gt_u); + test_for( + ValType::I32, + "lt_s", + swap_cmp_br_ops!(Instruction::branch_i32_le_s), + ); + test_for( + ValType::I32, + "lt_u", + swap_cmp_br_ops!(Instruction::branch_i32_le_u), + ); + test_for( + ValType::I32, + "le_s", + swap_cmp_br_ops!(Instruction::branch_i32_lt_s), + ); + test_for( + ValType::I32, + "le_u", + swap_cmp_br_ops!(Instruction::branch_i32_lt_u), + ); test_for(ValType::I32, "gt_s", Instruction::branch_i32_le_s); test_for(ValType::I32, "gt_u", Instruction::branch_i32_le_u); test_for(ValType::I32, "ge_s", Instruction::branch_i32_lt_s); @@ -403,10 +627,26 @@ fn if_forward() { test_for(ValType::I64, "eq", Instruction::branch_i64_ne); test_for(ValType::I64, "ne", Instruction::branch_i64_eq); - test_for(ValType::I64, "lt_s", Instruction::branch_i64_ge_s); - test_for(ValType::I64, "lt_u", Instruction::branch_i64_ge_u); - test_for(ValType::I64, "le_s", Instruction::branch_i64_gt_s); - test_for(ValType::I64, "le_u", Instruction::branch_i64_gt_u); + test_for( + ValType::I64, + "lt_s", + swap_cmp_br_ops!(Instruction::branch_i64_le_s), + ); + test_for( + ValType::I64, + "lt_u", + swap_cmp_br_ops!(Instruction::branch_i64_le_u), + ); + test_for( + ValType::I64, + "le_s", + swap_cmp_br_ops!(Instruction::branch_i64_lt_s), + ); + test_for( + ValType::I64, + "le_u", + swap_cmp_br_ops!(Instruction::branch_i64_lt_u), + ); test_for(ValType::I64, "gt_s", Instruction::branch_i64_le_s); test_for(ValType::I64, "gt_u", Instruction::branch_i64_le_u); test_for(ValType::I64, "ge_s", Instruction::branch_i64_lt_s); diff --git a/crates/wasmi/src/engine/translator/tests/op/i32_eqz.rs b/crates/wasmi/src/engine/translator/tests/op/i32_eqz.rs index 54bc02da98..5984a983d1 100644 --- a/crates/wasmi/src/engine/translator/tests/op/i32_eqz.rs +++ b/crates/wasmi/src/engine/translator/tests/op/i32_eqz.rs @@ -1,16 +1,29 @@ use super::*; +use core::fmt::Display; +use wasm_type::WasmTy; + +macro_rules! test_for { + ( $( ($input_ty:literal, $op:literal, $make_instr:expr) ),* $(,)? + ) => { + $( test_for($input_ty, $op, $make_instr); )* + }; +} #[test] #[cfg_attr(miri, ignore)] -fn binop_i32_eqz() { - fn test_for(op: &str, expect_instr: fn(result: Reg, lhs: Reg, rhs: Reg) -> Instruction) { +fn binop_i32_eqz_i64() { + fn test_for( + input_ty: &str, + op: &str, + expect_instr: fn(result: Reg, lhs: Reg, rhs: Reg) -> Instruction, + ) { let wasm = &format!( r" (module - (func (param i32 i32) (result i32) + (func (param {input_ty} {input_ty}) (result i32) (local.get 0) (local.get 1) - (i32.{op}) + ({input_ty}.{op}) (i32.eqz) ) )", @@ -22,37 +35,95 @@ fn binop_i32_eqz() { ]) .run() } - test_for("and", Instruction::i32_and_eqz); - test_for("or", Instruction::i32_or_eqz); - test_for("xor", Instruction::i32_xor_eqz); + test_for!( + ("i32", "and", Instruction::i32_and_eqz), + ("i32", "or", Instruction::i32_or_eqz), + ("i32", "xor", Instruction::i32_xor_eqz), + ("i32", "lt_s", swap_ops!(Instruction::i32_le_s)), + ("i32", "lt_u", swap_ops!(Instruction::i32_le_u)), + ("i32", "le_s", swap_ops!(Instruction::i32_lt_s)), + ("i32", "le_u", swap_ops!(Instruction::i32_lt_u)), + ("i32", "gt_s", Instruction::i32_le_s), + ("i32", "gt_u", Instruction::i32_le_u), + ("i32", "ge_s", Instruction::i32_lt_s), + ("i32", "ge_u", Instruction::i32_lt_u), + ("i64", "lt_s", swap_ops!(Instruction::i64_le_s)), + ("i64", "lt_u", swap_ops!(Instruction::i64_le_u)), + ("i64", "le_s", swap_ops!(Instruction::i64_lt_s)), + ("i64", "le_u", swap_ops!(Instruction::i64_lt_u)), + ("i64", "gt_s", Instruction::i64_le_s), + ("i64", "gt_u", Instruction::i64_le_u), + ("i64", "ge_s", Instruction::i64_lt_s), + ("i64", "ge_u", Instruction::i64_lt_u), + ("f32", "eq", Instruction::f32_ne), + ("f32", "ne", Instruction::f32_eq), + ("f64", "eq", Instruction::f64_ne), + ("f64", "ne", Instruction::f64_eq), + ); +} + +macro_rules! test_for_imm { + ( $( ($input_ty:ty, $op:literal, $make_instr:expr) ),* $(,)? + ) => { + $( test_for::<$input_ty>($op, 1, $make_instr); )* + }; } #[test] #[cfg_attr(miri, ignore)] fn binop_imm_i32_eqz() { - fn test_for( + fn test_for( op: &str, - expect_instr: fn(result: Reg, lhs: Reg, rhs: Const16) -> Instruction, - ) { + value: T, + expect_instr: fn(result: Reg, lhs: Reg, rhs: Const16) -> Instruction, + ) where + T: Display + WasmTy, + Const16: TryFrom, + DisplayWasm: Display, + { + let input_ty = T::NAME; + let display_value = DisplayWasm::from(value); let wasm = &format!( r" (module - (func (param i32 i32) (result i32) + (func (param {input_ty} {input_ty}) (result i32) (local.get 0) - (i32.const 1) - (i32.{op}) + ({input_ty}.const {display_value}) + ({input_ty}.{op}) (i32.eqz) ) )", ); TranslationTest::from_wat(wasm) .expect_func_instrs([ - expect_instr(Reg::from(2), Reg::from(0), Const16::from(1)), + expect_instr( + Reg::from(2), + Reg::from(0), + Const16::try_from(value).ok().unwrap(), + ), Instruction::return_reg(2), ]) .run() } - test_for("and", Instruction::i32_and_eqz_imm16); - test_for("or", Instruction::i32_or_eqz_imm16); - test_for("xor", Instruction::i32_xor_eqz_imm16); + test_for_imm!( + (i32, "and", Instruction::i32_and_eqz_imm16), + (i32, "or", Instruction::i32_or_eqz_imm16), + (i32, "xor", Instruction::i32_xor_eqz_imm16), + (i32, "lt_s", swap_ops!(Instruction::i32_le_s_imm16_lhs)), + (u32, "lt_u", swap_ops!(Instruction::i32_le_u_imm16_lhs)), + (i32, "le_s", swap_ops!(Instruction::i32_lt_s_imm16_lhs)), + (u32, "le_u", swap_ops!(Instruction::i32_lt_u_imm16_lhs)), + (i32, "gt_s", Instruction::i32_le_s_imm16_rhs), + (u32, "gt_u", Instruction::i32_le_u_imm16_rhs), + (i32, "ge_s", Instruction::i32_lt_s_imm16_rhs), + (u32, "ge_u", Instruction::i32_lt_u_imm16_rhs), + (i64, "lt_s", swap_ops!(Instruction::i64_le_s_imm16_lhs)), + (u64, "lt_u", swap_ops!(Instruction::i64_le_u_imm16_lhs)), + (i64, "le_s", swap_ops!(Instruction::i64_lt_s_imm16_lhs)), + (u64, "le_u", swap_ops!(Instruction::i64_lt_u_imm16_lhs)), + (i64, "gt_s", Instruction::i64_le_s_imm16_rhs), + (u64, "gt_u", Instruction::i64_le_u_imm16_rhs), + (i64, "ge_s", Instruction::i64_lt_s_imm16_rhs), + (u64, "ge_u", Instruction::i64_lt_u_imm16_rhs), + ); } diff --git a/crates/wasmi/src/engine/translator/tests/op/mod.rs b/crates/wasmi/src/engine/translator/tests/op/mod.rs index 922171b2d2..ec799a73df 100644 --- a/crates/wasmi/src/engine/translator/tests/op/mod.rs +++ b/crates/wasmi/src/engine/translator/tests/op/mod.rs @@ -28,6 +28,7 @@ use super::{ bspan, display_wasm::DisplayValueType, driver::ExpectedFunc, + swap_cmp_br_ops, swap_ops, test_binary_consteval, test_binary_reg_imm16_lhs, diff --git a/crates/wasmi/src/engine/translator/visit.rs b/crates/wasmi/src/engine/translator/visit.rs index d6833fb0fd..a3b7006d44 100644 --- a/crates/wasmi/src/engine/translator/visit.rs +++ b/crates/wasmi/src/engine/translator/visit.rs @@ -31,10 +31,10 @@ use crate::{ use core::num::{NonZeroU32, NonZeroU64}; use wasmparser::VisitOperator; -/// Used to swap operands of a `rev` variant [`Instruction`] constructor. +/// Used to swap operands of binary [`Instruction`] constructor. macro_rules! swap_ops { ($fn_name:path) => { - |result: Reg, lhs: Const16<_>, rhs: Reg| -> Instruction { $fn_name(result, rhs, lhs) } + |result: Reg, lhs, rhs| -> Instruction { $fn_name(result, rhs, lhs) } }; } @@ -1126,7 +1126,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i32_lt_s, Instruction::i32_lt_s_imm16_rhs, - swap_ops!(Instruction::i32_gt_s_imm16_rhs), + Instruction::i32_lt_s_imm16_lhs, TypedVal::i32_lt_s, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1159,7 +1159,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i32_lt_u, Instruction::i32_lt_u_imm16_rhs, - swap_ops!(Instruction::i32_gt_u_imm16_rhs), + Instruction::i32_lt_u_imm16_lhs, TypedVal::i32_lt_u, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1190,8 +1190,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i32_gt_s(&mut self) -> Self::Output { self.translate_binary( - Instruction::i32_gt_s, - Instruction::i32_gt_s_imm16_rhs, + swap_ops!(Instruction::i32_lt_s), + swap_ops!(Instruction::i32_lt_s_imm16_lhs), swap_ops!(Instruction::i32_lt_s_imm16_rhs), TypedVal::i32_gt_s, |this, lhs: Reg, rhs: Reg| { @@ -1223,8 +1223,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i32_gt_u(&mut self) -> Self::Output { self.translate_binary( - Instruction::i32_gt_u, - Instruction::i32_gt_u_imm16_rhs, + swap_ops!(Instruction::i32_lt_u), + swap_ops!(Instruction::i32_lt_u_imm16_lhs), swap_ops!(Instruction::i32_lt_u_imm16_rhs), TypedVal::i32_gt_u, |this, lhs: Reg, rhs: Reg| { @@ -1258,7 +1258,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i32_le_s, Instruction::i32_le_s_imm16_rhs, - swap_ops!(Instruction::i32_ge_s_imm16_rhs), + Instruction::i32_le_s_imm16_lhs, TypedVal::i32_le_s, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1291,7 +1291,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i32_le_u, Instruction::i32_le_u_imm16_rhs, - swap_ops!(Instruction::i32_ge_u_imm16_rhs), + Instruction::i32_le_u_imm16_lhs, TypedVal::i32_le_u, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1322,8 +1322,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i32_ge_s(&mut self) -> Self::Output { self.translate_binary( - Instruction::i32_ge_s, - Instruction::i32_ge_s_imm16_rhs, + swap_ops!(Instruction::i32_le_s), + swap_ops!(Instruction::i32_le_s_imm16_lhs), swap_ops!(Instruction::i32_le_s_imm16_rhs), TypedVal::i32_ge_s, |this, lhs: Reg, rhs: Reg| { @@ -1355,8 +1355,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i32_ge_u(&mut self) -> Self::Output { self.translate_binary( - Instruction::i32_ge_u, - Instruction::i32_ge_u_imm16_rhs, + swap_ops!(Instruction::i32_le_u), + swap_ops!(Instruction::i32_le_u_imm16_lhs), swap_ops!(Instruction::i32_le_u_imm16_rhs), TypedVal::i32_ge_u, |this, lhs: Reg, rhs: Reg| { @@ -1431,7 +1431,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i64_lt_s, Instruction::i64_lt_s_imm16_rhs, - swap_ops!(Instruction::i64_gt_s_imm16_rhs), + Instruction::i64_lt_s_imm16_lhs, TypedVal::i64_lt_s, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1464,7 +1464,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i64_lt_u, Instruction::i64_lt_u_imm16_rhs, - swap_ops!(Instruction::i64_gt_u_imm16_rhs), + Instruction::i64_lt_u_imm16_lhs, TypedVal::i64_lt_u, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1495,8 +1495,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i64_gt_s(&mut self) -> Self::Output { self.translate_binary( - Instruction::i64_gt_s, - Instruction::i64_gt_s_imm16_rhs, + swap_ops!(Instruction::i64_lt_s), + swap_ops!(Instruction::i64_lt_s_imm16_lhs), swap_ops!(Instruction::i64_lt_s_imm16_rhs), TypedVal::i64_gt_s, |this, lhs: Reg, rhs: Reg| { @@ -1528,8 +1528,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i64_gt_u(&mut self) -> Self::Output { self.translate_binary( - Instruction::i64_gt_u, - Instruction::i64_gt_u_imm16_rhs, + swap_ops!(Instruction::i64_lt_u), + swap_ops!(Instruction::i64_lt_u_imm16_lhs), swap_ops!(Instruction::i64_lt_u_imm16_rhs), TypedVal::i64_gt_u, |this, lhs: Reg, rhs: Reg| { @@ -1563,7 +1563,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i64_le_s, Instruction::i64_le_s_imm16_rhs, - swap_ops!(Instruction::i64_ge_s_imm16_rhs), + Instruction::i64_le_s_imm16_lhs, TypedVal::i64_le_s, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1596,7 +1596,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { self.translate_binary( Instruction::i64_le_u, Instruction::i64_le_u_imm16_rhs, - swap_ops!(Instruction::i64_ge_u_imm16_rhs), + Instruction::i64_le_u_imm16_lhs, TypedVal::i64_le_u, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1627,8 +1627,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i64_ge_s(&mut self) -> Self::Output { self.translate_binary( - Instruction::i64_ge_s, - Instruction::i64_ge_s_imm16_rhs, + swap_ops!(Instruction::i64_le_s), + swap_ops!(Instruction::i64_le_s_imm16_lhs), swap_ops!(Instruction::i64_le_s_imm16_rhs), TypedVal::i64_ge_s, |this, lhs: Reg, rhs: Reg| { @@ -1660,8 +1660,8 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_i64_ge_u(&mut self) -> Self::Output { self.translate_binary( - Instruction::i64_ge_u, - Instruction::i64_ge_u_imm16_rhs, + swap_ops!(Instruction::i64_le_u), + swap_ops!(Instruction::i64_le_u_imm16_lhs), swap_ops!(Instruction::i64_le_u_imm16_rhs), TypedVal::i64_ge_u, |this, lhs: Reg, rhs: Reg| { @@ -1766,7 +1766,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_f32_gt(&mut self) -> Self::Output { self.translate_fbinary( - Instruction::f32_gt, + swap_ops!(Instruction::f32_lt), TypedVal::f32_gt, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1831,7 +1831,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_f32_ge(&mut self) -> Self::Output { self.translate_fbinary( - Instruction::f32_ge, + swap_ops!(Instruction::f32_le), TypedVal::f32_ge, Self::no_custom_opt, |this, _lhs: Reg, rhs: f32| { @@ -1928,7 +1928,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_f64_gt(&mut self) -> Self::Output { self.translate_fbinary( - Instruction::f64_gt, + swap_ops!(Instruction::f64_lt), TypedVal::f64_gt, |this, lhs: Reg, rhs: Reg| { if lhs == rhs { @@ -1993,7 +1993,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { fn visit_f64_ge(&mut self) -> Self::Output { self.translate_fbinary( - Instruction::f64_ge, + swap_ops!(Instruction::f64_le), TypedVal::f64_ge, Self::no_custom_opt, |this, _lhs: Reg, rhs: f64| {