Skip to content

Commit 26e7830

Browse files
committed
Move a fusing operation from lowering to destacking, where it belongs.
1 parent f4f8ba7 commit 26e7830

11 files changed

Lines changed: 309 additions & 184 deletions

File tree

third_party/move/mono-move/specializer/src/destack/instr_utils.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ pub(crate) fn extract_imm_value(instr: &Instr) -> Option<(Slot, ImmValue)> {
179179
| Instr::Branch(_)
180180
| Instr::BrTrue(_, _)
181181
| Instr::BrFalse(_, _)
182+
| Instr::BrCmp(_, _, _, _)
183+
| Instr::BrCmpImm(_, _, _, _)
182184
| Instr::Ret(_)
183185
| Instr::Abort(_)
184186
| Instr::AbortMsg(_, _) => None,
@@ -189,15 +191,16 @@ pub(crate) fn extract_imm_value(instr: &Instr) -> Option<(Slot, ImmValue)> {
189191
/// without changing the result).
190192
#[inline]
191193
pub(crate) fn is_commutative(op: &BinaryOp) -> bool {
194+
use crate::stackless_exec_ir::CmpOp;
192195
matches!(
193196
op,
194197
BinaryOp::Add
195198
| BinaryOp::Mul
196199
| BinaryOp::BitOr
197200
| BinaryOp::BitAnd
198201
| BinaryOp::Xor
199-
| BinaryOp::Eq
200-
| BinaryOp::Neq
202+
| BinaryOp::Cmp(CmpOp::Eq)
203+
| BinaryOp::Cmp(CmpOp::Neq)
201204
| BinaryOp::Or
202205
| BinaryOp::And
203206
)
@@ -391,6 +394,11 @@ fn visit_slots<const DEFS: bool, const USES: bool>(
391394

392395
Instr::Branch(_) => {},
393396
Instr::BrTrue(_, cond) | Instr::BrFalse(_, cond) => used::<USES>(*cond, &mut f),
397+
Instr::BrCmp(_, _, lhs, rhs) => {
398+
used::<USES>(*lhs, &mut f);
399+
used::<USES>(*rhs, &mut f);
400+
},
401+
Instr::BrCmpImm(_, _, src, _) => used::<USES>(*src, &mut f),
394402
Instr::Ret(rets) => uses::<USES>(rets, &mut f),
395403
Instr::Abort(code) => used::<USES>(*code, &mut f),
396404
Instr::AbortMsg(code, msg) => {
@@ -662,6 +670,17 @@ fn rewrite_instr_slots<const DEFS: bool, const USES: bool, const SKIP_BORROW_LOC
662670
rewrite_slot(cond, &mut f);
663671
}
664672
},
673+
Instr::BrCmp(_, _, lhs, rhs) => {
674+
if USES {
675+
rewrite_slot(lhs, &mut f);
676+
rewrite_slot(rhs, &mut f);
677+
}
678+
},
679+
Instr::BrCmpImm(_, _, src, _) => {
680+
if USES {
681+
rewrite_slot(src, &mut f);
682+
}
683+
},
665684
Instr::Ret(rets) => {
666685
if USES {
667686
rewrite_slots(rets, &mut f);

third_party/move/mono-move/specializer/src/destack/ssa_conversion.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::{
1111
ssa_function::SSAFunction,
1212
type_conversion::{convert_sig_token, convert_sig_tokens},
1313
};
14-
use crate::stackless_exec_ir::{BasicBlock, BinaryOp, Instr, Label, Slot, UnaryOp};
14+
use crate::stackless_exec_ir::{BasicBlock, BinaryOp, CmpOp, Instr, Label, Slot, UnaryOp};
1515
use anyhow::{bail, ensure, Context, Result};
1616
use move_binary_format::{
1717
access::ModuleAccess,
@@ -441,12 +441,12 @@ impl<'a> SsaConverter<'a> {
441441
B::Shl => self.convert_binop(BinaryOp::Shl, false)?,
442442
B::Shr => self.convert_binop(BinaryOp::Shr, false)?,
443443
// --- Comparisons / logical (result type = bool) ---
444-
B::Lt => self.convert_binop(BinaryOp::Lt, true)?,
445-
B::Gt => self.convert_binop(BinaryOp::Gt, true)?,
446-
B::Le => self.convert_binop(BinaryOp::Le, true)?,
447-
B::Ge => self.convert_binop(BinaryOp::Ge, true)?,
448-
B::Eq => self.convert_binop(BinaryOp::Eq, true)?,
449-
B::Neq => self.convert_binop(BinaryOp::Neq, true)?,
444+
B::Lt => self.convert_binop(BinaryOp::Cmp(CmpOp::Lt), true)?,
445+
B::Gt => self.convert_binop(BinaryOp::Cmp(CmpOp::Gt), true)?,
446+
B::Le => self.convert_binop(BinaryOp::Cmp(CmpOp::Le), true)?,
447+
B::Ge => self.convert_binop(BinaryOp::Cmp(CmpOp::Ge), true)?,
448+
B::Eq => self.convert_binop(BinaryOp::Cmp(CmpOp::Eq), true)?,
449+
B::Neq => self.convert_binop(BinaryOp::Cmp(CmpOp::Neq), true)?,
450450
B::Or => self.convert_binop(BinaryOp::Or, true)?,
451451
B::And => self.convert_binop(BinaryOp::And, true)?,
452452

third_party/move/mono-move/specializer/src/destack/ssa_function.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//! once within its block and never crosses a block boundary.
1010
1111
use super::instr_utils::{extract_imm_value, is_commutative};
12-
use crate::stackless_exec_ir::{BasicBlock, Instr};
12+
use crate::stackless_exec_ir::{BasicBlock, BinaryOp, Instr};
1313
use move_vm_types::loaded_data::runtime_types::Type;
1414

1515
/// Intermediate SSA representation of a single function, before slot allocation.
@@ -31,6 +31,9 @@ impl SSAFunction {
3131
for block in &mut self.blocks {
3232
fuse_pairs(&mut block.instrs, try_fuse_field_access);
3333
fuse_pairs(&mut block.instrs, try_fuse_immediate_binop);
34+
// Must run after try_fuse_immediate_binop so that BinaryOpImm is
35+
// available for the BrCmpImm variant.
36+
fuse_pairs(&mut block.instrs, try_fuse_compare_branch);
3437
}
3538
self
3639
}
@@ -112,15 +115,48 @@ fn try_fuse_field_access(first: &Instr, second: &Instr) -> Option<Instr> {
112115
}
113116
}
114117

118+
/// Try to fuse a comparison + conditional branch pair into a single `BrCmp`/`BrCmpImm`.
119+
///
120+
/// Handles both `BrTrue` (keeps the comparison operator) and `BrFalse` (negates it).
121+
fn try_fuse_compare_branch(first: &Instr, second: &Instr) -> Option<Instr> {
122+
match (first, second) {
123+
// BinaryOp(dst, Cmp(cmp), lhs, rhs) + BrTrue(label, dst)
124+
(Instr::BinaryOp(dst, BinaryOp::Cmp(cmp), lhs, rhs), Instr::BrTrue(label, cond))
125+
if *dst == *cond =>
126+
{
127+
Some(Instr::BrCmp(*label, *cmp, *lhs, *rhs))
128+
},
129+
// BinaryOp(dst, Cmp(cmp), lhs, rhs) + BrFalse(label, dst)
130+
(Instr::BinaryOp(dst, BinaryOp::Cmp(cmp), lhs, rhs), Instr::BrFalse(label, cond))
131+
if *dst == *cond =>
132+
{
133+
Some(Instr::BrCmp(*label, cmp.negate(), *lhs, *rhs))
134+
},
135+
// BinaryOpImm(dst, Cmp(cmp), src, imm) + BrTrue(label, dst)
136+
(Instr::BinaryOpImm(dst, BinaryOp::Cmp(cmp), src, imm), Instr::BrTrue(label, cond))
137+
if *dst == *cond =>
138+
{
139+
Some(Instr::BrCmpImm(*label, *cmp, *src, *imm))
140+
},
141+
// BinaryOpImm(dst, Cmp(cmp), src, imm) + BrFalse(label, dst)
142+
(Instr::BinaryOpImm(dst, BinaryOp::Cmp(cmp), src, imm), Instr::BrFalse(label, cond))
143+
if *dst == *cond =>
144+
{
145+
Some(Instr::BrCmpImm(*label, cmp.negate(), *src, *imm))
146+
},
147+
_ => None,
148+
}
149+
}
150+
115151
/// Try to fuse a `Ld*` + `BinaryOp` pair into a `BinaryOpImm` instruction.
116152
fn try_fuse_immediate_binop(first: &Instr, second: &Instr) -> Option<Instr> {
117153
let (tmp, imm) = extract_imm_value(first)?;
118154
match second {
119155
Instr::BinaryOp(dst, op, lhs, rhs) if *rhs == tmp => {
120-
Some(Instr::BinaryOpImm(*dst, op.clone(), *lhs, imm))
156+
Some(Instr::BinaryOpImm(*dst, *op, *lhs, imm))
121157
},
122158
Instr::BinaryOp(dst, op, lhs, rhs) if *lhs == tmp && is_commutative(op) => {
123-
Some(Instr::BinaryOpImm(*dst, op.clone(), *rhs, imm))
159+
Some(Instr::BinaryOpImm(*dst, *op, *rhs, imm))
124160
},
125161
_ => None,
126162
}

0 commit comments

Comments
 (0)