Initial attempt at implementing optimization fuel and re-enabling struct field reordering.
This commit is contained in:
parent
6edc596853
commit
63ebf08be5
10 changed files with 138 additions and 39 deletions
|
@ -643,6 +643,8 @@ macro_rules! options {
|
||||||
Some("one of: `address`, `leak`, `memory` or `thread`");
|
Some("one of: `address`, `leak`, `memory` or `thread`");
|
||||||
pub const parse_linker_flavor: Option<&'static str> =
|
pub const parse_linker_flavor: Option<&'static str> =
|
||||||
Some(::rustc_back::LinkerFlavor::one_of());
|
Some(::rustc_back::LinkerFlavor::one_of());
|
||||||
|
pub const parse_optimization_fuel: Option<&'static str> =
|
||||||
|
Some("crate=integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -787,6 +789,21 @@ macro_rules! options {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
|
||||||
|
match v {
|
||||||
|
None => false,
|
||||||
|
Some(s) => {
|
||||||
|
let parts = s.split('=').collect::<Vec<_>>();
|
||||||
|
if parts.len() != 2 { return false; }
|
||||||
|
let crate_name = parts[0].to_string();
|
||||||
|
let fuel = parts[1].parse::<u64>();
|
||||||
|
if fuel.is_err() { return false; }
|
||||||
|
*slot = Some((crate_name, fuel.unwrap()));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) }
|
) }
|
||||||
|
|
||||||
|
@ -991,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||||
"Use a sanitizer"),
|
"Use a sanitizer"),
|
||||||
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
|
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
|
||||||
"Linker flavor"),
|
"Linker flavor"),
|
||||||
|
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
|
||||||
|
"Set the optimization fuel quota for a crate."),
|
||||||
|
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||||
|
"Make Rustc print the total optimization fuel used by a crate."),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_lib_output() -> CrateType {
|
pub fn default_lib_output() -> CrateType {
|
||||||
|
@ -1784,11 +1805,13 @@ mod dep_tracking {
|
||||||
|
|
||||||
impl_dep_tracking_hash_via_hash!(bool);
|
impl_dep_tracking_hash_via_hash!(bool);
|
||||||
impl_dep_tracking_hash_via_hash!(usize);
|
impl_dep_tracking_hash_via_hash!(usize);
|
||||||
|
impl_dep_tracking_hash_via_hash!(u64);
|
||||||
impl_dep_tracking_hash_via_hash!(String);
|
impl_dep_tracking_hash_via_hash!(String);
|
||||||
impl_dep_tracking_hash_via_hash!(lint::Level);
|
impl_dep_tracking_hash_via_hash!(lint::Level);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<bool>);
|
impl_dep_tracking_hash_via_hash!(Option<bool>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<usize>);
|
impl_dep_tracking_hash_via_hash!(Option<usize>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<String>);
|
impl_dep_tracking_hash_via_hash!(Option<String>);
|
||||||
|
impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
|
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
|
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
|
||||||
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
|
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
|
||||||
|
@ -1810,6 +1833,7 @@ mod dep_tracking {
|
||||||
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
|
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
|
||||||
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
|
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
|
||||||
Option<cstore::NativeLibraryKind>));
|
Option<cstore::NativeLibraryKind>));
|
||||||
|
impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
|
||||||
impl DepTrackingHash for SearchPaths {
|
impl DepTrackingHash for SearchPaths {
|
||||||
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
|
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
|
||||||
let mut elems: Vec<_> = self
|
let mut elems: Vec<_> = self
|
||||||
|
|
|
@ -123,6 +123,20 @@ pub struct Session {
|
||||||
pub code_stats: RefCell<CodeStats>,
|
pub code_stats: RefCell<CodeStats>,
|
||||||
|
|
||||||
next_node_id: Cell<ast::NodeId>,
|
next_node_id: Cell<ast::NodeId>,
|
||||||
|
|
||||||
|
/// If -zfuel=crate=n is specified, Some(crate).
|
||||||
|
optimization_fuel_crate: Option<String>,
|
||||||
|
/// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
|
||||||
|
optimization_fuel_limit: Cell<u64>,
|
||||||
|
/// We're rejecting all further optimizations.
|
||||||
|
out_of_fuel: Cell<bool>,
|
||||||
|
|
||||||
|
// The next two are public because the driver needs to read them.
|
||||||
|
|
||||||
|
/// If -zprint-fuel=crate, Some(crate).
|
||||||
|
pub print_fuel_crate: Option<String>,
|
||||||
|
/// Always set to zero and incremented so that we can print fuel expended by a crate.
|
||||||
|
pub print_fuel: Cell<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PerfStats {
|
pub struct PerfStats {
|
||||||
|
@ -507,6 +521,33 @@ impl Session {
|
||||||
println!("Total time spent decoding DefPath tables: {}",
|
println!("Total time spent decoding DefPath tables: {}",
|
||||||
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
|
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// We want to know if we're allowed to do an optimization for crate crate.
|
||||||
|
/// This expends fuel if applicable, and records fuel if applicable.
|
||||||
|
pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
|
||||||
|
let mut ret = true;
|
||||||
|
match self.optimization_fuel_crate {
|
||||||
|
Some(ref c) if c == crate_name => {
|
||||||
|
let fuel = self.optimization_fuel_limit.get();
|
||||||
|
ret = fuel != 0;
|
||||||
|
if fuel == 0 && !self.out_of_fuel.get(){
|
||||||
|
println!("optimization-fuel-exhausted: {}", msg());
|
||||||
|
self.out_of_fuel.set(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.optimization_fuel_limit.set(fuel-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match self.print_fuel_crate {
|
||||||
|
Some(ref c) if c == crate_name=> {
|
||||||
|
self.print_fuel.set(self.print_fuel.get()+1);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_session(sopts: config::Options,
|
pub fn build_session(sopts: config::Options,
|
||||||
|
@ -602,6 +643,12 @@ pub fn build_session_(sopts: config::Options,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
|
||||||
|
let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
|
||||||
|
.map(|i| i.1).unwrap_or(0));
|
||||||
|
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
|
||||||
|
let print_fuel = Cell::new(0);
|
||||||
|
|
||||||
let sess = Session {
|
let sess = Session {
|
||||||
dep_graph: dep_graph.clone(),
|
dep_graph: dep_graph.clone(),
|
||||||
target: target_cfg,
|
target: target_cfg,
|
||||||
|
@ -643,6 +690,11 @@ pub fn build_session_(sopts: config::Options,
|
||||||
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
|
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
|
||||||
},
|
},
|
||||||
code_stats: RefCell::new(CodeStats::new()),
|
code_stats: RefCell::new(CodeStats::new()),
|
||||||
|
optimization_fuel_crate: optimization_fuel_crate,
|
||||||
|
optimization_fuel_limit: optimization_fuel_limit,
|
||||||
|
print_fuel_crate: print_fuel_crate,
|
||||||
|
print_fuel: print_fuel,
|
||||||
|
out_of_fuel: Cell::new(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
init_llvm(&sess);
|
init_llvm(&sess);
|
||||||
|
|
|
@ -732,6 +732,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||||
}, f)
|
}, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
|
||||||
|
let cname = self.crate_name(LOCAL_CRATE).as_str();
|
||||||
|
self.sess.consider_optimizing(&cname, msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
|
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
|
||||||
|
|
|
@ -580,7 +580,6 @@ enum StructKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Struct {
|
impl<'a, 'gcx, 'tcx> Struct {
|
||||||
// FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
|
|
||||||
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
|
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
|
||||||
repr: &ReprOptions, kind: StructKind,
|
repr: &ReprOptions, kind: StructKind,
|
||||||
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
|
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
|
||||||
|
@ -598,12 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct {
|
||||||
// Neither do 1-member and 2-member structs.
|
// Neither do 1-member and 2-member structs.
|
||||||
// In addition, code in trans assume that 2-element structs can become pairs.
|
// In addition, code in trans assume that 2-element structs can become pairs.
|
||||||
// It's easier to just short-circuit here.
|
// It's easier to just short-circuit here.
|
||||||
let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
|
let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
|
||||||
&& ! (repr.c || repr.packed);
|
&& ! (repr.c || repr.packed || repr.linear || repr.simd);
|
||||||
|
|
||||||
// Disable field reordering until we can decide what to do.
|
|
||||||
// The odd pattern here avoids a warning about the value never being read.
|
|
||||||
if can_optimize { can_optimize = false; }
|
|
||||||
|
|
||||||
let (optimize, sort_ascending) = match kind {
|
let (optimize, sort_ascending) = match kind {
|
||||||
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
|
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
|
||||||
|
|
|
@ -1411,6 +1411,8 @@ pub struct ReprOptions {
|
||||||
pub packed: bool,
|
pub packed: bool,
|
||||||
pub simd: bool,
|
pub simd: bool,
|
||||||
pub int: Option<attr::IntType>,
|
pub int: Option<attr::IntType>,
|
||||||
|
// Internal only for now. If true, don't reorder fields.
|
||||||
|
pub linear: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_stable_hash_for!(struct ReprOptions {
|
impl_stable_hash_for!(struct ReprOptions {
|
||||||
|
@ -1440,6 +1442,9 @@ impl ReprOptions {
|
||||||
ret.simd = true;
|
ret.simd = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is here instead of layout because the choice must make it into metadata.
|
||||||
|
ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}",
|
||||||
|
tcx.item_path_str(did)));
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -517,6 +517,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
||||||
control.make_glob_map = resolve::MakeGlobMap::Yes;
|
control.make_glob_map = resolve::MakeGlobMap::Yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sess.print_fuel_crate.is_some() {
|
||||||
|
control.compilation_done.callback = box |state| {
|
||||||
|
let sess = state.session;
|
||||||
|
println!("Fuel used by {}: {}",
|
||||||
|
sess.print_fuel_crate.as_ref().unwrap(),
|
||||||
|
sess.print_fuel.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
control
|
control
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,17 @@ enum e3 {
|
||||||
a([u16; 0], u8), b
|
a([u16; 0], u8), b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ReorderedStruct {
|
||||||
|
a: u8,
|
||||||
|
b: u64,
|
||||||
|
c: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReorderedEnum {
|
||||||
|
A(u8, u64, u8),
|
||||||
|
B(u8, u64, u8),
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
assert_eq!(size_of::<u8>(), 1 as usize);
|
assert_eq!(size_of::<u8>(), 1 as usize);
|
||||||
assert_eq!(size_of::<u32>(), 4 as usize);
|
assert_eq!(size_of::<u32>(), 4 as usize);
|
||||||
|
@ -54,4 +65,6 @@ pub fn main() {
|
||||||
assert_eq!(size_of::<e1>(), 8 as usize);
|
assert_eq!(size_of::<e1>(), 8 as usize);
|
||||||
assert_eq!(size_of::<e2>(), 8 as usize);
|
assert_eq!(size_of::<e2>(), 8 as usize);
|
||||||
assert_eq!(size_of::<e3>(), 4 as usize);
|
assert_eq!(size_of::<e3>(), 4 as usize);
|
||||||
|
assert_eq!(size_of::<ReorderedStruct>(), 16);
|
||||||
|
assert_eq!(size_of::<ReorderedEnum>(), 16);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
|
print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
|
||||||
print-type-size field `.pre`: 1 bytes
|
print-type-size field `.nested`: 8 bytes
|
||||||
print-type-size padding: 3 bytes
|
|
||||||
print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
|
|
||||||
print-type-size field `.post`: 2 bytes
|
print-type-size field `.post`: 2 bytes
|
||||||
print-type-size end padding: 2 bytes
|
print-type-size field `.pre`: 1 bytes
|
||||||
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
|
print-type-size end padding: 1 bytes
|
||||||
print-type-size variant `Some`: 20 bytes
|
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
|
||||||
print-type-size field `.0`: 20 bytes
|
print-type-size variant `Some`: 12 bytes
|
||||||
print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
|
print-type-size field `.0`: 12 bytes
|
||||||
print-type-size variant `Record`: 10 bytes
|
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
|
||||||
print-type-size field `.pre`: 1 bytes
|
print-type-size variant `Record`: 7 bytes
|
||||||
print-type-size padding: 3 bytes
|
print-type-size field `.val`: 4 bytes
|
||||||
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
|
|
||||||
print-type-size field `.post`: 2 bytes
|
print-type-size field `.post`: 2 bytes
|
||||||
print-type-size end padding: 2 bytes
|
print-type-size field `.pre`: 1 bytes
|
||||||
print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
|
print-type-size end padding: 1 bytes
|
||||||
print-type-size field `.pre`: 1 bytes
|
print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
|
||||||
print-type-size padding: 3 bytes
|
print-type-size field `.val`: 4 bytes
|
||||||
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
|
|
||||||
print-type-size field `.post`: 2 bytes
|
print-type-size field `.post`: 2 bytes
|
||||||
print-type-size end padding: 2 bytes
|
print-type-size field `.pre`: 1 bytes
|
||||||
|
print-type-size end padding: 1 bytes
|
||||||
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
|
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
|
||||||
print-type-size variant `Some`: 4 bytes
|
print-type-size variant `Some`: 4 bytes
|
||||||
print-type-size field `.0`: 4 bytes
|
print-type-size field `.0`: 4 bytes
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
|
print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
|
||||||
|
print-type-size field `.g`: 4 bytes
|
||||||
|
print-type-size field `.h`: 2 bytes
|
||||||
print-type-size field `.a`: 1 bytes
|
print-type-size field `.a`: 1 bytes
|
||||||
print-type-size field `.b`: 1 bytes
|
print-type-size field `.b`: 1 bytes
|
||||||
print-type-size padding: 2 bytes
|
|
||||||
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
|
|
||||||
print-type-size field `.c`: 1 bytes
|
print-type-size field `.c`: 1 bytes
|
||||||
print-type-size padding: 1 bytes
|
|
||||||
print-type-size field `.h`: 2 bytes, alignment: 2 bytes
|
|
||||||
print-type-size field `.d`: 1 bytes
|
print-type-size field `.d`: 1 bytes
|
||||||
print-type-size end padding: 3 bytes
|
print-type-size end padding: 2 bytes
|
||||||
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
|
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
|
||||||
print-type-size field `.a`: 1 bytes
|
print-type-size field `.a`: 1 bytes
|
||||||
print-type-size field `.b`: 1 bytes
|
print-type-size field `.b`: 1 bytes
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
|
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
|
||||||
print-type-size discriminant: 4 bytes
|
print-type-size discriminant: 1 bytes
|
||||||
print-type-size variant `A`: 5 bytes
|
print-type-size variant `A`: 7 bytes
|
||||||
print-type-size field `.0`: 4 bytes
|
|
||||||
print-type-size field `.1`: 1 bytes
|
print-type-size field `.1`: 1 bytes
|
||||||
print-type-size variant `B`: 8 bytes
|
print-type-size padding: 2 bytes
|
||||||
print-type-size field `.0`: 8 bytes
|
print-type-size field `.0`: 4 bytes, alignment: 4 bytes
|
||||||
|
print-type-size variant `B`: 11 bytes
|
||||||
|
print-type-size padding: 3 bytes
|
||||||
|
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
|
||||||
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
|
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
|
||||||
print-type-size discriminant: 1 bytes
|
print-type-size discriminant: 1 bytes
|
||||||
print-type-size variant `A`: 7 bytes
|
print-type-size variant `A`: 7 bytes
|
||||||
|
@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes
|
||||||
print-type-size padding: 3 bytes
|
print-type-size padding: 3 bytes
|
||||||
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
|
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
|
||||||
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
|
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
|
||||||
|
print-type-size field `.g`: 4 bytes
|
||||||
print-type-size field `.a`: 1 bytes
|
print-type-size field `.a`: 1 bytes
|
||||||
print-type-size field `.b`: 1 bytes
|
print-type-size field `.b`: 1 bytes
|
||||||
print-type-size padding: 2 bytes
|
print-type-size end padding: 2 bytes
|
||||||
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue