Skip to content

Commit d1065e6

Browse files
committed
Auto merge of #83663 - AngelicosPhosphoros:simplify_binary_and_to_get_better_asm, r=nagisa
Simplify logical operations CFG This is basically same commit as e38e954 which was reverted later in 676953f In both cases, this changes weren't benchmarked. e38e954 leads to missed optimization described in [this issue](#62993) 676953f leads to missed optimization described in [this issue](#83623)
2 parents d474075 + 4464cc2 commit d1065e6

File tree

8 files changed

+352
-317
lines changed

8 files changed

+352
-317
lines changed

compiler/rustc_mir_build/src/build/expr/into.rs

+18-29
Original file line numberDiff line numberDiff line change
@@ -111,60 +111,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
111111
ExprKind::LogicalOp { op, lhs, rhs } => {
112112
// And:
113113
//
114-
// [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
115-
// | | (false)
116-
// +----------false-----------+------------------> [false_block]
114+
// [block: If(lhs)] -true-> [else_block: dest = (rhs)]
115+
// | (false)
116+
// [shortcurcuit_block: dest = false]
117117
//
118118
// Or:
119119
//
120-
// [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
121-
// | (true) | (false)
122-
// [true_block] [false_block]
120+
// [block: If(lhs)] -false-> [else_block: dest = (rhs)]
121+
// | (true)
122+
// [shortcurcuit_block: dest = true]
123123

124-
let (true_block, false_block, mut else_block, join_block) = (
125-
this.cfg.start_new_block(),
124+
let (shortcircuit_block, mut else_block, join_block) = (
126125
this.cfg.start_new_block(),
127126
this.cfg.start_new_block(),
128127
this.cfg.start_new_block(),
129128
);
130129

131130
let lhs = unpack!(block = this.as_local_operand(block, lhs));
132131
let blocks = match op {
133-
LogicalOp::And => (else_block, false_block),
134-
LogicalOp::Or => (true_block, else_block),
132+
LogicalOp::And => (else_block, shortcircuit_block),
133+
LogicalOp::Or => (shortcircuit_block, else_block),
135134
};
136135
let term = TerminatorKind::if_(this.tcx, lhs, blocks.0, blocks.1);
137136
this.cfg.terminate(block, source_info, term);
138137

139-
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
140-
let term = TerminatorKind::if_(this.tcx, rhs, true_block, false_block);
141-
this.cfg.terminate(else_block, source_info, term);
142-
143138
this.cfg.push_assign_constant(
144-
true_block,
139+
shortcircuit_block,
145140
source_info,
146141
destination,
147142
Constant {
148143
span: expr_span,
149144
user_ty: None,
150-
literal: ty::Const::from_bool(this.tcx, true).into(),
145+
literal: match op {
146+
LogicalOp::And => ty::Const::from_bool(this.tcx, false).into(),
147+
LogicalOp::Or => ty::Const::from_bool(this.tcx, true).into(),
148+
},
151149
},
152150
);
151+
this.cfg.goto(shortcircuit_block, source_info, join_block);
153152

154-
this.cfg.push_assign_constant(
155-
false_block,
156-
source_info,
157-
destination,
158-
Constant {
159-
span: expr_span,
160-
user_ty: None,
161-
literal: ty::Const::from_bool(this.tcx, false).into(),
162-
},
163-
);
153+
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
154+
this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs));
155+
this.cfg.goto(else_block, source_info, join_block);
164156

165-
// Link up both branches:
166-
this.cfg.goto(true_block, source_info, join_block);
167-
this.cfg.goto(false_block, source_info, join_block);
168157
join_block.unit()
169158
}
170159
ExprKind::Loop { body } => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// This test checks that jumps generated by logical operators can be optimized away
2+
3+
// compile-flags: -Copt-level=3
4+
// only-64bit
5+
6+
#![crate_type="lib"]
7+
8+
pub struct Blueprint {
9+
pub fuel_tank_size: u32,
10+
pub payload: u32,
11+
pub wheel_diameter: u32,
12+
pub wheel_width: u32,
13+
pub storage: u32,
14+
}
15+
16+
// && chains should not prevent SIMD optimizations for primitives
17+
impl PartialEq for Blueprint{
18+
fn eq(&self, other: &Self)->bool{
19+
// CHECK-NOT: call{{.*}}bcmp
20+
// CHECK-NOT: call{{.*}}memcmp
21+
// CHECK-NOT: br {{.*}}
22+
self.fuel_tank_size == other.fuel_tank_size
23+
&& self.payload == other.payload
24+
&& self.wheel_diameter == other.wheel_diameter
25+
&& self.wheel_width == other.wheel_width
26+
&& self.storage == other.storage
27+
}
28+
}
29+
30+
#[derive(PartialEq)]
31+
pub struct Blueprint2 {
32+
pub fuel_tank_size: u32,
33+
pub payload: u32,
34+
pub wheel_diameter: u32,
35+
pub wheel_width: u32,
36+
pub storage: u32,
37+
}
38+
39+
// Derived PartialEq should not generate jumps and should use SIMD
40+
#[no_mangle]
41+
pub fn partial_eq_should_not_jump(a: &Blueprint2, b:&Blueprint2)->bool{
42+
// CHECK-NOT: call{{.*}}bcmp
43+
// CHECK-NOT: call{{.*}}memcmp
44+
// CHECK-NOT: br {{.*}}
45+
a==b
46+
}

0 commit comments

Comments
 (0)