Initial attempt at implementing optimization fuel and re-enabling struct field reordering.

This commit is contained in:
Austin Hicks 2017-03-08 16:28:47 -05:00 committed by Simonas Kazlauskas
parent 6edc596853
commit 63ebf08be5
10 changed files with 138 additions and 39 deletions

View File

@ -643,6 +643,8 @@ macro_rules! options {
Some("one of: `address`, `leak`, `memory` or `thread`");
pub const parse_linker_flavor: Option<&'static str> =
Some(::rustc_back::LinkerFlavor::one_of());
pub const parse_optimization_fuel: Option<&'static str> =
Some("crate=integer");
}
#[allow(dead_code)]
@ -787,6 +789,21 @@ macro_rules! options {
}
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"),
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
"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 {
@ -1784,11 +1805,13 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(bool);
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!(lint::Level);
impl_dep_tracking_hash_via_hash!(Option<bool>);
impl_dep_tracking_hash_via_hash!(Option<usize>);
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<lint::Level>);
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, Option<String>,
Option<cstore::NativeLibraryKind>));
impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
impl DepTrackingHash for SearchPaths {
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
let mut elems: Vec<_> = self

View File

@ -123,6 +123,20 @@ pub struct Session {
pub code_stats: RefCell<CodeStats>,
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 {
@ -507,6 +521,33 @@ impl Session {
println!("Total time spent decoding DefPath tables: {}",
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,
@ -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 {
dep_graph: dep_graph.clone(),
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)),
},
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);

View File

@ -732,6 +732,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
}, 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> {

View File

@ -580,7 +580,6 @@ enum StructKind {
}
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>,
repr: &ReprOptions, kind: StructKind,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
@ -598,12 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct {
// Neither do 1-member and 2-member structs.
// In addition, code in trans assume that 2-element structs can become pairs.
// It's easier to just short-circuit here.
let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
&& ! (repr.c || repr.packed);
// 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 can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
&& ! (repr.c || repr.packed || repr.linear || repr.simd);
let (optimize, sort_ascending) = match kind {
StructKind::AlwaysSizedUnivariant => (can_optimize, false),

View File

@ -1411,6 +1411,8 @@ pub struct ReprOptions {
pub packed: bool,
pub simd: bool,
pub int: Option<attr::IntType>,
// Internal only for now. If true, don't reorder fields.
pub linear: bool,
}
impl_stable_hash_for!(struct ReprOptions {
@ -1440,6 +1442,9 @@ impl ReprOptions {
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
}

View File

@ -517,6 +517,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
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
}
}

View File

@ -31,6 +31,17 @@ enum e3 {
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() {
assert_eq!(size_of::<u8>(), 1 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::<e2>(), 8 as usize);
assert_eq!(size_of::<e3>(), 4 as usize);
assert_eq!(size_of::<ReorderedStruct>(), 16);
assert_eq!(size_of::<ReorderedEnum>(), 16);
}

View File

@ -1,25 +1,22 @@
print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
print-type-size padding: 3 bytes
print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
print-type-size field `.nested`: 8 bytes
print-type-size field `.post`: 2 bytes
print-type-size end padding: 2 bytes
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
print-type-size variant `Some`: 20 bytes
print-type-size field `.0`: 20 bytes
print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
print-type-size variant `Record`: 10 bytes
print-type-size field `.pre`: 1 bytes
print-type-size padding: 3 bytes
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
print-type-size end padding: 1 bytes
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
print-type-size variant `Some`: 12 bytes
print-type-size field `.0`: 12 bytes
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
print-type-size variant `Record`: 7 bytes
print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
print-type-size end padding: 2 bytes
print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
print-type-size padding: 3 bytes
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
print-type-size end padding: 1 bytes
print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
print-type-size field `.val`: 4 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 variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes

View File

@ -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 `.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 padding: 1 bytes
print-type-size field `.h`: 2 bytes, alignment: 2 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 field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes

View File

@ -1,10 +1,12 @@
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `A`: 5 bytes
print-type-size field `.0`: 4 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `A`: 7 bytes
print-type-size field `.1`: 1 bytes
print-type-size variant `B`: 8 bytes
print-type-size field `.0`: 8 bytes
print-type-size padding: 2 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 discriminant: 1 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 field `.0`: 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 `.b`: 1 bytes
print-type-size padding: 2 bytes
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
print-type-size end padding: 2 bytes