}
}
+pub(crate) fn link(
+ cgcx: &CodegenContext<LlvmCodegenBackend>,
+ diag_handler: &Handler,
+ mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
+) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
+ use super::lto::{Linker, ModuleBuffer};
+ // Sort the modules by name to ensure to ensure deterministic behavior.
+ modules.sort_by(|a, b| a.name.cmp(&b.name));
+ let (first, elements) =
+ modules.split_first().expect("Bug! modules must contain at least one module.");
+
+ let mut linker = Linker::new(first.module_llvm.llmod());
+ for module in elements {
+ let _timer =
+ cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name));
+ let buffer = ModuleBuffer::new(module.module_llvm.llmod());
+ linker.add(&buffer.data()).map_err(|()| {
+ let msg = format!("failed to serialize module {:?}", module.name);
+ llvm_err(&diag_handler, &msg)
+ })?;
+ }
+ drop(linker);
+ Ok(modules.remove(0))
+}
+
pub(crate) unsafe fn codegen(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
enum WorkItemResult<B: WriteBackendMethods> {
Compiled(CompiledModule),
+ NeedsLink(ModuleCodegen<B::Module>),
NeedsFatLTO(FatLTOInput<B>),
NeedsThinLTO(String, B::ThinBuffer),
}
None
};
- Ok(match lto_type {
- ComputedLtoType::No => {
- let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
- WorkItemResult::Compiled(module)
- }
+ match lto_type {
+ ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
ComputedLtoType::Thin => {
let (name, thin_buffer) = B::prepare_thin(module);
if let Some(path) = bitcode {
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
});
}
- WorkItemResult::NeedsThinLTO(name, thin_buffer)
+ Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))
}
ComputedLtoType::Fat => match bitcode {
Some(path) => {
fs::write(&path, buffer.data()).unwrap_or_else(|e| {
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
});
- WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })
+ Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }))
}
- None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)),
+ None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))),
},
- })
+ }
}
fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
cgcx: &CodegenContext<B>,
mut module: lto::LtoModuleCodegen<B>,
module_config: &ModuleConfig,
+) -> Result<WorkItemResult<B>, FatalError> {
+ let module = unsafe { module.optimize(cgcx)? };
+ finish_intra_module_work(cgcx, module, module_config)
+}
+
+fn finish_intra_module_work<B: ExtraBackendMethods>(
+ cgcx: &CodegenContext<B>,
+ module: ModuleCodegen<B::Module>,
+ module_config: &ModuleConfig,
) -> Result<WorkItemResult<B>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
- unsafe {
- let module = module.optimize(cgcx)?;
- let module = B::codegen(cgcx, &diag_handler, module, module_config)?;
+ if !cgcx.opts.debugging_opts.combine_cgu
+ || module.kind == ModuleKind::Metadata
+ || module.kind == ModuleKind::Allocator
+ {
+ let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
Ok(WorkItemResult::Compiled(module))
+ } else {
+ Ok(WorkItemResult::NeedsLink(module))
}
}
thin_buffer: B::ThinBuffer,
worker_id: usize,
},
+ NeedsLink {
+ module: ModuleCodegen<B::Module>,
+ worker_id: usize,
+ },
Done {
result: Result<CompiledModule, Option<WorkerFatalError>>,
worker_id: usize,
let mut compiled_modules = vec![];
let mut compiled_metadata_module = None;
let mut compiled_allocator_module = None;
+ let mut needs_link = Vec::new();
let mut needs_fat_lto = Vec::new();
let mut needs_thin_lto = Vec::new();
let mut lto_import_only_modules = Vec::new();
}
}
}
+ Message::NeedsLink { module, worker_id } => {
+ free_worker(worker_id);
+ needs_link.push(module);
+ }
Message::NeedsFatLTO { result, worker_id } => {
assert!(!started_lto);
free_worker(worker_id);
}
}
+ let needs_link = mem::take(&mut needs_link);
+ if !needs_link.is_empty() {
+ assert!(compiled_modules.is_empty());
+ let diag_handler = cgcx.create_diag_handler();
+ let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?;
+ let module = unsafe {
+ B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular))
+ .map_err(|_| ())?
+ };
+ compiled_modules.push(module);
+ }
+
// Drop to print timings
drop(llvm_start_time);
Some(Ok(WorkItemResult::Compiled(m))) => {
Message::Done::<B> { result: Ok(m), worker_id }
}
+ Some(Ok(WorkItemResult::NeedsLink(m))) => {
+ Message::NeedsLink::<B> { module: m, worker_id }
+ }
Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
Message::NeedsFatLTO::<B> { result: m, worker_id }
}