about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm/back
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2018-08-31 15:18:08 +0200
committerMichael Woerister <michaelwoerister@posteo>2018-08-31 15:22:52 +0200
commitabd5cc3364b9ec9500ef8f5e64699e25069bc51b (patch)
treed2cbe1a0ae30864067529fc06697c181fe18e276 /src/librustc_codegen_llvm/back
parent64a738d8ce457b8d9b3a750ca61835214b6b438c (diff)
downloadrust-abd5cc3364b9ec9500ef8f5e64699e25069bc51b.tar.gz
rust-abd5cc3364b9ec9500ef8f5e64699e25069bc51b.zip
Always add all modules to the global ThinLTO module analysis when compiling incrementally.
Diffstat (limited to 'src/librustc_codegen_llvm/back')
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs235
-rw-r--r--src/librustc_codegen_llvm/back/write.rs154
2 files changed, 125 insertions, 264 deletions
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 98131349927..6936a306780 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -11,17 +11,18 @@
 use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
 use back::symbol_export;
 use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use back::write::{self, DiagnosticHandlers};
+use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
 use errors::{FatalError, Handler};
 use llvm::archive_ro::ArchiveRO;
 use llvm::{True, False};
 use llvm;
 use memmap;
+use rustc::dep_graph::WorkProduct;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::session::config::{self, Lto};
 use rustc::util::common::time_ext;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use time_graph::Timeline;
 use {ModuleCodegen, ModuleLlvm, ModuleKind};
 
@@ -29,15 +30,10 @@ use libc;
 
 use std::ffi::{CStr, CString};
 use std::fs::File;
-use std::io;
-use std::mem;
-use std::path::Path;
 use std::ptr;
 use std::slice;
 use std::sync::Arc;
 
-pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-imports.bin";
-
 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
     match crate_type {
         config::CrateType::Executable |
@@ -105,11 +101,16 @@ impl LtoModuleCodegen {
     }
 }
 
+/// Performs LTO, which in the case of full LTO means merging all modules into
+/// a single one and returning it for further optimizing. For ThinLTO, it will
+/// do the global analysis necessary and return two lists, one of the modules
+/// the need optimization and another for modules that can simply be copied over
+/// from the incr. comp. cache.
 pub(crate) fn run(cgcx: &CodegenContext,
                   modules: Vec<ModuleCodegen>,
-                  import_only_modules: Vec<(SerializedModule, CString)>,
+                  cached_modules: Vec<(SerializedModule, WorkProduct)>,
                   timeline: &mut Timeline)
