Initial attempt at implementing optimization fuel and re-enabling struct field reordering.
This commit is contained in:
parent
6edc596853
commit
63ebf08be5
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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> {
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user