Skip to content

Commit 312b9df

Browse files
committed
Various inlining improvements
Don't add an unwind edge if the call/drop/assert is in a cleanup block. This allows the pass to inline more functions correctly. Don't penalize intrinsics as harshly. They were previously treated the same as regular calls but now have the same cost as a statement. Run the before/after hooks for the pass. Since this is a MirMapPass, the hooks weren't run. Run copy propagation each time a function is inlined to remove any unecessary copies introduced during integration. This also makes copy propagation remove any nops it generated once it has finished. Run simplify cfg after inlining has finished for a SCC. This removes the need for a separate simplify cfg pass to be run.
1 parent 5a448ca commit 312b9df

File tree

5 files changed

+105
-55
lines changed

5 files changed

+105
-55
lines changed

src/librustc/mir/repr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,7 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
14201420
},
14211421
StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
14221422
StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
1423+
Nop => Nop,
14231424
};
14241425
Statement {
14251426
source_info: self.source_info,
@@ -1434,7 +1435,8 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
14341435
Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
14351436
SetDiscriminant { ref lvalue, .. } |
14361437
StorageLive(ref lvalue) |
1437-
StorageDead(ref lvalue) => lvalue.visit_with(visitor)
1438+
StorageDead(ref lvalue) => lvalue.visit_with(visitor),
1439+
Nop => false,
14381440
}
14391441
}
14401442
}

src/librustc_driver/driver.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10271027

10281028
// No lifetime analysis based on borrowing can be done from here on out.
10291029
passes.push_pass(box mir::transform::inline::Inline);
1030-
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("inline"));
10311030
passes.push_pass(box mir::transform::instcombine::InstCombine::new());
10321031

10331032
passes.push_pass(box mir::transform::deaggregator::Deaggregator);

src/librustc_mir/transform/copy_prop.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ impl Pass for CopyPropagation {}
4141

4242
impl<'tcx> MirPass<'tcx> for CopyPropagation {
4343
fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {
44+
self.propagate_copies(mir);
45+
}
46+
}
47+
48+
impl CopyPropagation {
49+
pub fn propagate_copies<'tcx>(&self, mir: &mut Mir<'tcx>) {
4450
loop {
4551
let mut def_use_analysis = DefUseAnalysis::new(mir);
4652
def_use_analysis.analyze(mir);
@@ -175,6 +181,14 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
175181
break
176182
}
177183
}
184+
185+
// Strip out nops
186+
for blk in mir.basic_blocks_mut() {
187+
blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
188+
false
189+
} else {
190+
true
191+
})
192+
}
178193
}
179194
}
180-

src/librustc_mir/transform/inline.rs

+84-49
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ use rustc::ty::{self, Ty, TyCtxt};
2828
use rustc::ty::subst::{Subst,Substs};
2929
use rustc::util::nodemap::{DefIdMap, DefIdSet};
3030

31+
use super::simplify_cfg::{remove_dead_blocks, CfgSimplifier};
32+
use super::copy_prop::CopyPropagation;
33+
3134
use syntax::attr;
35+
use syntax::abi::Abi;
3236
use syntax_pos::Span;
3337

3438
use callgraph;
@@ -50,7 +54,7 @@ impl<'tcx> MirMapPass<'tcx> for Inline {
5054
&mut self,
5155
tcx: TyCtxt<'a, 'tcx, 'tcx>,
5256
map: &mut MirMap<'tcx>,
53-
_: &mut [Box<for<'s> MirPassHook<'s>>]) {
57+
hooks: &mut [Box<for<'s> MirPassHook<'s>>]) {
5458

5559
match tcx.sess.opts.debugging_opts.mir_opt_level {
5660
Some(0) |
@@ -68,10 +72,32 @@ impl<'tcx> MirMapPass<'tcx> for Inline {
6872
foreign_mirs: DefIdMap()
6973
};
7074

75+
let def_ids = map.map.keys();
76+
for &def_id in &def_ids {
77+
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
78+
let mir = map.map.get_mut(&def_id).unwrap();
79+
let id = tcx.map.as_local_node_id(def_id).unwrap();
80+
let src = MirSource::from_node(tcx, id);
81+
82+
for hook in &mut *hooks {
83+
hook.on_mir_pass(tcx, src, mir, self, false);
84+
}
85+
}
86+
7187
for scc in callgraph.scc_iter() {
72-
debug!("Inlining SCC {:?}", scc);
7388
inliner.inline_scc(map, &callgraph, &scc);
7489
}
90+
91+
for def_id in def_ids {
92+
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
93+
let mir = map.map.get_mut(&def_id).unwrap();
94+
let id = tcx.map.as_local_node_id(def_id).unwrap();
95+
let src = MirSource::from_node(tcx, id);
96+
97+
for hook in &mut *hooks {
98+
hook.on_mir_pass(tcx, src, mir, self, true);
99+
}
100+
}
75101
}
76102
}
77103

