Skip to content

Commit 994b91a

Browse files
committed
Optimize branches when the target is statically known to a jump
This can happen in generic code
1 parent 5f21ff2 commit 994b91a

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

src/base.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,9 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
307307
} => {
308308
let discr = codegen_operand(fx, discr).load_scalar(fx);
309309

310-
if switch_ty.kind() == fx.tcx.types.bool.kind() {
310+
let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
311+
|| (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
312+
if use_bool_opt {
311313
assert_eq!(targets.iter().count(), 1);
312314
let (then_value, then_block) = targets.iter().next().unwrap();
313315
let then_block = fx.get_block(then_block);
@@ -325,12 +327,22 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) {
325327
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
326328
let discr =
327329
crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
328-
if test_zero {
329-
fx.bcx.ins().brz(discr, then_block, &[]);
330-
fx.bcx.ins().jump(else_block, &[]);
330+
if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
331+
&fx.bcx, discr, test_zero,
332+
) {
333+
if taken {
334+
fx.bcx.ins().jump(then_block, &[]);
335+
} else {
336+
fx.bcx.ins().jump(else_block, &[]);
337+
}
331338
} else {
332-
fx.bcx.ins().brnz(discr, then_block, &[]);
333-
fx.bcx.ins().jump(else_block, &[]);
339+
if test_zero {
340+
fx.bcx.ins().brz(discr, then_block, &[]);
341+
fx.bcx.ins().jump(else_block, &[]);
342+
} else {
343+
fx.bcx.ins().brnz(discr, then_block, &[]);
344+
fx.bcx.ins().jump(else_block, &[]);
345+
}
334346
}
335347
} else {
336348
let mut switch = ::cranelift_frontend::Switch::new();

src/optimize/peephole.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,48 @@ pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -
7373
})()
7474
.unwrap_or_else(|| {
7575
match bcx.func.dfg.value_type(arg) {
76-
types::I8 | types::I32 => {
76+
types::I8 | types::I16 => {
7777
// WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
7878
bcx.ins().uextend(types::I32, arg)
7979
}
8080
_ => arg,
8181
}
8282
})
8383
}
84+
85+
/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
86+
pub(crate) fn maybe_known_branch_taken(
87+
bcx: &FunctionBuilder<'_>,
88+
arg: Value,
89+
test_zero: bool,
90+
) -> Option<bool> {
91+
let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
92+
arg_inst
93+
} else {
94+
return None;
95+
};
96+
97+
match bcx.func.dfg[arg_inst] {
98+
InstructionData::UnaryBool {
99+
opcode: Opcode::Bconst,
100+
imm,
101+
} => {
102+
if test_zero {
103+
Some(!imm)
104+
} else {
105+
Some(imm)
106+
}
107+
}
108+
InstructionData::UnaryImm {
109+
opcode: Opcode::Iconst,
110+
imm,
111+
} => {
112+
if test_zero {
113+
Some(imm.bits() == 0)
114+
} else {
115+
Some(imm.bits() != 0)
116+
}
117+
}
118+
_ => None,
119+
}
120+
}

0 commit comments

Comments
 (0)