Auto merge of #33171 - michaelwoerister:collector-drop-glue, r=nikomatsakis

Some preliminary work towards making trans "collector driven".

The `trans::collector` already collects all translation items and `trans::partitioning` distributes these translation items into codegen units. The changes in this PR provide the following extensions to this functionality:

1. Drop-glue is handled more accurately now, knowing about the difference between `DropGlueKind::Ty` and `DropGlueKind::TyContents`.
2. The partitioning module now supports the `FixedUnitCount` strategy which more or less corresponds to the partitioning one gets via supplying `-Ccodegen-units` today.
3. The partitioning scheme also takes care of assigned LLVM declarations to codegen units, not just definitions (declarations for external items not yet implemented).

It's debatable whether declarations should be handled by the partitioning scheme or whether they should just be emitted on demand.
This commit is contained in:
bors 2016-04-28 14:37:30 -07:00
commit 8da2bcac5d
20 changed files with 325 additions and 144 deletions

View File

@ -52,9 +52,8 @@ impl BitVector {
pub fn grow(&mut self, num_bits: usize) {
let num_words = u64s(num_bits);
let extra_words = self.data.len() - num_words;
if extra_words > 0 {
self.data.extend((0..extra_words).map(|_| 0));
if self.data.len() < num_words {
self.data.resize(num_words, 0)
}
}
@ -284,15 +283,27 @@ fn union_two_vecs() {
#[test]
fn grow() {
let mut vec1 = BitVector::new(65);
assert!(vec1.insert(3));
assert!(!vec1.insert(3));
assert!(vec1.insert(5));
assert!(vec1.insert(64));
for index in 0 .. 65 {
assert!(vec1.insert(index));
assert!(!vec1.insert(index));
}
vec1.grow(128);
assert!(vec1.contains(3));
assert!(vec1.contains(5));
assert!(vec1.contains(64));
assert!(!vec1.contains(126));
// Check if the bits set before growing are still set
for index in 0 .. 65 {
assert!(vec1.contains(index));
}
// Check if the new bits are all un-set
for index in 65 .. 128 {
assert!(!vec1.contains(index));
}
// Check that we can set all new bits without running out of bounds
for index in 65 .. 128 {
assert!(vec1.insert(index));
assert!(!vec1.insert(index));
}
}
#[test]

View File

@ -97,7 +97,7 @@ pub enum Visibility {
// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
// they've been removed in upstream LLVM commit r203866.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Linkage {
ExternalLinkage = 0,
AvailableExternallyLinkage = 1,

View File

@ -58,7 +58,6 @@ use attributes;
use build::*;
use builder::{Builder, noname};
use callee::{Callee, CallArgs, ArgExprs, ArgVals};
use partitioning;
use cleanup::{self, CleanupMethods, DropHint};
use closure;
use common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral};
@ -83,6 +82,7 @@ use machine::{llalign_of_min, llsize_of, llsize_of_real};
use meth;
use mir;
use monomorphize::{self, Instance};
use partitioning::{self, PartitioningStrategy, InstantiationMode};
use symbol_names_test;
use tvec;
use type_::Type;
@ -2934,12 +2934,21 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
None => TransItemCollectionMode::Lazy
};
let (items, inlining_map) = time(time_passes, "translation item collection", || {
let (items, reference_map) = time(time_passes, "translation item collection", || {
collector::collect_crate_translation_items(&ccx, collection_mode)
});
let strategy = if ccx.sess().opts.debugging_opts.incremental.is_some() {
PartitioningStrategy::PerModule
} else {
PartitioningStrategy::FixedUnitCount(ccx.sess().opts.cg.codegen_units)
};
let codegen_units = time(time_passes, "codegen unit partitioning", || {
partitioning::partition(ccx.tcx(), items.iter().cloned(), &inlining_map)
partitioning::partition(ccx.tcx(),
items.iter().cloned(),
strategy,
&reference_map)
});
if ccx.sess().opts.debugging_opts.print_trans_items.is_some() {
@ -2967,17 +2976,18 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
output.push_str(&cgu_name[..]);
let linkage_abbrev = match linkage {
llvm::ExternalLinkage => "External",
llvm::AvailableExternallyLinkage => "Available",
llvm::LinkOnceAnyLinkage => "OnceAny",
llvm::LinkOnceODRLinkage => "OnceODR",
llvm::WeakAnyLinkage => "WeakAny",
llvm::WeakODRLinkage => "WeakODR",
llvm::AppendingLinkage => "Appending",
llvm::InternalLinkage => "Internal",
llvm::PrivateLinkage => "Private",
llvm::ExternalWeakLinkage => "ExternalWeak",
llvm::CommonLinkage => "Common",
InstantiationMode::Def(llvm::ExternalLinkage) => "External",
InstantiationMode::Def(llvm::AvailableExternallyLinkage) => "Available",
InstantiationMode::Def(llvm::LinkOnceAnyLinkage) => "OnceAny",
InstantiationMode::Def(llvm::LinkOnceODRLinkage) => "OnceODR",
InstantiationMode::Def(llvm::WeakAnyLinkage) => "WeakAny",
InstantiationMode::Def(llvm::WeakODRLinkage) => "WeakODR",
InstantiationMode::Def(llvm::AppendingLinkage) => "Appending",
InstantiationMode::Def(llvm::InternalLinkage) => "Internal",
InstantiationMode::Def(llvm::PrivateLinkage) => "Private",
InstantiationMode::Def(llvm::ExternalWeakLinkage) => "ExternalWeak",
InstantiationMode::Def(llvm::CommonLinkage) => "Common",
InstantiationMode::Decl => "Declaration",
};
output.push_str("[");

View File

@ -188,6 +188,8 @@
//! this is not implemented however: a translation item will be produced
//! regardless of whether it is actually needed or not.
use rustc_data_structures::bitvec::BitVector;
use rustc::hir;
use rustc::hir::intravisit as hir_visit;
@ -211,7 +213,7 @@ use base::{custom_coerce_unsize_info, llvm_linkage_by_name};
use context::CrateContext;
use common::{fulfill_obligation, normalize_and_test_predicates,
type_is_sized};
use glue;
use glue::{self, DropGlueKind};
use llvm;
use meth;
use monomorphize::{self, Instance};
@ -227,7 +229,7 @@ pub enum TransItemCollectionMode {
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum TransItem<'tcx> {
DropGlue(Ty<'tcx>),
DropGlue(DropGlueKind<'tcx>),
Fn(Instance<'tcx>),
Static(NodeId)
}
@ -252,12 +254,76 @@ impl<'tcx> Hash for TransItem<'tcx> {
}
}
pub type InliningMap<'tcx> = FnvHashMap<TransItem<'tcx>, FnvHashSet<TransItem<'tcx>>>;
/// Maps every translation item to all translation items it references in its
/// body.
pub struct ReferenceMap<'tcx> {
// Maps a source translation item to a range of target translation items.
// The two numbers in the tuple are the start (inclusive) and
// end index (exclusive) within the `targets` and the `inlined` vecs.
index: FnvHashMap<TransItem<'tcx>, (usize, usize)>,
targets: Vec<TransItem<'tcx>>,
inlined: BitVector
}
impl<'tcx> ReferenceMap<'tcx> {
fn new() -> ReferenceMap<'tcx> {
ReferenceMap {
index: FnvHashMap(),
targets: Vec::new(),
inlined: BitVector::new(64 * 256),
}
}
fn record_references<I>(&mut self, source: TransItem<'tcx>, targets: I)
where I: Iterator<Item=(TransItem<'tcx>, bool)>
{
assert!(!self.index.contains_key(&source));
let start_index = self.targets.len();
for (target, inlined) in targets {
let index = self.targets.len();
self.targets.push(target);
self.inlined.grow(index + 1);
if inlined {
self.inlined.insert(index);
}
}
let end_index = self.targets.len();
self.index.insert(source, (start_index, end_index));
}
// Internally iterate over all items referenced by `source` which will be
// made available for inlining.
pub fn with_inlining_candidates<F>(&self, source: TransItem<'tcx>, mut f: F)
where F: FnMut(TransItem<'tcx>) {
if let Some(&(start_index, end_index)) = self.index.get(&source)
{
for index in start_index .. end_index {
if self.inlined.contains(index) {
f(self.targets[index])
}
}
}
}
pub fn get_direct_references_from(&self, source: TransItem<'tcx>) -> &[TransItem<'tcx>]
{
if let Some(&(start_index, end_index)) = self.index.get(&source) {
&self.targets[start_index .. end_index]
} else {
&self.targets[0 .. 0]
}
}
}
pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
mode: TransItemCollectionMode)
-> (FnvHashSet<TransItem<'tcx>>,
InliningMap<'tcx>) {
ReferenceMap<'tcx>) {
// We are not tracking dependencies of this pass as it has to be re-executed
// every time no matter what.
ccx.tcx().dep_graph.with_ignore(|| {
@ -266,17 +332,17 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("Building translation item graph, beginning at roots");
let mut visited = FnvHashSet();
let mut recursion_depths = DefIdMap();
let mut inlining_map = FnvHashMap();
let mut reference_map = ReferenceMap::new();
for root in roots {
collect_items_rec(ccx,
root,
&mut visited,
&mut recursion_depths,
&mut inlining_map);
&mut reference_map);
}
(visited, inlining_map)
(visited, reference_map)
})
}
@ -307,7 +373,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
starting_point: TransItem<'tcx>,
visited: &mut FnvHashSet<TransItem<'tcx>>,
recursion_depths: &mut DefIdMap<usize>,
inlining_map: &mut InliningMap<'tcx>) {
reference_map: &mut ReferenceMap<'tcx>) {
if !visited.insert(starting_point.clone()) {
// We've been here already, no need to search again.
return;
@ -326,7 +392,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
let def_id = ccx.tcx().map.local_def_id(node_id);
let ty = ccx.tcx().lookup_item_type(def_id).ty;
let ty = glue::get_drop_glue_type(ccx, ty);
neighbors.push(TransItem::DropGlue(ty));
neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
recursion_depth_reset = None;
}
TransItem::Fn(instance) => {
@ -351,9 +417,10 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
}
}
record_references(ccx, starting_point, &neighbors[..], reference_map);
for neighbour in neighbors {
record_inlined_use(ccx, starting_point, neighbour, inlining_map);
collect_items_rec(ccx, neighbour, visited, recursion_depths, inlining_map);
collect_items_rec(ccx, neighbour, visited, recursion_depths, reference_map);
}
if let Some((def_id, depth)) = recursion_depth_reset {
@ -363,16 +430,17 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
debug!("END collect_items_rec({})", starting_point.to_string(ccx));
}
fn record_inlined_use<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
caller: TransItem<'tcx>,
callee: TransItem<'tcx>,
inlining_map: &mut InliningMap<'tcx>) {
if callee.is_from_extern_crate() ||
callee.requests_inline(ccx.tcx()) {
inlining_map.entry(caller)
.or_insert_with(|| FnvHashSet())
.insert(callee);
}
fn record_references<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
caller: TransItem<'tcx>,
callees: &[TransItem<'tcx>],
reference_map: &mut ReferenceMap<'tcx>) {
let iter = callees.into_iter()
.map(|callee| {
let is_inlining_candidate = callee.is_from_extern_crate() ||
callee.requests_inline(ccx.tcx());
(*callee, is_inlining_candidate)
});
reference_map.record_references(caller, iter);
}
fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
@ -485,7 +553,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
&ty);
let ty = self.ccx.tcx().erase_regions(&ty);
let ty = glue::get_drop_glue_type(self.ccx, ty);
self.output.push(TransItem::DropGlue(ty));
self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
}
self.super_lvalue(lvalue, context);
@ -575,9 +643,17 @@ fn can_have_local_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: ty::Ty<'tcx>,
output: &mut Vec<TransItem<'tcx>>)
{
dg: DropGlueKind<'tcx>,
output: &mut Vec<TransItem<'tcx>>) {
let ty = match dg {
DropGlueKind::Ty(ty) => ty,
DropGlueKind::TyContents(_) => {
// We already collected the neighbors of this item via the
// DropGlueKind::Ty variant.
return
}
};
debug!("find_drop_glue_neighbors: {}", type_to_string(ccx, ty));
// Make sure the exchange_free_fn() lang-item gets translated if
@ -634,6 +710,10 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
&Substs::empty());
output.push(trans_item);
}
// This type has a Drop implementation, we'll need the contents-only
// version of the glue too.
output.push(TransItem::DropGlue(DropGlueKind::TyContents(ty)));
}
// Finally add the types of nested values
@ -661,7 +741,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let field_type = glue::get_drop_glue_type(ccx, field_type);
if glue::type_needs_drop(ccx.tcx(), field_type) {
output.push(TransItem::DropGlue(field_type));
output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type)));
}
}
}
@ -669,7 +749,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
for upvar_ty in &substs.upvar_tys {
let upvar_ty = glue::get_drop_glue_type(ccx, upvar_ty);
if glue::type_needs_drop(ccx.tcx(), upvar_ty) {
output.push(TransItem::DropGlue(upvar_ty));
output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty)));
}
}
}
@ -677,14 +757,14 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty::TyArray(inner_type, _) => {
let inner_type = glue::get_drop_glue_type(ccx, inner_type);
if glue::type_needs_drop(ccx.tcx(), inner_type) {
output.push(TransItem::DropGlue(inner_type));
output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
}
}
ty::TyTuple(ref args) => {
for arg in args {
let arg = glue::get_drop_glue_type(ccx, arg);
if glue::type_needs_drop(ccx.tcx(), arg) {
output.push(TransItem::DropGlue(arg));
output.push(TransItem::DropGlue(DropGlueKind::Ty(arg)));
}
}
}
@ -1000,7 +1080,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
self.ccx.tcx().map.local_def_id(item.id)));
let ty = glue::get_drop_glue_type(self.ccx, ty);
self.output.push(TransItem::DropGlue(ty));
self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
}
}
}
@ -1413,10 +1493,13 @@ impl<'tcx> TransItem<'tcx> {
let hir_map = &ccx.tcx().map;
return match *self {
TransItem::DropGlue(t) => {
TransItem::DropGlue(dg) => {
let mut s = String::with_capacity(32);
s.push_str("drop-glue ");
push_unique_type_name(ccx, t, &mut s);
match dg {
DropGlueKind::Ty(_) => s.push_str("drop-glue "),
DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "),
};
push_unique_type_name(ccx, dg.ty(), &mut s);
s
}
TransItem::Fn(instance) => {
@ -1442,8 +1525,8 @@ impl<'tcx> TransItem<'tcx> {
fn to_raw_string(&self) -> String {
match *self {
TransItem::DropGlue(t) => {
format!("DropGlue({})", t as *const _ as usize)
TransItem::DropGlue(dg) => {
format!("DropGlue({})", dg.ty() as *const _ as usize)
}
TransItem::Fn(instance) => {
format!("Fn({:?}, {})",

View File

@ -98,7 +98,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Even if there is no dtor for t, there might be one deeper down and we
// might need to pass in the vtable ptr.
if !type_is_sized(tcx, t) {
return t
return ccx.tcx().erase_regions(&t);
}
// FIXME (#22815): note that type_needs_drop conservatively
@ -121,10 +121,10 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if llsize_of_alloc(ccx, llty) == 0 {
tcx.types.i8
} else {
t
ccx.tcx().erase_regions(&t)
}
}
_ => t
_ => ccx.tcx().erase_regions(&t)
}
}
@ -215,11 +215,11 @@ pub enum DropGlueKind<'tcx> {
}
impl<'tcx> DropGlueKind<'tcx> {
fn ty(&self) -> Ty<'tcx> {
pub fn ty(&self) -> Ty<'tcx> {
match *self { DropGlueKind::Ty(t) | DropGlueKind::TyContents(t) => t }
}
fn map_ty<F>(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
pub fn map_ty<F>(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
{
match *self {
DropGlueKind::Ty(t) => DropGlueKind::Ty(f(t)),
@ -487,14 +487,13 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
-> Block<'blk, 'tcx> {
let t = g.ty();
if collector::collecting_debug_information(bcx.ccx()) {
bcx.ccx()
.record_translation_item_as_generated(TransItem::DropGlue(bcx.tcx()
.erase_regions(&t)));
.record_translation_item_as_generated(TransItem::DropGlue(g));
}
let t = g.ty();
let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");

View File

@ -116,8 +116,7 @@
//! source-level module, functions from the same module will be available for
//! inlining, even when they are not marked #[inline].
use collector::{InliningMap, TransItem};
use context::CrateContext;
use collector::{TransItem, ReferenceMap};
use monomorphize;
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
@ -127,9 +126,28 @@ use llvm;
use syntax::parse::token::{self, InternedString};
use util::nodemap::{FnvHashMap, FnvHashSet};
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum InstantiationMode {
/// This variant indicates that a translation item should be placed in some
/// codegen unit as a definition and with the given linkage.
Def(llvm::Linkage),
/// This variant indicates that only a declaration of some translation item
/// should be placed in a given codegen unit.
Decl
}
pub struct CodegenUnit<'tcx> {
pub name: InternedString,
pub items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>,
pub items: FnvHashMap<TransItem<'tcx>, InstantiationMode>,
}
pub enum PartitioningStrategy {
/// Generate one codegen unit per source-level module.
PerModule,
/// Partition the whole crate into a fixed number of codegen units.
FixedUnitCount(usize)
}
// Anything we can't find a proper codegen unit for goes into this.
@ -137,30 +155,47 @@ const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";
pub fn partition<'tcx, I>(tcx: &TyCtxt<'tcx>,
trans_items: I,
inlining_map: &InliningMap<'tcx>)
strategy: PartitioningStrategy,
reference_map: &ReferenceMap<'tcx>)
-> Vec<CodegenUnit<'tcx>>
where I: Iterator<Item = TransItem<'tcx>>
{
// In the first step, we place all regular translation items into their
// respective 'home' codegen unit. Regular translation items are all
// functions and statics defined in the local crate.
let initial_partitioning = place_root_translation_items(tcx, trans_items);
let mut initial_partitioning = place_root_translation_items(tcx, trans_items);
// If the partitioning should produce a fixed count of codegen units, merge
// until that count is reached.
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name[..]);
}
// In the next step, we use the inlining map to determine which addtional
// translation items have to go into each codegen unit. These additional
// translation items can be drop-glue, functions from external crates, and
// local functions the definition of which is marked with #[inline].
place_inlined_translation_items(initial_partitioning, inlining_map)
let post_inlining = place_inlined_translation_items(initial_partitioning,
reference_map);
// Now we know all *definitions* within all codegen units, thus we can
// easily determine which declarations need to be placed within each one.
let post_declarations = place_declarations(post_inlining, reference_map);
post_declarations.0
}
struct InitialPartitioning<'tcx> {
struct PreInliningPartitioning<'tcx> {
codegen_units: Vec<CodegenUnit<'tcx>>,
roots: FnvHashSet<TransItem<'tcx>>,
}
struct PostInliningPartitioning<'tcx>(Vec<CodegenUnit<'tcx>>);
struct PostDeclarationsPartitioning<'tcx>(Vec<CodegenUnit<'tcx>>);
fn place_root_translation_items<'tcx, I>(tcx: &TyCtxt<'tcx>,
trans_items: I)
-> InitialPartitioning<'tcx>
-> PreInliningPartitioning<'tcx>
where I: Iterator<Item = TransItem<'tcx>>
{
let mut roots = FnvHashSet();
@ -204,12 +239,13 @@ fn place_root_translation_items<'tcx, I>(tcx: &TyCtxt<'tcx>,
}
};
codegen_unit.items.insert(trans_item, linkage);
codegen_unit.items.insert(trans_item,
InstantiationMode::Def(linkage));
roots.insert(trans_item);
}
}
InitialPartitioning {
PreInliningPartitioning {
codegen_units: codegen_units.into_iter()
.map(|(_, codegen_unit)| codegen_unit)
.collect(),
@ -217,61 +253,115 @@ fn place_root_translation_items<'tcx, I>(tcx: &TyCtxt<'tcx>,
}
}
fn place_inlined_translation_items<'tcx>(initial_partitioning: InitialPartitioning<'tcx>,
inlining_map: &InliningMap<'tcx>)
-> Vec<CodegenUnit<'tcx>> {
let mut final_partitioning = Vec::new();
fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
target_cgu_count: usize,
crate_name: &str) {
if target_cgu_count >= initial_partitioning.codegen_units.len() {
return;
}
assert!(target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;
// Merge the two smallest codegen units until the target size is reached.
// Note that "size" is estimated here rather inaccurately as the number of
// translation items in a given unit. This could be improved on.
while codegen_units.len() > target_cgu_count {
// Sort small cgus to the back
codegen_units.as_mut_slice().sort_by_key(|cgu| -(cgu.items.len() as i64));
let smallest = codegen_units.pop().unwrap();
let second_smallest = codegen_units.last_mut().unwrap();
for (k, v) in smallest.items.into_iter() {
second_smallest.items.insert(k, v);
}
}
for (index, cgu) in codegen_units.iter_mut().enumerate() {
cgu.name = token::intern_and_get_ident(&format!("{}.{}", crate_name, index)[..]);
}
}
fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
reference_map: &ReferenceMap<'tcx>)
-> PostInliningPartitioning<'tcx> {
let mut new_partitioning = Vec::new();
for codegen_unit in &initial_partitioning.codegen_units[..] {
// Collect all items that need to be available in this codegen unit
let mut reachable = FnvHashSet();
for root in codegen_unit.items.keys() {
follow_inlining(*root, inlining_map, &mut reachable);
follow_inlining(*root, reference_map, &mut reachable);
}
let mut final_codegen_unit = CodegenUnit {
let mut new_codegen_unit = CodegenUnit {
name: codegen_unit.name.clone(),
items: FnvHashMap(),
};
// Add all translation items that are not already there
for trans_item in reachable {
if let Some(linkage) = codegen_unit.items.get(&trans_item) {
if let Some(instantiation_mode) = codegen_unit.items.get(&trans_item) {
// This is a root, just copy it over
final_codegen_unit.items.insert(trans_item, *linkage);
new_codegen_unit.items.insert(trans_item, *instantiation_mode);
} else {
if initial_partitioning.roots.contains(&trans_item) {
// This item will be instantiated in some other codegen unit,
// so we just add it here with AvailableExternallyLinkage
final_codegen_unit.items.insert(trans_item, llvm::AvailableExternallyLinkage);
new_codegen_unit.items.insert(trans_item,
InstantiationMode::Def(llvm::AvailableExternallyLinkage));
} else {
// We can't be sure if this will also be instantiated
// somewhere else, so we add an instance here with
// LinkOnceODRLinkage. That way the item can be discarded if
// it's not needed (inlined) after all.
final_codegen_unit.items.insert(trans_item, llvm::LinkOnceODRLinkage);
new_codegen_unit.items.insert(trans_item,
InstantiationMode::Def(llvm::LinkOnceODRLinkage));
}
}
}
final_partitioning.push(final_codegen_unit);
new_partitioning.push(new_codegen_unit);
}
return final_partitioning;
return PostInliningPartitioning(new_partitioning);
fn follow_inlining<'tcx>(trans_item: TransItem<'tcx>,
inlining_map: &InliningMap<'tcx>,
reference_map: &ReferenceMap<'tcx>,
visited: &mut FnvHashSet<TransItem<'tcx>>) {
if !visited.insert(trans_item) {
return;
}
if let Some(inlined_items) = inlining_map.get(&trans_item) {
for &inlined_item in inlined_items {
follow_inlining(inlined_item, inlining_map, visited);
reference_map.with_inlining_candidates(trans_item, |target| {
follow_inlining(target, reference_map, visited);
});
}
}
fn place_declarations<'tcx>(codegen_units: PostInliningPartitioning<'tcx>,
reference_map: &ReferenceMap<'tcx>)
-> PostDeclarationsPartitioning<'tcx> {
let PostInliningPartitioning(mut codegen_units) = codegen_units;
for codegen_unit in codegen_units.iter_mut() {
let mut declarations = FnvHashSet();
for (trans_item, _) in &codegen_unit.items {
for referenced_item in reference_map.get_direct_references_from(*trans_item) {
if !codegen_unit.items.contains_key(referenced_item) {
declarations.insert(*referenced_item);
}
}
}
codegen_unit.items
.extend(declarations.iter()
.map(|trans_item| (*trans_item,
InstantiationMode::Decl)));
}
PostDeclarationsPartitioning(codegen_units)
}
fn characteristic_def_id_of_trans_item<'tcx>(tcx: &TyCtxt<'tcx>,
@ -304,7 +394,7 @@ fn characteristic_def_id_of_trans_item<'tcx>(tcx: &TyCtxt<'tcx>,
Some(instance.def)
}
TransItem::DropGlue(t) => characteristic_def_id_of_type(t),
TransItem::DropGlue(dg) => characteristic_def_id_of_type(dg.ty()),
TransItem::Static(node_id) => Some(tcx.map.local_def_id(node_id)),
}
}
@ -340,24 +430,3 @@ fn compute_codegen_unit_name<'tcx>(tcx: &TyCtxt<'tcx>,
return token::intern_and_get_ident(&mod_path[..]);
}
impl<'tcx> CodegenUnit<'tcx> {
pub fn _dump<'a>(&self, ccx: &CrateContext<'a, 'tcx>) {
println!("CodegenUnit {} (", self.name);
let mut items: Vec<_> = self.items
.iter()
.map(|(trans_item, inst)| {
format!("{} -- ({:?})", trans_item.to_string(ccx), inst)
})
.collect();
items.as_mut_slice().sort();
for s in items {
println!(" {}", s);
}
println!(")");
}
}

