Skip to content

Commit 197e529

Browse files
ahicks92alexcrichton
authored andcommitted
Initial attempt at implementing optimization fuel and re-enabling struct field reordering.
1 parent a5483a7 commit 197e529

File tree

10 files changed

+138
-39
lines changed

10 files changed

+138
-39
lines changed

src/librustc/session/config.rs

+24
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ macro_rules! options {
636636
Some("either `panic` or `abort`");
637637
pub const parse_sanitizer: Option<&'static str> =
638638
Some("one of: `address`, `leak`, `memory` or `thread`");
639+
pub const parse_optimization_fuel: Option<&'static str> =
640+
Some("crate=integer");
639641
}
640642

641643
#[allow(dead_code)]
@@ -772,6 +774,21 @@ macro_rules! options {
772774
}
773775
true
774776
}
777+
778+
fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
779+
match v {
780+
None => false,
781+
Some(s) => {
782+
let parts = s.split('=').collect::<Vec<_>>();
783+
if parts.len() != 2 { return false; }
784+
let crate_name = parts[0].to_string();
785+
let fuel = parts[1].parse::<u64>();
786+
if fuel.is_err() { return false; }
787+
*slot = Some((crate_name, fuel.unwrap()));
788+
true
789+
}
790+
}
791+
}
775792
}
776793
) }
777794

@@ -974,6 +991,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
974991
"pass `-install_name @rpath/...` to the OSX linker"),
975992
sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
976993
"Use a sanitizer"),
994+
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
995+
"Set the optimization fuel quota for a crate."),
996+
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
997+
"Make Rustc print the total optimization fuel used by a crate."),
977998
}
978999

9791000
pub fn default_lib_output() -> CrateType {
@@ -1766,11 +1787,13 @@ mod dep_tracking {
17661787

17671788
impl_dep_tracking_hash_via_hash!(bool);
17681789
impl_dep_tracking_hash_via_hash!(usize);
1790+
impl_dep_tracking_hash_via_hash!(u64);
17691791
impl_dep_tracking_hash_via_hash!(String);
17701792
impl_dep_tracking_hash_via_hash!(lint::Level);
17711793
impl_dep_tracking_hash_via_hash!(Option<bool>);
17721794
impl_dep_tracking_hash_via_hash!(Option<usize>);
17731795
impl_dep_tracking_hash_via_hash!(Option<String>);
1796+
impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
17741797
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
17751798
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
17761799
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
@@ -1792,6 +1815,7 @@ mod dep_tracking {
17921815
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
17931816
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
17941817
Option<cstore::NativeLibraryKind>));
1818+
impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
17951819
impl DepTrackingHash for SearchPaths {
17961820
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
17971821
let mut elems: Vec<_> = self

src/librustc/session/mod.rs

+52
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,20 @@ pub struct Session {
123123
pub code_stats: RefCell<CodeStats>,
124124

125125
next_node_id: Cell<ast::NodeId>,
126+
127+
/// If -zfuel=crate=n is specified, Some(crate).
128+
optimization_fuel_crate: Option<String>,
129+
/// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
130+
optimization_fuel_limit: Cell<u64>,
131+
/// We're rejecting all further optimizations.
132+
out_of_fuel: Cell<bool>,
133+
134+
// The next two are public because the driver needs to read them.
135+
136+
/// If -zprint-fuel=crate, Some(crate).
137+
pub print_fuel_crate: Option<String>,
138+
/// Always set to zero and incremented so that we can print fuel expended by a crate.
139+
pub print_fuel: Cell<u64>,
126140
}
127141

128142
pub struct PerfStats {
@@ -504,6 +518,33 @@ impl Session {
504518
println!("Total time spent decoding DefPath tables: {}",
505519
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
506520
}
521+
522+
/// We want to know if we're allowed to do an optimization for crate crate.
523+
/// This expends fuel if applicable, and records fuel if applicable.
524+
pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
525+
let mut ret = true;
526+
match self.optimization_fuel_crate {
527+
Some(ref c) if c == crate_name => {
528+
let fuel = self.optimization_fuel_limit.get();
529+
ret = fuel != 0;
530+
if fuel == 0 && !self.out_of_fuel.get(){
531+
println!("optimization-fuel-exhausted: {}", msg());
532+
self.out_of_fuel.set(true);
533+
}
534+
else {
535+
self.optimization_fuel_limit.set(fuel-1);
536+
}
537+
}
538+
_ => {}
539+
}
540+
match self.print_fuel_crate {
541+
Some(ref c) if c == crate_name=> {
542+
self.print_fuel.set(self.print_fuel.get()+1);
543+
},
544+
_ => {}
545+
}
546+
ret
547+
}
507548
}
508549

509550
pub fn build_session(sopts: config::Options,
@@ -599,6 +640,12 @@ pub fn build_session_(sopts: config::Options,
599640
}
600641
);
601642

643+
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
644+
let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
645+
.map(|i| i.1).unwrap_or(0));
646+
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
647+
let print_fuel = Cell::new(0);
648+
602649
let sess = Session {
603650
dep_graph: dep_graph.clone(),
604651
target: target_cfg,
@@ -640,6 +687,11 @@ pub fn build_session_(sopts: config::Options,
640687
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
641688
},
642689
code_stats: RefCell::new(CodeStats::new()),
690+
optimization_fuel_crate: optimization_fuel_crate,
691+
optimization_fuel_limit: optimization_fuel_limit,
692+
print_fuel_crate: print_fuel_crate,
693+
print_fuel: print_fuel,
694+
out_of_fuel: Cell::new(false),
643695
};
644696

645697
init_llvm(&sess);

src/librustc/ty/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
728728
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
729729
}, f)
730730
}
731+
732+
pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
733+
let cname = self.crate_name(LOCAL_CRATE).as_str();
734+
self.sess.consider_optimizing(&cname, msg)
735+
}
731736
}
732737