-    -> Result<Vec<LtoModuleCodegen>, FatalError>
+    -> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
     let export_threshold = match cgcx.lto {
@@ -202,13 +203,14 @@ pub(crate) fn run(cgcx: &CodegenContext,
     match cgcx.lto {
         Lto::Yes | // `-C lto` == fat LTO by default
         Lto::Fat => {
-            assert!(import_only_modules.is_empty());
-            fat_lto(cgcx,
-                    &diag_handler,
-                    modules,
-                    upstream_modules,
-                    &symbol_white_list,
-                    timeline)
+            assert!(cached_modules.is_empty());
+            let opt_jobs = fat_lto(cgcx,
+                                  &diag_handler,
+                                  modules,
+                                  upstream_modules,
+                                  &symbol_white_list,
+                                  timeline);
+            opt_jobs.map(|opt_jobs| (opt_jobs, vec![]))
         }
         Lto::Thin |
         Lto::ThinLocal => {
@@ -220,7 +222,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
                      &diag_handler,
                      modules,
                      upstream_modules,
-                     import_only_modules,
+                     cached_modules,
                      &symbol_white_list,
                      timeline)
         }
@@ -388,14 +390,19 @@ fn thin_lto(cgcx: &CodegenContext,
             diag_handler: &Handler,
             modules: Vec<ModuleCodegen>,
             serialized_modules: Vec<(SerializedModule, CString)>,
-            import_only_modules: Vec<(SerializedModule, CString)>,
+            cached_modules: Vec<(SerializedModule, WorkProduct)>,
             symbol_white_list: &[*const libc::c_char],
             timeline: &mut Timeline)
-    -> Result<Vec<LtoModuleCodegen>, FatalError>
+    -> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
 {
     unsafe {
         info!("going for that thin, thin LTO");
 
+        let green_modules: FxHashMap<_, _> = cached_modules
+            .iter()
+            .map(|&(_, ref wp)| (wp.cgu_name.clone(), wp.clone()))
+            .collect();
+
         let mut thin_buffers = Vec::new();
         let mut module_names = Vec::new();
         let mut thin_modules = Vec::new();
@@ -411,6 +418,28 @@ fn thin_lto(cgcx: &CodegenContext,
             info!("local module: {} - {}", i, module.name);
             let name = CString::new(module.name.clone()).unwrap();
             let buffer = ThinBuffer::new(module.module_llvm.llmod());
+
+            // We emit the module after having serialized it into a ThinBuffer
+            // because only then it will contain the ThinLTO module summary.
+            if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
+                if cgcx.config(module.kind).emit_pre_thin_lto_bc {
+                    use std::io::Write;
+
+                    let path = incr_comp_session_dir
+                        .join(pre_lto_bitcode_filename(&module.name));
+                    let mut file = File::create(&path).unwrap_or_else(|e| {
+                        panic!("Failed to create pre-lto-bitcode file `{}`: {}",
+                               path.display(),
+                               e);
+                    });
+                    file.write_all(buffer.data()).unwrap_or_else(|e| {
+                        panic!("Error writing pre-lto-bitcode file `{}`: {}",
+                               path.display(),
+                               e);
+                    });
+                }
+            }
+
             thin_modules.push(llvm::ThinLTOModule {
                 identifier: name.as_ptr(),
                 data: buffer.data().as_ptr(),
@@ -438,24 +467,13 @@ fn thin_lto(cgcx: &CodegenContext,
         //        looking at upstream modules entirely sometimes (the contents,
         //        we must always unconditionally look at the index).
         let mut serialized = Vec::new();
-        for (module, name) in serialized_modules {
-            info!("foreign module {:?}", name);
-            thin_modules.push(llvm::ThinLTOModule {
-                identifier: name.as_ptr(),
-                data: module.data().as_ptr(),
-                len: module.data().len(),
-            });
-            serialized.push(module);
-            module_names.push(name);
-        }
 
-        // All the modules collected up to this point we actually want to
-        // optimize. The `import_only_modules` below need to be in the list of
-        // available modules but we don't need to run optimizations for them
-        // since we already have their optimized version cached.
-        let modules_to_optimize = module_names.len();
-        for (module, name) in import_only_modules {
-            info!("foreign module {:?}", name);
+        let cached_modules = cached_modules.into_iter().map(|(sm, wp)| {
+            (sm, CString::new(wp.cgu_name).unwrap())
+        });
+
+        for (module, name) in serialized_modules.into_iter().chain(cached_modules) {
+            info!("upstream or cached module {:?}", name);
             thin_modules.push(llvm::ThinLTOModule {
                 identifier: name.as_ptr(),
                 data: module.data().as_ptr(),
@@ -465,6 +483,9 @@ fn thin_lto(cgcx: &CodegenContext,
             module_names.push(name);
         }
 
+        // Sanity check
+        assert_eq!(thin_modules.len(), module_names.len());
+
         // Delegate to the C++ bindings to create some data here. Once this is a
         // tried-and-true interface we may wish to try to upstream some of this
         // to LLVM itself, right now we reimplement a lot of what they do
@@ -478,30 +499,7 @@ fn thin_lto(cgcx: &CodegenContext,
             write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
         })?;
 
-        // Save the ThinLTO import information for incremental compilation.
-        if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
-            let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME);
-
-            // The import information from the current compilation session. It
-            // does not contain info about modules that have been loaded from
-            // the cache instead of having been recompiled...
-            let current_imports = ThinLTOImports::from_thin_lto_data(data);
-
-            // ... so we load this additional information from the previous
-            // cache file if necessary.
-            let imports = if path.exists() {
-                let prev_imports = ThinLTOImports::load_from_file(&path).unwrap();
-                prev_imports.update(current_imports, &module_names)
-            } else {
-                current_imports
-            };
-
-            if let Err(err) = imports.save_to_file(&path) {
-                let msg = format!("Error while writing ThinLTO import data: {}",
-                                  err);
-                return Err(write::llvm_err(&diag_handler, msg));
-            }
-        }
+        let import_map = ThinLTOImports::from_thin_lto_data(data);
 
         let data = ThinData(data);
         info!("thin LTO data created");
@@ -517,12 +515,36 @@ fn thin_lto(cgcx: &CodegenContext,
             serialized_modules: serialized,
             module_names,
         });
-        Ok((0..modules_to_optimize).map(|i| {
-            LtoModuleCodegen::Thin(ThinModule {
+
+        let mut copy_jobs = vec![];
+        let mut opt_jobs = vec![];
+
+        for (module_index, module_name) in shared.module_names.iter().enumerate() {
+            let module_name = module_name_to_str(module_name);
+
+            if green_modules.contains_key(module_name) {
+                let mut imports_all_green = true;
+                for imported_module in import_map.modules_imported_by(module_name) {
+                    if !green_modules.contains_key(imported_module) {
+                        imports_all_green = false;
+                        break
+                    }
+                }
+
+                if imports_all_green {
+                    let work_product = green_modules[module_name].clone();
+                    copy_jobs.push(work_product);
+                    continue
+                }
+            }
+
+            opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
                 shared: shared.clone(),
-                idx: i,
-            })
-        }).collect())
+                idx: module_index,
+            }));
+        }
+
+        Ok((opt_jobs, copy_jobs))
     }
 }
 
@@ -850,44 +872,12 @@ pub struct ThinLTOImports {
 }
 
 impl ThinLTOImports {
-    pub fn new() -> ThinLTOImports {
-        ThinLTOImports {
-            imports: FxHashMap(),
-        }
-    }
-
     pub fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] {
         self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
     }
 
-    pub fn update(mut self, new: ThinLTOImports, module_names: &[CString]) -> ThinLTOImports {
-        let module_names: FxHashSet<_> = module_names.iter().map(|name| {
-            name.clone().into_string().unwrap()
-        }).collect();
-
-        // Remove all modules that don't exist anymore.
-        self.imports.retain(|k, _| module_names.contains(k));
-
-        // Overwrite old values
-        for (importing_module, imported_modules) in new.imports {
-            self.imports.insert(importing_module, imported_modules);
-        }
-
-        self
-    }
-
     /// Load the ThinLTO import map from ThinLTOData.
     unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports {
-        fn module_name_to_str(c_str: &CStr) -> &str {
-            match c_str.to_str() {
-                Ok(s) => s,
-                Err(e) => {
-                    bug!("Encountered non-utf8 LLVM module name `{}`: {}",
-                        c_str.to_string_lossy(),
-                        e)
-                }
-            }
-        }
         unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void,
                                                       importing_module_name: *const libc::c_char,
                                                       imported_module_name: *const libc::c_char) {
@@ -896,6 +886,7 @@ impl ThinLTOImports {
             let importing_module_name = module_name_to_str(&importing_module_name);
             let imported_module_name = CStr::from_ptr(imported_module_name);
             let imported_module_name = module_name_to_str(&imported_module_name);
+
             if !map.imports.contains_key(importing_module_name) {
                 map.imports.insert(importing_module_name.to_owned(), vec![]);
             }
@@ -913,47 +904,15 @@ impl ThinLTOImports {
                                               &mut map as *mut _ as *mut libc::c_void);
         map
     }
+}
 
-    pub fn save_to_file(&self, path: &Path) -> io::Result<()> {
-        use std::io::Write;
-        let file = File::create(path)?;
-        let mut writer = io::BufWriter::new(file);
-        for (importing_module_name, imported_modules) in &self.imports {
-            writeln!(writer, "{}", importing_module_name)?;
-            for imported_module in imported_modules {
-                writeln!(writer, "  {}", imported_module)?;
-            }
-            writeln!(writer)?;
-        }
-        Ok(())
-    }
-
-    pub fn load_from_file(path: &Path) -> io::Result<ThinLTOImports> {
-        use std::io::BufRead;
-        let mut imports = FxHashMap();
-        let mut current_module = None;
-        let mut current_imports = vec![];
-        let file = File::open(path)?;
-        for line in io::BufReader::new(file).lines() {
-            let line = line?;
-            if line.is_empty() {
-                let importing_module = current_module
-                    .take()
-                    .expect("Importing module not set");
-                imports.insert(importing_module,
-                               mem::replace(&mut current_imports, vec![]));
-            } else if line.starts_with(" ") {
-                // This is an imported module
-                assert_ne!(current_module, None);
-                current_imports.push(line.trim().to_string());
-            } else {
-                // This is the beginning of a new module
-                assert_eq!(current_module, None);
-                current_module = Some(line.trim().to_string());
-            }
+fn module_name_to_str(c_str: &CStr) -> &str {
+    match c_str.to_str() {
+        Ok(s) => s,
+        Err(e) => {
+            bug!("Encountered non-utf8 LLVM module name `{}`: {}",
+                c_str.to_string_lossy(),
+                e)
         }
-        Ok(ThinLTOImports {
-            imports
-        })
     }
-}
+}
\ No newline at end of file
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index e1d69db83b9..9c0f4c39790 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -28,7 +28,7 @@ use rustc::util::nodemap::FxHashMap;
 use time_graph::{self, TimeGraph, Timeline};
 use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
 use llvm_util;
-use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, ModuleLlvm,
+use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, // ModuleLlvm,
      CachedModuleCodegen};
 use CrateInfo;
 use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
@@ -228,8 +228,8 @@ pub struct ModuleConfig {
     pgo_use: String,
 
     // Flags indicating which outputs to produce.
+    pub emit_pre_thin_lto_bc: bool,
     emit_no_opt_bc: bool,
-    emit_pre_thin_lto_bc: bool,
     emit_bc: bool,
     emit_bc_compressed: bool,
     emit_lto_bc: bool,
@@ -625,20 +625,13 @@ unsafe fn optimize(cgcx: &CodegenContext,
         // Deallocate managers that we're now done with
         llvm::LLVMDisposePassManager(fpm);
         llvm::LLVMDisposePassManager(mpm);
-
-        if config.emit_pre_thin_lto_bc {
-            let out = cgcx.output_filenames.temp_path_ext(PRE_THIN_LTO_BC_EXT,
-                                                          module_name);
-            let out = path2cstr(&out);
-            llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
-        }
     }
     Ok(())
 }
 
 fn generate_lto_work(cgcx: &CodegenContext,
                      modules: Vec<ModuleCodegen>,
-                     import_only_modules: Vec<(SerializedModule, CString)>)
+                     import_only_modules: Vec<(SerializedModule, WorkProduct)>)
     -> Vec<(WorkItem, u64)>
 {
     let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
@@ -646,13 +639,22 @@ fn generate_lto_work(cgcx: &CodegenContext,
                  CODEGEN_WORK_PACKAGE_KIND,
                  "generate lto")
     }).unwrap_or(Timeline::noop());