View File

@ -46,19 +46,22 @@ struct NonGenericNoDrop(i32);
struct NonGenericWithDrop(i32);
//~ TRANS_ITEM drop-glue generic_drop_glue::NonGenericWithDrop[0]
//~ TRANS_ITEM drop-glue-contents generic_drop_glue::NonGenericWithDrop[0]
impl Drop for NonGenericWithDrop {
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
fn drop(&mut self) {}
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
}
//~ TRANS_ITEM fn generic_drop_glue::main[0]
fn main() {
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<i8, char>
//~ TRANS_ITEM drop-glue-contents generic_drop_glue::StructWithDrop[0]<i8, char>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
//~ TRANS_ITEM drop-glue-contents generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
@ -71,6 +74,7 @@ fn main() {
let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<i32, i64>
//~ TRANS_ITEM drop-glue-contents generic_drop_glue::EnumWithDrop[0]<i32, i64>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
let _ = match EnumWithDrop::A::<i32, i64>(0) {
EnumWithDrop::A(x) => x,
@ -78,6 +82,7 @@ fn main() {
};
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<f64, f32>
//~ TRANS_ITEM drop-glue-contents generic_drop_glue::EnumWithDrop[0]<f64, f32>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
EnumWithDrop::A(x) => x,

View File

@ -14,6 +14,7 @@
#![deny(dead_code)]
//~ TRANS_ITEM drop-glue non_generic_drop_glue::StructWithDrop[0]
//~ TRANS_ITEM drop-glue-contents non_generic_drop_glue::StructWithDrop[0]
struct StructWithDrop {
x: i32
}
@ -28,6 +29,7 @@ struct StructNoDrop {
}
//~ TRANS_ITEM drop-glue non_generic_drop_glue::EnumWithDrop[0]
//~ TRANS_ITEM drop-glue-contents non_generic_drop_glue::EnumWithDrop[0]
enum EnumWithDrop {
A(i32)
}

View File

@ -18,6 +18,7 @@ struct Root(Intermediate);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Intermediate[0]
struct Intermediate(Leaf);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Leaf[0]
//~ TRANS_ITEM drop-glue-contents transitive_drop_glue::Leaf[0]
struct Leaf;
impl Drop for Leaf {
@ -25,11 +26,8 @@ impl Drop for Leaf {
fn drop(&mut self) {}
}
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct RootGen<T>(IntermediateGen<T>);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct IntermediateGen<T>(LeafGen<T>);
//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0]
struct LeafGen<T>(T);
impl<T> Drop for LeafGen<T> {
@ -44,12 +42,14 @@ fn main() {
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<u32>
//~ TRANS_ITEM drop-glue-contents transitive_drop_glue::LeafGen[0]<u32>
//~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
let _ = RootGen(IntermediateGen(LeafGen(0u32)));
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<i16>
//~ TRANS_ITEM drop-glue-contents transitive_drop_glue::LeafGen[0]<i16>
//~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
let _ = RootGen(IntermediateGen(LeafGen(0i16)));
}

View File

@ -14,6 +14,7 @@
#![deny(dead_code)]
//~ TRANS_ITEM drop-glue tuple_drop_glue::Dropped[0]
//~ TRANS_ITEM drop-glue-contents tuple_drop_glue::Dropped[0]
struct Dropped;
impl Drop for Dropped {

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]
@ -18,6 +18,7 @@
extern crate cgu_extern_drop_glue;
//~ TRANS_ITEM drop-glue cgu_extern_drop_glue::Struct[0] @@ extern_drop_glue[OnceODR] extern_drop_glue-mod1[OnceODR]
//~ TRANS_ITEM drop-glue-contents cgu_extern_drop_glue::Struct[0] @@ extern_drop_glue[OnceODR] extern_drop_glue-mod1[OnceODR]
struct LocalStruct(cgu_extern_drop_glue::Struct);
@ -40,4 +41,3 @@ mod mod1 {
let _ = LocalStruct(cgu_extern_drop_glue::Struct(0));
}
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=eager
// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![crate_type="lib"]

View File

@ -9,18 +9,19 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]
//~ TRANS_ITEM drop-glue local_drop_glue::Struct[0] @@ local_drop_glue[OnceODR] local_drop_glue-mod1[OnceODR]
//~ TRANS_ITEM drop-glue-contents local_drop_glue::Struct[0] @@ local_drop_glue[OnceODR] local_drop_glue-mod1[OnceODR]
struct Struct {
_a: u32
}
impl Drop for Struct {
//~ TRANS_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[WeakODR]
//~ TRANS_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[WeakODR] local_drop_glue-mod1[Declaration]
fn drop(&mut self) {}
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=eager
// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]
@ -17,10 +17,10 @@
// Used in different modules/codegen units but always instantiated in the same
// codegen unit.
//~ TRANS_ITEM fn local_generic::generic[0]<u32> @@ local_generic.volatile[WeakODR]
//~ TRANS_ITEM fn local_generic::generic[0]<u64> @@ local_generic.volatile[WeakODR]
//~ TRANS_ITEM fn local_generic::generic[0]<char> @@ local_generic.volatile[WeakODR]
//~ TRANS_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[WeakODR]
//~ TRANS_ITEM fn local_generic::generic[0]<u32> @@ local_generic.volatile[WeakODR] local_generic[Declaration]
//~ TRANS_ITEM fn local_generic::generic[0]<u64> @@ local_generic.volatile[WeakODR] local_generic-mod1[Declaration]
//~ TRANS_ITEM fn local_generic::generic[0]<char> @@ local_generic.volatile[WeakODR] local_generic-mod1-mod1[Declaration]
//~ TRANS_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[WeakODR] local_generic-mod2[Declaration]
pub fn generic<T>(x: T) -> T { x }
//~ TRANS_ITEM fn local_generic::user[0] @@ local_generic[WeakODR]

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![allow(dead_code)]
@ -59,19 +59,19 @@ mod type2 {
//~ TRANS_ITEM fn methods_are_with_self_type::main[0]
fn main()
{
//~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0]<u32, u64> @@ methods_are_with_self_type.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0]<u32, u64> @@ methods_are_with_self_type.volatile[WeakODR] methods_are_with_self_type[Declaration]
SomeGenericType(0u32, 0u64).method();
//~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0]<char, &str> @@ methods_are_with_self_type.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0]<char, &str> @@ methods_are_with_self_type.volatile[WeakODR] methods_are_with_self_type[Declaration]
SomeGenericType::associated_fn('c', "&str");
//~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR] methods_are_with_self_type[Declaration]
type1::Struct.foo();
//~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR] methods_are_with_self_type[Declaration]
type2::Struct.foo();
//~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR] methods_are_with_self_type[Declaration]
type1::Struct.default();
//~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR]
//~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR] methods_are_with_self_type[Declaration]
type2::Struct.default();
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=eager
// compile-flags:-Zprint-trans-items=eager -Z incremental=tmp
#![allow(dead_code)]
#![crate_type="lib"]

View File

@ -9,7 +9,7 @@
// except according to those terms.
// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=lazy
// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp
#![crate_type="lib"]