733738
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {

src/librustc/ty/layout.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,6 @@ enum StructKind {
555555
}
556556

557557
impl<'a, 'gcx, 'tcx> Struct {
558-
// FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
559558
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
560559
repr: &ReprOptions, kind: StructKind,
561560
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
@@ -573,12 +572,8 @@ impl<'a, 'gcx, 'tcx> Struct {
573572
// Neither do 1-member and 2-member structs.
574573
// In addition, code in trans assume that 2-element structs can become pairs.
575574
// It's easier to just short-circuit here.
576-
let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
577-
&& ! (repr.c || repr.packed);
578-
579-
// Disable field reordering until we can decide what to do.
580-
// The odd pattern here avoids a warning about the value never being read.
581-
if can_optimize { can_optimize = false; }
575+
let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
576+
&& ! (repr.c || repr.packed || repr.linear || repr.simd);
582577

583578
let (optimize, sort_ascending) = match kind {
584579
StructKind::AlwaysSizedUnivariant => (can_optimize, false),

src/librustc/ty/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,8 @@ pub struct ReprOptions {
13761376
pub packed: bool,
13771377
pub simd: bool,
13781378
pub int: Option<attr::IntType>,
1379+
// Internal only for now. If true, don't reorder fields.
1380+
pub linear: bool,
13791381
}
13801382

13811383
impl ReprOptions {
@@ -1398,6 +1400,9 @@ impl ReprOptions {
13981400
ret.simd = true;
13991401
}
14001402

1403+
// This is here instead of layout because the choice must make it into metadata.
1404+
ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}",
1405+
tcx.item_path_str(did)));
14011406
ret
14021407
}
14031408

src/librustc_driver/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
514514
control.make_glob_map = resolve::MakeGlobMap::Yes;
515515
}
516516

517+
if sess.print_fuel_crate.is_some() {
518+
control.compilation_done.callback = box |state| {
519+
let sess = state.session;
520+
println!("Fuel used by {}: {}",
521+
sess.print_fuel_crate.as_ref().unwrap(),
522+
sess.print_fuel.get());
523+
}
524+
}
517525
control
518526
}
519527
}

src/test/run-pass/type-sizes.rs

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ enum e3 {
3131
a([u16; 0], u8), b
3232
}
3333

