2014-12-12 23:39:27 +00:00
|
|
|
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
|
2014-08-11 17:33:58 +00:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2018-04-23 22:17:07 +00:00
|
|
|
use attributes;
|
2017-10-20 01:44:33 +00:00
|
|
|
use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
|
2018-11-01 20:06:50 +00:00
|
|
|
use back::lto::{self, ThinBuffer, SerializedModule};
|
2017-06-15 14:08:18 +00:00
|
|
|
use back::link::{self, get_linker, remove};
|
2017-10-17 20:08:13 +00:00
|
|
|
use base;
|
|
|
|
use consts;
|
2018-08-20 15:13:01 +00:00
|
|
|
use memmap;
|
|
|
|
use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir,
|
|
|
|
in_incr_comp_dir, in_incr_comp_dir_sess};
|
2018-05-09 05:20:09 +00:00
|
|
|
use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
|
2018-09-18 14:33:24 +00:00
|
|
|
use rustc::dep_graph::cgu_reuse_tracker::CguReuseTracker;
|
2018-08-18 10:08:06 +00:00
|
|
|
use rustc::middle::cstore::EncodedMetadata;
|
2018-07-26 17:22:14 +00:00
|
|
|
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto};
|
2017-05-27 18:48:09 +00:00
|
|
|
use rustc::session::Session;
|
2017-09-13 20:22:20 +00:00
|
|
|
use rustc::util::nodemap::FxHashMap;
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
use time_graph::{self, TimeGraph, Timeline};
|
2018-07-17 11:17:47 +00:00
|
|
|
use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
|
2018-08-23 18:03:22 +00:00
|
|
|
use llvm_util;
|
2018-08-31 13:18:08 +00:00
|
|
|
use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, // ModuleLlvm,
|
2018-08-20 15:13:01 +00:00
|
|
|
CachedModuleCodegen};
|
2017-08-28 22:55:32 +00:00
|
|
|
use CrateInfo;
|
2017-09-13 20:22:20 +00:00
|
|
|
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
|
|
|
|
use rustc::ty::TyCtxt;
|
2017-12-03 13:21:23 +00:00
|
|
|
use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry};
|
2018-08-03 21:37:15 +00:00
|
|
|
use rustc_fs_util::{path2cstr, link_or_copy};
|
2018-08-07 14:04:34 +00:00
|
|
|
use rustc_data_structures::small_c_str::SmallCStr;
|
2018-08-18 10:08:06 +00:00
|
|
|
use rustc_data_structures::svh::Svh;
|
2018-10-20 12:45:08 +00:00
|
|
|
use rustc_codegen_utils::command::Command;
|
|
|
|
use rustc_codegen_utils::linker::LinkerInfo;
|
|
|
|
use rustc_codegen_utils::symbol_export::ExportedSymbols;
|
2017-10-27 06:21:22 +00:00
|
|
|
use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
|
2017-07-21 15:15:18 +00:00
|
|
|
use errors::emitter::{Emitter};
|
2017-09-13 20:22:20 +00:00
|
|
|
use syntax::attr;
|
2017-06-15 14:08:18 +00:00
|
|
|
use syntax::ext::hygiene::Mark;
|
2016-06-21 22:08:13 +00:00
|
|
|
use syntax_pos::MultiSpan;
|
2017-07-26 08:27:24 +00:00
|
|
|
use syntax_pos::symbol::Symbol;
|
2017-10-17 20:08:13 +00:00
|
|
|
use type_::Type;
|
2018-08-28 15:03:46 +00:00
|
|
|
use context::{is_pie_binary, get_reloc_model, CodegenCx};
|
2018-08-29 14:40:47 +00:00
|
|
|
use interfaces::CommonWriteMethods;
|
2017-06-15 14:08:18 +00:00
|
|
|
use jobserver::{Client, Acquired};
|
2017-06-29 14:52:43 +00:00
|
|
|
use rustc_demangle;
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2017-09-13 23:03:24 +00:00
|
|
|
use std::any::Any;
|
2017-10-17 20:08:13 +00:00
|
|
|
use std::ffi::{CString, CStr};
|
2018-01-10 16:58:39 +00:00
|
|
|
use std::fs;
|
|
|
|
use std::io::{self, Write};
|
2017-07-23 15:14:38 +00:00
|
|
|
use std::mem;
|
2015-09-30 17:08:37 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2014-08-11 17:33:58 +00:00
|
|
|
use std::str;
|
2017-07-24 12:21:28 +00:00
|
|
|
use std::sync::Arc;
|
2017-07-21 15:15:18 +00:00
|
|
|
use std::sync::mpsc::{channel, Sender, Receiver};
|
2017-06-29 14:52:43 +00:00
|
|
|
use std::slice;
|
2017-07-31 12:51:47 +00:00
|
|
|
use std::time::Instant;
|
2017-07-24 12:21:28 +00:00
|
|
|
use std::thread;
|
2017-06-29 14:52:43 +00:00
|
|
|
use libc::{c_uint, c_void, c_char, size_t};
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-10-06 09:50:34 +00:00
|
|
|
pub const RELOC_MODEL_ARGS : [(&str, llvm::RelocMode); 7] = [
|
2016-08-06 05:50:48 +00:00
|
|
|
("pic", llvm::RelocMode::PIC),
|
|
|
|
("static", llvm::RelocMode::Static),
|
|
|
|
("default", llvm::RelocMode::Default),
|
|
|
|
("dynamic-no-pic", llvm::RelocMode::DynamicNoPic),
|
2017-04-26 00:05:51 +00:00
|
|
|
("ropi", llvm::RelocMode::ROPI),
|
|
|
|
("rwpi", llvm::RelocMode::RWPI),
|
|
|
|
("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
|
2016-07-24 07:27:23 +00:00
|
|
|
];
|
|
|
|
|
2018-01-23 01:01:36 +00:00
|
|
|
pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
|
2016-08-06 05:50:48 +00:00
|
|
|
("small", llvm::CodeModel::Small),
|
|
|
|
("kernel", llvm::CodeModel::Kernel),
|
|
|
|
("medium", llvm::CodeModel::Medium),
|
|
|
|
("large", llvm::CodeModel::Large),
|
2016-07-24 07:27:23 +00:00
|
|
|
];
|
|
|
|
|
2018-10-06 09:50:34 +00:00
|
|
|
pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [
|
2017-10-31 18:24:04 +00:00
|
|
|
("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
|
|
|
|
("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
|
|
|
|
("initial-exec", llvm::ThreadLocalMode::InitialExec),
|
|
|
|
("local-exec", llvm::ThreadLocalMode::LocalExec),
|
|
|
|
];
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc";
|
|
|
|
|
2018-10-06 09:42:14 +00:00
|
|
|
pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
|
2015-10-23 05:07:19 +00:00
|
|
|
match llvm::last_error() {
|
2017-06-15 14:08:18 +00:00
|
|
|
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
|
|
|
|
None => handler.fatal(&msg),
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write_output_file(
|
2015-12-13 22:17:55 +00:00
|
|
|
handler: &errors::Handler,
|
2018-07-17 11:17:47 +00:00
|
|
|
target: &'ll llvm::TargetMachine,
|
|
|
|
pm: &llvm::PassManager<'ll>,
|
|
|
|
m: &'ll llvm::Module,
|
2014-08-11 17:33:58 +00:00
|
|
|
output: &Path,
|
2017-06-15 14:08:18 +00:00
|
|
|
file_type: llvm::FileType) -> Result<(), FatalError> {
|
2014-08-11 17:33:58 +00:00
|
|
|
unsafe {
|
2015-02-27 05:00:43 +00:00
|
|
|
let output_c = path2cstr(output);
|
2018-10-06 09:37:28 +00:00
|
|
|
let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type);
|
2016-08-01 21:16:16 +00:00
|
|
|
if result.into_result().is_err() {
|
2017-06-15 14:08:18 +00:00
|
|
|
let msg = format!("could not write output to {}", output.display());
|
2018-10-06 09:42:14 +00:00
|
|
|
Err(llvm_err(handler, &msg))
|
2017-06-15 14:08:18 +00:00
|
|
|
} else {
|
|
|
|
Ok(())
|
2016-07-07 18:57:09 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
|
|
|
|
match optimize {
|
2016-08-01 21:16:16 +00:00
|
|
|
config::OptLevel::No => llvm::CodeGenOptLevel::None,
|
|
|
|
config::OptLevel::Less => llvm::CodeGenOptLevel::Less,
|
|
|
|
config::OptLevel::Default => llvm::CodeGenOptLevel::Default,
|
|
|
|
config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive,
|
|
|
|
_ => llvm::CodeGenOptLevel::Default,
|
2016-03-27 19:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize {
|
|
|
|
match optimize {
|
|
|
|
config::OptLevel::Size => llvm::CodeGenOptSizeDefault,
|
|
|
|
config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive,
|
|
|
|
_ => llvm::CodeGenOptSizeNone,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-07-17 15:26:58 +00:00
|
|
|
pub fn create_target_machine(
|
|
|
|
sess: &Session,
|
|
|
|
find_features: bool,
|
|
|
|
) -> &'static mut llvm::TargetMachine {
|
2018-04-01 06:26:05 +00:00
|
|
|
target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
|
2018-10-06 09:42:14 +00:00
|
|
|
llvm_err(sess.diagnostic(), &err).raise()
|
2017-07-23 15:14:38 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-04-01 06:26:05 +00:00
|
|
|
// If find_features is true this won't access `sess.crate_types` by assuming
|
|
|
|
// that `is_pie_binary` is false. When we discover LLVM target features
|
|
|
|
// `sess.crate_types` is uninitialized so we cannot access it.
|
|
|
|
pub fn target_machine_factory(sess: &Session, find_features: bool)
|
2018-06-27 14:57:25 +00:00
|
|
|
-> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>
|
2017-07-23 15:14:38 +00:00
|
|
|
{
|
2016-07-14 21:40:14 +00:00
|
|
|
let reloc_model = get_reloc_model(sess);
|
2014-08-11 17:33:58 +00:00
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
let opt_level = get_llvm_opt_level(sess.opts.optimize);
|
|
|
|
let use_softfp = sess.opts.cg.soft_float;
|
|
|
|
|
2014-07-23 18:56:36 +00:00
|
|
|
let ffunction_sections = sess.target.target.options.function_sections;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
let fdata_sections = ffunction_sections;
|
|
|
|
|
2018-01-23 01:01:36 +00:00
|
|
|
let code_model_arg = sess.opts.cg.code_model.as_ref().or(
|
|
|
|
sess.target.target.options.code_model.as_ref(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let code_model = match code_model_arg {
|
|
|
|
Some(s) => {
|
|
|
|
match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) {
|
|
|
|
Some(x) => x.1,
|
|
|
|
_ => {
|
|
|
|
sess.err(&format!("{:?} is not a valid code model",
|
|
|
|
code_model_arg));
|
|
|
|
sess.abort_if_errors();
|
|
|
|
bug!();
|
|
|
|
}
|
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
2018-01-23 01:01:36 +00:00
|
|
|
None => llvm::CodeModel::None,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
};
|
|
|
|
|
2018-09-01 05:41:17 +00:00
|
|
|
let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
|
|
|
|
let mut singlethread = sess.target.target.options.singlethread;
|
|
|
|
|
|
|
|
// On the wasm target once the `atomics` feature is enabled that means that
|
|
|
|
// we're no longer single-threaded, or otherwise we don't want LLVM to
|
|
|
|
// lower atomic operations to single-threaded operations.
|
|
|
|
if singlethread &&
|
|
|
|
sess.target.target.llvm_target.contains("wasm32") &&
|
|
|
|
features.iter().any(|s| *s == "+atomics")
|
|
|
|
{
|
|
|
|
singlethread = false;
|
|
|
|
}
|
2017-10-23 03:01:00 +00:00
|
|
|
|
2018-08-07 14:04:34 +00:00
|
|
|
let triple = SmallCStr::new(&sess.target.target.llvm_target);
|
2018-08-23 18:03:22 +00:00
|
|
|
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
|
2018-09-01 05:41:17 +00:00
|
|
|
let features = features.join(",");
|
2018-04-23 22:17:07 +00:00
|
|
|
let features = CString::new(features).unwrap();
|
2018-04-01 06:26:05 +00:00
|
|
|
let is_pie_binary = !find_features && is_pie_binary(sess);
|
2017-11-11 15:08:00 +00:00
|
|
|
let trap_unreachable = sess.target.target.options.trap_unreachable;
|
2018-09-13 17:43:15 +00:00
|
|
|
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
|
2017-07-23 15:14:38 +00:00
|
|
|
|
2018-08-12 17:59:18 +00:00
|
|
|
let asm_comments = sess.asm_comments();
|
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
Arc::new(move || {
|
|
|
|
let tm = unsafe {
|
|
|
|
llvm::LLVMRustCreateTargetMachine(
|
|
|
|
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
|
|
|
|
code_model,
|
|
|
|
reloc_model,
|
|
|
|
opt_level,
|
|
|
|
use_softfp,
|
|
|
|
is_pie_binary,
|
|
|
|
ffunction_sections,
|
|
|
|
fdata_sections,
|
2017-11-11 15:08:00 +00:00
|
|
|
trap_unreachable,
|
2017-10-23 03:01:00 +00:00
|
|
|
singlethread,
|
2018-08-12 17:59:18 +00:00
|
|
|
asm_comments,
|
2018-09-13 17:43:15 +00:00
|
|
|
emit_stack_size_section,
|
2017-07-23 15:14:38 +00:00
|
|
|
)
|
|
|
|
};
|
2014-10-29 01:58:46 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
tm.ok_or_else(|| {
|
|
|
|
format!("Could not create LLVM TargetMachine for triple: {}",
|
|
|
|
triple.to_str().unwrap())
|
|
|
|
})
|
2017-07-23 15:14:38 +00:00
|
|
|
})
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Module-specific configuration for `optimize_and_codegen`.
|
2015-07-22 23:22:51 +00:00
|
|
|
pub struct ModuleConfig {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
/// Names of additional optimization passes to run.
|
|
|
|
passes: Vec<String>,
|
|
|
|
/// Some(level) to optimize at a certain level, or None to run
|
|
|
|
/// absolutely no optimizations (used for the metadata module).
|
2017-10-11 18:19:59 +00:00
|
|
|
pub opt_level: Option<llvm::CodeGenOptLevel>,
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2016-03-27 19:42:47 +00:00
|
|
|
/// Some(level) to optimize binary size, or None to not affect program size.
|
|
|
|
opt_size: Option<llvm::CodeGenOptSize>,
|
|
|
|
|
2018-02-19 00:57:12 +00:00
|
|
|
pgo_gen: Option<String>,
|
|
|
|
pgo_use: String,
|
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
// Flags indicating which outputs to produce.
|
2018-08-31 13:18:08 +00:00
|
|
|
pub emit_pre_thin_lto_bc: bool,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
emit_no_opt_bc: bool,
|
|
|
|
emit_bc: bool,
|
2017-10-20 01:44:33 +00:00
|
|
|
emit_bc_compressed: bool,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
emit_lto_bc: bool,
|
|
|
|
emit_ir: bool,
|
|
|
|
emit_asm: bool,
|
|
|
|
emit_obj: bool,
|
|
|
|
// Miscellaneous flags. These are mostly copied from command-line
|
|
|
|
// options.
|
2018-06-12 19:05:37 +00:00
|
|
|
pub verify_llvm_ir: bool,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
no_prepopulate_passes: bool,
|
|
|
|
no_builtins: bool,
|
|
|
|
time_passes: bool,
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
vectorize_loop: bool,
|
|
|
|
vectorize_slp: bool,
|
|
|
|
merge_functions: bool,
|
2015-11-27 19:44:33 +00:00
|
|
|
inline_threshold: Option<usize>,
|
|
|
|
// Instead of creating an object file by doing LLVM codegen, just
|
|
|
|
// make the object file bitcode. Provides easy compatibility with
|
|
|
|
// emscripten's ecc compiler, when used as the linker.
|
|
|
|
obj_is_bitcode: bool,
|
2018-01-15 13:42:44 +00:00
|
|
|
no_integrated_as: bool,
|
2018-03-09 15:25:54 +00:00
|
|
|
embed_bitcode: bool,
|
|
|
|
embed_bitcode_marker: bool,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ModuleConfig {
|
2017-09-14 03:26:39 +00:00
|
|
|
fn new(passes: Vec<String>) -> ModuleConfig {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
ModuleConfig {
|
2017-08-07 05:54:09 +00:00
|
|
|
passes,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
opt_level: None,
|
2016-03-27 19:42:47 +00:00
|
|
|
opt_size: None,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2018-02-19 00:57:12 +00:00
|
|
|
pgo_gen: None,
|
|
|
|
pgo_use: String::new(),
|
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
emit_no_opt_bc: false,
|
2018-08-20 15:13:01 +00:00
|
|
|
emit_pre_thin_lto_bc: false,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
emit_bc: false,
|
2017-10-20 01:44:33 +00:00
|
|
|
emit_bc_compressed: false,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
emit_lto_bc: false,
|
|
|
|
emit_ir: false,
|
|
|
|
emit_asm: false,
|
|
|
|
emit_obj: false,
|
2015-11-27 19:44:33 +00:00
|
|
|
obj_is_bitcode: false,
|
2018-03-09 15:25:54 +00:00
|
|
|
embed_bitcode: false,
|
|
|
|
embed_bitcode_marker: false,
|
2018-01-15 13:42:44 +00:00
|
|
|
no_integrated_as: false,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2018-06-12 19:05:37 +00:00
|
|
|
verify_llvm_ir: false,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
no_prepopulate_passes: false,
|
|
|
|
no_builtins: false,
|
|
|
|
time_passes: false,
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
vectorize_loop: false,
|
|
|
|
vectorize_slp: false,
|
|
|
|
merge_functions: false,
|
2015-11-20 00:07:09 +00:00
|
|
|
inline_threshold: None
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2017-07-26 09:41:34 +00:00
|
|
|
fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
|
2018-06-12 19:05:37 +00:00
|
|
|
self.verify_llvm_ir = sess.verify_llvm_ir();
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
|
2017-10-23 03:01:00 +00:00
|
|
|
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
self.time_passes = sess.time_passes();
|
2015-11-20 00:07:09 +00:00
|
|
|
self.inline_threshold = sess.opts.cg.inline_threshold;
|
2018-07-06 11:58:25 +00:00
|
|
|
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode ||
|
|
|
|
sess.opts.debugging_opts.cross_lang_lto.enabled();
|
2018-03-09 15:25:54 +00:00
|
|
|
let embed_bitcode = sess.target.target.options.embed_bitcode ||
|
2018-07-06 11:58:25 +00:00
|
|
|
sess.opts.debugging_opts.embed_bitcode;
|
2018-03-09 15:25:54 +00:00
|
|
|
if embed_bitcode {
|
|
|
|
match sess.opts.optimize {
|
|
|
|
config::OptLevel::No |
|
|
|
|
config::OptLevel::Less => {
|
|
|
|
self.embed_bitcode_marker = embed_bitcode;
|
|
|
|
}
|
|
|
|
_ => self.embed_bitcode = embed_bitcode,
|
|
|
|
}
|
|
|
|
}
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
|
|
|
|
// Copy what clang does by turning on loop vectorization at O2 and
|
|
|
|
// slp vectorization at O3. Otherwise configure other optimization aspects
|
|
|
|
// of this pass manager builder.
|
2017-02-20 22:20:06 +00:00
|
|
|
// Turn off vectorization for emscripten, as it's not very well supported.
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
|
2015-12-31 03:50:06 +00:00
|
|
|
(sess.opts.optimize == config::OptLevel::Default ||
|
2017-02-20 22:20:06 +00:00
|
|
|
sess.opts.optimize == config::OptLevel::Aggressive) &&
|
|
|
|
!sess.target.target.options.is_like_emscripten;
|
|
|
|
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
|
2017-02-20 22:20:06 +00:00
|
|
|
sess.opts.optimize == config::OptLevel::Aggressive &&
|
|
|
|
!sess.target.target.options.is_like_emscripten;
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
|
2015-12-31 03:50:06 +00:00
|
|
|
self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
|
|
|
|
sess.opts.optimize == config::OptLevel::Aggressive;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
2018-11-02 12:22:48 +00:00
|
|
|
|
|
|
|
pub fn bitcode_needed(&self) -> bool {
|
|
|
|
self.emit_bc || self.obj_is_bitcode
|
|
|
|
|| self.emit_bc_compressed || self.embed_bitcode
|
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
/// Assembler name and command used by codegen when no_integrated_as is enabled
|
|
|
|
struct AssemblerCommand {
|
|
|
|
name: PathBuf,
|
|
|
|
cmd: Command,
|
|
|
|
}
|
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
/// Additional resources used by optimize_and_codegen (not module specific)
|
2017-07-24 11:54:18 +00:00
|
|
|
#[derive(Clone)]
|
2017-07-24 12:21:28 +00:00
|
|
|
pub struct CodegenContext {
|
2018-08-19 13:30:23 +00:00
|
|
|
// Resources needed when running LTO
|
2017-06-15 14:08:18 +00:00
|
|
|
pub time_passes: bool,
|
2018-01-16 23:02:31 +00:00
|
|
|
pub lto: Lto,
|
2017-06-15 14:08:18 +00:00
|
|
|
pub no_landing_pads: bool,
|
2017-07-23 15:14:38 +00:00
|
|
|
pub save_temps: bool,
|
2018-01-04 20:19:23 +00:00
|
|
|
pub fewer_names: bool,
|
2018-02-14 20:08:21 +00:00
|
|
|
pub exported_symbols: Option<Arc<ExportedSymbols>>,
|
2017-07-24 12:21:28 +00:00
|
|
|
pub opts: Arc<config::Options>,
|
2017-06-15 14:08:18 +00:00
|
|
|
pub crate_types: Vec<config::CrateType>,
|
|
|
|
pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
|
2017-09-14 03:26:39 +00:00
|
|
|
output_filenames: Arc<OutputFilenames>,
|
|
|
|
regular_module_config: Arc<ModuleConfig>,
|
|
|
|
metadata_module_config: Arc<ModuleConfig>,
|
|
|
|
allocator_module_config: Arc<ModuleConfig>,
|
2018-06-27 14:57:25 +00:00
|
|
|
pub tm_factory: Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>,
|
2017-10-17 20:08:13 +00:00
|
|
|
pub msvc_imps_needed: bool,
|
|
|
|
pub target_pointer_width: String,
|
2018-07-26 17:41:10 +00:00
|
|
|
debuginfo: config::DebugInfo,
|
2017-09-14 03:26:39 +00:00
|
|
|
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
// Number of cgus excluding the allocator/metadata modules
|
|
|
|
pub total_cgus: usize,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
// Handler to use for diagnostics produced during codegen.
|
2017-07-24 11:54:18 +00:00
|
|
|
pub diag_emitter: SharedEmitter,
|
2015-04-08 19:52:58 +00:00
|
|
|
// LLVM passes added by plugins.
|
2017-06-15 14:08:18 +00:00
|
|
|
pub plugin_passes: Vec<String>,
|
2014-09-12 15:17:58 +00:00
|
|
|
// LLVM optimizations for which we want to print remarks.
|
2017-06-15 14:08:18 +00:00
|
|
|
pub remark: Passes,
|
2015-10-26 20:03:03 +00:00
|
|
|
// Worker thread number
|
2017-06-15 14:08:18 +00:00
|
|
|
pub worker: usize,
|
2016-08-11 23:02:39 +00:00
|
|
|
// The incremental compilation session directory, or None if we are not
|
|
|
|
// compiling incrementally
|
2017-06-15 14:08:18 +00:00
|
|
|
pub incr_comp_session_dir: Option<PathBuf>,
|
2018-09-18 14:33:24 +00:00
|
|
|
// Used to update CGU re-use information during the thinlto phase.
|
|
|
|
pub cgu_reuse_tracker: CguReuseTracker,
|
2017-06-15 14:08:18 +00:00
|
|
|
// Channel back to the main control thread to send messages to
|
2018-07-11 10:49:11 +00:00
|
|
|
coordinator_send: Sender<Box<dyn Any + Send>>,
|
2017-07-27 11:02:31 +00:00
|
|
|
// A reference to the TimeGraph so we can register timings. None means that
|
|
|
|
// measuring is disabled.
|
|
|
|
time_graph: Option<TimeGraph>,
|
2018-01-15 13:42:44 +00:00
|
|
|
// The assembler command if no_integrated_as option is enabled, None otherwise
|
|
|
|
assembler_cmd: Option<Arc<AssemblerCommand>>,
|
2017-07-24 11:54:18 +00:00
|
|
|
}
|
2017-07-21 15:15:18 +00:00
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
impl CodegenContext {
|
2017-07-23 15:14:38 +00:00
|
|
|
pub fn create_diag_handler(&self) -> Handler {
|
2017-07-24 11:54:18 +00:00
|
|
|
Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
|
|
|
|
}
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2017-12-28 09:11:26 +00:00
|
|
|
pub(crate) fn config(&self, kind: ModuleKind) -> &ModuleConfig {
|
2017-09-14 03:26:39 +00:00
|
|
|
match kind {
|
|
|
|
ModuleKind::Regular => &self.regular_module_config,
|
|
|
|
ModuleKind::Metadata => &self.metadata_module_config,
|
|
|
|
ModuleKind::Allocator => &self.allocator_module_config,
|
|
|
|
}
|
|
|
|
}
|
2017-07-23 15:14:38 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub(crate) fn save_temp_bitcode(&self, module: &ModuleCodegen, name: &str) {
|
2017-07-23 15:14:38 +00:00
|
|
|
if !self.save_temps {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
let ext = format!("{}.bc", name);
|
2018-05-08 13:10:16 +00:00
|
|
|
let cgu = Some(&module.name[..]);
|
2017-07-23 15:14:38 +00:00
|
|
|
let path = self.output_filenames.temp_path_ext(&ext, cgu);
|
|
|
|
let cstr = path2cstr(&path);
|
2018-08-20 15:13:01 +00:00
|
|
|
let llmod = module.module_llvm.llmod();
|
2017-07-23 15:14:38 +00:00
|
|
|
llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 23:20:51 +00:00
|
|
|
pub struct DiagnosticHandlers<'a> {
|
2018-07-14 23:52:45 +00:00
|
|
|
data: *mut (&'a CodegenContext, &'a Handler),
|
2018-06-27 14:57:25 +00:00
|
|
|
llcx: &'a llvm::Context,
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DiagnosticHandlers<'a> {
|
2018-07-17 23:20:51 +00:00
|
|
|
pub fn new(cgcx: &'a CodegenContext,
|
|
|
|
handler: &'a Handler,
|
|
|
|
llcx: &'a llvm::Context) -> Self {
|
2018-07-14 23:52:45 +00:00
|
|
|
let data = Box::into_raw(Box::new((cgcx, handler)));
|
2017-07-23 15:14:38 +00:00
|
|
|
unsafe {
|
2018-07-14 23:52:45 +00:00
|
|
|
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
|
|
|
|
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data as *mut _);
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
2018-07-14 23:52:45 +00:00
|
|
|
DiagnosticHandlers { data, llcx }
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
2014-09-12 15:17:58 +00:00
|
|
|
}
|
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
impl<'a> Drop for DiagnosticHandlers<'a> {
|
|
|
|
fn drop(&mut self) {
|
2018-07-14 23:52:45 +00:00
|
|
|
use std::ptr::null_mut;
|
2017-07-23 15:14:38 +00:00
|
|
|
unsafe {
|
2018-07-14 23:52:45 +00:00
|
|
|
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
|
|
|
|
llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
|
|
|
|
drop(Box::from_raw(self.data));
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-12 15:17:58 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
|
2015-05-26 08:34:50 +00:00
|
|
|
msg: &'b str,
|
|
|
|
cookie: c_uint) {
|
2018-10-06 09:50:00 +00:00
|
|
|
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
|
2014-09-27 08:33:36 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 10:59:41 +00:00
|
|
|
unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic,
|
2015-01-22 18:43:39 +00:00
|
|
|
user: *const c_void,
|
|
|
|
cookie: c_uint) {
|
2017-07-23 15:14:38 +00:00
|
|
|
if user.is_null() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let (cgcx, _) = *(user as *const (&CodegenContext, &Handler));
|
2015-01-22 18:43:39 +00:00
|
|
|
|
2016-08-01 23:35:09 +00:00
|
|
|
let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s))
|
2015-01-22 18:43:39 +00:00
|
|
|
.expect("non-UTF8 SMDiagnostic");
|
|
|
|
|
2017-03-24 08:31:26 +00:00
|
|
|
report_inline_asm(cgcx, &msg, cookie);
|
2015-01-22 18:43:39 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 10:59:41 +00:00
|
|
|
unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
|
2017-07-23 15:14:38 +00:00
|
|
|
if user.is_null() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let (cgcx, diag_handler) = *(user as *const (&CodegenContext, &Handler));
|
2014-09-12 15:17:58 +00:00
|
|
|
|
|
|
|
match llvm::diagnostic::Diagnostic::unpack(info) {
|
2015-01-22 18:43:39 +00:00
|
|
|
llvm::diagnostic::InlineAsm(inline) => {
|
|
|
|
report_inline_asm(cgcx,
|
2016-02-09 20:24:11 +00:00
|
|
|
&llvm::twine_to_string(inline.message),
|
2015-01-22 18:43:39 +00:00
|
|
|
inline.cookie);
|
|
|
|
}
|
|
|
|
|
2014-09-12 15:17:58 +00:00
|
|
|
llvm::diagnostic::Optimization(opt) => {
|
|
|
|
let enabled = match cgcx.remark {
|
2018-07-26 17:22:14 +00:00
|
|
|
Passes::All => true,
|
|
|
|
Passes::Some(ref v) => v.iter().any(|s| *s == opt.pass_name),
|
2014-09-12 15:17:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if enabled {
|
2017-07-24 11:54:18 +00:00
|
|
|
diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}",
|
2015-12-20 21:00:43 +00:00
|
|
|
opt.kind.describe(),
|
2016-11-28 14:15:51 +00:00
|
|
|
opt.pass_name,
|
2017-07-21 12:29:23 +00:00
|
|
|
opt.filename,
|
|
|
|
opt.line,
|
|
|
|
opt.column,
|
2016-11-24 16:33:47 +00:00
|
|
|
opt.message));
|
2014-09-12 15:17:58 +00:00
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
2018-07-17 23:20:51 +00:00
|
|
|
llvm::diagnostic::PGO(diagnostic_ref) |
|
|
|
|
llvm::diagnostic::Linker(diagnostic_ref) => {
|
2018-03-12 17:11:59 +00:00
|
|
|
let msg = llvm::build_string(|s| {
|
|
|
|
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
|
2018-07-17 23:20:51 +00:00
|
|
|
}).expect("non-UTF8 diagnostic");
|
2018-03-12 20:18:01 +00:00
|
|
|
diag_handler.warn(&msg);
|
2018-03-12 17:11:59 +00:00
|
|
|
}
|
|
|
|
llvm::diagnostic::UnknownDiagnostic(..) => {},
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unsafe due to LLVM calls.
|
2017-07-23 15:14:38 +00:00
|
|
|
unsafe fn optimize(cgcx: &CodegenContext,
|
|
|
|
diag_handler: &Handler,
|
2018-05-08 13:10:16 +00:00
|
|
|
module: &ModuleCodegen,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
config: &ModuleConfig,
|
|
|
|
timeline: &mut Timeline)
|
2017-07-23 15:14:38 +00:00
|
|
|
-> Result<(), FatalError>
|
2017-06-15 14:08:18 +00:00
|
|
|
{
|
2018-08-20 15:13:01 +00:00
|
|
|
let llmod = module.module_llvm.llmod();
|
|
|
|
let llcx = &*module.module_llvm.llcx;
|
|
|
|
let tm = &*module.module_llvm.tm;
|
2017-07-23 15:14:38 +00:00
|
|
|
let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
|
2014-09-12 15:17:58 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let module_name = module.name.clone();
|
2017-07-25 15:26:24 +00:00
|
|
|
let module_name = Some(&module_name[..]);
|
2016-05-14 00:48:32 +00:00
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
if config.emit_no_opt_bc {
|
2017-09-14 03:26:39 +00:00
|
|
|
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
|
2015-02-27 05:00:43 +00:00
|
|
|
let out = path2cstr(&out);
|
2014-11-25 21:28:35 +00:00
|
|
|
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 23:22:51 +00:00
|
|
|
if config.opt_level.is_some() {
|
|
|
|
// Create the two optimizing pass managers. These mirror what clang
|
|
|
|
// does, and are by populated by LLVM's default PassManagerBuilder.
|
|
|
|
// Each manager has a different set of passes, but they also share
|
|
|
|
// some common passes.
|
|
|
|
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
|
|
|
|
let mpm = llvm::LLVMCreatePassManager();
|
|
|
|
|
2018-07-17 11:17:47 +00:00
|
|
|
{
|
|
|
|
// If we're verifying or linting, add them to the function pass
|
|
|
|
// manager.
|
|
|
|
let addpass = |pass_name: &str| {
|
2018-08-07 14:04:34 +00:00
|
|
|
let pass_name = SmallCStr::new(pass_name);
|
2018-07-17 11:17:47 +00:00
|
|
|
let pass = match llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) {
|
|
|
|
Some(pass) => pass,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
let pass_manager = match llvm::LLVMRustPassKind(pass) {
|
|
|
|
llvm::PassKind::Function => &*fpm,
|
|
|
|
llvm::PassKind::Module => &*mpm,
|
|
|
|
llvm::PassKind::Other => {
|
|
|
|
diag_handler.err("Encountered LLVM pass kind we can't handle");
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
};
|
|
|
|
llvm::LLVMRustAddPass(pass_manager, pass);
|
|
|
|
true
|
2016-01-25 01:22:24 +00:00
|
|
|
};
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-07-17 11:17:47 +00:00
|
|
|
if config.verify_llvm_ir { assert!(addpass("verify")); }
|
2018-05-30 20:46:56 +00:00
|
|
|
|
|
|
|
// Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
|
|
|
|
// to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
|
|
|
|
// we'll get errors in LLVM.
|
2018-11-02 12:22:48 +00:00
|
|
|
let using_thin_buffers = config.bitcode_needed();
|
2018-05-30 20:46:56 +00:00
|
|
|
let mut have_name_anon_globals_pass = false;
|
2018-07-17 11:17:47 +00:00
|
|
|
if !config.no_prepopulate_passes {
|
|
|
|
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
|
|
|
|
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
|
|
|
|
let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
|
2018-08-03 15:04:53 +00:00
|
|
|
let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal ||
|
|
|
|
(cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled());
|
2018-05-30 20:46:56 +00:00
|
|
|
have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
|
|
|
|
if using_thin_buffers && !prepare_for_thin_lto {
|
|
|
|
assert!(addpass("name-anon-globals"));
|
|
|
|
have_name_anon_globals_pass = true;
|
|
|
|
}
|
2018-07-17 11:17:47 +00:00
|
|
|
with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
|
|
|
|
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
|
|
|
|
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
|
|
|
|
})
|
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-07-17 11:17:47 +00:00
|
|
|
for pass in &config.passes {
|
|
|
|
if !addpass(pass) {
|
2018-10-06 09:37:28 +00:00
|
|
|
diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass));
|
2018-07-17 11:17:47 +00:00
|
|
|
}
|
2018-05-30 20:46:56 +00:00
|
|
|
if pass == "name-anon-globals" {
|
|
|
|
have_name_anon_globals_pass = true;
|
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 11:17:47 +00:00
|
|
|
for pass in &cgcx.plugin_passes {
|
|
|
|
if !addpass(pass) {
|
|
|
|
diag_handler.err(&format!("a plugin asked for LLVM pass \
|
2018-10-06 09:37:28 +00:00
|
|
|
`{}` but LLVM does not \
|
|
|
|
recognize it", pass));
|
2018-07-17 11:17:47 +00:00
|
|
|
}
|
2018-05-30 20:46:56 +00:00
|
|
|
if pass == "name-anon-globals" {
|
|
|
|
have_name_anon_globals_pass = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if using_thin_buffers && !have_name_anon_globals_pass {
|
|
|
|
// As described above, this will probably cause an error in LLVM
|
|
|
|
if config.no_prepopulate_passes {
|
|
|
|
diag_handler.err("The current compilation is going to use thin LTO buffers \
|
2018-10-06 09:37:28 +00:00
|
|
|
without running LLVM's NameAnonGlobals pass. \
|
|
|
|
This will likely cause errors in LLVM. Consider adding \
|
|
|
|
-C passes=name-anon-globals to the compiler command line.");
|
2018-05-30 20:46:56 +00:00
|
|
|
} else {
|
|
|
|
bug!("We are using thin LTO buffers without running the NameAnonGlobals pass. \
|
2018-10-06 09:37:28 +00:00
|
|
|
This will likely cause errors in LLVM and should never happen.");
|
2018-05-30 20:46:56 +00:00
|
|
|
}
|
2015-04-08 19:52:58 +00:00
|
|
|
}
|
2015-07-22 23:22:51 +00:00
|
|
|
}
|
2015-04-08 19:52:58 +00:00
|
|
|
|
2017-07-24 11:54:18 +00:00
|
|
|
diag_handler.abort_if_errors();
|
2015-04-08 19:52:58 +00:00
|
|
|
|
2015-07-22 23:22:51 +00:00
|
|
|
// Finally, run the actual optimization passes
|
2017-12-03 13:21:23 +00:00
|
|
|
time_ext(config.time_passes,
|
|
|
|
None,
|
|
|
|
&format!("llvm function passes [{}]", module_name.unwrap()),
|
|
|
|
|| {
|
|
|
|
llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
|
|
|
|
});
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
timeline.record("fpm");
|
2017-12-03 13:21:23 +00:00
|
|
|
time_ext(config.time_passes,
|
|
|
|
None,
|
|
|
|
&format!("llvm module passes [{}]", module_name.unwrap()),
|
|
|
|
|| {
|
2018-10-23 07:59:14 +00:00
|
|
|
llvm::LLVMRunPassManager(mpm, llmod)
|
2017-12-03 13:21:23 +00:00
|
|
|
});
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2015-07-22 23:22:51 +00:00
|
|
|
// Deallocate managers that we're now done with
|
|
|
|
llvm::LLVMDisposePassManager(fpm);
|
|
|
|
llvm::LLVMDisposePassManager(mpm);
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
fn generate_lto_work(cgcx: &CodegenContext,
|
2018-08-20 15:13:01 +00:00
|
|
|
modules: Vec<ModuleCodegen>,
|
2018-08-31 13:18:08 +00:00
|
|
|
import_only_modules: Vec<(SerializedModule, WorkProduct)>)
|
2017-07-23 15:14:38 +00:00
|
|
|
-> Vec<(WorkItem, u64)>
|
|
|
|
{
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
|
2018-05-08 13:10:16 +00:00
|
|
|
tg.start(CODEGEN_WORKER_TIMELINE,
|
|
|
|
CODEGEN_WORK_PACKAGE_KIND,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
"generate lto")
|
|
|
|
}).unwrap_or(Timeline::noop());
|
2018-08-31 13:18:08 +00:00
|
|
|
let (lto_modules, copy_jobs) = lto::run(cgcx, modules, import_only_modules, &mut timeline)
|
2018-01-21 11:47:58 +00:00
|
|
|
.unwrap_or_else(|e| e.raise());
|
2017-07-23 15:14:38 +00:00
|
|
|
|
2018-08-31 13:18:08 +00:00
|
|
|
let lto_modules = lto_modules.into_iter().map(|module| {
|
2017-07-23 15:14:38 +00:00
|
|
|
let cost = module.cost();
|
|
|
|
(WorkItem::LTO(module), cost)
|
2018-08-31 13:18:08 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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()
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn codegen(cgcx: &CodegenContext,
|
|
|
|
diag_handler: &Handler,
|
2018-05-08 13:10:16 +00:00
|
|
|
module: ModuleCodegen,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
config: &ModuleConfig,
|
|
|
|
timeline: &mut Timeline)
|
2017-07-23 15:14:38 +00:00
|
|
|
-> Result<CompiledModule, FatalError>
|
|
|
|
{
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
timeline.record("codegen");
|
2014-12-09 18:44:51 +00:00
|
|
|
{
|
2018-08-20 15:13:01 +00:00
|
|
|
let llmod = module.module_llvm.llmod();
|
|
|
|
let llcx = &*module.module_llvm.llcx;
|
|
|
|
let tm = &*module.module_llvm.tm;
|
2018-06-27 14:57:25 +00:00
|
|
|
let module_name = module.name.clone();
|
|
|
|
let module_name = Some(&module_name[..]);
|
|
|
|
let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
|
2017-10-20 01:44:33 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if cgcx.msvc_imps_needed {
|
|
|
|
create_msvc_imps(cgcx, llcx, llmod);
|
2017-10-20 01:44:33 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
// A codegen-specific pass manager is used to generate object
|
|
|
|
// files for an LLVM module.
|
|
|
|
//
|
|
|
|
// Apparently each of these pass managers is a one-shot kind of
|
|
|
|
// thing, so we create a new one for each type of output. The
|
|
|
|
// pass manager passed to the closure should be ensured to not
|
|
|
|
// escape the closure itself, and the manager should only be
|
|
|
|
// used once.
|
2018-07-17 11:17:47 +00:00
|
|
|
unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
|
2018-10-06 09:37:28 +00:00
|
|
|
llmod: &'ll llvm::Module,
|
|
|
|
no_builtins: bool,
|
|
|
|
f: F) -> R
|
2018-07-17 11:17:47 +00:00
|
|
|
where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
|
2018-06-27 14:57:25 +00:00
|
|
|
{
|
|
|
|
let cpm = llvm::LLVMCreatePassManager();
|
|
|
|
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
|
|
|
|
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
|
|
|
f(cpm)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have the integrated assembler, then we need to emit asm
|
|
|
|
// from LLVM and use `gcc` to create the object file.
|
|
|
|
let asm_to_obj = config.emit_obj && config.no_integrated_as;
|
|
|
|
|
|
|
|
// Change what we write and cleanup based on whether obj files are
|
|
|
|
// just llvm bitcode. In that case write bitcode, and possibly
|
|
|
|
// delete the bitcode if it wasn't requested. Don't generate the
|
|
|
|
// machine code, instead copy the .o file from the .bc
|
|
|
|
let write_bc = config.emit_bc || config.obj_is_bitcode;
|
|
|
|
let rm_bc = !config.emit_bc && config.obj_is_bitcode;
|
|
|
|
let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj;
|
|
|
|
let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
|
|
|
|
|
|
|
|
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
|
|
|
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
|
|
|
|
|
|
|
|
|
|
|
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
|
2018-11-01 20:06:50 +00:00
|
|
|
let thin = ThinBuffer::new(llmod);
|
|
|
|
let data = thin.data();
|
2018-06-27 14:57:25 +00:00
|
|
|
timeline.record("make-bc");
|
2018-03-09 15:25:54 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if write_bc {
|
|
|
|
if let Err(e) = fs::write(&bc_out, data) {
|
|
|
|
diag_handler.err(&format!("failed to write bytecode: {}", e));
|
|
|
|
}
|
|
|
|
timeline.record("write-bc");
|
2017-10-20 01:44:33 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if config.embed_bitcode {
|
|
|
|
embed_bitcode(cgcx, llcx, llmod, Some(data));
|
|
|
|
timeline.record("embed-bc");
|
|
|
|
}
|
2017-06-29 14:52:43 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if config.emit_bc_compressed {
|
|
|
|
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
|
2018-08-14 15:55:22 +00:00
|
|
|
let data = bytecode::encode(&module.name, data);
|
2018-06-27 14:57:25 +00:00
|
|
|
if let Err(e) = fs::write(&dst, data) {
|
|
|
|
diag_handler.err(&format!("failed to write bytecode: {}", e));
|
|
|
|
}
|
|
|
|
timeline.record("compress-bc");
|
|
|
|
}
|
|
|
|
} else if config.embed_bitcode_marker {
|
|
|
|
embed_bitcode(cgcx, llcx, llmod, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|
|
|
|
|| -> Result<(), FatalError> {
|
|
|
|
if config.emit_ir {
|
|
|
|
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
|
|
|
|
let out = path2cstr(&out);
|
|
|
|
|
|
|
|
extern "C" fn demangle_callback(input_ptr: *const c_char,
|
|
|
|
input_len: size_t,
|
|
|
|
output_ptr: *mut c_char,
|
|
|
|
output_len: size_t) -> size_t {
|
|
|
|
let input = unsafe {
|
|
|
|
slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
|
|
|
|
};
|
2017-06-29 14:52:43 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
let input = match str::from_utf8(input) {
|
|
|
|
Ok(s) => s,
|
|
|
|
Err(_) => return 0,
|
|
|
|
};
|
2017-06-29 14:52:43 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
let output = unsafe {
|
|
|
|
slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
|
|
|
|
};
|
|
|
|
let mut cursor = io::Cursor::new(output);
|
|
|
|
|
|
|
|
let demangled = match rustc_demangle::try_demangle(input) {
|
|
|
|
Ok(d) => d,
|
|
|
|
Err(_) => return 0,
|
|
|
|
};
|
2017-06-29 14:52:43 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if let Err(_) = write!(cursor, "{:#}", demangled) {
|
|
|
|
// Possible only if provided buffer is not big enough
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor.position() as size_t
|
2017-06-29 14:52:43 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
|
|
|
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
|
|
|
|
llvm::LLVMDisposePassManager(cpm);
|
|
|
|
});
|
|
|
|
timeline.record("ir");
|
2017-06-29 14:52:43 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if config.emit_asm || asm_to_obj {
|
|
|
|
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
// We can't use the same module for asm and binary output, because that triggers
|
|
|
|
// various errors like invalid IR or broken binaries, so we might have to clone the
|
|
|
|
// module to produce the asm output
|
|
|
|
let llmod = if config.emit_obj {
|
|
|
|
llvm::LLVMCloneModule(llmod)
|
|
|
|
} else {
|
|
|
|
llmod
|
|
|
|
};
|
|
|
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
|
|
|
write_output_file(diag_handler, tm, cpm, llmod, &path,
|
2018-10-06 09:37:28 +00:00
|
|
|
llvm::FileType::AssemblyFile)
|
2018-06-27 14:57:25 +00:00
|
|
|
})?;
|
|
|
|
timeline.record("asm");
|
2015-12-18 00:24:40 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if write_obj {
|
|
|
|
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
|
|
|
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
|
2018-10-06 09:37:28 +00:00
|
|
|
llvm::FileType::ObjectFile)
|
2018-06-27 14:57:25 +00:00
|
|
|
})?;
|
|
|
|
timeline.record("obj");
|
|
|
|
} else if asm_to_obj {
|
|
|
|
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
|
|
|
run_assembler(cgcx, diag_handler, &assembly, &obj_out);
|
|
|
|
timeline.record("asm_to_obj");
|
|
|
|
|
|
|
|
if !config.emit_asm && !cgcx.save_temps {
|
|
|
|
drop(fs::remove_file(&assembly));
|
|
|
|
}
|
2018-01-15 13:42:44 +00:00
|
|
|
}
|
2017-06-15 14:08:18 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
Ok(())
|
|
|
|
})?;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if copy_bc_to_obj {
|
|
|
|
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
|
|
|
|
if let Err(e) = link_or_copy(&bc_out, &obj_out) {
|
|
|
|
diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
|
|
|
|
}
|
2015-11-27 19:44:33 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
if rm_bc {
|
|
|
|
debug!("removing_bitcode {:?}", bc_out);
|
|
|
|
if let Err(e) = fs::remove_file(&bc_out) {
|
|
|
|
diag_handler.err(&format!("failed to remove bitcode: {}", e));
|
|
|
|
}
|
2015-11-27 19:44:33 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
drop(handlers);
|
|
|
|
}
|
2018-05-08 13:10:16 +00:00
|
|
|
Ok(module.into_compiled_module(config.emit_obj,
|
2017-07-23 15:14:38 +00:00
|
|
|
config.emit_bc,
|
2017-10-20 01:44:33 +00:00
|
|
|
config.emit_bc_compressed,
|
2017-07-23 15:14:38 +00:00
|
|
|
&cgcx.output_filenames))
|
2016-06-30 20:32:13 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 15:25:54 +00:00
|
|
|
/// Embed the bitcode of an LLVM module in the LLVM module itself.
|
|
|
|
///
|
|
|
|
/// This is done primarily for iOS where it appears to be standard to compile C
|
|
|
|
/// code at least with `-fembed-bitcode` which creates two sections in the
|
|
|
|
/// executable:
|
|
|
|
///
|
|
|
|
/// * __LLVM,__bitcode
|
|
|
|
/// * __LLVM,__cmdline
|
|
|
|
///
|
|
|
|
/// It appears *both* of these sections are necessary to get the linker to
|
|
|
|
/// recognize what's going on. For us though we just always throw in an empty
|
|
|
|
/// cmdline section.
|
|
|
|
///
|
|
|
|
/// Furthermore debug/O1 builds don't actually embed bitcode but rather just
|
|
|
|
/// embed an empty section.
|
|
|
|
///
|
|
|
|
/// Basically all of this is us attempting to follow in the footsteps of clang
|
|
|
|
/// on iOS. See #35968 for lots more info.
|
|
|
|
unsafe fn embed_bitcode(cgcx: &CodegenContext,
|
2018-06-27 14:57:25 +00:00
|
|
|
llcx: &llvm::Context,
|
|
|
|
llmod: &llvm::Module,
|
2018-03-09 15:25:54 +00:00
|
|
|
bitcode: Option<&[u8]>) {
|
2018-08-28 15:03:46 +00:00
|
|
|
let llconst = CodegenCx::c_bytes_in_context(llcx, bitcode.unwrap_or(&[]));
|
2018-03-09 15:25:54 +00:00
|
|
|
let llglobal = llvm::LLVMAddGlobal(
|
|
|
|
llmod,
|
2018-08-28 15:03:46 +00:00
|
|
|
CodegenCx::val_ty(llconst),
|
2018-03-09 15:25:54 +00:00
|
|
|
"rustc.embedded.module\0".as_ptr() as *const _,
|
|
|
|
);
|
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2018-04-17 11:15:27 +00:00
|
|
|
|
|
|
|
let is_apple = cgcx.opts.target_triple.triple().contains("-ios") ||
|
|
|
|
cgcx.opts.target_triple.triple().contains("-darwin");
|
|
|
|
|
|
|
|
let section = if is_apple {
|
2018-03-09 15:25:54 +00:00
|
|
|
"__LLVM,__bitcode\0"
|
|
|
|
} else {
|
|
|
|
".llvmbc\0"
|
|
|
|
};
|
|
|
|
llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
|
|
|
|
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
2018-04-16 12:27:37 +00:00
|
|
|
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
2018-03-09 15:25:54 +00:00
|
|
|
|
2018-08-28 15:03:46 +00:00
|
|
|
let llconst = CodegenCx::c_bytes_in_context(llcx, &[]);
|
2018-03-09 15:25:54 +00:00
|
|
|
let llglobal = llvm::LLVMAddGlobal(
|
|
|
|
llmod,
|
2018-08-28 15:03:46 +00:00
|
|
|
CodegenCx::val_ty(llconst),
|
2018-03-09 15:25:54 +00:00
|
|
|
"rustc.embedded.cmdline\0".as_ptr() as *const _,
|
|
|
|
);
|
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2018-04-17 11:15:27 +00:00
|
|
|
let section = if is_apple {
|
2018-03-09 15:25:54 +00:00
|
|
|
"__LLVM,__cmdline\0"
|
|
|
|
} else {
|
|
|
|
".llvmcmd\0"
|
|
|
|
};
|
|
|
|
llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
|
|
|
|
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
|
|
|
}
|
|
|
|
|
2017-12-28 09:11:26 +00:00
|
|
|
pub(crate) struct CompiledModules {
|
2017-07-25 15:26:24 +00:00
|
|
|
pub modules: Vec<CompiledModule>,
|
|
|
|
pub metadata_module: CompiledModule,
|
|
|
|
pub allocator_module: Option<CompiledModule>,
|
2017-07-21 15:15:18 +00:00
|
|
|
}
|
|
|
|
|
2017-07-26 08:48:54 +00:00
|
|
|
fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
|
2018-07-26 17:13:11 +00:00
|
|
|
sess.crate_types.borrow().contains(&config::CrateType::Rlib) &&
|
2017-07-26 08:48:54 +00:00
|
|
|
sess.opts.output_types.contains_key(&OutputType::Exe)
|
|
|
|
}
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
fn need_pre_thin_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
|
|
|
|
if sess.opts.incremental.is_none() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
match sess.lto() {
|
|
|
|
Lto::Fat |
|
|
|
|
Lto::No => false,
|
|
|
|
Lto::Thin |
|
|
|
|
Lto::ThinLocal => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub fn start_async_codegen(tcx: TyCtxt,
|
2018-10-06 09:37:28 +00:00
|
|
|
time_graph: Option<TimeGraph>,
|
|
|
|
metadata: EncodedMetadata,
|
|
|
|
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
|
|
|
total_cgus: usize)
|
|
|
|
-> OngoingCodegen {
|
2017-09-13 20:22:20 +00:00
|
|
|
let sess = tcx.sess;
|
|
|
|
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
2018-08-18 10:08:06 +00:00
|
|
|
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
|
2017-09-13 20:22:20 +00:00
|
|
|
let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
|
|
|
|
let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
|
|
|
|
"windows_subsystem");
|
|
|
|
let windows_subsystem = subsystem.map(|subsystem| {
|
|
|
|
if subsystem != "windows" && subsystem != "console" {
|
|
|
|
tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \
|
|
|
|
`windows` and `console` are allowed",
|
|
|
|
subsystem));
|
|
|
|
}
|
|
|
|
subsystem.to_string()
|
|
|
|
});
|
|
|
|
|
|
|
|
let linker_info = LinkerInfo::new(tcx);
|
|
|
|
let crate_info = CrateInfo::new(tcx);
|
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
// Figure out what we actually need to build.
|
2017-09-14 03:26:39 +00:00
|
|
|
let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
|
|
|
|
let mut metadata_config = ModuleConfig::new(vec![]);
|
|
|
|
let mut allocator_config = ModuleConfig::new(vec![]);
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2016-12-30 04:28:11 +00:00
|
|
|
if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
|
|
|
|
match *sanitizer {
|
|
|
|
Sanitizer::Address => {
|
|
|
|
modules_config.passes.push("asan".to_owned());
|
|
|
|
modules_config.passes.push("asan-module".to_owned());
|
|
|
|
}
|
|
|
|
Sanitizer::Memory => {
|
|
|
|
modules_config.passes.push("msan".to_owned())
|
|
|
|
}
|
|
|
|
Sanitizer::Thread => {
|
|
|
|
modules_config.passes.push("tsan".to_owned())
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-13 09:57:50 +00:00
|
|
|
if sess.opts.debugging_opts.profile {
|
|
|
|
modules_config.passes.push("insert-gcov-profiling".to_owned())
|
|
|
|
}
|
|
|
|
|
2018-03-12 20:11:25 +00:00
|
|
|
modules_config.pgo_gen = sess.opts.debugging_opts.pgo_gen.clone();
|
|
|
|
modules_config.pgo_use = sess.opts.debugging_opts.pgo_use.clone();
|
2018-02-19 00:57:12 +00:00
|
|
|
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
|
2016-03-27 19:42:47 +00:00
|
|
|
modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
|
|
|
// Save all versions of the bytecode if we're saving our temporaries.
|
|
|
|
if sess.opts.cg.save_temps {
|
|
|
|
modules_config.emit_no_opt_bc = true;
|
2018-08-20 15:13:01 +00:00
|
|
|
modules_config.emit_pre_thin_lto_bc = true;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
modules_config.emit_bc = true;
|
|
|
|
modules_config.emit_lto_bc = true;
|
|
|
|
metadata_config.emit_bc = true;
|
2017-06-03 21:54:08 +00:00
|
|
|
allocator_config.emit_bc = true;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:44:33 +00:00
|
|
|
// Emit compressed bitcode files for the crate if we're emitting an rlib.
|
|
|
|
// Whenever an rlib is created, the bitcode is inserted into the archive in
|
|
|
|
// order to allow LTO against it.
|
2017-07-26 08:48:54 +00:00
|
|
|
if need_crate_bitcode_for_rlib(sess) {
|
2017-10-20 01:44:33 +00:00
|
|
|
modules_config.emit_bc_compressed = true;
|
|
|
|
allocator_config.emit_bc_compressed = true;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
modules_config.emit_pre_thin_lto_bc =
|
|
|
|
need_pre_thin_lto_bitcode_for_incr_comp(sess);
|
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
|
|
|
|
tcx.sess.target.target.options.no_integrated_as;
|
|
|
|
|
|
|
|
for output_type in sess.opts.output_types.keys() {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
match *output_type {
|
2016-12-23 06:39:20 +00:00
|
|
|
OutputType::Bitcode => { modules_config.emit_bc = true; }
|
|
|
|
OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
|
2015-09-30 17:08:37 +00:00
|
|
|
OutputType::Assembly => {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
modules_config.emit_asm = true;
|
|
|
|
// If we're not using the LLVM assembler, this function
|
|
|
|
// could be invoked specially with output_type_assembly, so
|
|
|
|
// in this case we still want the metadata object file.
|
2015-09-30 17:08:37 +00:00
|
|
|
if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
metadata_config.emit_obj = true;
|
2017-06-03 21:54:08 +00:00
|
|
|
allocator_config.emit_obj = true;
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
2016-12-23 06:39:20 +00:00
|
|
|
}
|
|
|
|
OutputType::Object => { modules_config.emit_obj = true; }
|
|
|
|
OutputType::Metadata => { metadata_config.emit_obj = true; }
|
2015-09-30 17:08:37 +00:00
|
|
|
OutputType::Exe => {
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
modules_config.emit_obj = true;
|
|
|
|
metadata_config.emit_obj = true;
|
2017-06-03 21:54:08 +00:00
|
|
|
allocator_config.emit_obj = true;
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
},
|
2017-02-16 21:59:09 +00:00
|
|
|
OutputType::Mir => {}
|
2015-09-30 17:08:37 +00:00
|
|
|
OutputType::DepInfo => {}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-26 09:41:34 +00:00
|
|
|
modules_config.set_flags(sess, no_builtins);
|
|
|
|
metadata_config.set_flags(sess, no_builtins);
|
|
|
|
allocator_config.set_flags(sess, no_builtins);
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-31 12:51:47 +00:00
|
|
|
// Exclude metadata and allocator modules from time_passes output, since
|
|
|
|
// they throw off the "LLVM passes" measurement.
|
|
|
|
metadata_config.time_passes = false;
|
|
|
|
allocator_config.time_passes = false;
|
|
|
|
|
2017-07-24 12:51:00 +00:00
|
|
|
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
2018-05-08 13:10:16 +00:00
|
|
|
let (codegen_worker_send, codegen_worker_receive) = channel();
|
2017-07-24 12:51:00 +00:00
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
let coordinator_thread = start_executing_work(tcx,
|
2017-08-28 22:55:32 +00:00
|
|
|
&crate_info,
|
2017-07-24 12:51:00 +00:00
|
|
|
shared_emitter,
|
2018-05-08 13:10:16 +00:00
|
|
|
codegen_worker_send,
|
2017-07-24 13:50:42 +00:00
|
|
|
coordinator_receive,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
total_cgus,
|
2018-04-23 15:00:08 +00:00
|
|
|
sess.jobserver.clone(),
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph.clone(),
|
2017-09-14 03:26:39 +00:00
|
|
|
Arc::new(modules_config),
|
|
|
|
Arc::new(metadata_config),
|
|
|
|
Arc::new(allocator_config));
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
OngoingCodegen {
|
2017-07-26 09:41:34 +00:00
|
|
|
crate_name,
|
2018-08-18 10:08:06 +00:00
|
|
|
crate_hash,
|
2017-07-26 09:41:34 +00:00
|
|
|
metadata,
|
|
|
|
windows_subsystem,
|
|
|
|
linker_info,
|
2017-08-28 22:55:32 +00:00
|
|
|
crate_info,
|
2017-07-26 09:41:34 +00:00
|
|
|
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph,
|
2018-03-26 19:31:45 +00:00
|
|
|
coordinator_send: tcx.tx_to_llvm_workers.lock().clone(),
|
2018-05-08 13:10:16 +00:00
|
|
|
codegen_worker_receive,
|
2017-07-26 09:41:34 +00:00
|
|
|
shared_emitter_main,
|
2017-09-14 03:26:39 +00:00
|
|
|
future: coordinator_thread,
|
|
|
|
output_filenames: tcx.output_filenames(LOCAL_CRATE),
|
2017-07-26 08:48:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 15:16:08 +00:00
|
|
|
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
2018-05-09 06:10:03 +00:00
|
|
|
sess: &Session,
|
2018-08-20 15:13:01 +00:00
|
|
|
compiled_modules: &CompiledModules,
|
2018-05-09 06:10:03 +00:00
|
|
|
) -> FxHashMap<WorkProductId, WorkProduct> {
|
2018-05-09 05:20:09 +00:00
|
|
|
let mut work_products = FxHashMap::default();
|
|
|
|
|
2017-07-26 08:48:54 +00:00
|
|
|
if sess.opts.incremental.is_none() {
|
2018-05-09 05:20:09 +00:00
|
|
|
return work_products;
|
2017-07-26 08:48:54 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
|
2016-07-25 14:51:14 +00:00
|
|
|
let mut files = vec![];
|
|
|
|
|
2017-10-20 01:44:33 +00:00
|
|
|
if let Some(ref path) = module.object {
|
|
|
|
files.push((WorkProductFileKind::Object, path.clone()));
|
2016-07-25 14:51:14 +00:00
|
|
|
}
|
2017-10-20 01:44:33 +00:00
|
|
|
if let Some(ref path) = module.bytecode {
|
|
|
|
files.push((WorkProductFileKind::Bytecode, path.clone()));
|
|
|
|
}
|
|
|
|
if let Some(ref path) = module.bytecode_compressed {
|
|
|
|
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
|
2016-07-25 14:51:14 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 15:16:08 +00:00
|
|
|
if let Some((id, product)) =
|
2018-10-06 09:37:28 +00:00
|
|
|
copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
|
|
|
|
{
|
2018-05-09 05:20:09 +00:00
|
|
|
work_products.insert(id, product);
|
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
2018-05-09 05:20:09 +00:00
|
|
|
|
|
|
|
work_products
|
2017-07-26 08:48:54 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-26 08:48:54 +00:00
|
|
|
fn produce_final_output_artifacts(sess: &Session,
|
|
|
|
compiled_modules: &CompiledModules,
|
|
|
|
crate_output: &OutputFilenames) {
|
2014-09-17 23:18:12 +00:00
|
|
|
let mut user_wants_bitcode = false;
|
2015-07-07 01:21:57 +00:00
|
|
|
let mut user_wants_objects = false;
|
2017-07-21 15:15:18 +00:00
|
|
|
|
2017-07-26 08:48:54 +00:00
|
|
|
// Produce final compile outputs.
|
|
|
|
let copy_gracefully = |from: &Path, to: &Path| {
|
|
|
|
if let Err(e) = fs::copy(from, to) {
|
|
|
|
sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let copy_if_one_unit = |output_type: OutputType,
|
|
|
|
keep_numbered: bool| {
|
|
|
|
if compiled_modules.modules.len() == 1 {
|
|
|
|
// 1) Only one codegen unit. In this case it's no difficulty
|
|
|
|
// to copy `foo.0.x` to `foo.x`.
|
|
|
|
let module_name = Some(&compiled_modules.modules[0].name[..]);
|
|
|
|
let path = crate_output.temp_path(output_type, module_name);
|
|
|
|
copy_gracefully(&path,
|
|
|
|
&crate_output.path(output_type));
|
|
|
|
if !sess.opts.cg.save_temps && !keep_numbered {
|
|
|
|
// The user just wants `foo.x`, not `foo.#module-name#.x`.
|
|
|
|
remove(sess, &path);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let ext = crate_output.temp_path(output_type, None)
|
|
|
|
.extension()
|
|
|
|
.unwrap()
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
.to_owned();
|
|
|
|
|
|
|
|
if crate_output.outputs.contains_key(&output_type) {
|
|
|
|
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
|
|
|
|
// no good solution for this case, so warn the user.
|
|
|
|
sess.warn(&format!("ignoring emit path because multiple .{} files \
|
|
|
|
were produced", ext));
|
|
|
|
} else if crate_output.single_output_file.is_some() {
|
|
|
|
// 3) Multiple codegen units, with `-o some_name`. We have
|
|
|
|
// no good solution for this case, so warn the user.
|
|
|
|
sess.warn(&format!("ignoring -o because multiple .{} files \
|
|
|
|
were produced", ext));
|
2017-07-21 15:15:18 +00:00
|
|
|
} else {
|
2017-07-26 08:48:54 +00:00
|
|
|
// 4) Multiple codegen units, but no explicit name. We
|
|
|
|
// just leave the `foo.0.x` files in place.
|
|
|
|
// (We don't have to do any work in this case.)
|
2014-11-16 01:30:33 +00:00
|
|
|
}
|
2017-07-26 08:48:54 +00:00
|
|
|
}
|
|
|
|
};
|
2017-07-21 15:15:18 +00:00
|
|
|
|
2017-07-26 08:48:54 +00:00
|
|
|
// Flag to indicate whether the user explicitly requested bitcode.
|
|
|
|
// Otherwise, we produced it only as a temporary output, and will need
|
|
|
|
// to get rid of it.
|
|
|
|
for output_type in crate_output.outputs.keys() {
|
|
|
|
match *output_type {
|
|
|
|
OutputType::Bitcode => {
|
|
|
|
user_wants_bitcode = true;
|
|
|
|
// Copy to .bc, but always keep the .0.bc. There is a later
|
|
|
|
// check to figure out if we should delete .0.bc files, or keep
|
|
|
|
// them for making an rlib.
|
|
|
|
copy_if_one_unit(OutputType::Bitcode, true);
|
|
|
|
}
|
|
|
|
OutputType::LlvmAssembly => {
|
|
|
|
copy_if_one_unit(OutputType::LlvmAssembly, false);
|
|
|
|
}
|
|
|
|
OutputType::Assembly => {
|
|
|
|
copy_if_one_unit(OutputType::Assembly, false);
|
|
|
|
}
|
|
|
|
OutputType::Object => {
|
|
|
|
user_wants_objects = true;
|
|
|
|
copy_if_one_unit(OutputType::Object, true);
|
2014-11-16 01:30:33 +00:00
|
|
|
}
|
2017-07-26 08:48:54 +00:00
|
|
|
OutputType::Mir |
|
|
|
|
OutputType::Metadata |
|
|
|
|
OutputType::Exe |
|
|
|
|
OutputType::DepInfo => {}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean up unwanted temporary files.
|
|
|
|
|
|
|
|
// We create the following files by default:
|
2017-02-07 17:24:43 +00:00
|
|
|
// - #crate#.#module-name#.bc
|
|
|
|
// - #crate#.#module-name#.o
|
|
|
|
// - #crate#.crate.metadata.bc
|
|
|
|
// - #crate#.crate.metadata.o
|
|
|
|
// - #crate#.o (linked from crate.##.o)
|
|
|
|
// - #crate#.bc (copied from crate.##.bc)
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
// We may create additional files if requested by the user (through
|
|
|
|
// `-C save-temps` or `--emit=` flags).
|
|
|
|
|
|
|
|
if !sess.opts.cg.save_temps {
|
2016-05-14 00:48:32 +00:00
|
|
|
// Remove the temporary .#module-name#.o objects. If the user didn't
|
2014-09-17 23:18:12 +00:00
|
|
|
// explicitly request bitcode (with --emit=bc), and the bitcode is not
|
2016-05-14 00:48:32 +00:00
|
|
|
// needed for building an rlib, then we must remove .#module-name#.bc as
|
|
|
|
// well.
|
2014-09-17 23:18:12 +00:00
|
|
|
|
2016-05-14 00:48:32 +00:00
|
|
|
// Specific rules for keeping .#module-name#.bc:
|
2014-09-17 23:18:12 +00:00
|
|
|
// - If the user requested bitcode (`user_wants_bitcode`), and
|
|
|
|
// codegen_units > 1, then keep it.
|
|
|
|
// - If the user requested bitcode but codegen_units == 1, then we
|
2016-05-14 00:48:32 +00:00
|
|
|
// can toss .#module-name#.bc because we copied it to .bc earlier.
|
2014-09-17 23:18:12 +00:00
|
|
|
// - If we're not building an rlib and the user didn't request
|
2016-05-14 00:48:32 +00:00
|
|
|
// bitcode, then delete .#module-name#.bc.
|
2014-09-17 23:18:12 +00:00
|
|
|
// If you change how this works, also update back::link::link_rlib,
|
2016-05-14 00:48:32 +00:00
|
|
|
// where .#module-name#.bc files are (maybe) deleted after making an
|
|
|
|
// rlib.
|
2017-07-26 08:48:54 +00:00
|
|
|
let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe);
|
|
|
|
|
2017-10-20 01:44:33 +00:00
|
|
|
let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units() > 1;
|
2014-09-17 23:18:12 +00:00
|
|
|
|
2015-07-07 01:21:57 +00:00
|
|
|
let keep_numbered_objects = needs_crate_object ||
|
2017-10-04 21:38:52 +00:00
|
|
|
(user_wants_objects && sess.codegen_units() > 1);
|
2015-07-07 01:21:57 +00:00
|
|
|
|
2017-07-25 15:26:24 +00:00
|
|
|
for module in compiled_modules.modules.iter() {
|
2017-10-20 01:44:33 +00:00
|
|
|
if let Some(ref path) = module.object {
|
|
|
|
if !keep_numbered_objects {
|
|
|
|
remove(sess, path);
|
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-10-20 01:44:33 +00:00
|
|
|
if let Some(ref path) = module.bytecode {
|
|
|
|
if !keep_numbered_bitcode {
|
|
|
|
remove(sess, path);
|
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-20 01:44:33 +00:00
|
|
|
if !user_wants_bitcode {
|
|
|
|
if let Some(ref path) = compiled_modules.metadata_module.bytecode {
|
2017-06-03 21:54:08 +00:00
|
|
|
remove(sess, &path);
|
|
|
|
}
|
2017-10-20 01:44:33 +00:00
|
|
|
|
|
|
|
if let Some(ref allocator_module) = compiled_modules.allocator_module {
|
|
|
|
if let Some(ref path) = allocator_module.bytecode {
|
|
|
|
remove(sess, path);
|
|
|
|
}
|
|
|
|
}
|
2017-06-03 21:54:08 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We leave the following files around by default:
|
2017-02-07 17:24:43 +00:00
|
|
|
// - #crate#.o
|
|
|
|
// - #crate#.crate.metadata.o
|
|
|
|
// - #crate#.bc
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
// These are used in linking steps and will be cleaned up afterward.
|
|
|
|
}
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
pub(crate) fn dump_incremental_data(_codegen_results: &CodegenResults) {
|
|
|
|
// FIXME(mw): This does not work at the moment because the situation has
|
|
|
|
// become more complicated due to incremental LTO. Now a CGU
|
|
|
|
// can have more than two caching states.
|
|
|
|
// println!("[incremental] Re-using {} out of {} modules",
|
|
|
|
// codegen_results.modules.iter().filter(|m| m.pre_existing).count(),
|
|
|
|
// codegen_results.modules.len());
|
2016-08-01 23:56:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
enum WorkItem {
|
2018-08-20 15:13:01 +00:00
|
|
|
/// Optimize a newly codegened, totally unoptimized module.
|
2018-05-08 13:10:16 +00:00
|
|
|
Optimize(ModuleCodegen),
|
2018-08-20 15:13:01 +00:00
|
|
|
/// Copy the post-LTO artifacts from the incremental cache to the output
|
|
|
|
/// directory.
|
|
|
|
CopyPostLtoArtifacts(CachedModuleCodegen),
|
|
|
|
/// Perform (Thin)LTO on the given module.
|
2018-05-08 13:10:16 +00:00
|
|
|
LTO(lto::LtoModuleCodegen),
|
2014-11-26 15:07:58 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
impl WorkItem {
|
2018-08-20 15:13:01 +00:00
|
|
|
fn module_kind(&self) -> ModuleKind {
|
2017-07-23 15:14:38 +00:00
|
|
|
match *self {
|
|
|
|
WorkItem::Optimize(ref m) => m.kind,
|
2018-08-20 15:13:01 +00:00
|
|
|
WorkItem::CopyPostLtoArtifacts(_) |
|
2017-07-23 15:14:38 +00:00
|
|
|
WorkItem::LTO(_) => ModuleKind::Regular,
|
|
|
|
}
|
2017-07-24 12:51:00 +00:00
|
|
|
}
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
fn name(&self) -> String {
|
|
|
|
match *self {
|
|
|
|
WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
|
2018-08-20 15:13:01 +00:00
|
|
|
WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
|
2017-07-23 15:14:38 +00:00
|
|
|
WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
2016-05-14 00:48:32 +00:00
|
|
|
}
|
2014-11-26 15:07:58 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
enum WorkItemResult {
|
|
|
|
Compiled(CompiledModule),
|
2018-05-08 13:10:16 +00:00
|
|
|
NeedsLTO(ModuleCodegen),
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
fn execute_work_item(cgcx: &CodegenContext,
|
|
|
|
work_item: WorkItem,
|
|
|
|
timeline: &mut Timeline)
|
2017-07-23 15:14:38 +00:00
|
|
|
-> Result<WorkItemResult, FatalError>
|
2017-06-15 14:08:18 +00:00
|
|
|
{
|
2018-09-03 10:42:27 +00:00
|
|
|
let module_config = cgcx.config(work_item.module_kind());
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
match work_item {
|
2018-09-03 10:42:27 +00:00
|
|
|
WorkItem::Optimize(module) => {
|
|
|
|
execute_optimize_work_item(cgcx, module, module_config, timeline)
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
2018-09-03 10:42:27 +00:00
|
|
|
WorkItem::CopyPostLtoArtifacts(module) => {
|
|
|
|
execute_copy_from_cache_work_item(cgcx, module, module_config, timeline)
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
2018-09-03 10:42:27 +00:00
|
|
|
WorkItem::LTO(module) => {
|
|
|
|
execute_lto_work_item(cgcx, module, module_config, timeline)
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute_optimize_work_item(cgcx: &CodegenContext,
|
2018-09-03 10:42:27 +00:00
|
|
|
module: ModuleCodegen,
|
|
|
|
module_config: &ModuleConfig,
|
2018-08-20 15:13:01 +00:00
|
|
|
timeline: &mut Timeline)
|
|
|
|
-> Result<WorkItemResult, FatalError>
|
|
|
|
{
|
2017-07-24 11:54:18 +00:00
|
|
|
let diag_handler = cgcx.create_diag_handler();
|
2018-08-20 15:13:01 +00:00
|
|
|
|
|
|
|
unsafe {
|
2018-09-03 10:42:27 +00:00
|
|
|
optimize(cgcx, &diag_handler, &module, module_config, timeline)?;
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let linker_does_lto = cgcx.opts.debugging_opts.cross_lang_lto.enabled();
|
|
|
|
|
|
|
|
// After we've done the initial round of optimizations we need to
|
|
|
|
// decide whether to synchronously codegen this module or ship it
|
|
|
|
// back to the coordinator thread for further LTO processing (which
|
|
|
|
// has to wait for all the initial modules to be optimized).
|
|
|
|
//
|
|
|
|
// Here we dispatch based on the `cgcx.lto` and kind of module we're
|
|
|
|
// codegenning...
|
|
|
|
let needs_lto = match cgcx.lto {
|
|
|
|
Lto::No => false,
|
|
|
|
|
|
|
|
// If the linker does LTO, we don't have to do it. Note that we
|
|
|
|
// keep doing full LTO, if it is requested, as not to break the
|
|
|
|
// assumption that the output will be a single module.
|
|
|
|
Lto::Thin | Lto::ThinLocal if linker_does_lto => false,
|
|
|
|
|
|
|
|
// Here we've got a full crate graph LTO requested. We ignore
|
|
|
|
// this, however, if the crate type is only an rlib as there's
|
|
|
|
// no full crate graph to process, that'll happen later.
|
|
|
|
//
|
|
|
|
// This use case currently comes up primarily for targets that
|
|
|
|
// require LTO so the request for LTO is always unconditionally
|
|
|
|
// passed down to the backend, but we don't actually want to do
|
|
|
|
// anything about it yet until we've got a final product.
|
2018-09-04 15:57:17 +00:00
|
|
|
Lto::Fat | Lto::Thin => {
|
2018-08-20 15:13:01 +00:00
|
|
|
cgcx.crate_types.len() != 1 ||
|
|
|
|
cgcx.crate_types[0] != config::CrateType::Rlib
|
|
|
|
}
|
|
|
|
|
|
|
|
// When we're automatically doing ThinLTO for multi-codegen-unit
|
|
|
|
// builds we don't actually want to LTO the allocator modules if
|
|
|
|
// it shows up. This is due to various linker shenanigans that
|
|
|
|
// we'll encounter later.
|
|
|
|
Lto::ThinLocal => {
|
2018-11-01 20:06:50 +00:00
|
|
|
module.kind != ModuleKind::Allocator
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
};
|
2017-07-25 15:26:24 +00:00
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
// Metadata modules never participate in LTO regardless of the lto
|
|
|
|
// settings.
|
|
|
|
let needs_lto = needs_lto && module.kind != ModuleKind::Metadata;
|
|
|
|
|
|
|
|
if needs_lto {
|
|
|
|
Ok(WorkItemResult::NeedsLTO(module))
|
|
|
|
} else {
|
|
|
|
let module = unsafe {
|
2018-09-03 10:42:27 +00:00
|
|
|
codegen(cgcx, &diag_handler, module, module_config, timeline)?
|
2018-08-20 15:13:01 +00:00
|
|
|
};
|
|
|
|
Ok(WorkItemResult::Compiled(module))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute_copy_from_cache_work_item(cgcx: &CodegenContext,
|
2018-09-03 10:42:27 +00:00
|
|
|
module: CachedModuleCodegen,
|
|
|
|
module_config: &ModuleConfig,
|
2018-08-20 15:13:01 +00:00
|
|
|
_: &mut Timeline)
|
|
|
|
-> Result<WorkItemResult, FatalError>
|
|
|
|
{
|
|
|
|
let incr_comp_session_dir = cgcx.incr_comp_session_dir
|
|
|
|
.as_ref()
|
|
|
|
.unwrap();
|
|
|
|
let mut object = None;
|
|
|
|
let mut bytecode = None;
|
|
|
|
let mut bytecode_compressed = None;
|
|
|
|
for (kind, saved_file) in &module.source.saved_files {
|
|
|
|
let obj_out = match kind {
|
|
|
|
WorkProductFileKind::Object => {
|
|
|
|
let path = cgcx.output_filenames.temp_path(OutputType::Object,
|
|
|
|
Some(&module.name));
|
|
|
|
object = Some(path.clone());
|
|
|
|
path
|
|
|
|
}
|
|
|
|
WorkProductFileKind::Bytecode => {
|
|
|
|
let path = cgcx.output_filenames.temp_path(OutputType::Bitcode,
|
|
|
|
Some(&module.name));
|
|
|
|
bytecode = Some(path.clone());
|
|
|
|
path
|
|
|
|
}
|
|
|
|
WorkProductFileKind::BytecodeCompressed => {
|
|
|
|
let path = cgcx.output_filenames.temp_path(OutputType::Bitcode,
|
|
|
|
Some(&module.name))
|
|
|
|
.with_extension(RLIB_BYTECODE_EXTENSION);
|
|
|
|
bytecode_compressed = Some(path.clone());
|
|
|
|
path
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let source_file = in_incr_comp_dir(&incr_comp_session_dir,
|
|
|
|
&saved_file);
|
|
|
|
debug!("copying pre-existing module `{}` from {:?} to {}",
|
|
|
|
module.name,
|
|
|
|
source_file,
|
|
|
|
obj_out.display());
|
2018-10-06 09:49:03 +00:00
|
|
|
if let Err(err) = link_or_copy(&source_file, &obj_out) {
|
|
|
|
let diag_handler = cgcx.create_diag_handler();
|
|
|
|
diag_handler.err(&format!("unable to copy {} to {}: {}",
|
|
|
|
source_file.display(),
|
|
|
|
obj_out.display(),
|
|
|
|
err));
|
2016-07-21 16:49:59 +00:00
|
|
|
}
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
|
|
|
|
2018-09-03 10:42:27 +00:00
|
|
|
assert_eq!(object.is_some(), module_config.emit_obj);
|
|
|
|
assert_eq!(bytecode.is_some(), module_config.emit_bc);
|
|
|
|
assert_eq!(bytecode_compressed.is_some(), module_config.emit_bc_compressed);
|
2018-08-20 15:13:01 +00:00
|
|
|
|
|
|
|
Ok(WorkItemResult::Compiled(CompiledModule {
|
|
|
|
name: module.name,
|
|
|
|
kind: ModuleKind::Regular,
|
|
|
|
object,
|
|
|
|
bytecode,
|
|
|
|
bytecode_compressed,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute_lto_work_item(cgcx: &CodegenContext,
|
2018-09-03 10:42:27 +00:00
|
|
|
mut module: lto::LtoModuleCodegen,
|
|
|
|
module_config: &ModuleConfig,
|
2018-08-20 15:13:01 +00:00
|
|
|
timeline: &mut Timeline)
|
|
|
|
-> Result<WorkItemResult, FatalError>
|
|
|
|
{
|
2018-09-03 10:42:27 +00:00
|
|
|
let diag_handler = cgcx.create_diag_handler();
|
2017-07-25 15:26:24 +00:00
|
|
|
|
2018-09-03 10:42:27 +00:00
|
|
|
unsafe {
|
|
|
|
let module = module.optimize(cgcx, timeline)?;
|
|
|
|
let module = codegen(cgcx, &diag_handler, module, module_config, timeline)?;
|
|
|
|
Ok(WorkItemResult::Compiled(module))
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
|
2017-07-26 14:12:34 +00:00
|
|
|
enum Message {
|
2017-06-15 14:08:18 +00:00
|
|
|
Token(io::Result<Acquired>),
|
2017-07-23 15:14:38 +00:00
|
|
|
NeedsLTO {
|
2018-05-08 13:10:16 +00:00
|
|
|
result: ModuleCodegen,
|
2017-07-23 15:14:38 +00:00
|
|
|
worker_id: usize,
|
|
|
|
},
|
2017-07-27 09:51:27 +00:00
|
|
|
Done {
|
|
|
|
result: Result<CompiledModule, ()>,
|
|
|
|
worker_id: usize,
|
|
|
|
},
|
2018-05-08 13:10:16 +00:00
|
|
|
CodegenDone {
|
2017-07-27 14:59:30 +00:00
|
|
|
llvm_work_item: WorkItem,
|
2017-07-28 12:28:08 +00:00
|
|
|
cost: u64,
|
2017-07-27 14:59:30 +00:00
|
|
|
},
|
2018-08-20 15:13:01 +00:00
|
|
|
AddImportOnlyModule {
|
|
|
|
module_data: SerializedModule,
|
2018-08-31 13:18:08 +00:00
|
|
|
work_product: WorkProduct,
|
2018-08-20 15:13:01 +00:00
|
|
|
},
|
2018-05-08 13:10:16 +00:00
|
|
|
CodegenComplete,
|
|
|
|
CodegenItem,
|
2018-10-31 18:32:27 +00:00
|
|
|
CodegenAborted,
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
|
2017-07-26 14:12:34 +00:00
|
|
|
struct Diagnostic {
|
2017-06-15 14:08:18 +00:00
|
|
|
msg: String,
|
2017-10-27 06:21:22 +00:00
|
|
|
code: Option<DiagnosticId>,
|
2017-06-15 14:08:18 +00:00
|
|
|
lvl: Level,
|
run optimization and codegen on worker threads
Refactor the code in `llvm::back` that invokes LLVM optimization and codegen
passes so that it can be called from worker threads. (Previously, it used
`&Session` extensively, and `Session` is not `Share`.) The new code can handle
multiple compilation units, by compiling each unit to `crate.0.o`, `crate.1.o`,
etc., and linking together all the `crate.N.o` files into a single `crate.o`
using `ld -r`. The later linking steps can then be run unchanged.
The new code preserves the behavior of `--emit`/`-o` when building a single
compilation unit. With multiple compilation units, the `--emit=asm/ir/bc`
options produce multiple files, so combinations like `--emit=ir -o foo.ll` will
not actually produce `foo.ll` (they instead produce several `foo.N.ll` files).
The new code supports `-Z lto` only when using a single compilation unit.
Compiling with multiple compilation units and `-Z lto` will produce an error.
(I can't think of any good reason to do such a thing.) Linking with `-Z lto`
against a library that was built as multiple compilation units will also fail,
because the rlib does not contain a `crate.bytecode.deflate` file. This could
be supported in the future by linking together the `crate.N.bc` files produced
when compiling the library into a single `crate.bc`, or by making the LTO code
support multiple `crate.N.bytecode.deflate` files.
2014-07-17 17:52:52 +00:00
|
|
|
}
|
|
|
|
|
2017-07-27 14:59:30 +00:00
|
|
|
#[derive(PartialEq, Clone, Copy, Debug)]
|
2017-07-28 12:28:08 +00:00
|
|
|
enum MainThreadWorkerState {
|
2017-07-27 14:59:30 +00:00
|
|
|
Idle,
|
2018-05-08 13:10:16 +00:00
|
|
|
Codegenning,
|
2017-07-27 14:59:30 +00:00
|
|
|
LLVMing,
|
|
|
|
}
|
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
fn start_executing_work(tcx: TyCtxt,
|
2017-08-28 22:55:32 +00:00
|
|
|
crate_info: &CrateInfo,
|
2017-07-24 12:51:00 +00:00
|
|
|
shared_emitter: SharedEmitter,
|
2018-05-08 13:10:16 +00:00
|
|
|
codegen_worker_send: Sender<Message>,
|
2018-07-11 10:49:11 +00:00
|
|
|
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
total_cgus: usize,
|
2017-07-24 12:51:00 +00:00
|
|
|
jobserver: Client,
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph: Option<TimeGraph>,
|
2017-09-14 03:26:39 +00:00
|
|
|
modules_config: Arc<ModuleConfig>,
|
|
|
|
metadata_config: Arc<ModuleConfig>,
|
|
|
|
allocator_config: Arc<ModuleConfig>)
|
2017-10-08 20:57:03 +00:00
|
|
|
-> thread::JoinHandle<Result<CompiledModules, ()>> {
|
2018-03-26 19:31:45 +00:00
|
|
|
let coordinator_send = tcx.tx_to_llvm_workers.lock().clone();
|
2017-09-14 03:26:39 +00:00
|
|
|
let sess = tcx.sess;
|
|
|
|
|
2018-02-27 16:52:07 +00:00
|
|
|
// Compute the set of symbols we need to retain when doing LTO (if we need to)
|
|
|
|
let exported_symbols = {
|
2018-10-16 08:44:26 +00:00
|
|
|
let mut exported_symbols = FxHashMap::default();
|
2018-02-27 16:52:07 +00:00
|
|
|
|
|
|
|
let copy_symbols = |cnum| {
|
|
|
|
let symbols = tcx.exported_symbols(cnum)
|
|
|
|
.iter()
|
|
|
|
.map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl))
|
|
|
|
.collect();
|
|
|
|
Arc::new(symbols)
|
|
|
|
};
|
|
|
|
|
|
|
|
match sess.lto() {
|
|
|
|
Lto::No => None,
|
|
|
|
Lto::ThinLocal => {
|
|
|
|
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
|
|
|
Some(Arc::new(exported_symbols))
|
|
|
|
}
|
2018-09-04 15:57:17 +00:00
|
|
|
Lto::Fat | Lto::Thin => {
|
2018-02-27 16:52:07 +00:00
|
|
|
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
|
|
|
for &cnum in tcx.crates().iter() {
|
|
|
|
exported_symbols.insert(cnum, copy_symbols(cnum));
|
|
|
|
}
|
|
|
|
Some(Arc::new(exported_symbols))
|
2018-02-14 20:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-06-15 14:08:18 +00:00
|
|
|
// First up, convert our jobserver into a helper thread so we can use normal
|
2018-01-09 21:09:01 +00:00
|
|
|
// mpsc channels to manage our messages and such.
|
|
|
|
// After we've requested tokens then we'll, when we can,
|
|
|
|
// get tokens on `coordinator_receive` which will
|
|
|
|
// get managed in the main loop below.
|
2017-07-24 13:50:42 +00:00
|
|
|
let coordinator_send2 = coordinator_send.clone();
|
2017-06-15 14:08:18 +00:00
|
|
|
let helper = jobserver.into_helper_thread(move |token| {
|
2017-09-13 23:03:24 +00:00
|
|
|
drop(coordinator_send2.send(Box::new(Message::Token(token))));
|
2017-06-15 14:08:18 +00:00
|
|
|
}).expect("failed to spawn helper thread");
|
|
|
|
|
2017-07-24 11:54:18 +00:00
|
|
|
let mut each_linked_rlib_for_lto = Vec::new();
|
2017-08-31 15:07:39 +00:00
|
|
|
drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
|
2017-10-23 03:01:00 +00:00
|
|
|
if link::ignored_for_lto(sess, crate_info, cnum) {
|
2017-07-24 11:54:18 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
|
|
|
}));
|
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
let assembler_cmd = if modules_config.no_integrated_as {
|
|
|
|
// HACK: currently we use linker (gcc) as our assembler
|
2018-08-09 21:08:12 +00:00
|
|
|
let (linker, flavor) = link::linker_and_flavor(sess);
|
|
|
|
|
|
|
|
let (name, mut cmd) = get_linker(sess, &linker, flavor);
|
2018-01-15 13:42:44 +00:00
|
|
|
cmd.args(&sess.target.target.options.asm_args);
|
2018-10-06 09:37:28 +00:00
|
|
|
|
|
|
|
Some(Arc::new(AssemblerCommand { name, cmd }))
|
2018-01-15 13:42:44 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2017-07-24 11:54:18 +00:00
|
|
|
let cgcx = CodegenContext {
|
|
|
|
crate_types: sess.crate_types.borrow().clone(),
|
2017-08-07 05:54:09 +00:00
|
|
|
each_linked_rlib_for_lto,
|
2018-01-16 23:02:31 +00:00
|
|
|
lto: sess.lto(),
|
2017-07-24 11:54:18 +00:00
|
|
|
no_landing_pads: sess.no_landing_pads(),
|
2018-01-04 20:19:23 +00:00
|
|
|
fewer_names: sess.fewer_names(),
|
2017-07-23 15:14:38 +00:00
|
|
|
save_temps: sess.opts.cg.save_temps,
|
2017-07-24 12:21:28 +00:00
|
|
|
opts: Arc::new(sess.opts.clone()),
|
2017-07-24 11:54:18 +00:00
|
|
|
time_passes: sess.time_passes(),
|
2017-08-07 05:54:09 +00:00
|
|
|
exported_symbols,
|
2017-07-24 11:54:18 +00:00
|
|
|
plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
|
|
|
|
remark: sess.opts.cg.remark.clone(),
|
|
|
|
worker: 0,
|
|
|
|
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
|
2018-09-18 14:33:24 +00:00
|
|
|
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
|
2017-08-07 05:54:09 +00:00
|
|
|
coordinator_send,
|
2017-07-24 11:54:18 +00:00
|
|
|
diag_emitter: shared_emitter.clone(),
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph,
|
2017-09-14 03:26:39 +00:00
|
|
|
output_filenames: tcx.output_filenames(LOCAL_CRATE),
|
|
|
|
regular_module_config: modules_config,
|
|
|
|
metadata_module_config: metadata_config,
|
|
|
|
allocator_module_config: allocator_config,
|
2018-04-01 06:26:05 +00:00
|
|
|
tm_factory: target_machine_factory(tcx.sess, false),
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
total_cgus,
|
2017-10-17 20:08:13 +00:00
|
|
|
msvc_imps_needed: msvc_imps_needed(tcx),
|
|
|
|
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
|
2017-10-23 03:01:00 +00:00
|
|
|
debuginfo: tcx.sess.opts.debuginfo,
|
2018-01-15 13:42:44 +00:00
|
|
|
assembler_cmd,
|
2017-07-24 11:54:18 +00:00
|
|
|
};
|
|
|
|
|
2017-06-15 14:08:18 +00:00
|
|
|
// This is the "main loop" of parallel work happening for parallel codegen.
|
|
|
|
// It's here that we manage parallelism, schedule work, and work with
|
|
|
|
// messages coming from clients.
|
|
|
|
//
|
2017-07-28 12:28:08 +00:00
|
|
|
// There are a few environmental pre-conditions that shape how the system
|
|
|
|
// is set up:
|
2017-06-15 14:08:18 +00:00
|
|
|
//
|
2017-07-28 12:28:08 +00:00
|
|
|
// - Error reporting only can happen on the main thread because that's the
|
|
|
|
// only place where we have access to the compiler `Session`.
|
|
|
|
// - LLVM work can be done on any thread.
|
2018-05-08 13:10:16 +00:00
|
|
|
// - Codegen can only happen on the main thread.
|
2017-07-28 12:28:08 +00:00
|
|
|
// - Each thread doing substantial work most be in possession of a `Token`
|
|
|
|
// from the `Jobserver`.
|
|
|
|
// - The compiler process always holds one `Token`. Any additional `Tokens`
|
|
|
|
// have to be requested from the `Jobserver`.
|
2017-06-15 14:08:18 +00:00
|
|
|
//
|
2017-07-28 12:28:08 +00:00
|
|
|
// Error Reporting
|
|
|
|
// ===============
|
|
|
|
// The error reporting restriction is handled separately from the rest: We
|
|
|
|
// set up a `SharedEmitter` the holds an open channel to the main thread.
|
|
|
|
// When an error occurs on any thread, the shared emitter will send the
|
|
|
|
// error message to the receiver main thread (`SharedEmitterMain`). The
|
|
|
|
// main thread will periodically query this error message queue and emit
|
|
|
|
// any error messages it has received. It might even abort compilation if
|
|
|
|
// has received a fatal error. In this case we rely on all other threads
|
|
|
|
// being torn down automatically with the main thread.
|
2018-05-08 13:10:16 +00:00
|
|
|
// Since the main thread will often be busy doing codegen work, error
|
2017-07-28 12:28:08 +00:00
|
|
|
// reporting will be somewhat delayed, since the message queue can only be
|
|
|
|
// checked in between to work packages.
|
|
|
|
//
|
|
|
|
// Work Processing Infrastructure
|
|
|
|
// ==============================
|
|
|
|
// The work processing infrastructure knows three major actors:
|
|
|
|
//
|
|
|
|
// - the coordinator thread,
|
|
|
|
// - the main thread, and
|
|
|
|
// - LLVM worker threads
|
|
|
|
//
|
|
|
|
// The coordinator thread is running a message loop. It instructs the main
|
|
|
|
// thread about what work to do when, and it will spawn off LLVM worker
|
|
|
|
// threads as open LLVM WorkItems become available.
|
|
|
|
//
|
2018-05-08 13:10:16 +00:00
|
|
|
// The job of the main thread is to codegen CGUs into LLVM work package
|
2017-07-28 12:28:08 +00:00
|
|
|
// (since the main thread is the only thread that can do this). The main
|
|
|
|
// thread will block until it receives a message from the coordinator, upon
|
2018-05-08 13:10:16 +00:00
|
|
|
// which it will codegen one CGU, send it to the coordinator and block
|
2017-07-28 12:28:08 +00:00
|
|
|
// again. This way the coordinator can control what the main thread is
|
|
|
|
// doing.
|
|
|
|
//
|
|
|
|
// The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is
|
|
|
|
// available, it will spawn off a new LLVM worker thread and let it process
|
|
|
|
// that a WorkItem. When a LLVM worker thread is done with its WorkItem,
|
|
|
|
// it will just shut down, which also frees all resources associated with
|
|
|
|
// the given LLVM module, and sends a message to the coordinator that the
|
|
|
|
// has been completed.
|
|
|
|
//
|
|
|
|
// Work Scheduling
|
|
|
|
// ===============
|
|
|
|
// The scheduler's goal is to minimize the time it takes to complete all
|
|
|
|
// work there is, however, we also want to keep memory consumption low
|
|
|
|
// if possible. These two goals are at odds with each other: If memory
|
|
|
|
// consumption were not an issue, we could just let the main thread produce
|
|
|
|
// LLVM WorkItems at full speed, assuring maximal utilization of
|
2018-05-08 13:10:16 +00:00
|
|
|
// Tokens/LLVM worker threads. However, since codegen usual is faster
|
2017-07-28 12:28:08 +00:00
|
|
|
// than LLVM processing, the queue of LLVM WorkItems would fill up and each
|
|
|
|
// WorkItem potentially holds on to a substantial amount of memory.
|
|
|
|
//
|
|
|
|
// So the actual goal is to always produce just enough LLVM WorkItems as
|
|
|
|
// not to starve our LLVM worker threads. That means, once we have enough
|
|
|
|
// WorkItems in our queue, we can block the main thread, so it does not
|
|
|
|
// produce more until we need them.
|
|
|
|
//
|
|
|
|
// Doing LLVM Work on the Main Thread
|
|
|
|
// ----------------------------------
|
|
|
|
// Since the main thread owns the compiler processes implicit `Token`, it is
|
|
|
|
// wasteful to keep it blocked without doing any work. Therefore, what we do
|
|
|
|
// in this case is: We spawn off an additional LLVM worker thread that helps
|
|
|
|
// reduce the queue. The work it is doing corresponds to the implicit
|
|
|
|
// `Token`. The coordinator will mark the main thread as being busy with
|
|
|
|
// LLVM work. (The actual work happens on another OS thread but we just care
|
|
|
|
// about `Tokens`, not actual threads).
|
|
|
|
//
|
|
|
|
// When any LLVM worker thread finishes while the main thread is marked as
|
|
|
|
// "busy with LLVM work", we can do a little switcheroo: We give the Token
|
|
|
|
// of the just finished thread to the LLVM worker thread that is working on
|
|
|
|
// behalf of the main thread's implicit Token, thus freeing up the main
|
|
|
|
// thread again. The coordinator can then again decide what the main thread
|
|
|
|
// should do. This allows the coordinator to make decisions at more points
|
|
|
|
// in time.
|
|
|
|
//
|
|
|
|
// Striking a Balance between Throughput and Memory Consumption
|
|
|
|
// ------------------------------------------------------------
|
|
|
|
// Since our two goals, (1) use as many Tokens as possible and (2) keep
|
|
|
|
// memory consumption as low as possible, are in conflict with each other,
|
|
|
|
// we have to find a trade off between them. Right now, the goal is to keep
|
|
|
|
// all workers busy, which means that no worker should find the queue empty
|
|
|
|
// when it is ready to start.
|
|
|
|
// How do we do achieve this? Good question :) We actually never know how
|
|
|
|
// many `Tokens` are potentially available so it's hard to say how much to
|
|
|
|
// fill up the queue before switching the main thread to LLVM work. Also we
|
|
|
|
// currently don't have a means to estimate how long a running LLVM worker
|
|
|
|
// will still be busy with it's current WorkItem. However, we know the
|
|
|
|
// maximal count of available Tokens that makes sense (=the number of CPU
|
|
|
|
// cores), so we can take a conservative guess. The heuristic we use here
|
|
|
|
// is implemented in the `queue_full_enough()` function.
|
|
|
|
//
|
|
|
|
// Some Background on Jobservers
|
|
|
|
// -----------------------------
|
2017-06-15 14:08:18 +00:00
|
|
|
// It's worth also touching on the management of parallelism here. We don't
|
|
|
|
// want to just spawn a thread per work item because while that's optimal
|
|
|
|
// parallelism it may overload a system with too many threads or violate our
|
|
|
|
// configuration for the maximum amount of cpu to use for this process. To
|
|
|
|
// manage this we use the `jobserver` crate.
|
|
|
|
//
|
|
|
|
// Job servers are an artifact of GNU make and are used to manage
|
|
|
|
// parallelism between processes. A jobserver is a glorified IPC semaphore
|
|
|
|
// basically. Whenever we want to run some work we acquire the semaphore,
|
|
|
|
// and whenever we're done with that work we release the semaphore. In this
|
|
|
|
// manner we can ensure that the maximum number of parallel workers is
|
|
|
|
// capped at any one point in time.
|
2017-07-23 15:14:38 +00:00
|
|
|
//
|
|
|
|
// LTO and the coordinator thread
|
|
|
|
// ------------------------------
|
|
|
|
//
|
|
|
|
// The final job the coordinator thread is responsible for is managing LTO
|
|
|
|
// and how that works. When LTO is requested what we'll to is collect all
|
|
|
|
// optimized LLVM modules into a local vector on the coordinator. Once all
|
2018-05-08 13:10:16 +00:00
|
|
|
// modules have been codegened and optimized we hand this to the `lto`
|
2017-07-23 15:14:38 +00:00
|
|
|
// module for further optimization. The `lto` module will return back a list
|
|
|
|
// of more modules to work on, which the coordinator will continue to spawn
|
|
|
|
// work for.
|
|
|
|
//
|
|
|
|
// Each LLVM module is automatically sent back to the coordinator for LTO if
|
|
|
|
// necessary. There's already optimizations in place to avoid sending work
|
|
|
|
// back to the coordinator if LTO isn't requested.
|
2017-07-28 12:28:08 +00:00
|
|
|
return thread::spawn(move || {
|
2017-07-31 12:51:47 +00:00
|
|
|
// We pretend to be within the top-level LLVM time-passes task here:
|
|
|
|
set_time_depth(1);
|
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
let max_workers = ::num_cpus::get();
|
2017-07-27 09:51:27 +00:00
|
|
|
let mut worker_id_counter = 0;
|
|
|
|
let mut free_worker_ids = Vec::new();
|
|
|
|
let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
|
|
|
|
if let Some(id) = free_worker_ids.pop() {
|
|
|
|
id
|
|
|
|
} else {
|
|
|
|
let id = worker_id_counter;
|
|
|
|
worker_id_counter += 1;
|
|
|
|
id
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
// This is where we collect codegen units that have gone all the way
|
2018-05-08 13:10:16 +00:00
|
|
|
// through codegen and LLVM.
|
2017-07-25 15:26:24 +00:00
|
|
|
let mut compiled_modules = vec![];
|
|
|
|
let mut compiled_metadata_module = None;
|
|
|
|
let mut compiled_allocator_module = None;
|
2017-07-23 15:14:38 +00:00
|
|
|
let mut needs_lto = Vec::new();
|
2018-08-20 15:13:01 +00:00
|
|
|
let mut lto_import_only_modules = Vec::new();
|
2017-07-23 15:14:38 +00:00
|
|
|
let mut started_lto = false;
|
2018-10-31 18:32:27 +00:00
|
|
|
let mut codegen_aborted = false;
|
2017-07-25 15:26:24 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// This flag tracks whether all items have gone through codegens
|
|
|
|
let mut codegen_done = false;
|
2017-07-28 12:28:08 +00:00
|
|
|
|
|
|
|
// This is the queue of LLVM work items that still need processing.
|
2017-09-14 03:26:39 +00:00
|
|
|
let mut work_items = Vec::<(WorkItem, u64)>::new();
|
2017-07-28 12:28:08 +00:00
|
|
|
|
|
|
|
// This are the Jobserver Tokens we currently hold. Does not include
|
|
|
|
// the implicit Token the compiler process owns no matter what.
|
2017-07-24 12:21:28 +00:00
|
|
|
let mut tokens = Vec::new();
|
2017-07-27 09:51:27 +00:00
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
let mut main_thread_worker_state = MainThreadWorkerState::Idle;
|
2017-07-24 12:21:28 +00:00
|
|
|
let mut running = 0;
|
2017-07-27 09:51:27 +00:00
|
|
|
|
2017-07-31 12:51:47 +00:00
|
|
|
let mut llvm_start_time = None;
|
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
// Run the message loop while there's still anything that needs message
|
2018-10-31 18:32:27 +00:00
|
|
|
// processing. Note that as soon as codegen is aborted we simply want to
|
|
|
|
// wait for all existing work to finish, so many of the conditions here
|
|
|
|
// only apply if codegen hasn't been aborted as they represent pending
|
|
|
|
// work to be done.
|
2018-05-08 13:10:16 +00:00
|
|
|
while !codegen_done ||
|
2017-07-27 14:59:30 +00:00
|
|
|
running > 0 ||
|
2018-10-31 18:32:27 +00:00
|
|
|
(!codegen_aborted && (
|
|
|
|
work_items.len() > 0 ||
|
|
|
|
needs_lto.len() > 0 ||
|
|
|
|
lto_import_only_modules.len() > 0 ||
|
|
|
|
main_thread_worker_state != MainThreadWorkerState::Idle
|
|
|
|
))
|
|
|
|
{
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// While there are still CGUs to be codegened, the coordinator has
|
2017-07-28 12:28:08 +00:00
|
|
|
// to decide how to utilize the compiler processes implicit Token:
|
2018-05-08 13:10:16 +00:00
|
|
|
// For codegenning more CGU or for running them through LLVM.
|
|
|
|
if !codegen_done {
|
2017-07-28 12:28:08 +00:00
|
|
|
if main_thread_worker_state == MainThreadWorkerState::Idle {
|
|
|
|
if !queue_full_enough(work_items.len(), running, max_workers) {
|
2018-05-08 13:10:16 +00:00
|
|
|
// The queue is not full enough, codegen more items:
|
|
|
|
if let Err(_) = codegen_worker_send.send(Message::CodegenItem) {
|
|
|
|
panic!("Could not send Message::CodegenItem to main thread")
|
2017-08-01 09:04:24 +00:00
|
|
|
}
|
2018-05-08 13:10:16 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::Codegenning;
|
2017-07-27 14:59:30 +00:00
|
|
|
} else {
|
2017-07-28 12:28:08 +00:00
|
|
|
// The queue is full enough to not let the worker
|
|
|
|
// threads starve. Use the implicit Token to do some
|
|
|
|
// LLVM work too.
|
2017-08-01 09:04:24 +00:00
|
|
|
let (item, _) = work_items.pop()
|
|
|
|
.expect("queue empty - queue_full_enough() broken?");
|
2017-07-27 14:59:30 +00:00
|
|
|
let cgcx = CodegenContext {
|
2017-07-28 12:28:08 +00:00
|
|
|
worker: get_worker_id(&mut free_worker_ids),
|
2017-07-27 14:59:30 +00:00
|
|
|
.. cgcx.clone()
|
|
|
|
};
|
2018-08-20 15:13:01 +00:00
|
|
|
maybe_start_llvm_timer(cgcx.config(item.module_kind()),
|
2017-09-14 03:26:39 +00:00
|
|
|
&mut llvm_start_time);
|
2017-07-28 12:28:08 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
2017-07-27 14:59:30 +00:00
|
|
|
spawn_work(cgcx, item);
|
|
|
|
}
|
|
|
|
}
|
2018-10-31 18:32:27 +00:00
|
|
|
} else if codegen_aborted {
|
|
|
|
// don't queue up any more work if codegen was aborted, we're
|
|
|
|
// just waiting for our existing children to finish
|
2017-07-27 14:59:30 +00:00
|
|
|
} else {
|
2018-05-08 13:10:16 +00:00
|
|
|
// If we've finished everything related to normal codegen
|
2017-07-23 15:14:38 +00:00
|
|
|
// then it must be the case that we've got some LTO work to do.
|
|
|
|
// Perform the serial work here of figuring out what we're
|
|
|
|
// going to LTO and then push a bunch of work items onto our
|
|
|
|
// queue to do LTO
|
|
|
|
if work_items.len() == 0 &&
|
|
|
|
running == 0 &&
|
|
|
|
main_thread_worker_state == MainThreadWorkerState::Idle {
|
|
|
|
assert!(!started_lto);
|
2018-08-31 13:18:08 +00:00
|
|
|
assert!(needs_lto.len() + lto_import_only_modules.len() > 0);
|
2017-07-23 15:14:38 +00:00
|
|
|
started_lto = true;
|
|
|
|
let modules = mem::replace(&mut needs_lto, Vec::new());
|
2018-08-20 15:13:01 +00:00
|
|
|
let import_only_modules =
|
|
|
|
mem::replace(&mut lto_import_only_modules, Vec::new());
|
|
|
|
for (work, cost) in generate_lto_work(&cgcx, modules, import_only_modules) {
|
2017-07-23 15:14:38 +00:00
|
|
|
let insertion_index = work_items
|
|
|
|
.binary_search_by_key(&cost, |&(_, cost)| cost)
|
|
|
|
.unwrap_or_else(|e| e);
|
|
|
|
work_items.insert(insertion_index, (work, cost));
|
2018-05-22 17:23:40 +00:00
|
|
|
if !cgcx.opts.debugging_opts.no_parallel_llvm {
|
|
|
|
helper.request_token();
|
|
|
|
}
|
2017-07-23 15:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// In this branch, we know that everything has been codegened,
|
2017-07-28 12:28:08 +00:00
|
|
|
// so it's just a matter of determining whether the implicit
|
|
|
|
// Token is free to use for LLVM work.
|
|
|
|
match main_thread_worker_state {
|
|
|
|
MainThreadWorkerState::Idle => {
|
|
|
|
if let Some((item, _)) = work_items.pop() {
|
2017-07-27 14:59:30 +00:00
|
|
|
let cgcx = CodegenContext {
|
2017-07-28 12:28:08 +00:00
|
|
|
worker: get_worker_id(&mut free_worker_ids),
|
2017-07-27 14:59:30 +00:00
|
|
|
.. cgcx.clone()
|
|
|
|
};
|
2018-08-20 15:13:01 +00:00
|
|
|
maybe_start_llvm_timer(cgcx.config(item.module_kind()),
|
2017-09-14 03:26:39 +00:00
|
|
|
&mut llvm_start_time);
|
2017-07-28 12:28:08 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
2017-07-27 14:59:30 +00:00
|
|
|
spawn_work(cgcx, item);
|
2017-08-09 16:18:48 +00:00
|
|
|
} else {
|
|
|
|
// There is no unstarted work, so let the main thread
|
|
|
|
// take over for a running worker. Otherwise the
|
|
|
|
// implicit token would just go to waste.
|
|
|
|
// We reduce the `running` counter by one. The
|
|
|
|
// `tokens.truncate()` below will take care of
|
|
|
|
// giving the Token back.
|
|
|
|
debug_assert!(running > 0);
|
|
|
|
running -= 1;
|
|
|
|
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
2017-07-27 14:59:30 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-08 13:10:16 +00:00
|
|
|
MainThreadWorkerState::Codegenning => {
|
|
|
|
bug!("codegen worker should not be codegenning after \
|
|
|
|
codegen was already completed")
|
2017-07-27 14:59:30 +00:00
|
|
|
}
|
2017-07-28 12:28:08 +00:00
|
|
|
MainThreadWorkerState::LLVMing => {
|
2017-07-27 14:59:30 +00:00
|
|
|
// Already making good use of that token
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-15 14:08:18 +00:00
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
// Spin up what work we can, only doing this while we've got available
|
|
|
|
// parallelism slots and work left to spawn.
|
2018-10-31 18:32:27 +00:00
|
|
|
while !codegen_aborted && work_items.len() > 0 && running < tokens.len() {
|
2017-07-28 12:28:08 +00:00
|
|
|
let (item, _) = work_items.pop().unwrap();
|
2017-07-26 12:18:11 +00:00
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
maybe_start_llvm_timer(cgcx.config(item.module_kind()),
|
2017-09-14 03:26:39 +00:00
|
|
|
&mut llvm_start_time);
|
2017-07-31 12:51:47 +00:00
|
|
|
|
2017-07-26 12:18:11 +00:00
|
|
|
let cgcx = CodegenContext {
|
2017-07-28 12:28:08 +00:00
|
|
|
worker: get_worker_id(&mut free_worker_ids),
|
2017-07-26 12:18:11 +00:00
|
|
|
.. cgcx.clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
spawn_work(cgcx, item);
|
|
|
|
running += 1;
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
2017-07-24 12:21:28 +00:00
|
|
|
|
|
|
|
// Relinquish accidentally acquired extra tokens
|
2017-07-27 14:59:30 +00:00
|
|
|
tokens.truncate(running);
|
2017-07-24 12:21:28 +00:00
|
|
|
|
2017-09-13 23:03:24 +00:00
|
|
|
let msg = coordinator_receive.recv().unwrap();
|
|
|
|
match *msg.downcast::<Message>().ok().unwrap() {
|
2017-07-24 12:21:28 +00:00
|
|
|
// Save the token locally and the next turn of the loop will use
|
|
|
|
// this to spawn a new unit of work, or it may get dropped
|
|
|
|
// immediately if we have no more work to spawn.
|
|
|
|
Message::Token(token) => {
|
2017-07-31 13:41:41 +00:00
|
|
|
match token {
|
|
|
|
Ok(token) => {
|
|
|
|
tokens.push(token);
|
|
|
|
|
|
|
|
if main_thread_worker_state == MainThreadWorkerState::LLVMing {
|
|
|
|
// If the main thread token is used for LLVM work
|
|
|
|
// at the moment, we turn that thread into a regular
|
|
|
|
// LLVM worker thread, so the main thread is free
|
2018-05-08 13:10:16 +00:00
|
|
|
// to react to codegen demand.
|
2017-07-31 13:41:41 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
|
|
|
running += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
let msg = &format!("failed to acquire jobserver token: {}", e);
|
|
|
|
shared_emitter.fatal(msg);
|
|
|
|
// Exit the coordinator thread
|
2017-08-01 09:04:24 +00:00
|
|
|
panic!("{}", msg)
|
2017-07-28 12:28:08 +00:00
|
|
|
}
|
2017-07-24 14:18:11 +00:00
|
|
|
}
|
2017-07-24 12:21:28 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
Message::CodegenDone { llvm_work_item, cost } => {
|
2017-07-28 12:28:08 +00:00
|
|
|
// We keep the queue sorted by estimated processing cost,
|
|
|
|
// so that more expensive items are processed earlier. This
|
|
|
|
// is good for throughput as it gives the main thread more
|
|
|
|
// time to fill up the queue and it avoids scheduling
|
|
|
|
// expensive items to the end.
|
|
|
|
// Note, however, that this is not ideal for memory
|
|
|
|
// consumption, as LLVM module sizes are not evenly
|
|
|
|
// distributed.
|
|
|
|
let insertion_index =
|
|
|
|
work_items.binary_search_by_key(&cost, |&(_, cost)| cost);
|
|
|
|
let insertion_index = match insertion_index {
|
|
|
|
Ok(idx) | Err(idx) => idx
|
|
|
|
};
|
|
|
|
work_items.insert(insertion_index, (llvm_work_item, cost));
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-05-22 17:23:40 +00:00
|
|
|
if !cgcx.opts.debugging_opts.no_parallel_llvm {
|
|
|
|
helper.request_token();
|
|
|
|
}
|
2018-10-31 18:32:27 +00:00
|
|
|
assert!(!codegen_aborted);
|
2017-09-14 03:26:39 +00:00
|
|
|
assert_eq!(main_thread_worker_state,
|
2018-05-08 13:10:16 +00:00
|
|
|
MainThreadWorkerState::Codegenning);
|
2017-09-14 03:26:39 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
|
|
|
}
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
Message::CodegenComplete => {
|
|
|
|
codegen_done = true;
|
2018-10-31 18:32:27 +00:00
|
|
|
assert!(!codegen_aborted);
|
2017-07-28 12:28:08 +00:00
|
|
|
assert_eq!(main_thread_worker_state,
|
2018-05-08 13:10:16 +00:00
|
|
|
MainThreadWorkerState::Codegenning);
|
2017-07-28 12:28:08 +00:00
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
2017-07-24 13:50:42 +00:00
|
|
|
}
|
|
|
|
|
2018-10-31 18:32:27 +00:00
|
|
|
// If codegen is aborted that means translation was aborted due
|
|
|
|
// to some normal-ish compiler error. In this situation we want
|
|
|
|
// to exit as soon as possible, but we want to make sure all
|
|
|
|
// existing work has finished. Flag codegen as being done, and
|
|
|
|
// then conditions above will ensure no more work is spawned but
|
|
|
|
// we'll keep executing this loop until `running` hits 0.
|
|
|
|
Message::CodegenAborted => {
|
|
|
|
assert!(!codegen_aborted);
|
|
|
|
codegen_done = true;
|
|
|
|
codegen_aborted = true;
|
|
|
|
assert_eq!(main_thread_worker_state,
|
|
|
|
MainThreadWorkerState::Codegenning);
|
|
|
|
}
|
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
// If a thread exits successfully then we drop a token associated
|
|
|
|
// with that worker and update our `running` count. We may later
|
|
|
|
// re-acquire a token to continue running more work. We may also not
|
|
|
|
// actually drop a token here if the worker was running with an
|
|
|
|
// "ephemeral token"
|
|
|
|
//
|
|
|
|
// Note that if the thread failed that means it panicked, so we
|
|
|
|
// abort immediately.
|
2017-07-27 09:51:27 +00:00
|
|
|
Message::Done { result: Ok(compiled_module), worker_id } => {
|
2017-07-28 12:28:08 +00:00
|
|
|
if main_thread_worker_state == MainThreadWorkerState::LLVMing {
|
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
2017-07-27 14:59:30 +00:00
|
|
|
} else {
|
|
|
|
running -= 1;
|
|
|
|
}
|
2017-07-25 15:26:24 +00:00
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
free_worker_ids.push(worker_id);
|
|
|
|
|
2017-07-25 15:26:24 +00:00
|
|
|
match compiled_module.kind {
|
|
|
|
ModuleKind::Regular => {
|
|
|
|
compiled_modules.push(compiled_module);
|
|
|
|
}
|
|
|
|
ModuleKind::Metadata => {
|
|
|
|
assert!(compiled_metadata_module.is_none());
|
|
|
|
compiled_metadata_module = Some(compiled_module);
|
|
|
|
}
|
|
|
|
ModuleKind::Allocator => {
|
|
|
|
assert!(compiled_allocator_module.is_none());
|
|
|
|
compiled_allocator_module = Some(compiled_module);
|
|
|
|
}
|
|
|
|
}
|
2017-07-24 12:21:28 +00:00
|
|
|
}
|
2017-07-23 15:14:38 +00:00
|
|
|
Message::NeedsLTO { result, worker_id } => {
|
|
|
|
assert!(!started_lto);
|
|
|
|
if main_thread_worker_state == MainThreadWorkerState::LLVMing {
|
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
|
|
|
} else {
|
|
|
|
running -= 1;
|
|
|
|
}
|
|
|
|
free_worker_ids.push(worker_id);
|
|
|
|
needs_lto.push(result);
|
|
|
|
}
|
2018-08-31 13:18:08 +00:00
|
|
|
Message::AddImportOnlyModule { module_data, work_product } => {
|
2018-08-20 15:13:01 +00:00
|
|
|
assert!(!started_lto);
|
|
|
|
assert!(!codegen_done);
|
2018-08-31 13:18:08 +00:00
|
|
|
assert_eq!(main_thread_worker_state,
|
|
|
|
MainThreadWorkerState::Codegenning);
|
|
|
|
lto_import_only_modules.push((module_data, work_product));
|
|
|
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
2017-07-27 09:51:27 +00:00
|
|
|
Message::Done { result: Err(()), worker_id: _ } => {
|
2018-10-12 20:25:22 +00:00
|
|
|
bug!("worker thread panicked");
|
2017-07-24 12:51:00 +00:00
|
|
|
}
|
2018-05-08 13:10:16 +00:00
|
|
|
Message::CodegenItem => {
|
|
|
|
bug!("the coordinator should not receive codegen requests")
|
2017-07-24 12:21:28 +00:00
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
2017-07-25 15:26:24 +00:00
|
|
|
|
2017-07-31 12:51:47 +00:00
|
|
|
if let Some(llvm_start_time) = llvm_start_time {
|
|
|
|
let total_llvm_time = Instant::now().duration_since(llvm_start_time);
|
|
|
|
// This is the top-level timing for all of LLVM, set the time-depth
|
|
|
|
// to zero.
|
|
|
|
set_time_depth(0);
|
|
|
|
print_time_passes_entry(cgcx.time_passes,
|
|
|
|
"LLVM passes",
|
|
|
|
total_llvm_time);
|
|
|
|
}
|
|
|
|
|
2017-09-25 19:26:25 +00:00
|
|
|
// Regardless of what order these modules completed in, report them to
|
|
|
|
// the backend in the same order every time to ensure that we're handing
|
|
|
|
// out deterministic results.
|
|
|
|
compiled_modules.sort_by(|a, b| a.name.cmp(&b.name));
|
|
|
|
|
2017-08-01 09:04:24 +00:00
|
|
|
let compiled_metadata_module = compiled_metadata_module
|
|
|
|
.expect("Metadata module not compiled?");
|
|
|
|
|
2017-10-08 20:57:03 +00:00
|
|
|
Ok(CompiledModules {
|
2017-07-25 15:26:24 +00:00
|
|
|
modules: compiled_modules,
|
2017-08-01 09:04:24 +00:00
|
|
|
metadata_module: compiled_metadata_module,
|
2017-07-25 15:26:24 +00:00
|
|
|
allocator_module: compiled_allocator_module,
|
2017-10-08 20:57:03 +00:00
|
|
|
})
|
2017-07-28 12:28:08 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// A heuristic that determines if we have enough LLVM WorkItems in the
|
2018-05-08 13:10:16 +00:00
|
|
|
// queue so that the main thread can do LLVM work instead of codegen
|
2017-07-28 12:28:08 +00:00
|
|
|
fn queue_full_enough(items_in_queue: usize,
|
|
|
|
workers_running: usize,
|
|
|
|
max_workers: usize) -> bool {
|
|
|
|
// Tune me, plz.
|
2017-08-01 09:04:24 +00:00
|
|
|
items_in_queue > 0 &&
|
2017-07-28 12:28:08 +00:00
|
|
|
items_in_queue >= max_workers.saturating_sub(workers_running / 2)
|
|
|
|
}
|
2017-07-31 12:51:47 +00:00
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
fn maybe_start_llvm_timer(config: &ModuleConfig,
|
2017-07-31 12:51:47 +00:00
|
|
|
llvm_start_time: &mut Option<Instant>) {
|
|
|
|
// We keep track of the -Ztime-passes output manually,
|
|
|
|
// since the closure-based interface does not fit well here.
|
2017-09-14 03:26:39 +00:00
|
|
|
if config.time_passes {
|
2017-07-31 12:51:47 +00:00
|
|
|
if llvm_start_time.is_none() {
|
|
|
|
*llvm_start_time = Some(Instant::now());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
|
|
|
|
pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId =
|
|
|
|
time_graph::TimelineId(CODEGEN_WORKER_ID);
|
|
|
|
pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]);
|
|
|
|
const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
|
|
|
|
time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]);
|
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
|
2017-06-15 14:08:18 +00:00
|
|
|
let depth = time_depth();
|
|
|
|
|
2017-07-24 12:21:28 +00:00
|
|
|
thread::spawn(move || {
|
2017-06-15 14:08:18 +00:00
|
|
|
set_time_depth(depth);
|
|
|
|
|
|
|
|
// Set up a destructor which will fire off a message that we're done as
|
|
|
|
// we exit.
|
|
|
|
struct Bomb {
|
2018-07-11 10:49:11 +00:00
|
|
|
coordinator_send: Sender<Box<dyn Any + Send>>,
|
2017-07-23 15:14:38 +00:00
|
|
|
result: Option<WorkItemResult>,
|
2017-07-27 09:51:27 +00:00
|
|
|
worker_id: usize,
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
|
|
|
impl Drop for Bomb {
|
|
|
|
fn drop(&mut self) {
|
2017-07-23 15:14:38 +00:00
|
|
|
let worker_id = self.worker_id;
|
|
|
|
let msg = match self.result.take() {
|
|
|
|
Some(WorkItemResult::Compiled(m)) => {
|
|
|
|
Message::Done { result: Ok(m), worker_id }
|
|
|
|
}
|
|
|
|
Some(WorkItemResult::NeedsLTO(m)) => {
|
|
|
|
Message::NeedsLTO { result: m, worker_id }
|
|
|
|
}
|
|
|
|
None => Message::Done { result: Err(()), worker_id }
|
2017-07-25 15:26:24 +00:00
|
|
|
};
|
2017-07-23 15:14:38 +00:00
|
|
|
drop(self.coordinator_send.send(Box::new(msg)));
|
2017-06-15 14:08:18 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-24 11:54:18 +00:00
|
|
|
|
2017-06-15 14:08:18 +00:00
|
|
|
let mut bomb = Bomb {
|
2017-07-24 11:54:18 +00:00
|
|
|
coordinator_send: cgcx.coordinator_send.clone(),
|
2017-07-25 15:26:24 +00:00
|
|
|
result: None,
|
2017-07-27 09:51:27 +00:00
|
|
|
worker_id: cgcx.worker,
|
2017-06-15 14:08:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Execute the work itself, and if it finishes successfully then flag
|
|
|
|
// ourselves as a success as well.
|
|
|
|
//
|
2017-10-04 11:45:14 +00:00
|
|
|
// Note that we ignore any `FatalError` coming out of `execute_work_item`,
|
|
|
|
// as a diagnostic was already sent off to the main thread - just
|
|
|
|
// surface that there was an error in this worker.
|
2017-07-27 14:59:30 +00:00
|
|
|
bomb.result = {
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
let timeline = cgcx.time_graph.as_ref().map(|tg| {
|
2017-07-23 15:14:38 +00:00
|
|
|
tg.start(time_graph::TimelineId(cgcx.worker),
|
|
|
|
LLVM_WORK_PACKAGE_KIND,
|
|
|
|
&work.name())
|
|
|
|
});
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
let mut timeline = timeline.unwrap_or(Timeline::noop());
|
|
|
|
execute_work_item(&cgcx, work, &mut timeline).ok()
|
2017-07-27 14:59:30 +00:00
|
|
|
};
|
2017-06-15 14:08:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) {
|
|
|
|
let assembler = cgcx.assembler_cmd
|
|
|
|
.as_ref()
|
|
|
|
.expect("cgcx.assembler_cmd is missing?");
|
2014-08-11 17:33:58 +00:00
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
let pname = &assembler.name;
|
|
|
|
let mut cmd = assembler.cmd.clone();
|
|
|
|
cmd.arg("-c").arg("-o").arg(object).arg(assembly);
|
2015-02-27 05:00:43 +00:00
|
|
|
debug!("{:?}", cmd);
|
2014-08-11 17:33:58 +00:00
|
|
|
|
|
|
|
match cmd.output() {
|
|
|
|
Ok(prog) => {
|
|
|
|
if !prog.status.success() {
|
2015-02-27 05:00:43 +00:00
|
|
|
let mut note = prog.stderr.clone();
|
2015-12-03 01:31:49 +00:00
|
|
|
note.extend_from_slice(&prog.stdout);
|
2015-12-20 21:00:43 +00:00
|
|
|
|
2018-01-15 13:42:44 +00:00
|
|
|
handler.struct_err(&format!("linking with `{}` failed: {}",
|
|
|
|
pname.display(),
|
|
|
|
prog.status))
|
2018-10-06 09:37:28 +00:00
|
|
|
.note(&format!("{:?}", &cmd))
|
|
|
|
.note(str::from_utf8(¬e[..]).unwrap())
|
|
|
|
.emit();
|
2018-01-15 13:42:44 +00:00
|
|
|
handler.abort_if_errors();
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => {
|
2018-01-15 13:42:44 +00:00
|
|
|
handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
|
|
|
|
handler.abort_if_errors();
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
pub unsafe fn with_llvm_pmb(llmod: &llvm::Module,
|
2015-07-22 23:22:51 +00:00
|
|
|
config: &ModuleConfig,
|
2017-10-11 18:19:59 +00:00
|
|
|
opt_level: llvm::CodeGenOptLevel,
|
2018-05-12 12:07:20 +00:00
|
|
|
prepare_for_thin_lto: bool,
|
2018-07-12 13:24:09 +00:00
|
|
|
f: &mut dyn FnMut(&llvm::PassManagerBuilder)) {
|
2018-02-19 00:57:12 +00:00
|
|
|
use std::ptr;
|
|
|
|
|
2014-08-11 17:33:58 +00:00
|
|
|
// Create the PassManagerBuilder for LLVM. We configure it with
|
|
|
|
// reasonable defaults and prepare it to actually populate the pass
|
|
|
|
// manager.
|
|
|
|
let builder = llvm::LLVMPassManagerBuilderCreate();
|
2016-03-27 19:42:47 +00:00
|
|
|
let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
|
2015-11-20 00:07:09 +00:00
|
|
|
let inline_threshold = config.inline_threshold;
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
|
2018-02-19 00:57:12 +00:00
|
|
|
let pgo_gen_path = config.pgo_gen.as_ref().map(|s| {
|
|
|
|
let s = if s.is_empty() { "default_%m.profraw" } else { s };
|
|
|
|
CString::new(s.as_bytes()).unwrap()
|
|
|
|
});
|
|
|
|
|
|
|
|
let pgo_use_path = if config.pgo_use.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(CString::new(config.pgo_use.as_bytes()).unwrap())
|
|
|
|
};
|
|
|
|
|
|
|
|
llvm::LLVMRustConfigurePassManagerBuilder(
|
|
|
|
builder,
|
|
|
|
opt_level,
|
|
|
|
config.merge_functions,
|
|
|
|
config.vectorize_slp,
|
|
|
|
config.vectorize_loop,
|
2018-05-12 12:07:20 +00:00
|
|
|
prepare_for_thin_lto,
|
2018-02-19 00:57:12 +00:00
|
|
|
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
|
|
|
|
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
|
|
|
|
);
|
|
|
|
|
2016-03-27 19:42:47 +00:00
|
|
|
llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
|
|
|
|
|
|
|
|
if opt_size != llvm::CodeGenOptSizeNone {
|
|
|
|
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
|
|
|
|
}
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
|
|
|
|
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
|
|
|
|
|
|
|
|
// Here we match what clang does (kinda). For O0 we only inline
|
|
|
|
// always-inline functions (but don't add lifetime intrinsics), at O1 we
|
|
|
|
// inline with lifetime intrinsics, and O2+ we add an inliner with a
|
|
|
|
// thresholds copied from clang.
|
2016-03-27 19:42:47 +00:00
|
|
|
match (opt_level, opt_size, inline_threshold) {
|
2016-08-26 16:23:42 +00:00
|
|
|
(.., Some(t)) => {
|
2015-11-20 00:07:09 +00:00
|
|
|
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
|
|
|
|
}
|
2016-08-26 16:23:42 +00:00
|
|
|
(llvm::CodeGenOptLevel::Aggressive, ..) => {
|
2016-03-27 19:42:47 +00:00
|
|
|
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
|
|
|
|
}
|
|
|
|
(_, llvm::CodeGenOptSizeDefault, _) => {
|
|
|
|
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
|
|
|
|
}
|
|
|
|
(_, llvm::CodeGenOptSizeAggressive, _) => {
|
|
|
|
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
|
|
|
|
}
|
2016-08-26 16:23:42 +00:00
|
|
|
(llvm::CodeGenOptLevel::None, ..) => {
|
2014-08-11 17:33:58 +00:00
|
|
|
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
|
|
|
|
}
|
2016-08-26 16:23:42 +00:00
|
|
|
(llvm::CodeGenOptLevel::Less, ..) => {
|
2014-08-11 17:33:58 +00:00
|
|
|
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
|
|
|
|
}
|
2016-08-26 16:23:42 +00:00
|
|
|
(llvm::CodeGenOptLevel::Default, ..) => {
|
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
2015-05-14 19:10:43 +00:00
|
|
|
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
2016-08-26 16:23:42 +00:00
|
|
|
(llvm::CodeGenOptLevel::Other, ..) => {
|
2016-08-01 21:16:16 +00:00
|
|
|
bug!("CodeGenOptLevel::Other selected")
|
|
|
|
}
|
2014-08-11 17:33:58 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 23:22:51 +00:00
|
|
|
f(builder);
|
2014-08-11 17:33:58 +00:00
|
|
|
llvm::LLVMPassManagerBuilderDispose(builder);
|
|
|
|
}
|
2017-07-21 15:15:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
enum SharedEmitterMessage {
|
|
|
|
Diagnostic(Diagnostic),
|
|
|
|
InlineAsmError(u32, String),
|
|
|
|
AbortIfErrors,
|
|
|
|
Fatal(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SharedEmitter {
|
|
|
|
sender: Sender<SharedEmitterMessage>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SharedEmitterMain {
|
|
|
|
receiver: Receiver<SharedEmitterMessage>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SharedEmitter {
|
|
|
|
pub fn new() -> (SharedEmitter, SharedEmitterMain) {
|
|
|
|
let (sender, receiver) = channel();
|
|
|
|
|
|
|
|
(SharedEmitter { sender }, SharedEmitterMain { receiver })
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inline_asm_error(&self, cookie: u32, msg: String) {
|
|
|
|
drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg)));
|
|
|
|
}
|
|
|
|
|
2017-07-24 14:18:11 +00:00
|
|
|
fn fatal(&self, msg: &str) {
|
|
|
|
drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string())));
|
2017-07-21 15:15:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Emitter for SharedEmitter {
|
|
|
|
fn emit(&mut self, db: &DiagnosticBuilder) {
|
|
|
|
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
|
|
|
msg: db.message(),
|
|
|
|
code: db.code.clone(),
|
|
|
|
lvl: db.level,
|
|
|
|
})));
|
|
|
|
for child in &db.children {
|
|
|
|
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
|
|
|
msg: child.message(),
|
|
|
|
code: None,
|
|
|
|
lvl: child.level,
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SharedEmitterMain {
|
2017-07-26 08:27:24 +00:00
|
|
|
pub fn check(&self, sess: &Session, blocking: bool) {
|
2017-07-21 15:15:18 +00:00
|
|
|
loop {
|
2017-07-26 08:27:24 +00:00
|
|
|
let message = if blocking {
|
|
|
|
match self.receiver.recv() {
|
|
|
|
Ok(message) => Ok(message),
|
|
|
|
Err(_) => Err(()),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match self.receiver.try_recv() {
|
|
|
|
Ok(message) => Ok(message),
|
|
|
|
Err(_) => Err(()),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match message {
|
2017-07-21 15:15:18 +00:00
|
|
|
Ok(SharedEmitterMessage::Diagnostic(diag)) => {
|
|
|
|
let handler = sess.diagnostic();
|
|
|
|
match diag.code {
|
|
|
|
Some(ref code) => {
|
|
|
|
handler.emit_with_code(&MultiSpan::new(),
|
|
|
|
&diag.msg,
|
2017-10-27 06:21:22 +00:00
|
|
|
code.clone(),
|
2017-07-21 15:15:18 +00:00
|
|
|
diag.lvl);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
handler.emit(&MultiSpan::new(),
|
|
|
|
&diag.msg,
|
|
|
|
diag.lvl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
|
|
|
|
match Mark::from_u32(cookie).expn_info() {
|
|
|
|
Some(ei) => sess.span_err(ei.call_site, &msg),
|
|
|
|
None => sess.err(&msg),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(SharedEmitterMessage::AbortIfErrors) => {
|
|
|
|
sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
Ok(SharedEmitterMessage::Fatal(msg)) => {
|
|
|
|
sess.fatal(&msg);
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-26 08:27:24 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub struct OngoingCodegen {
|
2017-07-26 14:12:34 +00:00
|
|
|
crate_name: Symbol,
|
2018-08-18 10:08:06 +00:00
|
|
|
crate_hash: Svh,
|
2017-07-26 14:12:34 +00:00
|
|
|
metadata: EncodedMetadata,
|
|
|
|
windows_subsystem: Option<String>,
|
|
|
|
linker_info: LinkerInfo,
|
2017-08-28 22:55:32 +00:00
|
|
|
crate_info: CrateInfo,
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph: Option<TimeGraph>,
|
2018-07-11 10:49:11 +00:00
|
|
|
coordinator_send: Sender<Box<dyn Any + Send>>,
|
2018-05-08 13:10:16 +00:00
|
|
|
codegen_worker_receive: Receiver<Message>,
|
2017-07-26 09:41:34 +00:00
|
|
|
shared_emitter_main: SharedEmitterMain,
|
2017-10-08 20:57:03 +00:00
|
|
|
future: thread::JoinHandle<Result<CompiledModules, ()>>,
|
2017-09-14 03:26:39 +00:00
|
|
|
output_filenames: Arc<OutputFilenames>,
|
2017-07-26 08:27:24 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
impl OngoingCodegen {
|
2018-05-09 06:10:03 +00:00
|
|
|
pub(crate) fn join(
|
|
|
|
self,
|
|
|
|
sess: &Session
|
2018-05-08 13:10:16 +00:00
|
|
|
) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
|
2017-07-26 09:41:34 +00:00
|
|
|
self.shared_emitter_main.check(sess, true);
|
2017-08-01 09:04:24 +00:00
|
|
|
let compiled_modules = match self.future.join() {
|
2017-10-08 20:57:03 +00:00
|
|
|
Ok(Ok(compiled_modules)) => compiled_modules,
|
|
|
|
Ok(Err(())) => {
|
|
|
|
sess.abort_if_errors();
|
|
|
|
panic!("expected abort due to worker thread errors")
|
|
|
|
},
|
2017-08-01 09:04:24 +00:00
|
|
|
Err(_) => {
|
2018-10-12 20:25:22 +00:00
|
|
|
bug!("panic during codegen/LLVM phase");
|
2017-08-01 09:04:24 +00:00
|
|
|
}
|
|
|
|
};
|
2017-07-26 09:41:34 +00:00
|
|
|
|
2018-09-18 14:33:24 +00:00
|
|
|
sess.cgu_reuse_tracker.check_expected_reuse(sess);
|
|
|
|
|
2017-07-26 09:41:34 +00:00
|
|
|
sess.abort_if_errors();
|
2017-07-26 08:27:24 +00:00
|
|
|
|
2017-07-27 11:02:31 +00:00
|
|
|
if let Some(time_graph) = self.time_graph {
|
|
|
|
time_graph.dump(&format!("{}-timings", self.crate_name));
|
|
|
|
}
|
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
let work_products =
|
|
|
|
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
|
2018-08-31 13:18:08 +00:00
|
|
|
&compiled_modules);
|
2017-07-26 10:35:23 +00:00
|
|
|
produce_final_output_artifacts(sess,
|
|
|
|
&compiled_modules,
|
|
|
|
&self.output_filenames);
|
2017-07-26 09:41:34 +00:00
|
|
|
|
|
|
|
// FIXME: time_llvm_passes support - does this use a global context or
|
|
|
|
// something?
|
2017-10-04 21:38:52 +00:00
|
|
|
if sess.codegen_units() == 1 && sess.time_llvm_passes() {
|
2017-07-26 09:41:34 +00:00
|
|
|
unsafe { llvm::LLVMRustPrintPassTimings(); }
|
|
|
|
}
|
2017-07-26 08:27:24 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
(CodegenResults {
|
2017-07-26 08:27:24 +00:00
|
|
|
crate_name: self.crate_name,
|
2018-08-18 10:08:06 +00:00
|
|
|
crate_hash: self.crate_hash,
|
2017-07-26 08:27:24 +00:00
|
|
|
metadata: self.metadata,
|
|
|
|
windows_subsystem: self.windows_subsystem,
|
|
|
|
linker_info: self.linker_info,
|
2017-08-28 22:55:32 +00:00
|
|
|
crate_info: self.crate_info,
|
2017-07-26 08:27:24 +00:00
|
|
|
|
2017-07-26 09:41:34 +00:00
|
|
|
modules: compiled_modules.modules,
|
|
|
|
allocator_module: compiled_modules.allocator_module,
|
2017-10-20 01:44:33 +00:00
|
|
|
metadata_module: compiled_modules.metadata_module,
|
2018-05-08 13:10:16 +00:00
|
|
|
}, work_products)
|
2017-07-26 08:27:24 +00:00
|
|
|
}
|
2017-07-26 10:35:23 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub(crate) fn submit_pre_codegened_module_to_llvm(&self,
|
2018-10-06 09:37:28 +00:00
|
|
|
tcx: TyCtxt,
|
|
|
|
module: ModuleCodegen) {
|
2018-05-08 13:10:16 +00:00
|
|
|
self.wait_for_signal_to_codegen_item();
|
2017-09-14 03:26:39 +00:00
|
|
|
self.check_for_errors(tcx.sess);
|
2017-07-28 12:28:08 +00:00
|
|
|
|
|
|
|
// These are generally cheap and won't through off scheduling.
|
|
|
|
let cost = 0;
|
2018-05-08 13:10:16 +00:00
|
|
|
submit_codegened_module_to_llvm(tcx, module, cost);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub fn codegen_finished(&self, tcx: TyCtxt) {
|
|
|
|
self.wait_for_signal_to_codegen_item();
|
2017-09-14 03:26:39 +00:00
|
|
|
self.check_for_errors(tcx.sess);
|
2018-05-08 13:10:16 +00:00
|
|
|
drop(self.coordinator_send.send(Box::new(Message::CodegenComplete)));
|
2017-07-26 12:18:11 +00:00
|
|
|
}
|
2017-07-26 14:02:32 +00:00
|
|
|
|
2018-10-31 18:32:27 +00:00
|
|
|
/// Consume this context indicating that codegen was entirely aborted, and
|
|
|
|
/// we need to exit as quickly as possible.
|
|
|
|
///
|
|
|
|
/// This method blocks the current thread until all worker threads have
|
|
|
|
/// finished, and all worker threads should have exited or be real close to
|
|
|
|
/// exiting at this point.
|
|
|
|
pub fn codegen_aborted(self) {
|
|
|
|
// Signal to the coordinator it should spawn no more work and start
|
|
|
|
// shutdown.
|
|
|
|
drop(self.coordinator_send.send(Box::new(Message::CodegenAborted)));
|
|
|
|
drop(self.future.join());
|
|
|
|
}
|
|
|
|
|
2017-07-26 14:02:32 +00:00
|
|
|
pub fn check_for_errors(&self, sess: &Session) {
|
|
|
|
self.shared_emitter_main.check(sess, false);
|
|
|
|
}
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub fn wait_for_signal_to_codegen_item(&self) {
|
|
|
|
match self.codegen_worker_receive.recv() {
|
|
|
|
Ok(Message::CodegenItem) => {
|
2017-07-27 14:59:30 +00:00
|
|
|
// Nothing to do
|
|
|
|
}
|
2017-07-23 15:14:38 +00:00
|
|
|
Ok(_) => panic!("unexpected message"),
|
2017-07-27 14:59:30 +00:00
|
|
|
Err(_) => {
|
|
|
|
// One of the LLVM threads must have panicked, fall through so
|
|
|
|
// error handling can be reached.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-26 08:27:24 +00:00
|
|
|
}
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2018-10-31 18:32:27 +00:00
|
|
|
// impl Drop for OngoingCodegen {
|
|
|
|
// fn drop(&mut self) {
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt,
|
2018-08-20 15:13:01 +00:00
|
|
|
module: ModuleCodegen,
|
|
|
|
cost: u64) {
|
2018-05-08 13:10:16 +00:00
|
|
|
let llvm_work_item = WorkItem::Optimize(module);
|
|
|
|
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
|
2017-09-14 03:26:39 +00:00
|
|
|
llvm_work_item,
|
|
|
|
cost,
|
|
|
|
})));
|
|
|
|
}
|
2017-10-17 20:08:13 +00:00
|
|
|
|
2018-08-20 15:13:01 +00:00
|
|
|
pub(crate) fn submit_post_lto_module_to_llvm(tcx: TyCtxt,
|
|
|
|
module: CachedModuleCodegen) {
|
|
|
|
let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module);
|
|
|
|
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
|
|
|
|
llvm_work_item,
|
|
|
|
cost: 0,
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
|
|
|
|
module: CachedModuleCodegen) {
|
2018-08-31 13:18:08 +00:00
|
|
|
let filename = pre_lto_bitcode_filename(&module.name);
|
2018-08-20 15:13:01 +00:00
|
|
|
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)
|
|
|
|
});
|
|
|
|
|
|
|
|
let mmap = unsafe {
|
|
|
|
memmap::Mmap::map(&file).unwrap_or_else(|e| {
|
|
|
|
panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
|
|
|
// Schedule the module to be loaded
|
|
|
|
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
|
2018-09-05 11:52:58 +00:00
|
|
|
module_data: SerializedModule::FromUncompressedFile(mmap),
|
2018-08-31 13:18:08 +00:00
|
|
|
work_product: module.source,
|
2018-08-20 15:13:01 +00:00
|
|
|
})));
|
|
|
|
}
|
|
|
|
|
2018-08-31 13:18:08 +00:00
|
|
|
pub(super) fn pre_lto_bitcode_filename(module_name: &str) -> String {
|
|
|
|
format!("{}.{}", module_name, PRE_THIN_LTO_BC_EXT)
|
2018-08-20 15:13:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 20:08:13 +00:00
|
|
|
fn msvc_imps_needed(tcx: TyCtxt) -> bool {
|
2018-08-02 12:26:27 +00:00
|
|
|
// This should never be true (because it's not supported). If it is true,
|
|
|
|
// something is wrong with commandline arg validation.
|
|
|
|
assert!(!(tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() &&
|
|
|
|
tcx.sess.target.target.options.is_like_msvc &&
|
|
|
|
tcx.sess.opts.cg.prefer_dynamic));
|
|
|
|
|
2017-10-17 20:08:13 +00:00
|
|
|
tcx.sess.target.target.options.is_like_msvc &&
|
2018-08-06 09:16:28 +00:00
|
|
|
tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib) &&
|
2018-08-02 12:26:27 +00:00
|
|
|
// ThinLTO can't handle this workaround in all cases, so we don't
|
|
|
|
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
|
|
|
|
// dynamic linking when cross-language LTO is enabled.
|
|
|
|
!tcx.sess.opts.debugging_opts.cross_lang_lto.enabled()
|
2017-10-17 20:08:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
|
|
|
|
// This is required to satisfy `dllimport` references to static data in .rlibs
|
|
|
|
// when using MSVC linker. We do this only for data, as linker can fix up
|
|
|
|
// code references on its own.
|
|
|
|
// See #26591, #27438
|
2018-06-27 14:57:25 +00:00
|
|
|
fn create_msvc_imps(cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module) {
|
2017-10-17 20:08:13 +00:00
|
|
|
if !cgcx.msvc_imps_needed {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// The x86 ABI seems to require that leading underscores are added to symbol
|
|
|
|
// names, so we need an extra underscore on 32-bit. There's also a leading
|
|
|
|
// '\x01' here which disables LLVM's symbol mangling (e.g. no extra
|
|
|
|
// underscores added in front).
|
|
|
|
let prefix = if cgcx.target_pointer_width == "32" {
|
|
|
|
"\x01__imp__"
|
|
|
|
} else {
|
|
|
|
"\x01__imp_"
|
|
|
|
};
|
|
|
|
unsafe {
|
2018-08-22 15:48:32 +00:00
|
|
|
let i8p_ty = Type::i8p_llcx(llcx);
|
2017-10-17 20:08:13 +00:00
|
|
|
let globals = base::iter_globals(llmod)
|
|
|
|
.filter(|&val| {
|
|
|
|
llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage &&
|
|
|
|
llvm::LLVMIsDeclaration(val) == 0
|
|
|
|
})
|
|
|
|
.map(move |val| {
|
|
|
|
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
|
|
|
|
let mut imp_name = prefix.as_bytes().to_vec();
|
|
|
|
imp_name.extend(name.to_bytes());
|
|
|
|
let imp_name = CString::new(imp_name).unwrap();
|
|
|
|
(imp_name, val)
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
for (imp_name, val) in globals {
|
|
|
|
let imp = llvm::LLVMAddGlobal(llmod,
|
2018-07-02 14:52:53 +00:00
|
|
|
i8p_ty,
|
2017-10-17 20:08:13 +00:00
|
|
|
imp_name.as_ptr() as *const _);
|
|
|
|
llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
|
|
|
|
llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|