Skip to content

Commit 7159aed

Browse files
committed
Use br instead of conditional when branching on constant
1 parent 397937d commit 7159aed

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
319319
targets: &SwitchTargets,
320320
) {
321321
let discr = self.codegen_operand(bx, discr);
322+
let discr_value = discr.immediate();
322323
let switch_ty = discr.layout.ty;
324+
// If our discriminant is a constant we can branch directly
325+
if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) {
326+
let target = targets.target_for_value(const_discr);
327+
bx.br(helper.llbb_with_cleanup(self, target));
328+
return;
329+
};
330+
323331
let mut target_iter = targets.iter();
324332
if target_iter.len() == 1 {
325333
// If there are two targets (one conditional, one fallback), emit `br` instead of
@@ -330,14 +338,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
330338
if switch_ty == bx.tcx().types.bool {
331339
// Don't generate trivial icmps when switching on bool.
332340
match test_value {
333-
0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
334-
1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
341+
0 => bx.cond_br(discr_value, llfalse, lltrue),
342+
1 => bx.cond_br(discr_value, lltrue, llfalse),
335343
_ => bug!(),
336344
}
337345
} else {
338346
let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
339347
let llval = bx.const_uint_big(switch_llty, test_value);
340-
let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
348+
let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
341349
bx.cond_br(cmp, lltrue, llfalse);
342350
}
343351
} else if self.cx.sess().opts.optimize == OptLevel::No
@@ -362,11 +370,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
362370
let ll2 = helper.llbb_with_cleanup(self, target2);
363371
let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
364372
let llval = bx.const_uint_big(switch_llty, test_value1);
365-
let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
373+
let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
366374
bx.cond_br(cmp, ll1, ll2);
367375
} else {
368376
bx.switch(
369-
discr.immediate(),
377+
discr_value,
370378
helper.llbb_with_cleanup(self, targets.otherwise()),
371379
target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))),
372380
);

tests/codegen/constant-branch.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0
2+
// make sure that branching on a constant does not emit a conditional
3+
// branch or a switch
4+
5+
#![crate_type = "lib"]
6+
7+
// CHECK-LABEL: @if_bool
8+
#[no_mangle]
9+
pub fn if_bool() {
10+
// CHECK: br label %{{.+}}
11+
_ = if true {
12+
0
13+
} else {
14+
1
15+
};
16+
17+
// CHECK: br label %{{.+}}
18+
_ = if false {
19+
0
20+
} else {
21+
1
22+
};
23+
}
24+
25+
// CHECK-LABEL: @if_constant_int_eq
26+
#[no_mangle]
27+
pub fn if_constant_int_eq() {
28+
let val = 0;
29+
// CHECK: br label %{{.+}}
30+
_ = if val == 0 {
31+
0
32+
} else {
33+
1
34+
};
35+
36+
// CHECK: br label %{{.+}}
37+
_ = if val == 1 {
38+
0
39+
} else {
40+
1
41+
};
42+
}
43+
44+
// CHECK-LABEL: @if_constant_match
45+
#[no_mangle]
46+
pub fn if_constant_match() {
47+
// CHECK: br label %{{.+}}
48+
_ = match 1 {
49+
1 => 2,
50+
2 => 3,
51+
_ => 4
52+
};
53+
54+
// CHECK: br label %{{.+}}
55+
_ = match 1 {
56+
2 => 3,
57+
_ => 4
58+
};
59+
60+
// CHECK: br label %[[MINUS1:.+]]
61+
_ = match -1 {
62+
// CHECK: [[MINUS1]]:
63+
// CHECK: store i32 1
64+
-1 => 1,
65+
_ => 0,
66+
}
67+
}

0 commit comments

Comments
 (0)