@@ -97,6 +123,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
97123
let mut callsites = Vec::new();
98124
let mut in_scc = DefIdSet();
99125

126+
let mut inlined_into = DefIdSet();
127+
100128
for &node in scc {
101129
let def_id = callgraph.def_id(node);
102130

@@ -190,6 +218,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
190218
continue;
191219
}
192220

221+
inlined_into.insert(callsite.caller);
222+
193223
// Add callsites from inlined function
194224
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) {
195225
// Only consider direct calls to functions
@@ -228,6 +258,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
228258
}
229259
}
230260

261+
// Simplify functions we inlined into.
262+
for def_id in inlined_into {
263+
let caller_mir = map.map.get_mut(&def_id).unwrap();
264+
debug!("Running simplify cfg on {:?}", def_id);
265+
CfgSimplifier::new(caller_mir).simplify();
266+
remove_dead_blocks(caller_mir);
267+
}
231268
changed
232269
}
233270

@@ -266,7 +303,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
266303

267304
let hinted = match hint {
268305
// Just treat inline(always) as a hint for now,
269-
// there are cases that prevent unwinding that we
306+
// there are cases that prevent inlining that we
270307
// need to check for first.
271308
attr::InlineAttr::Always => true,
272309
attr::InlineAttr::Never => return false,
@@ -318,31 +355,24 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
318355
// Don't count StorageLive/StorageDead in the inlining cost.
319356
match stmt.kind {
320357
StatementKind::StorageLive(_) |
321-
StatementKind::StorageDead(_) => {}
358+
StatementKind::StorageDead(_) |
359+
StatementKind::Nop => {}
322360
_ => cost += INSTR_COST
323361
}
324362
}
325363
match blk.terminator().kind {
326-
TerminatorKind::Drop { ref location, unwind, .. } |
327-
TerminatorKind::DropAndReplace { ref location, unwind, .. } => {
364+
TerminatorKind::Drop { ref location, .. } |
365+
TerminatorKind::DropAndReplace { ref location, .. } => {
328366
// If the location doesn't actually need dropping, treat it like
329367
// a regular goto.
330368
let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
331369
let ty = ty.to_ty(tcx);
332370
if tcx.type_needs_drop_given_env(ty, &param_env) {
333-
if unwind.is_some() {
334-
// FIXME: Should be able to handle this better
335-
return false;
336-
} else {
337-
cost += CALL_PENALTY;
338-
}
371+
cost += CALL_PENALTY;
339372
} else {
340373
cost += INSTR_COST;
341374
}
342375
}
343-
// FIXME: Should be able to handle this better
344-
TerminatorKind::Call { cleanup: Some(_), .. } |
345-
TerminatorKind::Assert { cleanup: Some(_), .. } => return false,
346376

347377
TerminatorKind::Unreachable |
348378
TerminatorKind::Call { destination: None, .. } if first_block => {
@@ -351,7 +381,16 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
351381
threshold = 0;
352382
}
353383

354-
TerminatorKind::Call { .. } |
384+
TerminatorKind::Call {func: Operand::Constant(ref f), .. } => {
385+
if let ty::TyFnDef(.., f) = f.ty.sty {
386+
// Don't give intrinsics the extra penalty for calls
387+
if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
388+
cost += INSTR_COST;
389+
} else {
390+
cost += CALL_PENALTY;
391+
}
392+
}
393+
}
355394
TerminatorKind::Assert { .. } => cost += CALL_PENALTY,
356395
_ => cost += INSTR_COST
357396
}
@@ -405,8 +444,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
405444

406445
let terminator = caller_mir[callsite.bb].terminator.take().unwrap();
407446
match terminator.kind {
408-
TerminatorKind::Call {
409-
func: _, args, destination: Some(destination), cleanup } => {
447+
TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
410448

411449
debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller);
412450

@@ -532,7 +570,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
532570
inline_location: callsite.location,
533571
destination: dest,
534572
return_block: return_block,
535-
cleanup_block: cleanup
573+
cleanup_block: cleanup,
574+
in_cleanup_block: false
536575
};
537576

538577

@@ -548,6 +587,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
548587

549588
caller_mir[callsite.bb].terminator = Some(terminator);
550589

590+
// Run copy propagation on the function to clean up any unnecessary
591+
// assignments from integration. This also increases the chance that
592+
// this function will be inlined as well
593+
debug!("Running copy propagation");
594+
CopyPropagation.propagate_copies(caller_mir);
595+
551596
true
552597
}
553598
kind => {
@@ -580,7 +625,8 @@ struct Integrator<'a, 'tcx: 'a> {
580625
inline_location: SourceInfo,
581626
destination: Lvalue<'tcx>,
582627
return_block: BasicBlock,
583-
cleanup_block: Option<BasicBlock>
628+
cleanup_block: Option<BasicBlock>,
629+
in_cleanup_block: bool,
584630
}
585631

