Skip to content

Commit

Permalink
Rollup merge of rust-lang#62809 - alexcrichton:wasm-llvm-9, r=nikic
Browse files Browse the repository at this point in the history
rustc: Update wasm32 support for LLVM 9

This commit brings in a number of minor updates for rustc's support for
the wasm target which has changed in the LLVM 9 update. Notable updates
include:

* The compiler now no longer manually inserts the `producers` section,
  instead relying on LLVM to do so. LLVM uses the `llvm.ident` metadata
  for the `processed-by` directive (which is now emitted on the wasm
  target in this PR) and it uses debuginfo to figure out what `language`
  to put in the `producers` section.

* Threaded WebAssembly code now requires different flags to be passed
  with LLD. In LLD we now pass:

  * `--shared-memory` - required since objects are compiled with
    atomics. This also means that the generated memory will be marked as
    `shared`.
  * `--max-memory=1GB` - required with the `--shared-memory` argument
    since shared memories in WebAssembly must have a maximum size. The
    1GB number is intended to be a conservative estimate for rustc, but
    it should be overridable with `-C link-arg` if necessary.
  * `--passive-segments` - this has become the default for multithreaded
    memory, but when compiling a threaded module all data segments need
    to be marked as passive to ensure they don't re-initialize memory
    for each thread. This will also cause LLD to emit a synthetic
    function to initialize memory which users will have to arrange to
    call.
  * The `__heap_base` and `__data_end` globals are explicitly exported
    since they're now hidden by default due to the `--export` flags we
    pass to LLD.
  • Loading branch information
Centril authored Jul 29, 2019
2 parents c7312fe + dc50a63 commit 778b631
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 338 deletions.
22 changes: 20 additions & 2 deletions src/librustc_codegen_llvm/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,9 +913,12 @@ pub fn compile_unit_metadata(
}

debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
let rustc_producer = format!(
"rustc version {}",
option_env!("CFG_VERSION").expect("CFG_VERSION"),
);
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
let producer = format!("clang LLVM (rustc version {})",
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
let producer = format!("clang LLVM ({})", rustc_producer);

let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
Expand Down Expand Up @@ -980,6 +983,21 @@ pub fn compile_unit_metadata(
gcov_metadata);
}

// Insert `llvm.ident` metadata on the wasm32 targets since that will
// get hooked up to the "producer" sections `processed-by` information.
if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
let name_metadata = llvm::LLVMMDStringInContext(
debug_context.llcontext,
rustc_producer.as_ptr() as *const _,
rustc_producer.as_bytes().len() as c_uint,
);
llvm::LLVMAddNamedMetadataOperand(
debug_context.llmod,
const_cstr!("llvm.ident").as_ptr(),
llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
);
}

return unit_metadata;
};

Expand Down
8 changes: 0 additions & 8 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,14 +678,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
sess.fatal(&format!("failed to run dsymutil: {}", e))
}
}

if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" {
super::wasm::add_producer_section(
&out_filename,
&sess.edition().to_string(),
option_env!("CFG_VERSION").unwrap_or("unknown"),
);
}
}

/// Returns a boolean indicating whether the specified crate should be ignored
Expand Down
47 changes: 46 additions & 1 deletion src/librustc_codegen_ssa/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,45 @@ pub struct WasmLd<'a> {
}

