Skip to content

Commit 52abd1c

Browse files
committed
auto merge of #7636 : dotdash/rust/scope_cleanup, r=graydon
Currently, scopes are tied to LLVM basic blocks. For each scope, there are two new basic blocks, which means two extra jumps in the unoptimized IR. These blocks aren't actually required, but only used to act as the boundary for cleanups. By keeping track of the current scope within a single basic block, we can avoid those extra blocks and jumps, shrinking the pre-optimization IR quite considerably. For example, the IR for trans_intrinsic goes from ~22k lines to ~16k lines, almost 30% less. The impact on the build times of optimized builds is rather small (about 1%), but unoptimized builds are about 11% faster. The testsuite for unoptimized builds runs between 15% (CPU time) and 7.5% (wallclock time on my i7) faster. Also, in some situations this helps LLVM to generate better code by inlining functions that it previously considered to be too large. Likely because of the pointless blocks/jumps that were still present at the time the inlining pass runs. Refs #7462
2 parents 3c44265 + e41e435 commit 52abd1c

File tree

4 files changed

+203
-161
lines changed

4 files changed

+203
-161
lines changed

Diff for: src/librustc/middle/trans/base.rs

+109-87
Original file line numberDiff line numberDiff line change
@@ -863,10 +863,10 @@ pub fn need_invoke(bcx: block) -> bool {
863863

864864
// Walk the scopes to look for cleanups
865865
let mut cur = bcx;
866+
let mut cur_scope = cur.scope;
866867
loop {
867-
match cur.kind {
868-
block_scope(inf) => {
869-
let inf = &mut *inf; // FIXME(#5074) workaround old borrowck
868+
cur_scope = match cur_scope {
869+
Some(inf) => {
870870
for inf.cleanups.iter().advance |cleanup| {
871871
match *cleanup {
872872
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => {
@@ -876,12 +876,15 @@ pub fn need_invoke(bcx: block) -> bool {
876876
}
877877
}
878878
}
879+
inf.parent
880+
}
881+
None => {
882+
cur = match cur.parent {
883+
Some(next) => next,
884+
None => return false
885+
};
886+
cur.scope
879887
}
880-
_ => ()
881-
}
882-
cur = match cur.parent {
883-
Some(next) => next,
884-
None => return false
885888
}
886889
}
887890
}
@@ -899,23 +902,21 @@ pub fn have_cached_lpad(bcx: block) -> bool {
899902

900903
pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) {
901904
let mut bcx = bcx;
905+
let mut cur_scope = bcx.scope;
902906
loop {
903-
{
904-
match bcx.kind {
905-
block_scope(inf) => {
906-
let len = { // FIXME(#5074) workaround old borrowck
907-
let inf = &mut *inf;
908-
inf.cleanups.len()
909-
};
910-
if len > 0u || bcx.parent.is_none() {
911-
f(inf);
912-
return;
913-
}
907+
cur_scope = match cur_scope {
908+
Some(inf) => {
909+
if !inf.empty_cleanups() || (inf.parent.is_none() && bcx.parent.is_none()) {
910+
f(inf);
911+
return;
914912
}
915-
_ => ()
913+
inf.parent
914+
}
915+
None => {
916+
bcx = block_parent(bcx);
917+
bcx.scope
916918
}
917919
}
918-
bcx = block_parent(bcx);
919920
}
920921
}
921922

@@ -972,27 +973,31 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
972973

973974
pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
974975
let mut bcx_sid = bcx;
976+
let mut cur_scope = bcx_sid.scope;
975977
loop {
976-
bcx_sid = match bcx_sid.node_info {
977-
Some(NodeInfo { id, _ }) if id == scope_id => {
978-
return bcx_sid
979-
}
980-
981-
// FIXME(#6268, #6248) hacky cleanup for nested method calls
982-
Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => {
983-
return bcx_sid
984-
}
985-
986-
_ => {
987-
match bcx_sid.parent {
988-
None => bcx.tcx().sess.bug(
989-
fmt!("no enclosing scope with id %d", scope_id)),
990-
Some(bcx_par) => bcx_par
978+
cur_scope = match cur_scope {
979+
Some(inf) => {
980+
match inf.node_info {
981+
Some(NodeInfo { id, _ }) if id == scope_id => {
982+
return bcx_sid
991983
}
984+
// FIXME(#6268, #6248) hacky cleanup for nested method calls
985+
Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => {
986+
return bcx_sid
987+
}
988+
_ => inf.parent
992989
}
993990
}
991+
None => {
992+
bcx_sid = match bcx_sid.parent {
993+
None => bcx.tcx().sess.bug(fmt!("no enclosing scope with id %d", scope_id)),
994+
Some(bcx_par) => bcx_par
995+
};
996+
bcx_sid.scope
997+
}
994998
}
995999
}
1000+
}
9961001

9971002

9981003
pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
@@ -1145,7 +1150,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
11451150

11461151
// You probably don't want to use this one. See the
11471152
// next three functions instead.
1148-
pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind,
1153+
pub fn new_block(cx: fn_ctxt, parent: Option<block>, scope: Option<@mut scope_info>,
11491154
is_lpad: bool, name: &str, opt_node_info: Option<NodeInfo>)
11501155
-> block {
11511156

@@ -1155,10 +1160,10 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind,
11551160
};
11561161
let bcx = mk_block(llbb,
11571162
parent,
1158-
kind,
11591163
is_lpad,
11601164
opt_node_info,
11611165
cx);
1166+
bcx.scope = scope;
11621167
for parent.iter().advance |cx| {
11631168
if cx.unreachable {
11641169
Unreachable(bcx);
@@ -1169,27 +1174,30 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind,
11691174
}
11701175
}
11711176

1172-
pub fn simple_block_scope() -> block_kind {
1173-
block_scope(@mut scope_info {
1177+
pub fn simple_block_scope(parent: Option<@mut scope_info>,
1178+
node_info: Option<NodeInfo>) -> @mut scope_info {
1179+
@mut scope_info {
1180+
parent: parent,
11741181
loop_break: None,
11751182
loop_label: None,
11761183
cleanups: ~[],
11771184
cleanup_paths: ~[],
1178-
landing_pad: None
1179-
})
1185+
landing_pad: None,
1186+
node_info: node_info,
1187+
}
11801188
}
11811189

11821190
// Use this when you're at the top block of a function or the like.
11831191
pub fn top_scope_block(fcx: fn_ctxt, opt_node_info: Option<NodeInfo>)
11841192
-> block {
1185-
return new_block(fcx, None, simple_block_scope(), false,
1193+
return new_block(fcx, None, Some(simple_block_scope(None, opt_node_info)), false,
11861194
"function top level", opt_node_info);
11871195
}
11881196

11891197
pub fn scope_block(bcx: block,
11901198
opt_node_info: Option<NodeInfo>,
11911199
n: &str) -> block {
1192-
return new_block(bcx.fcx, Some(bcx), simple_block_scope(), bcx.is_lpad,
1200+
return new_block(bcx.fcx, Some(bcx), Some(simple_block_scope(None, opt_node_info)), bcx.is_lpad,
11931201
n, opt_node_info);
11941202
}
11951203

@@ -1198,27 +1206,29 @@ pub fn loop_scope_block(bcx: block,
11981206
loop_label: Option<ident>,
11991207
n: &str,
12001208
opt_node_info: Option<NodeInfo>) -> block {
1201-
return new_block(bcx.fcx, Some(bcx), block_scope(@mut scope_info {
1209+
return new_block(bcx.fcx, Some(bcx), Some(@mut scope_info {
1210+
parent: None,
12021211
loop_break: Some(loop_break),
12031212
loop_label: loop_label,
12041213
cleanups: ~[],
12051214
cleanup_paths: ~[],
1206-
landing_pad: None
1215+
landing_pad: None,
1216+
node_info: opt_node_info,
12071217
}), bcx.is_lpad, n, opt_node_info);
12081218
}
12091219

12101220
// Use this when creating a block for the inside of a landing pad.
12111221
pub fn lpad_block(bcx: block, n: &str) -> block {
1212-
new_block(bcx.fcx, Some(bcx), block_non_scope, true, n, None)
1222+
new_block(bcx.fcx, Some(bcx), None, true, n, None)
12131223
}
12141224

12151225
// Use this when you're making a general CFG BB within a scope.
12161226
pub fn sub_block(bcx: block, n: &str) -> block {
1217-
new_block(bcx.fcx, Some(bcx), block_non_scope, bcx.is_lpad, n, None)
1227+
new_block(bcx.fcx, Some(bcx), None, bcx.is_lpad, n, None)
12181228
}
12191229

12201230
pub fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block {
1221-
mk_block(llbb, None, block_non_scope, is_lpad, None, fcx)
1231+
mk_block(llbb, None, is_lpad, None, fcx)
12221232
}
12231233

12241234

@@ -1277,42 +1287,47 @@ pub fn cleanup_and_leave(bcx: block,
12771287
(fmt!("cleanup_and_leave(%s)", cur.to_str())).to_managed());
12781288
}
12791289

1280-
match cur.kind {
1281-
block_scope(inf) if !inf.empty_cleanups() => {
1282-
let (sub_cx, dest, inf_cleanups) = {
1283-
let inf = &mut *inf;
1284-
let mut skip = 0;
1285-
let mut dest = None;
1286-
{
1287-
let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave);
1288-
for r.iter().advance |cp| {
1289-
if cp.size == inf.cleanups.len() {
1290-
Br(bcx, cp.dest);
1291-
return;
1290+
let mut cur_scope = cur.scope;
1291+
loop {
1292+
cur_scope = match cur_scope {
1293+
Some (inf) if !inf.empty_cleanups() => {
1294+
let (sub_cx, dest, inf_cleanups) = {
1295+
let inf = &mut *inf;
1296+
let mut skip = 0;
1297+
let mut dest = None;
1298+
{
1299+
let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave);
1300+
for r.iter().advance |cp| {
1301+
if cp.size == inf.cleanups.len() {
1302+
Br(bcx, cp.dest);
1303+
return;
1304+
}
1305+
1306+
skip = cp.size;
1307+
dest = Some(cp.dest);
12921308
}
1293-
1294-
skip = cp.size;
1295-
dest = Some(cp.dest);
12961309
}
1310+
let sub_cx = sub_block(bcx, "cleanup");
1311+
Br(bcx, sub_cx.llbb);
1312+
inf.cleanup_paths.push(cleanup_path {
1313+
target: leave,
1314+
size: inf.cleanups.len(),
1315+
dest: sub_cx.llbb
1316+
});
1317+
(sub_cx, dest, inf.cleanups.tailn(skip).to_owned())
1318+
};
1319+
bcx = trans_block_cleanups_(sub_cx,
1320+
inf_cleanups,
1321+
is_lpad);
1322+
for dest.iter().advance |&dest| {
1323+
Br(bcx, dest);
1324+
return;
12971325
}
1298-
let sub_cx = sub_block(bcx, "cleanup");
1299-
Br(bcx, sub_cx.llbb);
1300-
inf.cleanup_paths.push(cleanup_path {
1301-
target: leave,
1302-
size: inf.cleanups.len(),
1303-
dest: sub_cx.llbb
1304-
});
1305-
(sub_cx, dest, inf.cleanups.tailn(skip).to_owned())
1306-
};
1307-
bcx = trans_block_cleanups_(sub_cx,
1308-
inf_cleanups,
1309-
is_lpad);
1310-
for dest.iter().advance |&dest| {
1311-
Br(bcx, dest);
1312-
return;
1326+
inf.parent
13131327
}
1328+
Some(inf) => inf.parent,
1329+
None => break
13141330
}
1315-
_ => ()
13161331
}
13171332

13181333
match upto {
@@ -1353,20 +1368,27 @@ pub fn with_scope(bcx: block,
13531368
bcx.to_str(), opt_node_info, name);
13541369
let _indenter = indenter();
13551370

1356-
let scope_cx = scope_block(bcx, opt_node_info, name);
1357-
Br(bcx, scope_cx.llbb);
1358-
leave_block(f(scope_cx), scope_cx)
1371+
let scope = simple_block_scope(bcx.scope, opt_node_info);
1372+
bcx.scope = Some(scope);
1373+
let ret = f(bcx);
1374+
let ret = trans_block_cleanups_(ret, /*bad*/copy scope.cleanups, false);
1375+
bcx.scope = scope.parent;
1376+
ret
13591377
}
13601378

13611379
pub fn with_scope_result(bcx: block,
13621380
opt_node_info: Option<NodeInfo>,
13631381
name: &str,
13641382
f: &fn(block) -> Result) -> Result {
13651383
let _icx = push_ctxt("with_scope_result");
1366-
let scope_cx = scope_block(bcx, opt_node_info, name);
1367-
Br(bcx, scope_cx.llbb);
1368-
let Result {bcx, val} = f(scope_cx);
1369-
rslt(leave_block(bcx, scope_cx), val)
1384+
1385+
let scope = simple_block_scope(bcx.scope, opt_node_info);
1386+
bcx.scope = Some(scope);
1387+
let Result { bcx: out_bcx, val } = f(bcx);
1388+
let out_bcx = trans_block_cleanups_(out_bcx, /*bad*/copy scope.cleanups, false);
1389+
bcx.scope = scope.parent;
1390+
1391+
rslt(out_bcx, val)
13701392
}
13711393

13721394
pub fn with_scope_datumblock(bcx: block, opt_node_info: Option<NodeInfo>,

0 commit comments

Comments
 (0)