1+ use std:: cmp;
12use std:: collections:: hash_map:: Entry ;
23
34use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
@@ -14,10 +15,7 @@ use rustc_span::symbol::Symbol;
1415
1516use super :: PartitioningCx ;
1617use crate :: collector:: InliningMap ;
17- use crate :: partitioning:: merging;
18- use crate :: partitioning:: {
19- MonoItemPlacement , Partition , PostInliningPartitioning , PreInliningPartitioning ,
20- } ;
18+ use crate :: partitioning:: { MonoItemPlacement , Partition , PlacedRootMonoItems } ;
2119
2220pub struct DefaultPartitioning ;
2321
@@ -26,7 +24,7 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
2624 & mut self ,
2725 cx : & PartitioningCx < ' _ , ' tcx > ,
2826 mono_items : & mut I ,
29- ) -> PreInliningPartitioning < ' tcx >
27+ ) -> PlacedRootMonoItems < ' tcx >
3028 where
3129 I : Iterator < Item = MonoItem < ' tcx > > ,
3230 {
@@ -91,38 +89,120 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
9189 codegen_units. insert ( codegen_unit_name, CodegenUnit :: new ( codegen_unit_name) ) ;
9290 }
9391
94- PreInliningPartitioning {
95- codegen_units : codegen_units. into_values ( ) . collect ( ) ,
96- roots,
97- internalization_candidates,
98- }
92+ let codegen_units = codegen_units. into_values ( ) . collect ( ) ;
93+ PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
9994 }
10095
10196 fn merge_codegen_units (
10297 & mut self ,
10398 cx : & PartitioningCx < ' _ , ' tcx > ,
104- initial_partitioning : & mut PreInliningPartitioning < ' tcx > ,
99+ codegen_units : & mut Vec < CodegenUnit < ' tcx > > ,
105100 ) {
106- merging:: merge_codegen_units ( cx, initial_partitioning) ;
101+ assert ! ( cx. target_cgu_count >= 1 ) ;
102+
103+ // Note that at this point in time the `codegen_units` here may not be
104+ // in a deterministic order (but we know they're deterministically the
105+ // same set). We want this merging to produce a deterministic ordering
106+ // of codegen units from the input.
107+ //
108+ // Due to basically how we've implemented the merging below (merge the
109+ // two smallest into each other) we're sure to start off with a
110+ // deterministic order (sorted by name). This'll mean that if two cgus
111+ // have the same size the stable sort below will keep everything nice
112+ // and deterministic.
113+ codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
114+
115+ // This map keeps track of what got merged into what.
116+ let mut cgu_contents: FxHashMap < Symbol , Vec < Symbol > > =
117+ codegen_units. iter ( ) . map ( |cgu| ( cgu. name ( ) , vec ! [ cgu. name( ) ] ) ) . collect ( ) ;
118+
119+ // Merge the two smallest codegen units until the target size is
120+ // reached.
121+ while codegen_units. len ( ) > cx. target_cgu_count {
122+ // Sort small cgus to the back
123+ codegen_units. sort_by_cached_key ( |cgu| cmp:: Reverse ( cgu. size_estimate ( ) ) ) ;
124+ let mut smallest = codegen_units. pop ( ) . unwrap ( ) ;
125+ let second_smallest = codegen_units. last_mut ( ) . unwrap ( ) ;
126+
127+ // Move the mono-items from `smallest` to `second_smallest`
128+ second_smallest. modify_size_estimate ( smallest. size_estimate ( ) ) ;
129+ for ( k, v) in smallest. items_mut ( ) . drain ( ) {
130+ second_smallest. items_mut ( ) . insert ( k, v) ;
131+ }
132+
133+ // Record that `second_smallest` now contains all the stuff that was
134+ // in `smallest` before.
135+ let mut consumed_cgu_names = cgu_contents. remove ( & smallest. name ( ) ) . unwrap ( ) ;
136+ cgu_contents. get_mut ( & second_smallest. name ( ) ) . unwrap ( ) . append ( & mut consumed_cgu_names) ;
137+
138+ debug ! (
139+ "CodegenUnit {} merged into CodegenUnit {}" ,
140+ smallest. name( ) ,
141+ second_smallest. name( )
142+ ) ;
143+ }
144+
145+ let cgu_name_builder = & mut CodegenUnitNameBuilder :: new ( cx. tcx ) ;
146+
147+ if cx. tcx . sess . opts . incremental . is_some ( ) {
148+ // If we are doing incremental compilation, we want CGU names to
149+ // reflect the path of the source level module they correspond to.
150+ // For CGUs that contain the code of multiple modules because of the
151+ // merging done above, we use a concatenation of the names of all
152+ // contained CGUs.
153+ let new_cgu_names: FxHashMap < Symbol , String > = cgu_contents
154+ . into_iter ( )
155+ // This `filter` makes sure we only update the name of CGUs that
156+ // were actually modified by merging.
157+ . filter ( |( _, cgu_contents) | cgu_contents. len ( ) > 1 )
158+ . map ( |( current_cgu_name, cgu_contents) | {
159+ let mut cgu_contents: Vec < & str > =
160+ cgu_contents. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
161+
162+ // Sort the names, so things are deterministic and easy to
163+ // predict. We are sorting primitive `&str`s here so we can
164+ // use unstable sort.
165+ cgu_contents. sort_unstable ( ) ;
166+
167+ ( current_cgu_name, cgu_contents. join ( "--" ) )
168+ } )
169+ . collect ( ) ;
170+
171+ for cgu in codegen_units. iter_mut ( ) {
172+ if let Some ( new_cgu_name) = new_cgu_names. get ( & cgu. name ( ) ) {
173+ if cx. tcx . sess . opts . unstable_opts . human_readable_cgu_names {
174+ cgu. set_name ( Symbol :: intern ( & new_cgu_name) ) ;
175+ } else {
176+ // If we don't require CGU names to be human-readable,
177+ // we use a fixed length hash of the composite CGU name
178+ // instead.
179+ let new_cgu_name = CodegenUnit :: mangle_name ( & new_cgu_name) ;
180+ cgu. set_name ( Symbol :: intern ( & new_cgu_name) ) ;
181+ }
182+ }
183+ }
184+ } else {
185+ // If we are compiling non-incrementally we just generate simple CGU
186+ // names containing an index.
187+ for ( index, cgu) in codegen_units. iter_mut ( ) . enumerate ( ) {
188+ let numbered_codegen_unit_name =
189+ cgu_name_builder. build_cgu_name_no_mangle ( LOCAL_CRATE , & [ "cgu" ] , Some ( index) ) ;
190+ cgu. set_name ( numbered_codegen_unit_name) ;
191+ }
192+ }
107193 }
108194
109195 fn place_inlined_mono_items (
110196 & mut self ,
111197 cx : & PartitioningCx < ' _ , ' tcx > ,
112- initial_partitioning : PreInliningPartitioning < ' tcx > ,
113- ) -> PostInliningPartitioning < ' tcx > {
114- let mut new_partitioning = Vec :: new ( ) ;
198+ codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
199+ roots : FxHashSet < MonoItem < ' tcx > > ,
200+ ) -> FxHashMap < MonoItem < ' tcx > , MonoItemPlacement > {
115201 let mut mono_item_placements = FxHashMap :: default ( ) ;
116202
117- let PreInliningPartitioning {
118- codegen_units : initial_cgus,
119- roots,
120- internalization_candidates,
121- } = initial_partitioning;
122-
123- let single_codegen_unit = initial_cgus. len ( ) == 1 ;
203+ let single_codegen_unit = codegen_units. len ( ) == 1 ;
124204
125- for old_codegen_unit in initial_cgus {
205+ for old_codegen_unit in codegen_units . iter_mut ( ) {
126206 // Collect all items that need to be available in this codegen unit.
127207 let mut reachable = FxHashSet :: default ( ) ;
128208 for root in old_codegen_unit. items ( ) . keys ( ) {
@@ -174,14 +254,10 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
174254 }
175255 }
176256
177- new_partitioning . push ( new_codegen_unit) ;
257+ * old_codegen_unit = new_codegen_unit;
178258 }
179259
180- return PostInliningPartitioning {
181- codegen_units : new_partitioning,
182- mono_item_placements,
183- internalization_candidates,
184- } ;
260+ return mono_item_placements;
185261
186262 fn follow_inlining < ' tcx > (
187263 mono_item : MonoItem < ' tcx > ,
@@ -201,14 +277,16 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
201277 fn internalize_symbols (
202278 & mut self ,
203279 cx : & PartitioningCx < ' _ , ' tcx > ,
204- partitioning : & mut PostInliningPartitioning < ' tcx > ,
280+ codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
281+ mono_item_placements : FxHashMap < MonoItem < ' tcx > , MonoItemPlacement > ,
282+ internalization_candidates : FxHashSet < MonoItem < ' tcx > > ,
205283 ) {
206- if partitioning . codegen_units . len ( ) == 1 {
284+ if codegen_units. len ( ) == 1 {
207285 // Fast path for when there is only one codegen unit. In this case we
208286 // can internalize all candidates, since there is nowhere else they
209287 // could be accessed from.
210- for cgu in & mut partitioning . codegen_units {
211- for candidate in & partitioning . internalization_candidates {
288+ for cgu in codegen_units {
289+ for candidate in & internalization_candidates {
212290 cgu. items_mut ( ) . insert ( * candidate, ( Linkage :: Internal , Visibility :: Default ) ) ;
213291 }
214292 }
@@ -225,15 +303,13 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
225303 }
226304 } ) ;
227305
228- let mono_item_placements = & partitioning. mono_item_placements ;
229-
230306 // For each internalization candidates in each codegen unit, check if it is
231307 // accessed from outside its defining codegen unit.
232- for cgu in & mut partitioning . codegen_units {
308+ for cgu in codegen_units {
233309 let home_cgu = MonoItemPlacement :: SingleCgu { cgu_name : cgu. name ( ) } ;
234310
235311 for ( accessee, linkage_and_visibility) in cgu. items_mut ( ) {
236- if !partitioning . internalization_candidates . contains ( accessee) {
312+ if !internalization_candidates. contains ( accessee) {
237313 // This item is no candidate for internalizing, so skip it.
238314 continue ;
239315 }
0 commit comments