impl<'a> WasmLd<'a> {
fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
// If the atomics feature is enabled for wasm then we need a whole bunch
// of flags:
//
// * `--shared-memory` - the link won't even succeed without this, flags
// the one linear memory as `shared`
//
// * `--max-memory=1G` - when specifying a shared memory this must also
// be specified. We conservatively choose 1GB but users should be able
// to override this with `-C link-arg`.
//
// * `--import-memory` - it doesn't make much sense for memory to be
// exported in a threaded module because typically you're
// sharing memory and instantiating the module multiple times. As a
// result if it were exported then we'd just have no sharing.
//
// * `--passive-segments` - all memory segments should be passive to
// prevent each module instantiation from reinitializing memory.
//
// * `--export=__wasm_init_memory` - when using `--passive-segments` the
// linker will synthesize this function, and so we need to make sure
// that our usage of `--export` below won't accidentally cause this
// function to get deleted.
//
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
// symbols are how the TLS segments are initialized and configured.
let atomics = sess.opts.cg.target_feature.contains("+atomics") ||
sess.target.target.options.features.contains("+atomics");
if atomics {
cmd.arg("--shared-memory");
cmd.arg("--max-memory=1073741824");
cmd.arg("--import-memory");
cmd.arg("--passive-segments");
cmd.arg("--export=__wasm_init_memory");
cmd.arg("--export=__wasm_init_tls");
cmd.arg("--export=__tls_size");
cmd.arg("--export=__tls_align");
cmd.arg("--export=__tls_base");
}
WasmLd { cmd, sess, info }
}
}
Expand Down Expand Up @@ -1004,6 +1042,13 @@ impl<'a> Linker for WasmLd<'a> {
for sym in self.info.exports[&crate_type].iter() {
self.cmd.arg("--export").arg(&sym);
}

// LLD will hide these otherwise-internal symbols since our `--export`
// list above is a whitelist of what to export. Various bits and pieces
// of tooling use this, so be sure these symbols make their way out of
// the linker as well.
self.cmd.arg("--export=__heap_base");
self.cmd.arg("--export=__data_end");
}

fn subsystem(&mut self, _subsystem: &str) {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_codegen_ssa/back/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ pub mod command;
pub mod symbol_export;
pub mod archive;
pub mod rpath;
pub mod wasm;
191 changes: 0 additions & 191 deletions src/librustc_codegen_ssa/back/wasm.rs

This file was deleted.

8 changes: 8 additions & 0 deletions src/librustc_target/spec/wasm32_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ pub fn options() -> TargetOptions {
// non-relative calls and such later on).
relocation_model: "static".to_string(),

// When the atomics feature is activated then these two keys matter,
// otherwise they're basically ignored by the standard library. In this
// mode, however, the `#[thread_local]` attribute works (i.e.
// `has_elf_tls`) and we need to get it to work by specifying
// `local-exec` as that's all that's implemented in LLVM today for wasm.
has_elf_tls: true,
tls_model: "local-exec".to_string(),

.. Default::default()
}
}
5 changes: 0 additions & 5 deletions src/libstd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@ panic_immediate_abort = ["core/panic_immediate_abort"]
# requires rebuilding the standard library to use it.
wasm_syscall = []

# An off-by-default features to enable libstd to assume that wasm-bindgen is in
# the environment for hooking up some thread-related information like the
# current thread id and accessing/getting the current thread's TCB
wasm-bindgen-threads = []

# Enable std_detect default features for stdarch/crates/std_detect:
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
std_detect_file_io = []
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/sys/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub mod stdio;
pub mod thread;
#[path = "../wasm/thread_local.rs"]
pub mod thread_local;
#[path = "../wasm/fast_thread_local.rs"]
pub mod fast_thread_local;
pub mod time;
pub mod ext;

Expand Down
9 changes: 9 additions & 0 deletions src/libstd/sys/wasm/fast_thread_local.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![unstable(feature = "thread_local_internals", issue = "0")]

pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) {
// FIXME: right now there is no concept of "thread exit", but this is likely
// going to show up at some point in the form of an exported symbol that the
// wasm runtime is oging to be expected to call. For now we basically just
// ignore the arguments, but if such a function starts to exist it will
// likely look like the OSX implementation in `unix/fast_thread_local.rs`
}
5 changes: 2 additions & 3 deletions src/libstd/sys/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub mod stack_overflow;
pub mod thread;
pub mod time;
pub mod stdio;
pub mod thread_local;
pub mod fast_thread_local;

pub use crate::sys_common::os_str_bytes as os_str;

Expand All @@ -48,13 +50,10 @@ cfg_if::cfg_if! {
pub mod mutex;
#[path = "rwlock_atomics.rs"]
pub mod rwlock;
#[path = "thread_local_atomics.rs"]
pub mod thread_local;
} else {
pub mod condvar;
pub mod mutex;
pub mod rwlock;
pub mod thread_local;
}
}

Expand Down
Loading

0 comments on commit 778b631

Please sign in to comment.