Skip to content

Commit fef6c64

Browse files
committed
Auto merge of #32779 - michaelwoerister:partitioning, r=nikomatsakis
Add initial version of codegen unit partitioning for incremental compilation. The task of the partitioning module is to take the complete set of translation items of a crate and produce a set of codegen units from it, where a codegen unit is a named set of (translation-item, linkage) pairs. That is, this module decides which translation item appears in which codegen units with which linkage. This version only handles the case of partitioning for incremental compilation, not the regular N-codegen units case. In the future the regular case should be handled too, maybe even doing a bit more analysis to intelligently figure out a good partitioning. One thing that could be improved is the syntax of the codegen unit tests. Right now they still use the compile-fail error specification infrastructure, so everything has to be on one line. Would be nice to be able to format things in a more readable way.
2 parents 576229f + e8441b6 commit fef6c64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1326
-69
lines changed

src/compiletest/runtest.rs

+130-17
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,7 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
19111911
}
19121912

19131913
fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1914+
19141915
assert!(props.revisions.is_empty(), "revisions not relevant here");
19151916

19161917
let proc_res = compile_test(config, props, testpaths);
@@ -1921,36 +1922,148 @@ fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPa
19211922

19221923
check_no_compiler_crash(None, &proc_res);
19231924

1924-
let prefix = "TRANS_ITEM ";
1925+
const PREFIX: &'static str = "TRANS_ITEM ";
1926+
const CGU_MARKER: &'static str = "@@";
19251927

1926-
let actual: HashSet<String> = proc_res
1928+
let actual: Vec<TransItem> = proc_res
19271929
.stdout
19281930
.lines()
1929-
.filter(|line| line.starts_with(prefix))
1930-
.map(|s| (&s[prefix.len()..]).to_string())
1931+
.filter(|line| line.starts_with(PREFIX))
1932+
.map(str_to_trans_item)
19311933
.collect();
19321934

1933-
let expected: HashSet<String> = errors::load_errors(&testpaths.file, None)
1935+
let expected: Vec<TransItem> = errors::load_errors(&testpaths.file, None)
19341936
.iter()
1935-
.map(|e| e.msg.trim().to_string())
1937+
.map(|e| str_to_trans_item(&e.msg[..]))
19361938
.collect();
19371939

1938-
if actual != expected {
1939-
let mut missing: Vec<_> = expected.difference(&actual).collect();
1940+
let mut missing = Vec::new();
1941+
let mut wrong_cgus = Vec::new();
1942+
1943+
for expected_item in &expected {
1944+
let actual_item_with_same_name = actual.iter()
1945+
.find(|ti| ti.name == expected_item.name);
1946+
1947+
if let Some(actual_item) = actual_item_with_same_name {
1948+
if !expected_item.codegen_units.is_empty() {
1949+
// Also check for codegen units
1950+
if expected_item.codegen_units != actual_item.codegen_units {
1951+
wrong_cgus.push((expected_item.clone(), actual_item.clone()));
1952+
}
1953+
}
1954+
} else {
1955+
missing.push(expected_item.string.clone());
1956+
}
1957+
}
1958+
1959+
let unexpected: Vec<_> =
1960+
actual.iter()
1961+
.filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
1962+
.map(|acgu| acgu.string.clone())
1963+
.collect();
1964+
1965+
if !missing.is_empty() {
19401966
missing.sort();
19411967

1942-
let mut too_much: Vec<_> = actual.difference(&expected).collect();
1943-
too_much.sort();
1968+
println!("\nThese items should have been contained but were not:\n");
1969+
1970+
for item in &missing {
1971+
println!("{}", item);
1972+
}
19441973

1945-
println!("Expected and actual sets of codegen-items differ.\n\
1946-
These items should have been contained but were not:\n\n\
1947-
{}\n\n\
1948-
These items were contained but should not have been:\n\n\
1949-
{}\n\n",
1950-
missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
1951-
too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));
1974+
println!("\n");
1975+
}
1976+
1977+
if !unexpected.is_empty() {
1978+
let sorted = {
1979+
let mut sorted = unexpected.clone();
1980+
sorted.sort();
1981+
sorted
1982+
};
1983+
1984+
println!("\nThese items were contained but should not have been:\n");
1985+
1986+
for item in sorted {
1987+
println!("{}", item);
1988+
}
1989+
1990+
println!("\n");
1991+
}
1992+
1993+
if !wrong_cgus.is_empty() {
1994+
wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
1995+
println!("\nThe following items were assigned to wrong codegen units:\n");
1996+
1997+
for &(ref expected_item, ref actual_item) in &wrong_cgus {
1998+
println!("{}", expected_item.name);
1999+
println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units));
2000+
println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units));
2001+
println!("");
2002+
}
2003+
}
2004+
2005+
if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())
2006+
{
19522007
panic!();
19532008
}
2009+
2010+
#[derive(Clone, Eq, PartialEq)]
2011+
struct TransItem {
2012+
name: String,
2013+
codegen_units: HashSet<String>,
2014+
string: String,
2015+
}
2016+
2017+
// [TRANS_ITEM] name [@@ (cgu)+]
2018+
fn str_to_trans_item(s: &str) -> TransItem {
2019+
let s = if s.starts_with(PREFIX) {
2020+
(&s[PREFIX.len()..]).trim()
2021+
} else {
2022+
s.trim()
2023+
};
2024+
2025+
let full_string = format!("{}{}", PREFIX, s.trim().to_owned());
2026+
2027+
let parts: Vec<&str> = s.split(CGU_MARKER)
2028+
.map(str::trim)
2029+
.filter(|s| !s.is_empty())
2030+
.collect();
2031+
2032+
let name = parts[0].trim();
2033+
2034+
let cgus = if parts.len() > 1 {
2035+
let cgus_str = parts[1];
2036+
2037+
cgus_str.split(" ")
2038+
.map(str::trim)
2039+
.filter(|s| !s.is_empty())
2040+
.map(str::to_owned)
2041+
.collect()
2042+
}
2043+
else {
2044+
HashSet::new()
2045+
};
2046+
2047+
TransItem {
2048+
name: name.to_owned(),
2049+
codegen_units: cgus,
2050+
string: full_string,
2051+
}
2052+
}
2053+
2054+
fn codegen_units_to_str(cgus: &HashSet<String>) -> String
2055+
{
2056+
let mut cgus: Vec<_> = cgus.iter().collect();
2057+
cgus.sort();
2058+
2059+
let mut string = String::new();
2060+
for cgu in cgus {
2061+
string.push_str(&cgu[..]);
2062+
string.push_str(" ");
2063+
}
2064+
2065+
string
2066+
}
19542067
}
19552068

