Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement cmp+branch instruction fusion #789

Merged
merged 32 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b247433
add 16-bit BranchOffset16 utility type
Robbepop Nov 19, 2023
2f98f46
move new BranchOffset16 to regmach module
Robbepop Nov 19, 2023
493ad3b
create new utility BranchBinOpInstr[Imm] types
Robbepop Nov 19, 2023
713d242
add fused cmp+branch instructions
Robbepop Nov 19, 2023
cbcaa53
fixed signedness of some branch_cmp_imm instructions
Robbepop Nov 19, 2023
a015886
implement fused cmp+branch_nez instruction translation
Robbepop Nov 19, 2023
6465fa1
remove invalid debug_assert
Robbepop Nov 19, 2023
e0013a6
add minimal test for fused cmp+branch instruction translation
Robbepop Nov 19, 2023
36a8510
change count_until.wat benchmark to allow for fused cmp+branch
Robbepop Nov 19, 2023
1abe535
fix bug in InstrEncoder::encode_branch_nez
Robbepop Nov 19, 2023
b178161
more fixes for the same bug
Robbepop Nov 19, 2023
30e32f7
add another test
Robbepop Nov 19, 2023
3b4dbe2
fix bug with default encoding
Robbepop Nov 20, 2023
143f5e1
special fusing cmp+br with cmp={eq,ne} and rhs=0
Robbepop Nov 20, 2023
4e56eb9
rename internal function
Robbepop Nov 20, 2023
83b5e50
make cmp+branch fusion possible for uninit offsets
Robbepop Nov 20, 2023
481398e
add TODO comment for future
Robbepop Nov 20, 2023
3c2bfcf
do not fuse cmp+branch if cmp stores into a local
Robbepop Nov 20, 2023
0225462
apply rustfmt
Robbepop Nov 20, 2023
41398f0
no longer optimize local.set when result is a local
Robbepop Nov 20, 2023
463b1f6
apply manual less verbose formatting
Robbepop Nov 20, 2023
f120625
separate reg and imm variants in cmp+branch fusion
Robbepop Nov 20, 2023
0791b9c
implement branch_eqz cmp+branch fusion
Robbepop Nov 20, 2023
ee970fc
add some more cmp+branch fusion translation tests
Robbepop Nov 20, 2023
1a5a2ba
extend new loop_backward test
Robbepop Nov 20, 2023
e0cc5bb
apply rustfmt
Robbepop Nov 20, 2023
4e2c3fa
extend another test case to be more generic
Robbepop Nov 20, 2023
4830169
extend another test
Robbepop Nov 20, 2023
df92d3e
extend block_forward test
Robbepop Nov 20, 2023
47cd46a
extend block_forward_no_copy test
Robbepop Nov 20, 2023
6cb3500
extend if_forward_multi_value test
Robbepop Nov 20, 2023
9522600
extend if_forward test
Robbepop Nov 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions crates/wasmi/benches/wat/count_until.wat
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@
(module
(func (export "count_until") (param $limit i32) (result i32)
(local $counter i32)
(block
(loop
(br_if
1
(i32.eq
(local.tee $counter
(i32.add
(local.get $counter)
(i32.const 1)
)
(loop
(br_if
0
(i32.ne
(local.tee $counter
(i32.add
(local.get $counter)
(i32.const 1)
)
(local.get $limit)
)
(local.get $limit)
)
(br 0)
)
)
(return (local.get $counter))
Expand Down
1 change: 0 additions & 1 deletion crates/wasmi/src/engine/bytecode/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ impl AddressOffset {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BranchOffset(i32);

#[cfg(test)]
impl From<i32> for BranchOffset {
fn from(index: i32) -> Self {
Self(index)
Expand Down
90 changes: 89 additions & 1 deletion crates/wasmi/src/engine/regmach/bytecode/construct.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use super::{
utils::{CopysignImmInstr, Sign},
utils::{BranchOffset16, CopysignImmInstr, Sign},
AnyConst32,
BinInstr,
BinInstrImm16,
BranchBinOpInstr,
BranchBinOpInstrImm,
CallIndirectParams,
Const16,
Const32,
Expand Down Expand Up @@ -160,6 +162,92 @@ macro_rules! constructor_for {
};
}

macro_rules! constructor_for_branch_binop {
( $( fn $name:ident() -> Self::$op_code:ident; )* ) => {
impl Instruction {
$(
#[doc = concat!("Creates a new [`Instruction::", stringify!($op_code), "`].")]
pub fn $name(lhs: Register, rhs: Register, offset: BranchOffset16) -> Self {
Self::$op_code(BranchBinOpInstr::new(lhs, rhs, offset))
}
)*
}
}
}
constructor_for_branch_binop! {
fn branch_i32_eq() -> Self::BranchI32Eq;
fn branch_i32_ne() -> Self::BranchI32Ne;
fn branch_i32_lt_s() -> Self::BranchI32LtS;
fn branch_i32_lt_u() -> Self::BranchI32LtU;
fn branch_i32_le_s() -> Self::BranchI32LeS;
fn branch_i32_le_u() -> Self::BranchI32LeU;
fn branch_i32_gt_s() -> Self::BranchI32GtS;
fn branch_i32_gt_u() -> Self::BranchI32GtU;
fn branch_i32_ge_s() -> Self::BranchI32GeS;
fn branch_i32_ge_u() -> Self::BranchI32GeU;

fn branch_i64_eq() -> Self::BranchI64Eq;
fn branch_i64_ne() -> Self::BranchI64Ne;
fn branch_i64_lt_s() -> Self::BranchI64LtS;
fn branch_i64_lt_u() -> Self::BranchI64LtU;
fn branch_i64_le_s() -> Self::BranchI64LeS;
fn branch_i64_le_u() -> Self::BranchI64LeU;
fn branch_i64_gt_s() -> Self::BranchI64GtS;
fn branch_i64_gt_u() -> Self::BranchI64GtU;
fn branch_i64_ge_s() -> Self::BranchI64GeS;
fn branch_i64_ge_u() -> Self::BranchI64GeU;

fn branch_f32_eq() -> Self::BranchF32Eq;
fn branch_f32_ne() -> Self::BranchF32Ne;
fn branch_f32_lt() -> Self::BranchF32Lt;
fn branch_f32_le() -> Self::BranchF32Le;
fn branch_f32_gt() -> Self::BranchF32Gt;
fn branch_f32_ge() -> Self::BranchF32Ge;

fn branch_f64_eq() -> Self::BranchF64Eq;
fn branch_f64_ne() -> Self::BranchF64Ne;
fn branch_f64_lt() -> Self::BranchF64Lt;
fn branch_f64_le() -> Self::BranchF64Le;
fn branch_f64_gt() -> Self::BranchF64Gt;
fn branch_f64_ge() -> Self::BranchF64Ge;
}

macro_rules! constructor_for_branch_binop_imm {
( $( fn $name:ident($ty:ty) -> Self::$op_code:ident; )* ) => {
impl Instruction {
$(
#[doc = concat!("Creates a new [`Instruction::", stringify!($op_code), "`].")]
pub fn $name(lhs: Register, rhs: Const16<$ty>, offset: BranchOffset16) -> Self {
Self::$op_code(BranchBinOpInstrImm::new(lhs, rhs, offset))
}
)*
}
}
}
constructor_for_branch_binop_imm! {
fn branch_i32_eq_imm(i32) -> Self::BranchI32EqImm;
fn branch_i32_ne_imm(i32) -> Self::BranchI32NeImm;
fn branch_i32_lt_s_imm(i32) -> Self::BranchI32LtSImm;
fn branch_i32_lt_u_imm(u32) -> Self::BranchI32LtUImm;
fn branch_i32_le_s_imm(i32) -> Self::BranchI32LeSImm;
fn branch_i32_le_u_imm(u32) -> Self::BranchI32LeUImm;
fn branch_i32_gt_s_imm(i32) -> Self::BranchI32GtSImm;
fn branch_i32_gt_u_imm(u32) -> Self::BranchI32GtUImm;
fn branch_i32_ge_s_imm(i32) -> Self::BranchI32GeSImm;
fn branch_i32_ge_u_imm(u32) -> Self::BranchI32GeUImm;

fn branch_i64_eq_imm(i64) -> Self::BranchI64EqImm;
fn branch_i64_ne_imm(i64) -> Self::BranchI64NeImm;
fn branch_i64_lt_s_imm(i64) -> Self::BranchI64LtSImm;
fn branch_i64_lt_u_imm(u64) -> Self::BranchI64LtUImm;
fn branch_i64_le_s_imm(i64) -> Self::BranchI64LeSImm;
fn branch_i64_le_u_imm(u64) -> Self::BranchI64LeUImm;
fn branch_i64_gt_s_imm(i64) -> Self::BranchI64GtSImm;
fn branch_i64_gt_u_imm(u64) -> Self::BranchI64GtUImm;
fn branch_i64_ge_s_imm(i64) -> Self::BranchI64GeSImm;
fn branch_i64_ge_u_imm(u64) -> Self::BranchI64GeUImm;
}

impl Instruction {
/// Creates a new [`Instruction::Const32`] from the given `value`.
pub fn const32(value: impl Into<AnyConst32>) -> Self {
Expand Down
14 changes: 14 additions & 0 deletions crates/wasmi/src/engine/regmach/bytecode/immediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ pub struct Const16<T> {
marker: PhantomData<fn() -> T>,
}

impl Const16<i32> {
/// Returns `true` if the [`Const16`]`<i32>` is equal to zero.
pub fn is_zero(&self) -> bool {
self.inner == AnyConst16::from(0_i16)
}
}

impl Const16<i64> {
/// Returns `true` if the [`Const16`]`<i64>` is equal to zero.
pub fn is_zero(&self) -> bool {
self.inner == AnyConst16::from(0_i16)
}
}

impl<T> Const16<T> {
/// Crete a new typed [`Const16`] value.
pub fn new(inner: AnyConst16) -> Self {
Expand Down
195 changes: 195 additions & 0 deletions crates/wasmi/src/engine/regmach/bytecode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub(crate) use self::{
utils::{
BinInstr,
BinInstrImm16,
BranchBinOpInstr,
BranchBinOpInstrImm,
BranchOffset16,
CallIndirectParams,
CopysignImmInstr,
LoadAtInstr,
Expand Down Expand Up @@ -387,6 +390,198 @@ pub enum Instruction {
offset: BranchOffset,
},

/// A fused [`Instruction::I32Eq`] and [`Instruction::BranchNez`] instruction.
BranchI32Eq(BranchBinOpInstr),
/// A fused [`Instruction::I32Eq`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32Eq`] with 16-bit encoded constant `rhs`.
BranchI32EqImm(BranchBinOpInstrImm<i32>),
/// A fused [`Instruction::I32Ne`] and [`Instruction::BranchNez`] instruction.
BranchI32Ne(BranchBinOpInstr),
/// A fused [`Instruction::I32Ne`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32Ne`] with 16-bit encoded constant `rhs`.
BranchI32NeImm(BranchBinOpInstrImm<i32>),

/// A fused [`Instruction::I32LtS`] and [`Instruction::BranchNez`] instruction.
BranchI32LtS(BranchBinOpInstr),
/// A fused [`Instruction::I32LtS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32LtS`] with 16-bit encoded constant `rhs`.
BranchI32LtSImm(BranchBinOpInstrImm<i32>),
/// A fused [`Instruction::I32LtU`] and [`Instruction::BranchNez`] instruction.
BranchI32LtU(BranchBinOpInstr),
/// A fused [`Instruction::I32LtU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32LtU`] with 16-bit encoded constant `rhs`.
BranchI32LtUImm(BranchBinOpInstrImm<u32>),
/// A fused [`Instruction::I32LeS`] and [`Instruction::BranchNez`] instruction.
BranchI32LeS(BranchBinOpInstr),
/// A fused [`Instruction::I32LeS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32LeS`] with 16-bit encoded constant `rhs`.
BranchI32LeSImm(BranchBinOpInstrImm<i32>),
/// A fused [`Instruction::I32LeU`] and [`Instruction::BranchNez`] instruction.
BranchI32LeU(BranchBinOpInstr),
/// A fused [`Instruction::I32LeU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32LeU`] with 16-bit encoded constant `rhs`.
BranchI32LeUImm(BranchBinOpInstrImm<u32>),
/// A fused [`Instruction::I32GtS`] and [`Instruction::BranchNez`] instruction.
BranchI32GtS(BranchBinOpInstr),
/// A fused [`Instruction::I32GtS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32GtS`] with 16-bit encoded constant `rhs`.
BranchI32GtSImm(BranchBinOpInstrImm<i32>),
/// A fused [`Instruction::I32GtU`] and [`Instruction::BranchNez`] instruction.
BranchI32GtU(BranchBinOpInstr),
/// A fused [`Instruction::I32GtU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32GtU`] with 16-bit encoded constant `rhs`.
BranchI32GtUImm(BranchBinOpInstrImm<u32>),
/// A fused [`Instruction::I32GeS`] and [`Instruction::BranchNez`] instruction.
BranchI32GeS(BranchBinOpInstr),
/// A fused [`Instruction::I32GeS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32GeS`] with 16-bit encoded constant `rhs`.
BranchI32GeSImm(BranchBinOpInstrImm<i32>),
/// A fused [`Instruction::I32GeU`] and [`Instruction::BranchNez`] instruction.
BranchI32GeU(BranchBinOpInstr),
/// A fused [`Instruction::I32GeU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI32GeU`] with 16-bit encoded constant `rhs`.
BranchI32GeUImm(BranchBinOpInstrImm<u32>),

/// A fused [`Instruction::I64Eq`] and [`Instruction::BranchNez`] instruction.
BranchI64Eq(BranchBinOpInstr),
/// A fused [`Instruction::I64Eq`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64Eq`] with 16-bit encoded constant `rhs`.
BranchI64EqImm(BranchBinOpInstrImm<i64>),
/// A fused [`Instruction::I64Ne`] and [`Instruction::BranchNez`] instruction.
BranchI64Ne(BranchBinOpInstr),
/// A fused [`Instruction::I64Ne`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64Ne`] with 16-bit encoded constant `rhs`.
BranchI64NeImm(BranchBinOpInstrImm<i64>),

/// A fused [`Instruction::I64LtS`] and [`Instruction::BranchNez`] instruction.
BranchI64LtS(BranchBinOpInstr),
/// A fused [`Instruction::I64LtS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64LtS`] with 16-bit encoded constant `rhs`.
BranchI64LtSImm(BranchBinOpInstrImm<i64>),
/// A fused [`Instruction::I64LtU`] and [`Instruction::BranchNez`] instruction.
BranchI64LtU(BranchBinOpInstr),
/// A fused [`Instruction::I64LtU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64LtU`] with 16-bit encoded constant `rhs`.
BranchI64LtUImm(BranchBinOpInstrImm<u64>),
/// A fused [`Instruction::I64LeS`] and [`Instruction::BranchNez`] instruction.
BranchI64LeS(BranchBinOpInstr),
/// A fused [`Instruction::I64LeS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64LeS`] with 16-bit encoded constant `rhs`.
BranchI64LeSImm(BranchBinOpInstrImm<i64>),
/// A fused [`Instruction::I64LeU`] and [`Instruction::BranchNez`] instruction.
BranchI64LeU(BranchBinOpInstr),
/// A fused [`Instruction::I64LeU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64LeU`] with 16-bit encoded constant `rhs`.
BranchI64LeUImm(BranchBinOpInstrImm<u64>),
/// A fused [`Instruction::I64GtS`] and [`Instruction::BranchNez`] instruction.
BranchI64GtS(BranchBinOpInstr),
/// A fused [`Instruction::I64GtS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64GtS`] with 16-bit encoded constant `rhs`.
BranchI64GtSImm(BranchBinOpInstrImm<i64>),
/// A fused [`Instruction::I64GtU`] and [`Instruction::BranchNez`] instruction.
BranchI64GtU(BranchBinOpInstr),
/// A fused [`Instruction::I64GtU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64GtU`] with 16-bit encoded constant `rhs`.
BranchI64GtUImm(BranchBinOpInstrImm<u64>),
/// A fused [`Instruction::I64GeS`] and [`Instruction::BranchNez`] instruction.
BranchI64GeS(BranchBinOpInstr),
/// A fused [`Instruction::I64GeS`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64GeS`] with 16-bit encoded constant `rhs`.
BranchI64GeSImm(BranchBinOpInstrImm<i64>),
/// A fused [`Instruction::I64GeU`] and [`Instruction::BranchNez`] instruction.
BranchI64GeU(BranchBinOpInstr),
/// A fused [`Instruction::I64GeU`] and [`Instruction::BranchNez`] instruction.
///
/// # Note
///
/// Variant of [`Instruction::BranchI64GeU`] with 16-bit encoded constant `rhs`.
BranchI64GeUImm(BranchBinOpInstrImm<u64>),

/// A fused [`Instruction::F32Eq`] and [`Instruction::BranchNez`] instruction.
BranchF32Eq(BranchBinOpInstr),
/// A fused [`Instruction::F32Ne`] and [`Instruction::BranchNez`] instruction.
BranchF32Ne(BranchBinOpInstr),

/// A fused [`Instruction::F32Lt`] and [`Instruction::BranchNez`] instruction.
BranchF32Lt(BranchBinOpInstr),
/// A fused [`Instruction::F32Le`] and [`Instruction::BranchNez`] instruction.
BranchF32Le(BranchBinOpInstr),
/// A fused [`Instruction::F32Gt`] and [`Instruction::BranchNez`] instruction.
BranchF32Gt(BranchBinOpInstr),
/// A fused [`Instruction::F32Ge`] and [`Instruction::BranchNez`] instruction.
BranchF32Ge(BranchBinOpInstr),

/// A fused [`Instruction::F64Eq`] and [`Instruction::BranchNez`] instruction.
BranchF64Eq(BranchBinOpInstr),
/// A fused [`Instruction::F64Ne`] and [`Instruction::BranchNez`] instruction.
BranchF64Ne(BranchBinOpInstr),

/// A fused [`Instruction::F64Lt`] and [`Instruction::BranchNez`] instruction.
BranchF64Lt(BranchBinOpInstr),
/// A fused [`Instruction::F64Le`] and [`Instruction::BranchNez`] instruction.
BranchF64Le(BranchBinOpInstr),
/// A fused [`Instruction::F64Gt`] and [`Instruction::BranchNez`] instruction.
BranchF64Gt(BranchBinOpInstr),
/// A fused [`Instruction::F64Ge`] and [`Instruction::BranchNez`] instruction.
BranchF64Ge(BranchBinOpInstr),

/// A Wasm `br_table` instruction.
///
/// # Encoding
Expand Down
Loading
Loading