Skip to content

Commit 2ac9b1d

Browse files
authored
Rollup merge of rust-lang#39648 - Aatch:mir-inlining-2, r=eddyb
[MIR] Implement Inlining Fairly basic implementation of inlining for MIR. Uses conservative heuristics for inlining. Doesn't handle a number of cases, but can be extended later. This is basically the same as the previous inlining PR, but without the span-related changes (as the bugs it was dealing with have since been fixed). /cc @rust-lang/compiler
2 parents 1c0daa5 + 3eb26d1 commit 2ac9b1d

File tree

12 files changed

+1505
-8
lines changed

12 files changed

+1505
-8
lines changed

src/librustc/mir/mod.rs

+346-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use hir::def::CtorKind;
1919
use hir::def_id::DefId;
2020
use ty::subst::Substs;
2121
use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
22+
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
2223
use util::ppaux;
2324
use rustc_back::slice;
2425
use hir::InlineAsm;
@@ -63,8 +64,7 @@ macro_rules! newtype_index {
6364
}
6465

6566
/// Lowered representation of a single function.
66-
// Do not implement clone for Mir, which can be accidently done and kind of expensive.
67-
#[derive(RustcEncodable, RustcDecodable, Debug)]
67+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
6868
pub struct Mir<'tcx> {
6969
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
7070
/// that indexes into this vector.
@@ -1333,3 +1333,347 @@ impl Location {
13331333
}
13341334
}
13351335
}
1336+
1337+
1338+
/*
1339+
* TypeFoldable implementations for MIR types
1340+
*/
1341+
1342+
impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
1343+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1344+
Mir {
1345+
basic_blocks: self.basic_blocks.fold_with(folder),
1346+
visibility_scopes: self.visibility_scopes.clone(),
1347+
promoted: self.promoted.fold_with(folder),
1348+
return_ty: self.return_ty.fold_with(folder),
1349+
local_decls: self.local_decls.fold_with(folder),
1350+
arg_count: self.arg_count,
1351+
upvar_decls: self.upvar_decls.clone(),
1352+
spread_arg: self.spread_arg,
1353+
span: self.span,
1354+
cache: cache::Cache::new()
1355+
}
1356+
}
1357+
1358+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1359+
self.basic_blocks.visit_with(visitor) ||
1360+
self.promoted.visit_with(visitor) ||
1361+
self.return_ty.visit_with(visitor) ||
1362+
self.local_decls.visit_with(visitor)
1363+
}
1364+
}
1365+
1366+
impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
1367+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1368+
LocalDecl {
1369+
ty: self.ty.fold_with(folder),
1370+
..self.clone()
1371+
}
1372+
}
1373+
1374+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1375+
self.ty.visit_with(visitor)
1376+
}
1377+
}
1378+
1379+
impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
1380+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1381+
BasicBlockData {
1382+
statements: self.statements.fold_with(folder),
1383+
terminator: self.terminator.fold_with(folder),
1384+
is_cleanup: self.is_cleanup
1385+
}
1386+
}
1387+
1388+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1389+
self.statements.visit_with(visitor) || self.terminator.visit_with(visitor)
1390+
}
1391+
}
1392+
1393+
impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
1394+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1395+
use mir::StatementKind::*;
1396+
1397+
let kind = match self.kind {
1398+
Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)),
1399+
SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant {
1400+
lvalue: lvalue.fold_with(folder),
1401+
variant_index: variant_index
1402+
},
1403+
StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
1404+
StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
1405+
InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
1406+
asm: asm.clone(),
1407+
outputs: outputs.fold_with(folder),
1408+
inputs: inputs.fold_with(folder)
1409+
},
1410+
Nop => Nop,
1411+
};
1412+
Statement {
1413+
source_info: self.source_info,
1414+
kind: kind
1415+
}
1416+
}
1417+
1418+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1419+
use mir::StatementKind::*;
1420+
1421+
match self.kind {
1422+
Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
1423+
SetDiscriminant { ref lvalue, .. } |
1424+
StorageLive(ref lvalue) |
1425+
StorageDead(ref lvalue) => lvalue.visit_with(visitor),
1426+
InlineAsm { ref outputs, ref inputs, .. } =>
1427+
outputs.visit_with(visitor) || inputs.visit_with(visitor),
1428+
Nop => false,
1429+
}
1430+
}
1431+
}
1432+
1433+
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
1434+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1435+
use mir::TerminatorKind::*;
1436+
1437+
let kind = match self.kind {
1438+
Goto { target } => Goto { target: target },
1439+
SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
1440+
discr: discr.fold_with(folder),
1441+
switch_ty: switch_ty.fold_with(folder),
1442+
values: values.clone(),
1443+
targets: targets.clone()
1444+
},
1445+
Drop { ref location, target, unwind } => Drop {
1446+
location: location.fold_with(folder),
1447+
target: target,
1448+
unwind: unwind
1449+
},
1450+
DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
1451+
location: location.fold_with(folder),
1452+
value: value.fold_with(folder),
1453+
target: target,
1454+
unwind: unwind
1455+
},
1456+
Call { ref func, ref args, ref destination, cleanup } => {
1457+
let dest = destination.as_ref().map(|&(ref loc, dest)| {
1458+
(loc.fold_with(folder), dest)
1459+
});
1460+
1461+
Call {
1462+
func: func.fold_with(folder),
1463+
args: args.fold_with(folder),
1464+
destination: dest,
1465+
cleanup: cleanup
1466+
}
1467+
},
1468+
Assert { ref cond, expected, ref msg, target, cleanup } => {
1469+
let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
1470+
AssertMessage::BoundsCheck {
1471+
len: len.fold_with(folder),
1472+
index: index.fold_with(folder),
1473+
}
1474+
} else {
1475+
msg.clone()
1476+
};
1477+
Assert {
1478+
cond: cond.fold_with(folder),
1479+
expected: expected,
1480+
msg: msg,
1481+
target: target,
1482+
cleanup: cleanup
1483+
}
1484+
},
1485+
Resume => Resume,
1486+
Return => Return,
1487+
Unreachable => Unreachable,
1488+
};
1489+
Terminator {
1490+
source_info: self.source_info,
1491+
kind: kind
1492+
}
1493+
}
1494+
1495+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1496+
use mir::TerminatorKind::*;
1497+
1498+
match self.kind {
1499+
SwitchInt { ref discr, switch_ty, .. } =>
1500+
discr.visit_with(visitor) || switch_ty.visit_with(visitor),
1501+
Drop { ref location, ..} => location.visit_with(visitor),
1502+
DropAndReplace { ref location, ref value, ..} =>
1503+
location.visit_with(visitor) || value.visit_with(visitor),
1504+
Call { ref func, ref args, ref destination, .. } => {
1505+
let dest = if let Some((ref loc, _)) = *destination {
1506+
loc.visit_with(visitor)
1507+
} else { false };
1508+
dest || func.visit_with(visitor) || args.visit_with(visitor)
1509+
},
1510+
Assert { ref cond, ref msg, .. } => {
1511+
if cond.visit_with(visitor) {
1512+
if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
1513+
len.visit_with(visitor) || index.visit_with(visitor)
1514+
} else {
1515+
false
1516+
}
1517+
} else {
1518+
false
1519+
}
1520+
},
1521+
Goto { .. } |
1522+
Resume |
1523+
Return |
1524+
Unreachable => false
1525+
}
1526+
}
1527+
}
1528+
1529+
impl<'tcx> TypeFoldable<'tcx> for Lvalue<'tcx> {
1530+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1531+
match self {
1532+
&Lvalue::Projection(ref p) => Lvalue::Projection(p.fold_with(folder)),
1533+
_ => self.clone()
1534+
}
1535+
}
1536+
1537+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1538+
if let &Lvalue::Projection(ref p) = self {
1539+
p.visit_with(visitor)
1540+
} else {
1541+
false
1542+
}
1543+
}
1544+
}
1545+
1546+
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
1547+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1548+
use mir::Rvalue::*;
1549+
match *self {
1550+
Use(ref op) => Use(op.fold_with(folder)),
1551+
Repeat(ref op, len) => Repeat(op.fold_with(folder), len),
1552+
Ref(region, bk, ref lval) => Ref(region.fold_with(folder), bk, lval.fold_with(folder)),
1553+
Len(ref lval) => Len(lval.fold_with(folder)),
1554+
Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
1555+
BinaryOp(op, ref rhs, ref lhs) =>
1556+
BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)),
1557+
CheckedBinaryOp(op, ref rhs, ref lhs) =>
1558+
CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)),
1559+
UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
1560+
Discriminant(ref lval) => Discriminant(lval.fold_with(folder)),
1561+
Box(ty) => Box(ty.fold_with(folder)),
1562+
Aggregate(ref kind, ref fields) => {
1563+
let kind = match *kind {
1564+
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
1565+
AggregateKind::Tuple => AggregateKind::Tuple,
1566+
AggregateKind::Adt(def, v, substs, n) =>
1567+
AggregateKind::Adt(def, v, substs.fold_with(folder), n),
1568+
AggregateKind::Closure(id, substs) =>
1569+
AggregateKind::Closure(id, substs.fold_with(folder))
1570+
};
1571+
Aggregate(kind, fields.fold_with(folder))
1572+
}
1573+
}
1574+
}
1575+
1576+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1577+
use mir::Rvalue::*;
1578+
match *self {
1579+
Use(ref op) => op.visit_with(visitor),
1580+
Repeat(ref op, _) => op.visit_with(visitor),
1581+
Ref(region, _, ref lval) => region.visit_with(visitor) || lval.visit_with(visitor),
1582+
Len(ref lval) => lval.visit_with(visitor),
1583+
Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
1584+
BinaryOp(_, ref rhs, ref lhs) |
1585+
CheckedBinaryOp(_, ref rhs, ref lhs) =>
1586+
rhs.visit_with(visitor) || lhs.visit_with(visitor),
1587+
UnaryOp(_, ref val) => val.visit_with(visitor),
1588+
Discriminant(ref lval) => lval.visit_with(visitor),
1589+
Box(ty) => ty.visit_with(visitor),
1590+
Aggregate(ref kind, ref fields) => {
1591+
(match *kind {
1592+
AggregateKind::Array(ty) => ty.visit_with(visitor),
1593+
AggregateKind::Tuple => false,
1594+
AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
1595+
AggregateKind::Closure(_, substs) => substs.visit_with(visitor)
1596+
}) || fields.visit_with(visitor)
1597+
}
1598+
}
1599+
}
1600+
}
1601+
1602+
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
1603+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1604+
match *self {
1605+
Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
1606+
Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
1607+
}
1608+
}
1609+
1610+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1611+
match *self {
1612+
Operand::Consume(ref lval) => lval.visit_with(visitor),
1613+
Operand::Constant(ref c) => c.visit_with(visitor)
1614+
}
1615+
}
1616+
}
1617+
1618+
impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V>
1619+
where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>
1620+
{
1621+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1622+
use mir::ProjectionElem::*;
1623+
1624+
let base = self.base.fold_with(folder);
1625+
let elem = match self.elem {
1626+
Deref => Deref,
1627+
Field(f, ty) => Field(f, ty.fold_with(folder)),
1628+
Index(ref v) => Index(v.fold_with(folder)),
1629+
ref elem => elem.clone()
1630+
};
1631+
1632+
Projection {
1633+
base: base,
1634+
elem: elem
1635+
}
1636+
}
1637+
1638+
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
1639+
use mir::ProjectionElem::*;
1640+
1641+
self.base.visit_with(visitor) ||
1642+
match self.elem {
1643+
Field(_, ty) => ty.visit_with(visitor),
1644+
Index(ref v) => v.visit_with(visitor),
1645+
_ => false
1646+
}
1647+
}
1648+
}
1649+
1650+
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
1651+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1652+
Constant {
1653+
span: self.span.clone(),
1654+
ty: self.ty.fold_with(folder),
1655+
literal: self.literal.fold_with(folder)
1656+
}
1657+
}
1658+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1659+
self.ty.visit_with(visitor) || self.literal.visit_with(visitor)
1660+
}
1661+
}
1662+
1663+
impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
1664+
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
1665+
match *self {
1666+
Literal::Item { def_id, substs } => Literal::Item {
1667+
def_id: def_id,
1668+
substs: substs.fold_with(folder)
1669+
},
1670+
_ => self.clone()
1671+
}
1672+
}
1673+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1674+
match *self {
1675+
Literal::Item { substs, .. } => substs.visit_with(visitor),
1676+
_ => false
1677+
}
1678+
}
1679+
}

src/librustc/ty/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -2302,6 +2302,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
23022302
queries::mir::get(self, DUMMY_SP, did).borrow()
23032303
}
23042304

2305+
/// Given the DefId of an item, returns its MIR, borrowed immutably.
2306+
/// Returns None if there is no MIR for the DefId
2307+
pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
2308+
if did.is_local() && !self.maps.mir.borrow().contains_key(&did) {
2309+
return None;
2310+
}
2311+
2312+
if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) {
2313+
return None;
2314+
}
2315+
2316+
Some(self.item_mir(did))
2317+
}
2318+
23052319
/// If `type_needs_drop` returns true, then `ty` is definitely
23062320
/// non-copy and *might* have a destructor attached; if it returns
23072321
/// false, then `ty` definitely has no destructor (i.e. no drop glue).

0 commit comments

Comments
 (0)