34+
struct ReorderedStruct {
35+
a: u8,
36+
b: u64,
37+
c: u8
38+
}
39+
40+
enum ReorderedEnum {
41+
A(u8, u64, u8),
42+
B(u8, u64, u8),
43+
}
44+
3445
pub fn main() {
3546
assert_eq!(size_of::<u8>(), 1 as usize);
3647
assert_eq!(size_of::<u32>(), 4 as usize);
@@ -54,4 +65,6 @@ pub fn main() {
5465
assert_eq!(size_of::<e1>(), 8 as usize);
5566
assert_eq!(size_of::<e2>(), 8 as usize);
5667
assert_eq!(size_of::<e3>(), 4 as usize);
68+
assert_eq!(size_of::<ReorderedStruct>(), 16);
69+
assert_eq!(size_of::<ReorderedEnum>(), 16);
5770
}

src/test/ui/print_type_sizes/nullable.stdout

+16-19
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
2-
print-type-size field `.pre`: 1 bytes
3-
print-type-size padding: 3 bytes
4-
print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
1+
print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
2+
print-type-size field `.nested`: 8 bytes
53
print-type-size field `.post`: 2 bytes
6-
print-type-size end padding: 2 bytes
7-
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
8-
print-type-size variant `Some`: 20 bytes
9-
print-type-size field `.0`: 20 bytes
10-
print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
11-
print-type-size variant `Record`: 10 bytes
12-
print-type-size field `.pre`: 1 bytes
13-
print-type-size padding: 3 bytes
14-
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
15-
print-type-size field `.post`: 2 bytes
16-
print-type-size end padding: 2 bytes
17-
print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
184
print-type-size field `.pre`: 1 bytes
19-
print-type-size padding: 3 bytes
20-
print-type-size field `.val`: 4 bytes, alignment: 4 bytes
5+
print-type-size end padding: 1 bytes
6+
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
7+
print-type-size variant `Some`: 12 bytes
8+
print-type-size field `.0`: 12 bytes
9+
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
10+
print-type-size variant `Record`: 7 bytes
11+
print-type-size field `.val`: 4 bytes
12+
print-type-size field `.post`: 2 bytes
13+
print-type-size field `.pre`: 1 bytes
14+
print-type-size end padding: 1 bytes
15+
print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
16+
print-type-size field `.val`: 4 bytes
2117
print-type-size field `.post`: 2 bytes
22-
print-type-size end padding: 2 bytes
18+
print-type-size field `.pre`: 1 bytes
19+
print-type-size end padding: 1 bytes
2320
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
2421
print-type-size variant `Some`: 4 bytes
2522
print-type-size field `.0`: 4 bytes

src/test/ui/print_type_sizes/packed.stdout

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
1+
print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
2+
print-type-size field `.g`: 4 bytes
3+
print-type-size field `.h`: 2 bytes
24
print-type-size field `.a`: 1 bytes
35
print-type-size field `.b`: 1 bytes
4-
print-type-size padding: 2 bytes
5-
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
66
print-type-size field `.c`: 1 bytes
7-
print-type-size padding: 1 bytes
8-
print-type-size field `.h`: 2 bytes, alignment: 2 bytes
97
print-type-size field `.d`: 1 bytes
10-
print-type-size end padding: 3 bytes
8+
print-type-size end padding: 2 bytes
119
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
1210
print-type-size field `.a`: 1 bytes
1311
print-type-size field `.b`: 1 bytes
+9-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
2-
print-type-size discriminant: 4 bytes
3-
print-type-size variant `A`: 5 bytes
4-
print-type-size field `.0`: 4 bytes
2+
print-type-size discriminant: 1 bytes
3+
print-type-size variant `A`: 7 bytes
54
print-type-size field `.1`: 1 bytes
6-
print-type-size variant `B`: 8 bytes
7-
print-type-size field `.0`: 8 bytes
5+
print-type-size padding: 2 bytes
6+
print-type-size field `.0`: 4 bytes, alignment: 4 bytes
7+
print-type-size variant `B`: 11 bytes
8+
print-type-size padding: 3 bytes
9+
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
810
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
911
print-type-size discriminant: 1 bytes
1012
print-type-size variant `A`: 7 bytes
@@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes
1517
print-type-size padding: 3 bytes
1618
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
1719
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
20+
print-type-size field `.g`: 4 bytes
1821
print-type-size field `.a`: 1 bytes
1922
print-type-size field `.b`: 1 bytes
20-
print-type-size padding: 2 bytes
21-
print-type-size field `.g`: 4 bytes, alignment: 4 bytes
23+
print-type-size end padding: 2 bytes

0 commit comments

Comments
 (0)