99//! once within its block and never crosses a block boundary.
1010
1111use 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 } ;
1313use 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.
116152fn 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