586632
impl<'a, 'tcx> Integrator<'a, 'tcx> {
@@ -594,29 +640,25 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
594640
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
595641
fn visit_lvalue(&mut self,
596642
lvalue: &mut Lvalue<'tcx>,
597-
_ctxt: LvalueContext,
643+
_ctxt: LvalueContext<'tcx>,
598644
_location: Location) {
599645
match *lvalue {
600646
Lvalue::Var(ref mut var) => {
601647
if let Some(v) = self.var_map.get(*var).cloned() {
602-
debug!("Replacing {:?} with {:?}", var, v);
603648
*var = v;
604649
}
605650
}
606651
Lvalue::Temp(ref mut tmp) => {
607652
if let Some(t) = self.tmp_map.get(*tmp).cloned() {
608-
debug!("Replacing {:?} with {:?}", tmp, t);
609653
*tmp = t;
610654
}
611655
}
612656
Lvalue::ReturnPointer => {
613-
debug!("Replacing return pointer with {:?}", self.destination);
614657
*lvalue = self.destination.clone();
615658
}
616659
Lvalue::Arg(arg) => {
617660
let idx = arg.index();
618661
if let Operand::Consume(ref lval) = self.args[idx] {
619-
debug!("Replacing {:?} with {:?}", lvalue, lval);
620662
*lvalue = lval.clone();
621663
}
622664
}
@@ -628,13 +670,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
628670
if let Operand::Consume(Lvalue::Arg(arg)) = *operand {
629671
let idx = arg.index();
630672
let new_arg = self.args[idx].clone();
631-
debug!("Replacing use of {:?} with {:?}", arg, new_arg);
632673
*operand = new_arg;
633674
} else {
634675
self.super_operand(operand, location);
635676
}
636677
}
637678

679+
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
680+
self.in_cleanup_block = data.is_cleanup;
681+
self.super_basic_block_data(block, data);
682+
self.in_cleanup_block = false;
683+
}
684+
638685
fn visit_terminator_kind(&mut self, block: BasicBlock,
639686
kind: &mut TerminatorKind<'tcx>, loc: Location) {
640687
match *kind {
@@ -656,44 +703,32 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
656703
*target = self.update_target(*target);
657704
if let Some(tgt) = *unwind {
658705
*unwind = Some(self.update_target(tgt));
659-
} else {
660-
if Some(*target) != self.cleanup_block {
661-
*unwind = self.cleanup_block;
662-
}
663-
}
664-
665-
if Some(*target) == *unwind {
666-
*unwind == None;
706+
} else if !self.in_cleanup_block {
707+
// Unless this drop is in a cleanup block, add an unwind edge to
708+
// the orignal call's cleanup block
709+
*unwind = self.cleanup_block;
667710
}
668711
}
669712
TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
670-
let mut target = None;
671713
if let Some((_, ref mut tgt)) = *destination {
672714
*tgt = self.update_target(*tgt);
673-
target = Some(*tgt);
674715
}
675716
if let Some(tgt) = *cleanup {
676717
*cleanup = Some(self.update_target(tgt));
677-
} else {
718+
} else if !self.in_cleanup_block {
719+
// Unless this call is in a cleanup block, add an unwind edge to
720+
// the orignal call's cleanup block
678721
*cleanup = self.cleanup_block;
679722
}
680-
681-
if target == *cleanup {
682-
*cleanup == None;
683-
}
684723
}
685724
TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
686725
*target = self.update_target(*target);
687726
if let Some(tgt) = *cleanup {
688727
*cleanup = Some(self.update_target(tgt));
689-
} else {
690-
if Some(*target) != self.cleanup_block {
691-
*cleanup = self.cleanup_block;
692-
}
693-
}
694-
695-
if Some(*target) == *cleanup {
696-
*cleanup == None;
728+
} else if !self.in_cleanup_block{
729+
// Unless this assert is in a cleanup block, add an unwind edge to
730+
// the orignal call's cleanup block
731+
*cleanup = self.cleanup_block;
697732
}
698733
}
699734
TerminatorKind::Return => {

src/librustc_mir/transform/simplify_cfg.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub struct CfgSimplifier<'a, 'tcx: 'a> {
7373
}
7474

7575
impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
76-
fn new(mir: &'a mut Mir<'tcx>) -> Self {
76+
pub fn new(mir: &'a mut Mir<'tcx>) -> Self {
7777
let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks());
7878

7979
// we can't use mir.predecessors() here because that counts
@@ -94,7 +94,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
9494
}
9595
}
9696

97-
fn simplify(mut self) {
97+
pub fn simplify(mut self) {
9898
loop {
9999
let mut changed = false;
100100

@@ -219,7 +219,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
219219
}
220220
}
221221

222-
fn remove_dead_blocks(mir: &mut Mir) {
222+
pub fn remove_dead_blocks(mir: &mut Mir) {
223223
let mut seen = BitVector::new(mir.basic_blocks().len());
224224
for (bb, _) in traversal::preorder(mir) {
225225
seen.insert(bb.index());

0 commit comments

Comments
 (0)