Skip to content

Commit 66075b9

Browse files
authored
Clean-up InstrEncoder::encode_branch_{nez,eqz} methods (#1229)
* add and impl ComparatorExt trait * add ComparatorExtImm trait and impls * refactor InstrEncoder::encode_branch_nez * refactor InstrEncoder::encode_branch_eqz * deduplicate `make_branch_cmp_fallback` helper * deduplicate `fuse` helper method * deduplicate `fuse_imm` helper method * move encode_branch_unopt helpers into InstrEncoder * add forgotten F64{Eq,Ne} branch+cmp fusion * return Option in ComparatorExt::negate This now returns None for all comparators that cannot be negated while preserving their semantics with respect to NaN value handling. * deduplicate matcher in encode_branch_{eqz,nez} * rename last_instr to instr * add docs to try_fuse_branch_cmp_for_instr helper * move ComparatorExtImm trait closer to its impls * fix clippy warning by introducing type alias * move Comparator extension traits into their own submodule * add docs to Comparator extension traits * simplify imports
1 parent bd735a0 commit 66075b9

File tree

3 files changed

+478
-356
lines changed

3 files changed

+478
-356
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
use crate::ir::{self, BranchOffset16, Comparator, Const16, Instruction, Reg};
2+
3+
/// Extensional functionality for [`Comparator`].
4+
pub trait ComparatorExt: Sized {
5+
/// Creates a [`Comparator`] from an [`Instruction`].
6+
fn from_cmp_instruction(instr: Instruction) -> Option<Self>;
7+
8+
/// Returns the negated version of `self` if possible.
9+
///
10+
/// # Note
11+
///
12+
/// Comparators for `f32` and `f64` that are not symmetric (`Eq` and `Ne`)
13+
/// cannot be negated since NaN value handling would not preserve semantics.
14+
fn negate(self) -> Option<Self>;
15+
16+
/// Returns the [`Instruction`] constructor for `self` without immediate value.
17+
fn branch_cmp_instr(self) -> fn(lhs: Reg, rhs: Reg, offset: BranchOffset16) -> ir::Instruction;
18+
}
19+
20+
impl ComparatorExt for Comparator {
21+
fn from_cmp_instruction(instr: Instruction) -> Option<Self> {
22+
use Instruction as I;
23+
let cmp = match instr {
24+
I::I32And { .. } | I::I32AndImm16 { .. } => Self::I32And,
25+
I::I32Or { .. } | I::I32OrImm16 { .. } => Self::I32Or,
26+
I::I32Xor { .. } | I::I32XorImm16 { .. } => Self::I32Xor,
27+
I::I32AndEqz { .. } | I::I32AndEqzImm16 { .. } => Self::I32AndEqz,
28+
I::I32OrEqz { .. } | I::I32OrEqzImm16 { .. } => Self::I32OrEqz,
29+
I::I32XorEqz { .. } | I::I32XorEqzImm16 { .. } => Self::I32XorEqz,
30+
I::I32Eq { .. } | I::I32EqImm16 { .. } => Self::I32Eq,
31+
I::I32Ne { .. } | I::I32NeImm16 { .. } => Self::I32Ne,
32+
I::I32LtS { .. } | I::I32LtSImm16 { .. } => Self::I32LtS,
33+
I::I32LtU { .. } | I::I32LtUImm16 { .. } => Self::I32LtU,
34+
I::I32LeS { .. } | I::I32LeSImm16 { .. } => Self::I32LeS,
35+
I::I32LeU { .. } | I::I32LeUImm16 { .. } => Self::I32LeU,
36+
I::I32GtS { .. } | I::I32GtSImm16 { .. } => Self::I32GtS,
37+
I::I32GtU { .. } | I::I32GtUImm16 { .. } => Self::I32GtU,
38+
I::I32GeS { .. } | I::I32GeSImm16 { .. } => Self::I32GeS,
39+
I::I32GeU { .. } | I::I32GeUImm16 { .. } => Self::I32GeU,
40+
I::I64Eq { .. } | I::I64EqImm16 { .. } => Self::I64Eq,
41+
I::I64Ne { .. } | I::I64NeImm16 { .. } => Self::I64Ne,
42+
I::I64LtS { .. } | I::I64LtSImm16 { .. } => Self::I64LtS,
43+
I::I64LtU { .. } | I::I64LtUImm16 { .. } => Self::I64LtU,
44+
I::I64LeS { .. } | I::I64LeSImm16 { .. } => Self::I64LeS,
45+
I::I64LeU { .. } | I::I64LeUImm16 { .. } => Self::I64LeU,
46+
I::I64GtS { .. } | I::I64GtSImm16 { .. } => Self::I64GtS,
47+
I::I64GtU { .. } | I::I64GtUImm16 { .. } => Self::I64GtU,
48+
I::I64GeS { .. } | I::I64GeSImm16 { .. } => Self::I64GeS,
49+
I::I64GeU { .. } | I::I64GeUImm16 { .. } => Self::I64GeU,
50+
I::F32Eq { .. } => Self::F32Eq,
51+
I::F32Ne { .. } => Self::F32Ne,
52+
I::F32Lt { .. } => Self::F32Lt,
53+
I::F32Le { .. } => Self::F32Le,
54+
I::F32Gt { .. } => Self::F32Gt,
55+
I::F32Ge { .. } => Self::F32Ge,
56+
I::F64Eq { .. } => Self::F64Eq,
57+
I::F64Ne { .. } => Self::F64Ne,
58+
I::F64Lt { .. } => Self::F64Lt,
59+
I::F64Le { .. } => Self::F64Le,
60+
I::F64Gt { .. } => Self::F64Gt,
61+
I::F64Ge { .. } => Self::F64Ge,
62+
_ => return None,
63+
};
64+
Some(cmp)
65+
}
66+
67+
fn negate(self) -> Option<Self> {
68+
let negated = match self {
69+
Self::I32And => Self::I32AndEqz,
70+
Self::I32Or => Self::I32OrEqz,
71+
Self::I32Xor => Self::I32XorEqz,
72+
Self::I32AndEqz => Self::I32And,
73+
Self::I32OrEqz => Self::I32Or,
74+
Self::I32XorEqz => Self::I32Xor,
75+
Self::I32Eq => Self::I32Ne,
76+
Self::I32Ne => Self::I32Eq,
77+
Self::I32LtS => Self::I32GeS,
78+
Self::I32LtU => Self::I32GeU,
79+
Self::I32LeS => Self::I32GtS,
80+
Self::I32LeU => Self::I32GtU,
81+
Self::I32GtS => Self::I32LeS,
82+
Self::I32GtU => Self::I32LeU,
83+
Self::I32GeS => Self::I32LtS,
84+
Self::I32GeU => Self::I32LtU,
85+
Self::I64Eq => Self::I64Ne,
86+
Self::I64Ne => Self::I64Eq,
87+
Self::I64LtS => Self::I64GeS,
88+
Self::I64LtU => Self::I64GeU,
89+
Self::I64LeS => Self::I64GtS,
90+
Self::I64LeU => Self::I64GtU,
91+
Self::I64GtS => Self::I64LeS,
92+
Self::I64GtU => Self::I64LeU,
93+
Self::I64GeS => Self::I64LtS,
94+
Self::I64GeU => Self::I64LtU,
95+
Self::F32Eq => Self::F32Ne,
96+
Self::F32Ne => Self::F32Eq,
97+
Self::F64Eq => Self::F64Ne,
98+
Self::F64Ne => Self::F64Eq,
99+
// Note: Due to non-semantics preserving NaN handling we cannot
100+
// negate `F{32,64}{Lt,Le,Gt,Ge}` comparators.
101+
_ => return None,
102+
};
103+
Some(negated)
104+
}
105+
106+
fn branch_cmp_instr(self) -> fn(lhs: Reg, rhs: Reg, offset: BranchOffset16) -> ir::Instruction {
107+
match self {
108+
Self::I32And => Instruction::branch_i32_and,
109+
Self::I32Or => Instruction::branch_i32_or,
110+
Self::I32Xor => Instruction::branch_i32_xor,
111+
Self::I32AndEqz => Instruction::branch_i32_and_eqz,
112+
Self::I32OrEqz => Instruction::branch_i32_or_eqz,
113+
Self::I32XorEqz => Instruction::branch_i32_xor_eqz,
114+
Self::I32Eq => Instruction::branch_i32_eq,
115+
Self::I32Ne => Instruction::branch_i32_ne,
116+
Self::I32LtS => Instruction::branch_i32_lt_s,
117+
Self::I32LtU => Instruction::branch_i32_lt_u,
118+
Self::I32LeS => Instruction::branch_i32_le_s,
119+
Self::I32LeU => Instruction::branch_i32_le_u,
120+
Self::I32GtS => Instruction::branch_i32_gt_s,
121+
Self::I32GtU => Instruction::branch_i32_gt_u,
122+
Self::I32GeS => Instruction::branch_i32_ge_s,
123+
Self::I32GeU => Instruction::branch_i32_ge_u,
124+
Self::I64Eq => Instruction::branch_i64_eq,
125+
Self::I64Ne => Instruction::branch_i64_ne,
126+
Self::I64LtS => Instruction::branch_i64_lt_s,
127+
Self::I64LtU => Instruction::branch_i64_lt_u,
128+
Self::I64LeS => Instruction::branch_i64_le_s,
129+
Self::I64LeU => Instruction::branch_i64_le_u,
130+
Self::I64GtS => Instruction::branch_i64_gt_s,
131+
Self::I64GtU => Instruction::branch_i64_gt_u,
132+
Self::I64GeS => Instruction::branch_i64_ge_s,
133+
Self::I64GeU => Instruction::branch_i64_ge_u,
134+
Self::F32Eq => Instruction::branch_f32_eq,
135+
Self::F32Ne => Instruction::branch_f32_ne,
136+
Self::F32Lt => Instruction::branch_f32_lt,
137+
Self::F32Le => Instruction::branch_f32_le,
138+
Self::F32Gt => Instruction::branch_f32_gt,
139+
Self::F32Ge => Instruction::branch_f32_ge,
140+
Self::F64Eq => Instruction::branch_f64_eq,
141+
Self::F64Ne => Instruction::branch_f64_ne,
142+
Self::F64Lt => Instruction::branch_f64_lt,
143+
Self::F64Le => Instruction::branch_f64_le,
144+
Self::F64Gt => Instruction::branch_f64_gt,
145+
Self::F64Ge => Instruction::branch_f64_ge,
146+
}
147+
}
148+
}
149+
150+
/// Extensional functionality for [`Comparator`] with immediate value [`Instruction`].
151+
pub trait ComparatorExtImm<T> {
152+
/// Returns the [`Instruction`] constructor for `self` without immediate value of type `T` if any.
153+
fn branch_cmp_instr_imm(self) -> Option<MakeBranchCmpInstrImm<T>>;
154+
}
155+
156+
/// Constructor for branch+cmp [`Instruction`] with an immediate value of type `T`.
157+
type MakeBranchCmpInstrImm<T> =
158+
fn(lhs: Reg, rhs: Const16<T>, offset: BranchOffset16) -> ir::Instruction;
159+
160+
impl ComparatorExtImm<i32> for Comparator {
161+
fn branch_cmp_instr_imm(self) -> Option<MakeBranchCmpInstrImm<i32>> {
162+
use Instruction as I;
163+
let make_instr = match self {
164+
Self::I32And => I::branch_i32_and_imm,
165+
Self::I32Or => I::branch_i32_or_imm,
166+
Self::I32Xor => I::branch_i32_xor_imm,
167+
Self::I32AndEqz => I::branch_i32_and_eqz_imm,
168+
Self::I32OrEqz => I::branch_i32_or_eqz_imm,
169+
Self::I32XorEqz => I::branch_i32_xor_eqz_imm,
170+
Self::I32Eq => I::branch_i32_eq_imm,
171+
Self::I32Ne => I::branch_i32_ne_imm,
172+
Self::I32LtS => I::branch_i32_lt_s_imm,
173+
Self::I32LeS => I::branch_i32_le_s_imm,
174+
Self::I32GtS => I::branch_i32_gt_s_imm,
175+
Self::I32GeS => I::branch_i32_ge_s_imm,
176+
_ => return None,
177+
};
178+
Some(make_instr)
179+
}
180+
}
181+
182+
impl ComparatorExtImm<u32> for Comparator {
183+
fn branch_cmp_instr_imm(self) -> Option<MakeBranchCmpInstrImm<u32>> {
184+
use Instruction as I;
185+
let make_instr = match self {
186+
Self::I32LtU => I::branch_i32_lt_u_imm,
187+
Self::I32LeU => I::branch_i32_le_u_imm,
188+
Self::I32GtU => I::branch_i32_gt_u_imm,
189+
Self::I32GeU => I::branch_i32_ge_u_imm,
190+
_ => return None,
191+
};
192+
Some(make_instr)
193+
}
194+
}
195+
196+
impl ComparatorExtImm<i64> for Comparator {
197+
fn branch_cmp_instr_imm(self) -> Option<MakeBranchCmpInstrImm<i64>> {
198+
use Instruction as I;
199+
let make_instr = match self {
200+
Self::I64Eq => I::branch_i64_eq_imm,
201+
Self::I64Ne => I::branch_i64_ne_imm,
202+
Self::I64LtS => I::branch_i64_lt_s_imm,
203+
Self::I64LeS => I::branch_i64_le_s_imm,
204+
Self::I64GtS => I::branch_i64_gt_s_imm,
205+
Self::I64GeS => I::branch_i64_ge_s_imm,
206+
_ => return None,
207+
};
208+
Some(make_instr)
209+
}
210+
}
211+
212+
impl ComparatorExtImm<u64> for Comparator {
213+
fn branch_cmp_instr_imm(self) -> Option<MakeBranchCmpInstrImm<u64>> {
214+
use Instruction as I;
215+
let make_instr = match self {
216+
Self::I64LtU => I::branch_i64_lt_u_imm,
217+
Self::I64LeU => I::branch_i64_le_u_imm,
218+
Self::I64GtU => I::branch_i64_gt_u_imm,
219+
Self::I64GeU => I::branch_i64_ge_u_imm,
220+
_ => return None,
221+
};
222+
Some(make_instr)
223+
}
224+
}

0 commit comments

Comments
 (0)