-    let lto_modules = lto::run(cgcx, modules, import_only_modules, &mut timeline)
+    let (lto_modules, copy_jobs) = lto::run(cgcx, modules, import_only_modules, &mut timeline)
         .unwrap_or_else(|e| e.raise());
 
-    lto_modules.into_iter().map(|module| {
+    let lto_modules = lto_modules.into_iter().map(|module| {
         let cost = module.cost();
         (WorkItem::LTO(module), cost)
-    }).collect()
+    });
+
+    let copy_jobs = copy_jobs.into_iter().map(|wp| {
+        (WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
+            name: wp.cgu_name.clone(),
+            source: wp,
+        }), 0)
+    });
+
+    lto_modules.chain(copy_jobs).collect()
 }
 
 unsafe fn codegen(cgcx: &CodegenContext,
@@ -1083,7 +1085,6 @@ pub fn start_async_codegen(tcx: TyCtxt,
 fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
     sess: &Session,
     compiled_modules: &CompiledModules,
-    output_filenames: &OutputFilenames,
 ) -> FxHashMap<WorkProductId, WorkProduct> {
     let mut work_products = FxHashMap::default();
 
@@ -1104,13 +1105,6 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
             files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
         }
 
-        let pre_thin_lto_bytecode_path =
-            output_filenames.temp_path_ext(PRE_THIN_LTO_BC_EXT, Some(&module.name));
-
-        if pre_thin_lto_bytecode_path.exists() {
-            files.push((WorkProductFileKind::PreThinLtoBytecode, pre_thin_lto_bytecode_path));
-        }
-
         if let Some((id, product)) =
                 copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
             work_products.insert(id, product);
@@ -1285,9 +1279,6 @@ enum WorkItem {
     /// Copy the post-LTO artifacts from the incremental cache to the output
     /// directory.
     CopyPostLtoArtifacts(CachedModuleCodegen),
-    /// Load the pre-LTO version of a module from the incremental cache, so it
-    /// can be run through LTO again.
-    LoadPreLtoModule(CachedModuleCodegen),
     /// Perform (Thin)LTO on the given module.
     LTO(lto::LtoModuleCodegen),
 }
@@ -1297,7 +1288,6 @@ impl WorkItem {
         match *self {
             WorkItem::Optimize(ref m) => m.kind,
             WorkItem::CopyPostLtoArtifacts(_) |
-            WorkItem::LoadPreLtoModule(_) |
             WorkItem::LTO(_) => ModuleKind::Regular,
         }
     }
@@ -1305,7 +1295,6 @@ impl WorkItem {
     fn name(&self) -> String {
         match *self {
             WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
-            WorkItem::LoadPreLtoModule(ref m) => format!("load pre-lto module: {}", m.name),
             WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
             WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
         }
@@ -1326,9 +1315,6 @@ fn execute_work_item(cgcx: &CodegenContext,
         work_item @ WorkItem::Optimize(_) => {
             execute_optimize_work_item(cgcx, work_item, timeline)
         }
-        work_item @ WorkItem::LoadPreLtoModule(_) => {
-            execute_load_pre_lto_mod_work_item(cgcx, work_item, timeline)
-        }
         work_item @ WorkItem::CopyPostLtoArtifacts(_) => {
             execute_copy_from_cache_work_item(cgcx, work_item, timeline)
         }
@@ -1454,9 +1440,6 @@ fn execute_copy_from_cache_work_item(cgcx: &CodegenContext,
                 bytecode_compressed = Some(path.clone());
                 path
             }
-            WorkProductFileKind::PreThinLtoBytecode => {
-                continue;
-            }
         };
         let source_file = in_incr_comp_dir(&incr_comp_session_dir,
                                            &saved_file);
@@ -1509,69 +1492,6 @@ fn execute_lto_work_item(cgcx: &CodegenContext,
     }
 }
 
-fn execute_load_pre_lto_mod_work_item(cgcx: &CodegenContext,
-                                      work_item: WorkItem,
-                                      _: &mut Timeline)
-    -> Result<WorkItemResult, FatalError>
-{
-    let module = if let WorkItem::LoadPreLtoModule(module) = work_item {
-        module
-    } else {
-        bug!("execute_load_pre_lto_mod_work_item() called with wrong WorkItem kind.")
-    };
-
-    let work_product = module.source.clone();
-    let incr_comp_session_dir = cgcx.incr_comp_session_dir
-                                    .as_ref()
-                                    .unwrap();
-
-    let filename = pre_lto_bitcode_filename(&work_product);
-    let bc_path = in_incr_comp_dir(&incr_comp_session_dir, &filename);
-
-    let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
-        panic!("failed to open bitcode file `{}`: {}",
-                           bc_path.display(),
-                           e);
-    });
-
-    let module_llvm = unsafe {
-        let data = ::memmap::Mmap::map(&file).unwrap_or_else(|e| {
-            panic!("failed to create mmap for bitcode file `{}`: {}",
-                               bc_path.display(),
-                               e);
-        });
-
-        let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
-        let mod_name_c = SmallCStr::new(&module.name);
-        let llmod_raw = match llvm::LLVMRustParseBitcodeForThinLTO(
-            llcx,
-            data.as_ptr(),
-            data.len(),
-            mod_name_c.as_ptr(),
-        ) {
-            Some(m) => m as *const _,
-            None => {
-                panic!("failed to parse bitcode for thin LTO module `{}`",
-                        module.name);
-            }
-        };
-
-        let tm = (cgcx.tm_factory)().unwrap();
-
-        ModuleLlvm {
-            llmod_raw,
-            llcx,
-            tm,
-        }
-    };
-
-    Ok(WorkItemResult::NeedsLTO(ModuleCodegen {
-        name: module.name.to_string(),
-        module_llvm,
-        kind: ModuleKind::Regular,
-    }))
-}
-
 enum Message {
     Token(io::Result<Acquired>),
     NeedsLTO {
@@ -1588,7 +1508,7 @@ enum Message {
     },
     AddImportOnlyModule {
         module_data: SerializedModule,
-        module_name: CString,
+        work_product: WorkProduct,
     },
     CodegenComplete,
     CodegenItem,
@@ -1893,6 +1813,7 @@ fn start_executing_work(tcx: TyCtxt,
               work_items.len() > 0 ||
               running > 0 ||
               needs_lto.len() > 0 ||
+              lto_import_only_modules.len() > 0 ||
               main_thread_worker_state != MainThreadWorkerState::Idle {
 
             // While there are still CGUs to be codegened, the coordinator has
@@ -1932,7 +1853,7 @@ fn start_executing_work(tcx: TyCtxt,
                    running == 0 &&
                    main_thread_worker_state == MainThreadWorkerState::Idle {
                     assert!(!started_lto);
-                    assert!(needs_lto.len() > 0);
+                    assert!(needs_lto.len() + lto_import_only_modules.len() > 0);
                     started_lto = true;
                     let modules = mem::replace(&mut needs_lto, Vec::new());
                     let import_only_modules =
@@ -2104,10 +2025,13 @@ fn start_executing_work(tcx: TyCtxt,
                     free_worker_ids.push(worker_id);
                     needs_lto.push(result);
                 }
-                Message::AddImportOnlyModule { module_data, module_name } => {
+                Message::AddImportOnlyModule { module_data, work_product } => {
                     assert!(!started_lto);
                     assert!(!codegen_done);
-                    lto_import_only_modules.push((module_data, module_name));
+                    assert_eq!(main_thread_worker_state,
+                               MainThreadWorkerState::Codegenning);
+                    lto_import_only_modules.push((module_data, work_product));
+                    main_thread_worker_state = MainThreadWorkerState::Idle;
                 }
                 Message::Done { result: Err(()), worker_id: _ } => {
                     shared_emitter.fatal("aborting due to worker thread failure");
@@ -2483,8 +2407,7 @@ impl OngoingCodegen {
 
         let work_products =
             copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
-                                                             &compiled_modules,
-                                                             &self.output_filenames);
+                                                             &compiled_modules);
         produce_final_output_artifacts(sess,
                                        &compiled_modules,
                                        &self.output_filenames);
@@ -2565,19 +2488,7 @@ pub(crate) fn submit_post_lto_module_to_llvm(tcx: TyCtxt,
 
 pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
                                             module: CachedModuleCodegen) {
-    let llvm_work_item = WorkItem::LoadPreLtoModule(module);
-
-    drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
-        llvm_work_item,
-        // We don't know the size of the module, but just loading will have smaller
-        // cost than optimizing.
-        cost: 10,
-    })));
-}
-
-pub(crate) fn submit_import_only_module_to_llvm(tcx: TyCtxt,
-                                                module: CachedModuleCodegen) {
-    let filename = pre_lto_bitcode_filename(&module.source);
+    let filename = pre_lto_bitcode_filename(&module.name);
     let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
     let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
         panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e)
@@ -2592,21 +2503,12 @@ pub(crate) fn submit_import_only_module_to_llvm(tcx: TyCtxt,
     // Schedule the module to be loaded
     drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
         module_data: SerializedModule::FromUncompressedFile(mmap, file),
-        module_name: CString::new(module.name.clone()).unwrap(),
+        work_product: module.source,
     })));
-
-    // Note: We also schedule for the cached files to be copied to the output
-    // directory
-    submit_post_lto_module_to_llvm(tcx, module);
 }
 
-fn pre_lto_bitcode_filename(wp: &WorkProduct) -> String {
-    wp.saved_files
-      .iter()
-      .find(|&&(kind, _)| kind == WorkProductFileKind::PreThinLtoBytecode)
-      .map(|&(_, ref filename)| filename.clone())
-      .unwrap_or_else(|| panic!("Couldn't find pre-thin-lto bytecode for `{}`",
-                                wp.cgu_name))
+pub(super) fn pre_lto_bitcode_filename(module_name: &str) -> String {
+    format!("{}.{}", module_name, PRE_THIN_LTO_BC_EXT)
 }
 
 fn msvc_imps_needed(tcx: TyCtxt) -> bool {