@@ -183,14 +183,40 @@ pub(crate) fn prepare_thin(
183
183
184
184
fn fat_lto ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
185
185
diag_handler : & Handler ,
186
- mut modules : Vec < FatLTOInput < LlvmCodegenBackend > > ,
186
+ modules : Vec < FatLTOInput < LlvmCodegenBackend > > ,
187
187
cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
188
188
mut serialized_modules : Vec < ( SerializedModule < ModuleBuffer > , CString ) > ,
189
189
symbol_white_list : & [ * const libc:: c_char ] )
190
190
-> Result < LtoModuleCodegen < LlvmCodegenBackend > , FatalError >
191
191
{
192
192
info ! ( "going for a fat lto" ) ;
193
193
194
+ // Sort out all our lists of incoming modules into two lists.
195
+ //
196
+ // * `serialized_modules` (also and argument to this function) contains all
197
+ // modules that are serialized in-memory.
198
+ // * `in_memory` contains modules which are already parsed and in-memory,
199
+ // such as from multi-CGU builds.
200
+ //
201
+ // All of `cached_modules` (cached from previous incremental builds) can
202
+ // immediately go onto the `serialized_modules` modules list and then we can
203
+ // split the `modules` array into these two lists.
204
+ let mut in_memory = Vec :: new ( ) ;
205
+ serialized_modules. extend ( cached_modules. into_iter ( ) . map ( |( buffer, wp) | {
206
+ info ! ( "pushing cached module {:?}" , wp. cgu_name) ;
207
+ ( buffer, CString :: new ( wp. cgu_name ) . unwrap ( ) )
208
+ } ) ) ;
209
+ for module in modules {
210
+ match module {
211
+ FatLTOInput :: InMemory ( m) => in_memory. push ( m) ,
212
+ FatLTOInput :: Serialized { name, buffer } => {
213
+ info ! ( "pushing serialized module {:?}" , name) ;
214
+ let buffer = SerializedModule :: Local ( buffer) ;
215
+ serialized_modules. push ( ( buffer, CString :: new ( name) . unwrap ( ) ) ) ;
216
+ }
217
+ }
218
+ }
219
+
194
220
// Find the "costliest" module and merge everything into that codegen unit.
195
221
// All the other modules will be serialized and reparsed into the new
196
222
// context, so this hopefully avoids serializing and parsing the largest
@@ -200,14 +226,8 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
200
226
// file copy operations in the backend work correctly. The only other kind
201
227
// of module here should be an allocator one, and if your crate is smaller
202
228
// than the allocator module then the size doesn't really matter anyway.
203
- let costliest_module = modules . iter ( )
229
+ let costliest_module = in_memory . iter ( )
204
230
. enumerate ( )
205
- . filter_map ( |( i, module) | {
206
- match module {
207
- FatLTOInput :: InMemory ( m) => Some ( ( i, m) ) ,
208
- FatLTOInput :: Serialized { .. } => None ,
209
- }
210
- } )
211
231
. filter ( |& ( _, module) | module. kind == ModuleKind :: Regular )
212
232
. map ( |( i, module) | {
213
233
let cost = unsafe {
@@ -223,26 +243,14 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
223
243
// re-executing the LTO passes. If that's the case deserialize the first
224
244
// module and create a linker with it.
225
245
let module: ModuleCodegen < ModuleLlvm > = match costliest_module {
226
- Some ( ( _cost, i) ) => {
227
- match modules. remove ( i) {
228
- FatLTOInput :: InMemory ( m) => m,
229
- FatLTOInput :: Serialized { .. } => unreachable ! ( ) ,
230
- }
231
- }
246
+ Some ( ( _cost, i) ) => in_memory. remove ( i) ,
232
247
None => {
233
- let pos = modules. iter ( ) . position ( |m| {
234
- match m {
235
- FatLTOInput :: InMemory ( _) => false ,
236
- FatLTOInput :: Serialized { .. } => true ,
237
- }
238
- } ) . expect ( "must have at least one serialized module" ) ;
239
- let ( name, buffer) = match modules. remove ( pos) {
240
- FatLTOInput :: Serialized { name, buffer } => ( name, buffer) ,
241
- FatLTOInput :: InMemory ( _) => unreachable ! ( ) ,
242
- } ;
248
+ assert ! ( serialized_modules. len( ) > 0 , "must have at least one serialized module" ) ;
249
+ let ( buffer, name) = serialized_modules. remove ( 0 ) ;
250
+ info ! ( "no in-memory regular modules to choose from, parsing {:?}" , name) ;
243
251
ModuleCodegen {
244
- module_llvm : ModuleLlvm :: parse ( cgcx, & name, & buffer, diag_handler) ?,
245
- name,
252
+ module_llvm : ModuleLlvm :: parse ( cgcx, & name, buffer. data ( ) , diag_handler) ?,
253
+ name : name . into_string ( ) . unwrap ( ) ,
246
254
kind : ModuleKind :: Regular ,
247
255
}
248
256
}
@@ -265,25 +273,13 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
265
273
// and we want to move everything to the same LLVM context. Currently the
266
274
// way we know of to do that is to serialize them to a string and them parse
267
275
// them later. Not great but hey, that's why it's "fat" LTO, right?
268
- let mut new_modules = modules. into_iter ( ) . map ( |module| {
269
- match module {
270
- FatLTOInput :: InMemory ( module) => {
271
- let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
272
- let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
273
- ( SerializedModule :: Local ( buffer) , llmod_id)
274
- }
275
- FatLTOInput :: Serialized { name, buffer } => {
276
- let llmod_id = CString :: new ( name) . unwrap ( ) ;
277
- ( SerializedModule :: Local ( buffer) , llmod_id)
278
- }
279
- }
280
- } ) . collect :: < Vec < _ > > ( ) ;
276
+ for module in in_memory {
277
+ let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
278
+ let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
279
+ serialized_modules. push ( ( SerializedModule :: Local ( buffer) , llmod_id) ) ;
280
+ }
281
281
// Sort the modules to ensure we produce deterministic results.
282
- new_modules. sort_by ( |module1, module2| module1. 1 . partial_cmp ( & module2. 1 ) . unwrap ( ) ) ;
283
- serialized_modules. extend ( new_modules) ;
284
- serialized_modules. extend ( cached_modules. into_iter ( ) . map ( |( buffer, wp) | {
285
- ( buffer, CString :: new ( wp. cgu_name ) . unwrap ( ) )
286
- } ) ) ;
282
+ serialized_modules. sort_by ( |module1, module2| module1. 1 . cmp ( & module2. 1 ) ) ;
287
283
288
284
// For all serialized bitcode files we parse them and link them in as we did
289
285
// above, this is all mostly handled in C++. Like above, though, we don't
@@ -850,7 +846,7 @@ fn module_name_to_str(c_str: &CStr) -> &str {
850
846
bug ! ( "Encountered non-utf8 LLVM module name `{}`: {}" , c_str. to_string_lossy( ) , e) )
851
847
}
852
848
853
- fn parse_module < ' a > (
849
+ pub fn parse_module < ' a > (
854
850
cx : & ' a llvm:: Context ,
855
851
name : & CStr ,
856
852
data : & [ u8 ] ,
0 commit comments