19562069
fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {

src/librustc/hir/map/collector.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
136136
ItemDefaultImpl(..) | ItemImpl(..) =>
137137
DefPathData::Impl,
138138
ItemEnum(..) | ItemStruct(..) | ItemTrait(..) |
139-
ItemExternCrate(..) | ItemMod(..) | ItemForeignMod(..) |
140-
ItemTy(..) =>
139+
ItemExternCrate(..) | ItemForeignMod(..) | ItemTy(..) =>
141140
DefPathData::TypeNs(i.name),
141+
ItemMod(..) =>
142+
DefPathData::Module(i.name),
142143
ItemStatic(..) | ItemConst(..) | ItemFn(..) =>
143144
DefPathData::ValueNs(i.name),
144145
ItemUse(..) =>

src/librustc/hir/map/definitions.rs

+2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ pub enum DefPathData {
147147
Impl,
148148
TypeNs(ast::Name), // something in the type NS
149149
ValueNs(ast::Name), // something in the value NS
150+
Module(ast::Name),
150151
MacroDef(ast::Name),
151152
ClosureExpr,
152153

@@ -288,6 +289,7 @@ impl DefPathData {
288289
match *self {
289290
TypeNs(name) |
290291
ValueNs(name) |
292+
Module(name) |
291293
MacroDef(name) |
292294
TypeParam(name) |
293295
LifetimeDef(name) |

src/librustc/ty/item_path.rs

+43-33
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ impl<'tcx> TyCtxt<'tcx> {
147147
data @ DefPathData::Misc |
148148
data @ DefPathData::TypeNs(..) |
149149
data @ DefPathData::ValueNs(..) |
150+
data @ DefPathData::Module(..) |
150151
data @ DefPathData::TypeParam(..) |
151152
data @ DefPathData::LifetimeDef(..) |
152153
data @ DefPathData::EnumVariant(..) |
@@ -189,7 +190,7 @@ impl<'tcx> TyCtxt<'tcx> {
189190
// the impl is either in the same module as the self-type or
190191
// as the trait.
191192
let self_ty = self.lookup_item_type(impl_def_id).ty;
192-
let in_self_mod = match self.characteristic_def_id_of_type(self_ty) {
193+
let in_self_mod = match characteristic_def_id_of_type(self_ty) {
193194
None => false,
194195
Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
195196
};
@@ -268,38 +269,6 @@ impl<'tcx> TyCtxt<'tcx> {
268269
buffer.push(&format!("<impl at {}>", span_str));
269270
}
270271

271-
/// As a heuristic, when we see an impl, if we see that the
272-
/// 'self-type' is a type defined in the same module as the impl,
273-
/// we can omit including the path to the impl itself. This
274-
/// function tries to find a "characteristic def-id" for a
275-
/// type. It's just a heuristic so it makes some questionable
276-
/// decisions and we may want to adjust it later.
277-
fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option<DefId> {
278-
match ty.sty {
279-
ty::TyStruct(adt_def, _) |
280-
ty::TyEnum(adt_def, _) =>
281-
Some(adt_def.did),
282-
283-
ty::TyTrait(ref data) =>
284-
Some(data.principal_def_id()),
285-
286-
ty::TyBox(subty) =>
287-
self.characteristic_def_id_of_type(subty),
288-
289-
ty::TyRawPtr(mt) |
290-
ty::TyRef(_, mt) =>
291-
self.characteristic_def_id_of_type(mt.ty),
292-
293-
ty::TyTuple(ref tys) =>
294-
tys.iter()
295-
.filter_map(|ty| self.characteristic_def_id_of_type(ty))
296-
.next(),
297-
298-
_ =>
299-
None
300-
}
301-
}
302-
303272
/// Returns the def-id of `def_id`'s parent in the def tree. If
304273
/// this returns `None`, then `def_id` represents a crate root or
305274
/// inlined root.
@@ -309,6 +278,47 @@ impl<'tcx> TyCtxt<'tcx> {
309278
}
310279
}
311280

281+
/// As a heuristic, when we see an impl, if we see that the
282+
/// 'self-type' is a type defined in the same module as the impl,
283+
/// we can omit including the path to the impl itself. This
284+
/// function tries to find a "characteristic def-id" for a
285+
/// type. It's just a heuristic so it makes some questionable
286+
/// decisions and we may want to adjust it later.
287+
pub fn characteristic_def_id_of_type<'tcx>(ty: Ty<'tcx>) -> Option<DefId> {
288+
match ty.sty {
289+
ty::TyStruct(adt_def, _) |
290+
ty::TyEnum(adt_def, _) => Some(adt_def.did),
291+
292+
ty::TyTrait(ref data) => Some(data.principal_def_id()),
293+
294+
ty::TyArray(subty, _) |
295+
ty::TySlice(subty) |
296+
ty::TyBox(subty) => characteristic_def_id_of_type(subty),
297+
298+
ty::TyRawPtr(mt) |
299+
ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
300+
301+
ty::TyTuple(ref tys) => tys.iter()
302+
.filter_map(|ty| characteristic_def_id_of_type(ty))
303+
.next(),
304+
305+
ty::TyFnDef(def_id, _, _) |
306+
ty::TyClosure(def_id, _) => Some(def_id),
307+
308+
ty::TyBool |
309+
ty::TyChar |
310+
ty::TyInt(_) |
311+
ty::TyUint(_) |
312+
ty::TyStr |
313+
ty::TyFnPtr(_) |
314+
ty::TyProjection(_) |
315+
ty::TyParam(_) |
316+
ty::TyInfer(_) |
317+
ty::TyError |
318+
ty::TyFloat(_) => None,
319+
}
320+
}
321+
312322
/// Unifying Trait for different kinds of item paths we might
313323
/// construct. The basic interface is that components get pushed: the
314324
/// instance can also customize how we handle the root of a crate.

src/librustc_llvm/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub enum Visibility {
9797
// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
9898
// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
9999
// they've been removed in upstream LLVM commit r203866.
100-
#[derive(Copy, Clone)]
100+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
101101
pub enum Linkage {
102102
ExternalLinkage = 0,
103103
AvailableExternallyLinkage = 1,

src/librustc_metadata/def_key.rs

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub enum DefPathData {
3131
Impl,
3232
TypeNs,
3333
ValueNs,
34+
Module,
3435
MacroDef,
3536
ClosureExpr,
3637
TypeParam,
@@ -61,6 +62,7 @@ fn simplify_def_path_data(data: hir_map::DefPathData) -> DefPathData {
6162
hir_map::DefPathData::Impl => DefPathData::Impl,
6263
hir_map::DefPathData::TypeNs(_) => DefPathData::TypeNs,
6364
hir_map::DefPathData::ValueNs(_) => DefPathData::ValueNs,
65+
hir_map::DefPathData::Module(_) => DefPathData::Module,
6466
hir_map::DefPathData::MacroDef(_) => DefPathData::MacroDef,
6567
hir_map::DefPathData::ClosureExpr => DefPathData::ClosureExpr,
6668
hir_map::DefPathData::TypeParam(_) => DefPathData::TypeParam,
@@ -91,6 +93,7 @@ fn recover_def_path_data(data: DefPathData, name: Option<Name>) -> hir_map::DefP
9193
DefPathData::Impl => hir_map::DefPathData::Impl,
9294
DefPathData::TypeNs => hir_map::DefPathData::TypeNs(name.unwrap()),
9395
DefPathData::ValueNs => hir_map::DefPathData::ValueNs(name.unwrap()),
96+
DefPathData::Module => hir_map::DefPathData::Module(name.unwrap()),
9497
DefPathData::MacroDef => hir_map::DefPathData::MacroDef(name.unwrap()),
9598
DefPathData::ClosureExpr => hir_map::DefPathData::ClosureExpr,
9699
DefPathData::TypeParam => hir_map::DefPathData::TypeParam(name.unwrap()),

0 commit comments

Comments
 (0)