diff --git a/.gitignore b/.gitignore
index 57407a2399a2f..dea64425be24b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,7 +63,6 @@ __pycache__/
 /*-*-*/
 /Makefile
 /build
-/config.toml
 /dist/
 /dl/
 /doc
@@ -105,3 +104,9 @@ version.texi
 
 no_llvm_build
 
+# ignore guix stuff
+cc
+build-env.sh
+manifest.scm
+profile
+profile-1-link
diff --git a/.gitmodules b/.gitmodules
index fc2f8bbc8a350..b3486f17b98f7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,7 @@
 [submodule "src/llvm"]
 	path = src/llvm
-	url = https://github.com/rust-lang/llvm.git
-	branch = master
+	url = https://github.com/riscv-rust/llvm.git
+	branch = rust-llvm-release-6-0-0-riscv
 [submodule "src/jemalloc"]
 	path = src/jemalloc
 	url = https://github.com/rust-lang/jemalloc.git
@@ -10,7 +10,8 @@
 	url = https://github.com/rust-lang/rust-installer.git
 [submodule "src/liblibc"]
 	path = src/liblibc
-	url = https://github.com/rust-lang/libc.git
+	url = https://github.com/riscv-rust/libc.git
+	branch = riscv
 [submodule "src/doc/nomicon"]
 	path = src/doc/nomicon
 	url = https://github.com/rust-lang-nursery/nomicon.git
@@ -35,18 +36,16 @@
 [submodule "src/tools/rustfmt"]
 	path = src/tools/rustfmt
 	url = https://github.com/rust-lang-nursery/rustfmt.git
-[submodule "src/tools/miri"]
-	path = src/tools/miri
-	url = https://github.com/solson/miri.git
 [submodule "src/dlmalloc"]
 	path = src/dlmalloc
 	url = https://github.com/alexcrichton/dlmalloc-rs.git
-[submodule "src/binaryen"]
-	path = src/binaryen
-	url = https://github.com/alexcrichton/binaryen.git
 [submodule "src/doc/rust-by-example"]
 	path = src/doc/rust-by-example
 	url = https://github.com/rust-lang/rust-by-example
 [submodule "src/llvm-emscripten"]
 	path = src/llvm-emscripten
 	url = https://github.com/rust-lang/llvm
+[submodule "src/tools/lld"]
+	path = src/tools/lld
+	url = https://github.com/riscv-rust/riscv-lld.git
+	branch = rust-llvm-release-6-0-0-riscv
diff --git a/.travis.yml b/.travis.yml
index 280da05699506..c748882ca8443 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -81,7 +81,7 @@ matrix:
     # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7.
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler --enable-emscripten"
+        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -95,7 +95,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler --enable-emscripten"
+        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
diff --git a/README.md b/README.md
index 589aa1afe35ec..951e78bf11b6c 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# The Rust Programming Language
+# The Rust Programming Language (with RISC-V support)
 
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
@@ -129,9 +129,6 @@ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.
 python x.py build
 ```
 
-If you are seeing build failure when compiling `rustc_binaryen`, make sure the path
-length of the rust folder is not longer than 22 characters.
-
 #### Specifying an ABI
 [specifying-an-abi]: #specifying-an-abi
 
diff --git a/appveyor.yml b/appveyor.yml
index 0ea15dd671c8b..0735ead8923cc 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -67,21 +67,19 @@ environment:
   # 32/64 bit MSVC and GNU deployment
   - RUST_CONFIGURE_ARGS: >
       --build=x86_64-pc-windows-msvc
-      --enable-extended
+      --enable-full-tools
       --enable-profiler
-      --enable-emscripten
     SCRIPT: python x.py dist
     DEPLOY: 1
   - RUST_CONFIGURE_ARGS: >
       --build=i686-pc-windows-msvc
       --target=i586-pc-windows-msvc
-      --enable-extended
+      --enable-full-tools
       --enable-profiler
-      --enable-emscripten
     SCRIPT: python x.py dist
     DEPLOY: 1
   - MSYS_BITS: 32
-    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-emscripten
+    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools
     SCRIPT: python x.py dist
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
@@ -89,7 +87,7 @@ environment:
     DEPLOY: 1
   - MSYS_BITS: 64
     SCRIPT: python x.py dist
-    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-emscripten
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
     MINGW_DIR: mingw64
diff --git a/config.toml b/config.toml
new file mode 100644
index 0000000000000..a02b528c02550
--- /dev/null
+++ b/config.toml
@@ -0,0 +1,423 @@
+# Sample TOML configuration file for building Rust.
+#
+# To configure rustbuild, copy this file to the directory from which you will be
+# running the build, and name it config.toml.
+#
+# All options are commented out by default in this file, and they're commented
+# out with their default values. The build system by default looks for
+# `config.toml` in the current directory of a build for build configuration, but
+# a custom configuration file can also be specified with `--config` to the build
+# system.
+
+# =============================================================================
+# Tweaking how LLVM is compiled
+# =============================================================================
+[llvm]
+
+# Indicates whether rustc will support compilation with LLVM
+# note: rustc does not compile without LLVM at the moment
+#enabled = true
+
+# Indicates whether the LLVM build is a Release or Debug build
+#optimize = true
+
+# Indicates whether an LLVM Release build should include debug info
+release-debuginfo = true
+
+# Indicates whether the LLVM assertions are enabled or not
+assertions = true
+
+# Indicates whether ccache is used when building LLVM
+#ccache = false
+# or alternatively ...
+#ccache = "/path/to/ccache"
+
+# If an external LLVM root is specified, we automatically check the version by
+# default to make sure it's within the range that we're expecting, but setting
+# this flag will indicate that this version check should not be done.
+#version-check = true
+
+# Link libstdc++ statically into the librustc_llvm instead of relying on a
+# dynamic version to be available.
+#static-libstdcpp = false
+
+# Tell the LLVM build system to use Ninja instead of the platform default for
+# the generated build system. This can sometimes be faster than make, for
+# example.
+ninja = true
+
+# LLVM targets to build support for.
+# Note: this is NOT related to Rust compilation targets. However, as Rust is
+# dependent on LLVM for code generation, turning targets off here WILL lead to
+# the resulting rustc being unable to compile for the disabled architectures.
+# Also worth pointing out is that, in case support for new targets are added to
+# LLVM, enabling them here doesn't mean Rust is automatically gaining said
+# support. You'll need to write a target specification at least, and most
+# likely, teach rustc about the C ABI of the target. Get in touch with the
+# Rust team and file an issue if you need assistance in porting!
+targets = "X86"
+
+# LLVM experimental targets to build support for. These targets are specified in
+# the same format as above, but since these targets are experimental, they are
+# not built by default and the experimental Rust compilation targets that depend
+# on them will not work unless the user opts in to building them. By default the
+# `WebAssembly` target is enabled when compiling LLVM from scratch.
+experimental-targets = "RISCV"
+
+# Cap the number of parallel linker invocations when compiling LLVM.
+# This can be useful when building LLVM with debug info, which significantly
+# increases the size of binaries and consequently the memory required by
+# each linker process.
+# If absent or 0, linker invocations are treated like any other job and
+# controlled by rustbuild's -j parameter.
+#link-jobs = 0
+
+# When invoking `llvm-config` this configures whether the `--shared` argument is
+# passed to prefer linking to shared libraries.
+#link-shared = false
+
+# =============================================================================
+# General build configuration options
+# =============================================================================
+[build]
+
+# Build triple for the original snapshot compiler. This must be a compiler that
+# nightlies are already produced for. The current platform must be able to run
+# binaries of this build triple and the nightly will be used to bootstrap the
+# first compiler.
+#build = "x86_64-unknown-linux-gnu"    # defaults to your host platform
+
+# In addition to the build triple, other triples to produce full compiler
+# toolchains for. Each of these triples will be bootstrapped from the build
+# triple and then will continue to bootstrap themselves. This platform must
+# currently be able to run all of the triples provided here.
+#host = ["x86_64-unknown-linux-gnu"]   # defaults to just the build triple
+
+# In addition to all host triples, other triples to produce the standard library
+# for. Each host triple will be used to produce a copy of the standard library
+# for each target triple.
+#target = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple
+
+# Instead of downloading the src/stage0.txt version of Cargo specified, use
+# this Cargo binary instead to build all Rust code
+#cargo = "/path/to/bin/cargo"
+
+# Instead of downloading the src/stage0.txt version of the compiler
+# specified, use this rustc binary instead as the stage0 snapshot compiler.
+#rustc = "/path/to/bin/rustc"
+
+# Flag to specify whether any documentation is built. If false, rustdoc and
+# friends will still be compiled but they will not be used to generate any
+# documentation.
+docs = false
+
+# Indicate whether the compiler should be documented in addition to the standard
+# library and facade crates.
+#compiler-docs = false
+
+# Indicate whether submodules are managed and updated automatically.
+#submodules = true
+
+# The path to (or name of) the GDB executable to use. This is only used for
+# executing the debuginfo test suite.
+#gdb = "gdb"
+
+# The node.js executable to use. Note that this is only used for the emscripten
+# target when running tests, otherwise this can be omitted.
+#nodejs = "node"
+
+# Python interpreter to use for various tasks throughout the build, notably
+# rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
+# Note that Python 2 is currently required.
+#python = "python2.7"
+
+# Force Cargo to check that Cargo.lock describes the precise dependency
+# set that all the Cargo.toml files create, instead of updating it.
+#locked-deps = false
+
+# Indicate whether the vendored sources are used for Rust dependencies or not
+#vendor = false
+
+# Typically the build system will build the rust compiler twice. The second
+# compiler, however, will simply use its own libraries to link against. If you
+# would rather to perform a full bootstrap, compiling the compiler three times,
+# then you can set this option to true. You shouldn't ever need to set this
+# option to true.
+#full-bootstrap = false
+
+# Enable a build of the extended rust tool set which is not only the compiler
+# but also tools such as Cargo. This will also produce "combined installers"
+# which are used to install Rust and Cargo together. This is disabled by
+# default.
+extended = true
+
+# Installs choosen set of extended tools if enables. By default builds all.
+# If choosen tool failed to build the installation fails.
+#tools = ["cargo", "rls", "rustfmt", "analysis", "src"]
+
+# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
+#verbose = 0
+
+# Build the sanitizer runtimes
+#sanitizers = false
+
+# Build the profiler runtime
+#profiler = false
+
+# Indicates whether the OpenSSL linked into Cargo will be statically linked or
+# not. If static linkage is specified then the build system will download a
+# known-good version of OpenSSL, compile it, and link it to Cargo.
+#openssl-static = false
+
+# Run the build with low priority, by setting the process group's "nice" value
+# to +10 on Unix platforms, and by using a "low priority" job object on Windows.
+#low-priority = false
+
+# Arguments passed to the `./configure` script, used during distcheck. You
+# probably won't fill this in but rather it's filled in by the `./configure`
+# script.
+#configure-args = []
+
+# Indicates that a local rebuild is occurring instead of a full bootstrap,
+# essentially skipping stage0 as the local compiler is recompiling itself again.
+#local-rebuild = false
+
+# =============================================================================
+# General install configuration options
+# =============================================================================
+[install]
+
+# Instead of installing to /usr/local, install to this path instead.
+prefix = "/opt/rust"
+
+# Where to install system configuration files
+# If this is a relative path, it will get installed in `prefix` above
+sysconfdir = "etc"
+
+# Where to install documentation in `prefix` above
+#docdir = "share/doc/rust"
+
+# Where to install binaries in `prefix` above
+#bindir = "bin"
+
+# Where to install libraries in `prefix` above
+#libdir = "lib"
+
+# Where to install man pages in `prefix` above
+#mandir = "share/man"
+
+# Where to install data in `prefix` above (currently unused)
+#datadir = "share"
+
+# Where to install additional info in `prefix` above (currently unused)
+#infodir = "share/info"
+
+# Where to install local state (currently unused)
+# If this is a relative path, it will get installed in `prefix` above
+localstatedir = "var/lib"
+
+# =============================================================================
+# Options for compiling Rust code itself
+# =============================================================================
+[rust]
+
+# Indicates that the build should be optimized for debugging Rust. Note that
+# this is typically not what you want as it takes an incredibly large amount of
+# time to have a debug-mode rustc compile any code (notably libstd). If this
+# value is set to `true` it will affect a number of configuration options below
+# as well, if unconfigured.
+#debug = false
+
+# Whether or not to optimize the compiler and standard library
+# Note: the slowness of the non optimized compiler compiling itself usually
+#       outweighs the time gains in not doing optimizations, therefore a
+#       full bootstrap takes much more time with optimize set to false.
+#optimize = true
+
+# Number of codegen units to use for each compiler invocation. A value of 0
+# means "the number of cores on this machine", and 1+ is passed through to the
+# compiler.
+#codegen-units = 1
+
+# Whether to enable ThinLTO (and increase the codegen units to either a default
+# or the configured value). On by default. If we want the fastest possible
+# compiler, we should disable this.
+#thinlto = true
+
+# Whether or not debug assertions are enabled for the compiler and standard
+# library. Also enables compilation of debug! and trace! logging macros.
+#debug-assertions = false
+
+# Whether or not debuginfo is emitted
+debuginfo = true
+
+# Whether or not line number debug information is emitted
+debuginfo-lines = true
+
+# Whether or not to only build debuginfo for the standard library if enabled.
+# If enabled, this will not compile the compiler with debuginfo, just the
+# standard library.
+#debuginfo-only-std = false
+
+# Whether or not jemalloc is built and enabled
+use-jemalloc = false
+
+# Whether or not jemalloc is built with its debug option set
+#debug-jemalloc = false
+
+# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
+backtrace = false
+
+# The default linker that will be hard-coded into the generated compiler for
+# targets that don't specify linker explicitly in their target specifications.
+# Note that this is not the linker used to link said compiler.
+default-linker = "gcc"
+
+# The "channel" for the Rust build to produce. The stable/beta channels only
+# allow using stable features, whereas the nightly and dev channels allow using
+# nightly features
+channel = "dev"
+
+# By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix
+# platforms to ensure that the compiler is usable by default from the build
+# directory (as it links to a number of dynamic libraries). This may not be
+# desired in distributions, for example.
+#rpath = true
+
+# Suppresses extraneous output from tests to ensure the output of the test
+# harness is relatively clean.
+#quiet-tests = false
+
+# Flag indicating whether tests are compiled with optimizations (the -O flag) or
+# with debuginfo (the -g flag)
+#optimize-tests = true
+#debuginfo-tests = true
+
+# Flag indicating whether codegen tests will be run or not. If you get an error
+# saying that the FileCheck executable is missing, you may want to disable this.
+#codegen-tests = true
+
+# Flag indicating whether git info will be retrieved from .git automatically.
+# Having the git information can cause a lot of rebuilds during development.
+# Note: If this attribute is not explicitly set (e.g. if left commented out) it
+# will default to true if channel = "dev", but will default to false otherwise.
+#ignore-git = true
+
+# When creating source tarballs whether or not to create a source tarball.
+#dist-src = false
+
+# Whether to also run the Miri tests suite when running tests.
+# As a side-effect also generates MIR for all libraries.
+#test-miri = false
+
+# After building or testing extended tools (e.g. clippy and rustfmt), append the
+# result (broken, compiling, testing) into this JSON file.
+#save-toolstates = "/path/to/toolstates.json"
+
+# This is an array of the codegen backends that will be compiled for the rustc
+# that's being compiled. The default is to only build the LLVM codegen backend,
+# but you can also optionally enable the "emscripten" backend for asm.js or
+# make this an empty array (but that probably won't get too far in the
+# bootstrap)
+#codegen-backends = ["llvm"]
+
+# Flag indicating whether `libstd` calls an imported function to handle basic IO
+# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
+# target, as without this option the test output will not be captured.
+#wasm-syscall = false
+
+# Indicates whether LLD will be compiled and made available in the sysroot for
+# rustc to execute.
+lld = true
+
+# =============================================================================
+# Options for specific targets
+#
+# Each of the following options is scoped to the specific target triple in
+# question and is used for determining how to compile each target.
+# =============================================================================
+[target.x86_64-unknown-linux-gnu]
+
+# C compiler to be used to compiler C code. Note that the
+# default value is platform specific, and if not specified it may also depend on
+# what platform is crossing to what platform.
+#cc = "cc"
+
+# C++ compiler to be used to compiler C++ code (e.g. LLVM and our LLVM shims).
+# This is only used for host targets.
+#cxx = "c++"
+
+# Archiver to be used to assemble static libraries compiled from C/C++ code.
+# Note: an absolute path should be used, otherwise LLVM build will break.
+#ar = "ar"
+
+# Linker to be used to link Rust code. Note that the
+# default value is platform specific, and if not specified it may also depend on
+# what platform is crossing to what platform.
+#linker = "cc"
+
+# Path to the `llvm-config` binary of the installation of a custom LLVM to link
+# against. Note that if this is specified we don't compile LLVM at all for this
+# target.
+#llvm-config = "../path/to/llvm/root/bin/llvm-config"
+
+# Path to the custom jemalloc static library to link into the standard library
+# by default. This is only used if jemalloc is still enabled above
+#jemalloc = "/path/to/jemalloc/libjemalloc_pic.a"
+
+# If this target is for Android, this option will be required to specify where
+# the NDK for the target lives. This is used to find the C compiler to link and
+# build native code.
+#android-ndk = "/path/to/ndk"
+
+# Force static or dynamic linkage of the standard library for this target. If
+# this target is a host for rustc, this will also affect the linkage of the
+# compiler itself. This is useful for building rustc on targets that normally
+# only use static libraries. If unset, the target's default linkage is used.
+# crt-static = true
+
+# The root location of the MUSL installation directory. The library directory
+# will also need to contain libunwind.a for an unwinding implementation. Note
+# that this option only makes sense for MUSL targets that produce statically
+# linked binaries
+#musl-root = "..."
+
+# Used in testing for configuring where the QEMU images are located, you
+# probably don't want to use this.
+#qemu-rootfs = "..."
+
+# =============================================================================
+# Distribution options
+#
+# These options are related to distribution, mostly for the Rust project itself.
+# You probably won't need to concern yourself with any of these options
+# =============================================================================
+[dist]
+
+# This is the folder of artifacts that the build system will sign. All files in
+# this directory will be signed with the default gpg key using the system `gpg`
+# binary. The `asc` and `sha256` files will all be output into the standard dist
+# output folder (currently `build/dist`)
+#
+# This folder should be populated ahead of time before the build system is
+# invoked.
+#sign-folder = "path/to/folder/to/sign"
+
+# This is a file which contains the password of the default gpg key. This will
+# be passed to `gpg` down the road when signing all files in `sign-folder`
+# above. This should be stored in plaintext.
+#gpg-password-file = "path/to/gpg/password"
+
+# The remote address that all artifacts will eventually be uploaded to. The
+# build system generates manifests which will point to these urls, and for the
+# manifests to be correct they'll have to have the right URLs encoded.
+#
+# Note that this address should not contain a trailing slash as file names will
+# be appended to it.
+#upload-addr = "https://example.com/folder"
+
+# Whether to build a plain source tarball to upload
+# We disable that on Windows not to override the one already uploaded on S3
+# as the one built on Windows will contain backslashes in paths causing problems
+# on linux
+#src-tarball = true
diff --git a/config.toml.example b/config.toml.example
index 8d1fa3eec5cf2..5c2b0e846e944 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -62,7 +62,7 @@
 # not built by default and the experimental Rust compilation targets that depend
 # on them will not work unless the user opts in to building them. By default the
 # `WebAssembly` target is enabled when compiling LLVM from scratch.
-#experimental-targets = "WebAssembly"
+#experimental-targets = "WebAssembly;RISCV"
 
 # Cap the number of parallel linker invocations when compiling LLVM.
 # This can be useful when building LLVM with debug info, which significantly
@@ -326,6 +326,10 @@
 # target, as without this option the test output will not be captured.
 #wasm-syscall = false
 
+# Indicates whether LLD will be compiled and made available in the sysroot for
+# rustc to execute.
+#lld = false
+
 # =============================================================================
 # Options for specific targets
 #
diff --git a/riscv32g-unknown-linux-gnu.json b/riscv32g-unknown-linux-gnu.json
new file mode 100644
index 0000000000000..32d0ce5d05caa
--- /dev/null
+++ b/riscv32g-unknown-linux-gnu.json
@@ -0,0 +1,22 @@
+{
+    "llvm-target": "riscv32",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
+    "arch": "riscv",
+    "target-family": "unix",
+    "os": "linux",
+    "env": "gnu",
+    "cpu": "generic-rv32",
+    "features": "+m,+a,+c,+f,+d",
+    "max-atomic-width": 32,
+    "target-c-int-width": "32",
+    "linker": "ld.lld",
+    "linker-flavor": "ld",
+    "executables": true,
+    "panic-strategy": "abort",
+    "relocation-model": "static",
+    "dynamic_linking": true,
+    "position_independent_executable": true,
+    "has_elf_tls": true
+}
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 8f25820d3a527..3cb0081bd0e8b 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -417,7 +417,6 @@ dependencies = [
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1133,17 +1132,6 @@ dependencies = [
  "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "miri"
-version = "0.1.0"
-dependencies = [
- "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "multiple_bins"
 version = "0.1.0"
@@ -1759,15 +1747,6 @@ dependencies = [
  "syntax 0.0.0",
 ]
 
-[[package]]
-name = "rustc_binaryen"
-version = "0.0.0"
-dependencies = [
- "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "rustc_borrowck"
 version = "0.0.0"
@@ -2044,7 +2023,6 @@ dependencies = [
  "rustc_allocator 0.0.0",
  "rustc_apfloat 0.0.0",
  "rustc_back 0.0.0",
- "rustc_binaryen 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
diff --git a/src/Cargo.toml b/src/Cargo.toml
index c03301852cd3b..59ebb35f8b2ad 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -21,7 +21,6 @@ members = [
   "tools/rustdoc",
   "tools/rls",
   "tools/rustfmt",
-  "tools/miri",
   "tools/rustdoc-themes",
   # FIXME(https://github.com/rust-lang/cargo/issues/4089): move these to exclude
   "tools/rls/test_data/bin_lib",
diff --git a/src/binaryen b/src/binaryen
deleted file mode 160000
index 17841e155edf8..0000000000000
--- a/src/binaryen
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 17841e155edf858c8ea7802dd5f5ecbef54b989f
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index ca35a896e08c8..6c3c48aba72f1 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -224,7 +224,7 @@ fn main() {
                 // flesh out rpath support more fully in the future.
                 cmd.arg("-Z").arg("osx-rpath-install-name");
                 Some("-Wl,-rpath,@loader_path/../lib")
-            } else if !target.contains("windows") {
+            } else if !target.contains("windows") && !target.contains("wasm32") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
             } else {
                 None
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5966bb65df9c8..8c329ccc733d9 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -396,7 +396,7 @@ def fix_executable(fname):
         if ostype != "Linux":
             return
 
-        if not os.path.exists("/etc/NIXOS"):
+        if not os.path.exists("/etc/NIXOS") and not os.path.exists("/etc/guix"):
             return
         if os.path.exists("/lib"):
             return
@@ -417,7 +417,7 @@ def fix_executable(fname):
 
         try:
             ldd_output = subprocess.check_output(
-                ['ldd', '/run/current-system/sw/bin/sh'])
+                ['ldd', '/bin/sh'])
             ldd_output = ldd_output.strip().decode(default_encoding)
         except subprocess.CalledProcessError as reason:
             print("warning: unable to call ldd:", reason)
@@ -654,6 +654,10 @@ def update_submodules(self):
                     continue
                 if self.get_toml('jemalloc'):
                     continue
+            if module.endswith("lld"):
+                config = self.get_toml('lld')
+                if config is None or config == 'false':
+                    continue
             filtered_submodules.append(module)
         run(["git", "submodule", "update",
              "--init", "--recursive"] + filtered_submodules,
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index b5946b44e05ef..67aa070da1f20 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -316,7 +316,7 @@ impl<'a> Builder<'a> {
                 tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
                 tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
                 tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
-                native::Llvm, tool::Rustfmt, tool::Miri),
+                native::Llvm, tool::Rustfmt, native::Lld),
             Kind::Check => describe!(check::Std, check::Test, check::Rustc),
             Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
                 test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index e531fdaf2923b..9e1b1f7db2f99 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -79,6 +79,9 @@ pub fn find(build: &mut Build) {
         let mut cfg = cc::Build::new();
         cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false)
            .target(&target).host(&build.build);
+        if target.contains("msvc") {
+            cfg.static_crt(true);
+        }
 
         let config = build.config.target_config.get(&target);
         if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index c85b04ddc0245..9df4c0c200715 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -745,6 +745,21 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
     }
 }
 
+fn copy_lld_to_sysroot(builder: &Builder,
+                       target_compiler: Compiler,
+                       lld_install_root: &Path) {
+    let target = target_compiler.host;
+
+    let dst = builder.sysroot_libdir(target_compiler, target)
+        .parent()
+        .unwrap()
+        .join("bin");
+    t!(fs::create_dir_all(&dst));
+
+    let exe = exe("lld", &target);
+    copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
+}
+
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
 pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
@@ -894,6 +909,14 @@ impl Step for Assemble {
             }
         }
 
+        let lld_install = if build.config.lld_enabled && target_compiler.stage > 0 {
+            Some(builder.ensure(native::Lld {
+                target: target_compiler.host,
+            }))
+        } else {
+            None
+        };
+
         let stage = target_compiler.stage;
         let host = target_compiler.host;
         println!("Assembling stage{} compiler ({})", stage, host);
@@ -913,6 +936,9 @@ impl Step for Assemble {
         copy_codegen_backends_to_sysroot(builder,
                                          build_compiler,
                                          target_compiler);
+        if let Some(lld_install) = lld_install {
+            copy_lld_to_sysroot(builder, target_compiler, &lld_install);
+        }
 
         // Link the compiler binary itself into place
         let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 6bc20181a0330..55f61587c1b06 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -81,6 +81,8 @@ pub struct Config {
     pub llvm_experimental_targets: String,
     pub llvm_link_jobs: Option<u32>,
 
+    pub lld_enabled: bool,
+
     // rust codegen options
     pub rust_optimize: bool,
     pub rust_codegen_units: Option<u32>,
@@ -290,6 +292,7 @@ struct Rust {
     save_toolstates: Option<String>,
     codegen_backends: Option<Vec<String>>,
     wasm_syscall: Option<bool>,
+    lld: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -477,6 +480,7 @@ impl Config {
             set(&mut config.quiet_tests, rust.quiet_tests);
             set(&mut config.test_miri, rust.test_miri);
             set(&mut config.wasm_syscall, rust.wasm_syscall);
+            set(&mut config.lld_enabled, rust.lld);
             config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
             config.rustc_default_linker = rust.default_linker.clone();
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 99a3ee4e4c369..e9b4a233d0af5 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -66,6 +66,7 @@ def v(*args):
 o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
 o("emscripten", None, "compile the emscripten backend as well as LLVM")
+o("full-tools", None, "enable all tools")
 
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
@@ -326,6 +327,10 @@ def set(key, value):
         set('build.target', value.split(','))
     elif option.name == 'emscripten':
         set('rust.codegen-backends', ['llvm', 'emscripten'])
+    elif option.name == 'full-tools':
+        set('rust.codegen-backends', ['llvm', 'emscripten'])
+        set('rust.lld', True)
+        set('build.extended', True)
     elif option.name == 'option-checking':
         # this was handled above
         pass
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index e7aed7eb4fead..56e7ad33c2329 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -28,7 +28,7 @@ use build_helper::output;
 
 use {Build, Compiler, Mode};
 use channel;
-use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file};
+use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file, exe};
 use builder::{Builder, RunConfig, ShouldRun, Step};
 use compile;
 use native;
@@ -443,6 +443,22 @@ impl Step for Rustc {
             t!(fs::create_dir_all(&backends_dst));
             cp_r(&backends_src, &backends_dst);
 
+            // Copy over lld if it's there
+            if builder.config.lld_enabled {
+                let exe = exe("lld", &compiler.host);
+                let src = builder.sysroot_libdir(compiler, host)
+                    .parent()
+                    .unwrap()
+                    .join("bin")
+                    .join(&exe);
+                let dst = image.join("lib/rustlib")
+                    .join(&*host)
+                    .join("bin")
+                    .join(&exe);
+                t!(fs::create_dir_all(&dst.parent().unwrap()));
+                copy(&src, &dst);
+            }
+
             // Man pages
             t!(fs::create_dir_all(image.join("share/man/man1")));
             let man_src = build.src.join("src/doc/man");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 90f50275b6bb4..f3d9246c6fc6c 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -501,6 +501,10 @@ impl Build {
         self.out.join(&*target).join("llvm-emscripten")
     }
 
+    fn lld_out(&self, target: Interned<String>) -> PathBuf {
+        self.out.join(&*target).join("lld")
+    }
+
     /// Output directory for all documentation for a target
     fn doc_out(&self, target: Interned<String>) -> PathBuf {
         self.out.join(&*target).join("doc")
@@ -685,7 +689,9 @@ impl Build {
                                                        .and_then(|c| c.linker.as_ref()) {
             Some(linker)
         } else if target != self.config.build &&
-                  !target.contains("msvc") && !target.contains("emscripten") {
+                  !target.contains("msvc") &&
+                  !target.contains("emscripten") &&
+                  !target.contains("wasm32") {
             Some(self.cc(target))
         } else {
             None
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 15dd7fabfa58b..ad912a178f6b9 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -81,11 +81,11 @@ impl Step for Llvm {
 
         let (out_dir, llvm_config_ret_dir) = if emscripten {
             let dir = build.emscripten_llvm_out(target);
-            let config_dir = dir.join("bin");
+            let config_dir = dir.join("build/bin");
             (dir, config_dir)
         } else {
             (build.llvm_out(target),
-                build.llvm_out(build.config.build).join("bin"))
+                build.llvm_out(build.config.build).join("build/bin"))
         };
         let done_stamp = out_dir.join("llvm-finished-building");
         let build_llvm_config = llvm_config_ret_dir
@@ -110,9 +110,6 @@ impl Step for Llvm {
         // http://llvm.org/docs/CMake.html
         let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" };
         let mut cfg = cmake::Config::new(build.src.join(root));
-        if build.config.ninja {
-            cfg.generator("Ninja");
-        }
 
         let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
             (false, _) => "Debug",
@@ -139,9 +136,7 @@ impl Step for Llvm {
 
         let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
 
-        cfg.target(&target)
-           .host(&build.build)
-           .out_dir(&out_dir)
+        cfg.out_dir(&out_dir)
            .profile(profile)
            .define("LLVM_ENABLE_ASSERTIONS", assertions)
            .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
@@ -213,67 +208,7 @@ impl Step for Llvm {
             cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build"));
         }
 
-        let sanitize_cc = |cc: &Path| {
-            if target.contains("msvc") {
-                OsString::from(cc.to_str().unwrap().replace("\\", "/"))
-            } else {
-                cc.as_os_str().to_owned()
-            }
-        };
-
-        let configure_compilers = |cfg: &mut cmake::Config| {
-            // MSVC with CMake uses msbuild by default which doesn't respect these
-            // vars that we'd otherwise configure. In that case we just skip this
-            // entirely.
-            if target.contains("msvc") && !build.config.ninja {
-                return
-            }
-
-            let cc = build.cc(target);
-            let cxx = build.cxx(target).unwrap();
-
-            // Handle msvc + ninja + ccache specially (this is what the bots use)
-            if target.contains("msvc") &&
-               build.config.ninja &&
-               build.config.ccache.is_some() {
-                let mut cc = env::current_exe().expect("failed to get cwd");
-                cc.set_file_name("sccache-plus-cl.exe");
-
-               cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
-                  .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
-               cfg.env("SCCACHE_PATH",
-                       build.config.ccache.as_ref().unwrap())
-                  .env("SCCACHE_TARGET", target);
-
-            // If ccache is configured we inform the build a little differently hwo
-            // to invoke ccache while also invoking our compilers.
-            } else if let Some(ref ccache) = build.config.ccache {
-               cfg.define("CMAKE_C_COMPILER", ccache)
-                  .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc))
-                  .define("CMAKE_CXX_COMPILER", ccache)
-                  .define("CMAKE_CXX_COMPILER_ARG1", sanitize_cc(cxx));
-            } else {
-               cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc))
-                  .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx));
-            }
-
-            cfg.build_arg("-j").build_arg(build.jobs().to_string());
-            cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
-            cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" "));
-            if let Some(ar) = build.ar(target) {
-                if ar.is_absolute() {
-                    // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
-                    // tries to resolve this path in the LLVM build directory.
-                    cfg.define("CMAKE_AR", sanitize_cc(ar));
-                }
-            }
-        };
-
-        configure_compilers(&mut cfg);
-
-        if env::var_os("SCCACHE_ERROR_LOG").is_some() {
-            cfg.env("RUST_LOG", "sccache=warn");
-        }
+        configure_cmake(build, target, &mut cfg);
 
         // FIXME: we don't actually need to build all LLVM tools and all LLVM
         //        libraries here, e.g. we just want a few components and a few
@@ -304,6 +239,131 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
     panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
 }
 
+fn configure_cmake(build: &Build,
+                   target: Interned<String>,
+                   cfg: &mut cmake::Config) {
+    if build.config.ninja {
+        cfg.generator("Ninja");
+    }
+    cfg.target(&target)
+       .host(&build.config.build);
+
+    let sanitize_cc = |cc: &Path| {
+        if target.contains("msvc") {
+            OsString::from(cc.to_str().unwrap().replace("\\", "/"))
+        } else {
+            cc.as_os_str().to_owned()
+        }
+    };
+
+    // MSVC with CMake uses msbuild by default which doesn't respect these
+    // vars that we'd otherwise configure. In that case we just skip this
+    // entirely.
+    if target.contains("msvc") && !build.config.ninja {
+        return
+    }
+
+    let cc = build.cc(target);
+    let cxx = build.cxx(target).unwrap();
+
+    // Handle msvc + ninja + ccache specially (this is what the bots use)
+    if target.contains("msvc") &&
+       build.config.ninja &&
+       build.config.ccache.is_some() {
+        let mut cc = env::current_exe().expect("failed to get cwd");
+        cc.set_file_name("sccache-plus-cl.exe");
+
+       cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
+          .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
+       cfg.env("SCCACHE_PATH",
+               build.config.ccache.as_ref().unwrap())
+          .env("SCCACHE_TARGET", target);
+
+    // If ccache is configured we inform the build a little differently hwo
+    // to invoke ccache while also invoking our compilers.
+    } else if let Some(ref ccache) = build.config.ccache {
+       cfg.define("CMAKE_C_COMPILER", ccache)
+          .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc))
+          .define("CMAKE_CXX_COMPILER", ccache)
+          .define("CMAKE_CXX_COMPILER_ARG1", sanitize_cc(cxx));
+    } else {
+       cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc))
+          .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx));
+    }
+
+    cfg.build_arg("-j").build_arg(build.jobs().to_string());
+    cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
+    let mut cxxflags = build.cflags(target).join(" ");
+    if build.config.llvm_static_stdcpp && !target.contains("windows") {
+        cxxflags.push_str(" -static-libstdc++");
+    }
+    cfg.define("CMAKE_CXX_FLAGS", cxxflags);
+    if let Some(ar) = build.ar(target) {
+        if ar.is_absolute() {
+            // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
+            // tries to resolve this path in the LLVM build directory.
+            cfg.define("CMAKE_AR", sanitize_cc(ar));
+        }
+    }
+
+    if env::var_os("SCCACHE_ERROR_LOG").is_some() {
+        cfg.env("RUST_LOG", "sccache=warn");
+    }
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Lld {
+    pub target: Interned<String>,
+}
+
+impl Step for Lld {
+    type Output = PathBuf;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/lld")
+    }
+
+    fn make_run(run: RunConfig) {
+        run.builder.ensure(Lld { target: run.target });
+    }
+
+    /// Compile LLVM for `target`.
+    fn run(self, builder: &Builder) -> PathBuf {
+        let target = self.target;
+        let build = builder.build;
+
+        let llvm_config = builder.ensure(Llvm {
+            target: self.target,
+            emscripten: false,
+        });
+
+        let out_dir = build.lld_out(target);
+        let done_stamp = out_dir.join("lld-finished-building");
+        if done_stamp.exists() {
+            return out_dir
+        }
+
+        let _folder = build.fold_output(|| "lld");
+        println!("Building LLD for {}", target);
+        let _time = util::timeit();
+        t!(fs::create_dir_all(&out_dir));
+
+        let mut cfg = cmake::Config::new(build.src.join("src/tools/lld"));
+        configure_cmake(build, target, &mut cfg);
+
+        cfg.out_dir(&out_dir)
+           .profile("Release")
+           .define("LLVM_CONFIG_PATH", llvm_config)
+           .define("LLVM_INCLUDE_TESTS", "OFF");
+
+        cfg.build();
+
+        t!(File::create(&done_stamp));
+        out_dir
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct TestHelpers {
     pub target: Interned<String>,
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index bd8c36a296c09..62fcb6587b71d 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -912,7 +912,7 @@ impl Step for Compiletest {
         }
 
         if build.config.llvm_enabled {
-            let llvm_config = build.llvm_config(target);
+            let llvm_config = build.llvm_config(build.config.build);
             let llvm_version = output(Command::new(&llvm_config).arg("--version"));
             cmd.arg("--llvm-version").arg(llvm_version);
             if !build.is_rust_llvm(target) {
diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile
index 5e405aa72e83d..829166d2237a6 100644
--- a/src/ci/docker/dist-i686-linux/Dockerfile
+++ b/src/ci/docker/dist-i686-linux/Dockerfile
@@ -83,10 +83,9 @@ ENV HOSTS=i686-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS \
       --host=$HOSTS \
-      --enable-extended \
+      --enable-full-tools \
       --enable-sanitizers \
       --enable-profiler \
-      --enable-emscripten \
       --build=i686-unknown-linux-gnu
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
 
diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile
index d368a00b55bd5..f5c24bf508651 100644
--- a/src/ci/docker/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/dist-x86_64-linux/Dockerfile
@@ -83,10 +83,9 @@ ENV HOSTS=x86_64-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS \
       --host=$HOSTS \
-      --enable-extended \
+      --enable-full-tools \
       --enable-sanitizers \
-      --enable-profiler \
-      --enable-emscripten
+      --enable-profiler
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
 
 # This is the only builder which will create source tarballs
diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile
index dc1727b7014c3..3965d2d40c1df 100644
--- a/src/ci/docker/wasm32-unknown/Dockerfile
+++ b/src/ci/docker/wasm32-unknown/Dockerfile
@@ -23,7 +23,8 @@ ENV TARGETS=wasm32-unknown-unknown
 
 ENV RUST_CONFIGURE_ARGS \
   --target=$TARGETS \
-  --set build.nodejs=/node-v9.2.0-linux-x64/bin/node
+  --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \
+  --set rust.lld
 
 ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
   src/test/ui \
diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js
index 69647f37eecc6..98d6202a63fbf 100644
--- a/src/etc/wasm32-shim.js
+++ b/src/etc/wasm32-shim.js
@@ -107,6 +107,8 @@ imports.env = {
   exp2f: function(x) { return Math.pow(2, x); },
   ldexp: function(x, y) { return x * Math.pow(2, y); },
   ldexpf: function(x, y) { return x * Math.pow(2, y); },
+  log: Math.log,
+  log2: Math.log2,
   log10: Math.log10,
   log10f: Math.log10,
 
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index d7370ae400dac..6eef588432a25 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -75,7 +75,9 @@ mod contents {
     // add fast paths for low alignment values.
     #[cfg(all(any(target_arch = "arm",
                   target_arch = "mips",
-                  target_arch = "powerpc")))]
+                  target_arch = "powerpc",
+                  all(target_arch = "riscv",
+                      target_pointer_width = "32"))))]
     const MIN_ALIGN: usize = 8;
     #[cfg(all(any(target_arch = "x86",
                   target_arch = "x86_64",
@@ -83,7 +85,9 @@ mod contents {
                   target_arch = "powerpc64",
                   target_arch = "mips64",
                   target_arch = "s390x",
-                  target_arch = "sparc64")))]
+                  target_arch = "sparc64",
+                  all(target_arch = "riscv",
+                      target_pointer_width = "64"))))]
     const MIN_ALIGN: usize = 16;
 
     // MALLOCX_ALIGN(a) macro
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 1d5e7b73be557..416e4ab84e2bc 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -32,14 +32,18 @@
               target_arch = "powerpc",
               target_arch = "powerpc64",
               target_arch = "asmjs",
-              target_arch = "wasm32")))]
+              target_arch = "wasm32",
+              all(target_arch = "riscv",
+                  target_pointer_width = "32"))))]
 #[allow(dead_code)]
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
               target_arch = "aarch64",
               target_arch = "mips64",
               target_arch = "s390x",
-              target_arch = "sparc64")))]
+              target_arch = "sparc64",
+              all(target_arch = "riscv",
+                  target_pointer_width = "64"))))]
 #[allow(dead_code)]
 const MIN_ALIGN: usize = 16;
 
diff --git a/src/liblibc b/src/liblibc
index 56444a4545bd7..41e0461d7b9b3 160000
--- a/src/liblibc
+++ b/src/liblibc
@@ -1 +1 @@
-Subproject commit 56444a4545bd71430d64b86b8a71714cfdbe9f5d
+Subproject commit 41e0461d7b9b3872fa0a3f9f918d44162b1d7cef
diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs
index 63e44f71a3a8f..705f201668d22 100644
--- a/src/libpanic_unwind/gcc.rs
+++ b/src/libpanic_unwind/gcc.rs
@@ -127,6 +127,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
 #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
 const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
 
+#[cfg(target_arch = "riscv")]
+const UNWIND_DATA_REG: (i32, i32) = (10, 11); // A0, A1
+
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
 const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
 
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index 8bf60b091a7ad..9de56cca3394f 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -43,14 +43,32 @@ use std::str::FromStr;
 
 use serialize::json::{Json, ToJson};
 
-macro_rules! linker_flavor {
-    ($(($variant:ident, $string:expr),)+) => {
-        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
-                 RustcEncodable, RustcDecodable)]
-        pub enum LinkerFlavor {
-            $($variant,)+
-        }
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
+         RustcEncodable, RustcDecodable)]
+pub enum LinkerFlavor {
+    Em,
+    Gcc,
+    Ld,
+    Msvc,
+    Lld(LldFlavor),
+}
+
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
+         RustcEncodable, RustcDecodable)]
+pub enum LldFlavor {
+    Wasm,
+    Ld64,
+    Ld,
+    Link,
+}
 
+impl ToJson for LinkerFlavor {
+    fn to_json(&self) -> Json {
+        self.desc().to_json()
+    }
+}
+macro_rules! flavor_mappings {
+    ($((($($flavor:tt)*), $string:expr),)*) => (
         impl LinkerFlavor {
             pub const fn one_of() -> &'static str {
                 concat!("one of: ", $($string, " ",)+)
@@ -58,32 +76,30 @@ macro_rules! linker_flavor {
 
             pub fn from_str(s: &str) -> Option<Self> {
                 Some(match s {
-                    $($string => LinkerFlavor::$variant,)+
+                    $($string => $($flavor)*,)+
                     _ => return None,
                 })
             }
 
             pub fn desc(&self) -> &str {
                 match *self {
-                    $(LinkerFlavor::$variant => $string,)+
+                    $($($flavor)* => $string,)+
                 }
             }
         }
-
-        impl ToJson for LinkerFlavor {
-            fn to_json(&self) -> Json {
-                self.desc().to_json()
-            }
-        }
-    }
+    )
 }
 
-linker_flavor! {
-    (Em, "em"),
-    (Binaryen, "binaryen"),
-    (Gcc, "gcc"),
-    (Ld, "ld"),
-    (Msvc, "msvc"),
+
+flavor_mappings! {
+    ((LinkerFlavor::Em), "em"),
+    ((LinkerFlavor::Gcc), "gcc"),
+    ((LinkerFlavor::Ld), "ld"),
+    ((LinkerFlavor::Msvc), "msvc"),
+    ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
+    ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
+    ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
+    ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_back/target/aarch64_unknown_cloudabi.rs b/src/librustc_back/target/aarch64_unknown_cloudabi.rs
index 59c82e06a679c..a5d0e5bf166dd 100644
--- a/src/librustc_back/target/aarch64_unknown_cloudabi.rs
+++ b/src/librustc_back/target/aarch64_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.max_atomic_width = Some(128);
     base.abi_blacklist = super::arm_base::abi_blacklist();
-    base.linker = "aarch64-unknown-cloudabi-cc".to_string();
+    base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
 
     Ok(Target {
         llvm_target: "aarch64-unknown-cloudabi".to_string(),
diff --git a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
index faa2c4fdceb9b..fa66a35abbf35 100644
--- a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
     base.features = "+v7,+vfp3,+neon".to_string();
     base.abi_blacklist = super::arm_base::abi_blacklist();
-    base.linker = "armv7-unknown-cloudabi-eabihf-cc".to_string();
+    base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
 
     Ok(Target {
         llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index 5d9f0f6012bf2..f114926740a5e 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut args = LinkArgs::new();
@@ -19,8 +18,6 @@ pub fn target() -> Result<Target, String> {
                      "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         exe_suffix: ".js".to_string(),
diff --git a/src/librustc_back/target/emscripten_base.rs b/src/librustc_back/target/emscripten_base.rs
deleted file mode 100644
index bacada3f5ab02..0000000000000
--- a/src/librustc_back/target/emscripten_base.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-pub fn cmd(name: &str) -> String {
-    if cfg!(windows) {
-        format!("{}.bat", name)
-    } else {
-        name.to_string()
-    }
-}
diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs
index 112f424f7a8bb..a1ccb632cab79 100644
--- a/src/librustc_back/target/haiku_base.rs
+++ b/src/librustc_back/target/haiku_base.rs
@@ -13,7 +13,6 @@ use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
-        linker: "cc".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: false,
diff --git a/src/librustc_back/target/i686_unknown_cloudabi.rs b/src/librustc_back/target/i686_unknown_cloudabi.rs
index e244f443d3e3a..69c3b298caba0 100644
--- a/src/librustc_back/target/i686_unknown_cloudabi.rs
+++ b/src/librustc_back/target/i686_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
-    base.linker = "i686-unknown-cloudabi-cc".to_string();
+    base.linker = Some("i686-unknown-cloudabi-cc".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
diff --git a/src/librustc_back/target/l4re_base.rs b/src/librustc_back/target/l4re_base.rs
index 31d428d266839..7cb7f8d613dee 100644
--- a/src/librustc_back/target/l4re_base.rs
+++ b/src/librustc_back/target/l4re_base.rs
@@ -73,7 +73,6 @@ pub fn opts() -> Result<TargetOptions, String> {
         has_elf_tls: false,
         exe_allocation_crate: None,
         panic_strategy: PanicStrategy::Abort,
-        linker: "ld".to_string(),
         pre_link_args,
         post_link_args,
         target_family: Some("unix".to_string()),
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index d356105e39314..f823232d8d8cb 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -58,7 +58,6 @@ mod arm_base;
 mod bitrig_base;
 mod cloudabi_base;
 mod dragonfly_base;
-mod emscripten_base;
 mod freebsd_base;
 mod haiku_base;
 mod linux_base;
@@ -237,6 +236,8 @@ supported_targets! {
     ("armv7-unknown-cloudabi-eabihf", armv7_unknown_cloudabi_eabihf),
     ("i686-unknown-cloudabi", i686_unknown_cloudabi),
     ("x86_64-unknown-cloudabi", x86_64_unknown_cloudabi),
+
+    ("riscv32im-unknown-none", riscv32im_unknown_none),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
@@ -278,8 +279,8 @@ pub struct TargetOptions {
     /// Whether the target is built-in or loaded from a custom target specification.
     pub is_builtin: bool,
 
-    /// Linker to invoke. Defaults to "cc".
-    pub linker: String,
+    /// Linker to invoke
+    pub linker: Option<String>,
 
     /// Linker arguments that are unconditionally passed *before* any
     /// user-defined libraries.
@@ -482,7 +483,7 @@ impl Default for TargetOptions {
     fn default() -> TargetOptions {
         TargetOptions {
             is_builtin: false,
-            linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
+            linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             pre_link_args: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
@@ -732,7 +733,7 @@ impl Target {
         }
 
         key!(is_builtin, bool);
-        key!(linker);
+        key!(linker, optional);
         key!(pre_link_args, link_args);
         key!(pre_link_objects_exe, list);
         key!(pre_link_objects_dll, list);
diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs
index 966df897f01f1..d0f512ae47cd9 100644
--- a/src/librustc_back/target/msp430_none_elf.rs
+++ b/src/librustc_back/target/msp430_none_elf.rs
@@ -32,7 +32,7 @@ pub fn target() -> TargetResult {
             // to gcc to get object files. For this reason we have a hard
             // dependency on this specific gcc.
             asm_args: vec!["-mcpu=msp430".to_string()],
-            linker: "msp430-elf-gcc".to_string(),
+            linker: Some("msp430-elf-gcc".to_string()),
             no_integrated_as: true,
 
             // There are no atomic instructions available in the MSP430
diff --git a/src/librustc_back/target/riscv32im_unknown_none.rs b/src/librustc_back/target/riscv32im_unknown_none.rs
new file mode 100644
index 0000000000000..9122064f9e88f
--- /dev/null
+++ b/src/librustc_back/target/riscv32im_unknown_none.rs
@@ -0,0 +1,44 @@
+use {LinkerFlavor, PanicStrategy};
+use target::{Target, TargetOptions, TargetResult};
+use syntax::abi::{Abi};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+        llvm_target: "riscv32".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_os: "none".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        arch: "riscv".to_string(),
+        linker_flavor: LinkerFlavor::Ld,
+
+
+        options: TargetOptions {
+            linker: Some("ld.lld".to_string()),
+            cpu: "generic-rv32".to_string(),
+            max_atomic_width: Some(0),
+            features: "+m".to_string(),
+            executables: true,
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: "static".to_string(),
+            abi_blacklist: vec![
+                Abi::Cdecl,
+                Abi::Stdcall,
+                Abi::Fastcall,
+                Abi::Vectorcall,
+                Abi::Thiscall,
+                Abi::Aapcs,
+                Abi::Win64,
+                Abi::SysV64,
+                Abi::PtxKernel,
+                Abi::Msp430Interrupt,
+                Abi::X86Interrupt,
+            ],
+            .. Default::default()
+        },
+    })
+}
+
diff --git a/src/librustc_back/target/thumb_base.rs b/src/librustc_back/target/thumb_base.rs
index 6bb496649a858..6a8f52f509310 100644
--- a/src/librustc_back/target/thumb_base.rs
+++ b/src/librustc_back/target/thumb_base.rs
@@ -45,7 +45,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         // In 99%+ of cases, we want to use the `arm-none-eabi-gcc` compiler (there aren't many
         // options around)
-        linker: "arm-none-eabi-gcc".to_string(),
+        linker: Some("arm-none-eabi-gcc".to_string()),
         // Because these devices have very little resources having an unwinder is too onerous so we
         // default to "abort" because the "unwind" strategy is very rare.
         panic_strategy: PanicStrategy::Abort,
diff --git a/src/librustc_back/target/wasm32_experimental_emscripten.rs b/src/librustc_back/target/wasm32_experimental_emscripten.rs
index a261c982b3f24..13dee3a576869 100644
--- a/src/librustc_back/target/wasm32_experimental_emscripten.rs
+++ b/src/librustc_back/target/wasm32_experimental_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut post_link_args = LinkArgs::new();
@@ -24,8 +23,6 @@ pub fn target() -> Result<Target, String> {
                                "-g3".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         // Today emcc emits two files - a .js file to bootstrap and
diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs
index 4823541f2262c..2770e67e30a5b 100644
--- a/src/librustc_back/target/wasm32_unknown_emscripten.rs
+++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs
@@ -10,7 +10,6 @@
 
 use LinkerFlavor;
 use super::{LinkArgs, Target, TargetOptions};
-use super::emscripten_base::{cmd};
 
 pub fn target() -> Result<Target, String> {
     let mut post_link_args = LinkArgs::new();
@@ -21,8 +20,6 @@ pub fn target() -> Result<Target, String> {
                                "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
 
     let opts = TargetOptions {
-        linker: cmd("emcc"),
-
         dynamic_linking: false,
         executables: true,
         // Today emcc emits two files - a .js file to bootstrap and
diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs
index 242860e5c6e92..1d84e13751740 100644
--- a/src/librustc_back/target/wasm32_unknown_unknown.rs
+++ b/src/librustc_back/target/wasm32_unknown_unknown.rs
@@ -8,41 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// The wasm32-unknown-unknown target is currently a highly experimental version
-// of a wasm-based target which does *not* use the Emscripten toolchain. Instead
-// this is a pretty flavorful (aka hacked up) target right now. The definition
-// and semantics of this target are likely to change and so this shouldn't be
-// relied on just yet.
+// The wasm32-unknown-unknown target is currently an experimental version of a
+// wasm-based target which does *not* use the Emscripten toolchain. Instead
+// this toolchain is based purely on LLVM's own toolchain, using LLVM's native
+// WebAssembly backend as well as LLD for a native linker.
 //
-// In general everyone is currently waiting on a linker for wasm code. In the
-// meantime we have no means of actually making use of the traditional separate
-// compilation model. At a high level this means that assembling Rust programs
-// into a WebAssembly program looks like:
-//
-//  1. All intermediate artifacts are LLVM bytecode. We'll be using LLVM as
-//     a linker later on.
-//  2. For the final artifact we emit one giant assembly file (WebAssembly
-//     doesn't have an object file format). To do this we force LTO to be turned
-//     on (`requires_lto` below) to ensure all Rust code is in one module. Any
-//     "linked" C library is basically just ignored.
-//  3. Using LLVM we emit a `foo.s` file (assembly) with some... what I can only
-//     describe as arcane syntax. From there we need to actually change this
-//     into a wasm module. For this step we use the `binaryen` project. This
-//     project is mostly intended as a WebAssembly code generator, but for now
-//     we're just using its LLVM-assembly-to-wasm-module conversion utilities.
-//
-// And voila, out comes a web assembly module! There's some various tweaks here
-// and there, but that's the high level at least. Note that this will be
-// rethought from the ground up once a linker (lld) is available, so this is all
-// temporary and should improve in the future.
+// There's some trickery below on crate types supported and various defaults
+// (aka panic=abort by default), but otherwise this is in general a relatively
+// standard target.
 
-use LinkerFlavor;
+use {LinkerFlavor, LldFlavor};
 use super::{Target, TargetOptions, PanicStrategy};
 
 pub fn target() -> Result<Target, String> {
     let opts = TargetOptions {
-        linker: "not-used".to_string(),
-
         // we allow dynamic linking, but only cdylibs. Basically we allow a
         // final library artifact that exports some symbols (a wasm module) but
         // we don't allow intermediate `dylib` crate types
@@ -58,9 +37,6 @@ pub fn target() -> Result<Target, String> {
         dll_suffix: ".wasm".to_string(),
         linker_is_gnu: false,
 
-        // We're storing bitcode for now in all the rlibs
-        obj_is_bitcode: true,
-
         // A bit of a lie, but "eh"
         max_atomic_width: Some(32),
 
@@ -69,27 +45,17 @@ pub fn target() -> Result<Target, String> {
         // the future once unwinding is implemented. Don't rely on this.
         panic_strategy: PanicStrategy::Abort,
 
-        // There's no linker yet so we're forced to use LLVM as a linker. This
-        // means that we must always enable LTO for final artifacts.
-        requires_lto: true,
-
         // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
         // threaded model which will legalize atomics to normal operations.
         singlethread: true,
 
-        // Because we're always enabling LTO we can't enable builtin lowering as
-        // otherwise we'll lower the definition of the `memcpy` function to
-        // memcpy itself. Note that this is specifically because we're
-        // performing LTO with compiler-builtins.
-        no_builtins: true,
-
         // no dynamic linking, no need for default visibility!
         default_hidden_visibility: true,
 
         .. Default::default()
     };
     Ok(Target {
-        llvm_target: "wasm32-unknown-unknown".to_string(),
+        llvm_target: "wasm32-unknown-unknown-wasm".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
@@ -100,8 +66,7 @@ pub fn target() -> Result<Target, String> {
         target_vendor: "unknown".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
-        // A bit of a lie, but it gets the job done
-        linker_flavor: LinkerFlavor::Binaryen,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
         options: opts,
     })
 }
diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs
index cc40b8b052983..b3eb65ecdce37 100644
--- a/src/librustc_back/target/windows_base.rs
+++ b/src/librustc_back/target/windows_base.rs
@@ -75,7 +75,6 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         // FIXME(#13846) this should be enabled for windows
         function_sections: false,
-        linker: "gcc".to_string(),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index 64df6624dd1c2..b57c9e62f484a 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -20,7 +20,6 @@ pub fn opts() -> TargetOptions {
 
     TargetOptions {
         function_sections: true,
-        linker: "link.exe".to_string(),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index 18f6380b6eedf..3158665a2e28d 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
+    base.linker = Some("x86_64-rumprun-netbsd-gcc".to_string());
     base.max_atomic_width = Some(64);
 
     base.dynamic_linking = false;
diff --git a/src/librustc_back/target/x86_64_unknown_cloudabi.rs b/src/librustc_back/target/x86_64_unknown_cloudabi.rs
index 1ce3c6444f1ea..d1a9cb1cd7e7d 100644
--- a/src/librustc_back/target/x86_64_unknown_cloudabi.rs
+++ b/src/librustc_back/target/x86_64_unknown_cloudabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.linker = "x86_64-unknown-cloudabi-cc".to_string();
+    base.linker = Some("x86_64-unknown-cloudabi-cc".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp
deleted file mode 100644
index 55f11665f6d0b..0000000000000
--- a/src/librustc_binaryen/BinaryenWrapper.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-// This is a small C API inserted on top of the Binaryen C++ API which we use
-// from Rust. Once we have a real linker for we'll be able to remove all this,
-// and otherwise this is just all on a "as we need it" basis for now.
-
-#include <stdint.h>
-#include <string>
-#include <sstream>
-#include <stdlib.h>
-
-#include "s2wasm.h"
-#include "wasm-binary.h"
-#include "wasm-linker.h"
-
-using namespace wasm;
-
-struct BinaryenRustModule {
-  BufferWithRandomAccess buffer;
-  std::string sourceMapJSON;
-};
-
-struct BinaryenRustModuleOptions {
-  uint64_t globalBase;
-  bool debug;
-  uint64_t stackAllocation;
-  uint64_t initialMem;
-  uint64_t maxMem;
-  bool importMemory;
-  bool ignoreUnknownSymbols;
-  bool debugInfo;
-  std::string startFunction;
-  std::string sourceMapUrl;
-
-  BinaryenRustModuleOptions() :
-    globalBase(0),
-    debug(false),
-    stackAllocation(0),
-    initialMem(0),
-    maxMem(0),
-    importMemory(false),
-    ignoreUnknownSymbols(false),
-    debugInfo(false),
-    startFunction(""),
-    sourceMapUrl("")
-  {}
-
-};
-
-extern "C" BinaryenRustModuleOptions*
-BinaryenRustModuleOptionsCreate() {
-  return new BinaryenRustModuleOptions;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsFree(BinaryenRustModuleOptions *options) {
-  delete options;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsSetDebugInfo(BinaryenRustModuleOptions *options,
-                                      bool debugInfo) {
-  options->debugInfo = debugInfo;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
-                                  char *start) {
-  options->startFunction = start;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
-                                         char *sourceMapUrl) {
-  options->sourceMapUrl = sourceMapUrl;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
-                                            uint64_t stack) {
-  options->stackAllocation = stack;
-}
-
-extern "C" void
-BinaryenRustModuleOptionsSetImportMemory(BinaryenRustModuleOptions *options,
-                                         bool import) {
-  options->importMemory = import;
-}
-
-extern "C" BinaryenRustModule*
-BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options,
-                         const char *assembly) {
-  Linker linker(
-      options->globalBase,
-      options->stackAllocation,
-      options->initialMem,
-      options->maxMem,
-      options->importMemory,
-      options->ignoreUnknownSymbols,
-      options->startFunction,
-      options->debug);
-
-  S2WasmBuilder mainbuilder(assembly, options->debug);
-  linker.linkObject(mainbuilder);
-  linker.layout();
-
-  auto ret = make_unique<BinaryenRustModule>();
-  {
-    WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
-    writer.setNamesSection(options->debugInfo);
-
-    std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
-    {
-      sourceMapStream = make_unique<std::ostringstream>();
-      writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
-    }
-
-    // FIXME: support symbol maps?
-    // writer.setSymbolMap(symbolMap);
-    writer.write();
-
-    if (sourceMapStream) {
-      ret->sourceMapJSON = sourceMapStream->str();
-    }
-  }
-  return ret.release();
-}
-
-extern "C" const uint8_t*
-BinaryenRustModulePtr(const BinaryenRustModule *M) {
-  return M->buffer.data();
-}
-
-extern "C" size_t
-BinaryenRustModuleLen(const BinaryenRustModule *M) {
-  return M->buffer.size();
-}
-
-extern "C" const char*
-BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
-  return M->sourceMapJSON.data();
-}
-
-extern "C" size_t
-BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
-  return M->sourceMapJSON.length();
-}
-
-extern "C" void
-BinaryenRustModuleFree(BinaryenRustModule *M) {
-  delete M;
-}
diff --git a/src/librustc_binaryen/Cargo.toml b/src/librustc_binaryen/Cargo.toml
deleted file mode 100644
index 9573c89471404..0000000000000
--- a/src/librustc_binaryen/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Wondering what this crate is? Take a look at the `lib.rs`!
-
-[package]
-name = "rustc_binaryen"
-version = "0.0.0"
-authors = ["The Rust Project Developers"]
-
-[lib]
-path = "lib.rs"
-
-[dependencies]
-libc = "0.2"
-
-[build-dependencies]
-cmake = "0.1"
-cc = "1.0"
diff --git a/src/librustc_binaryen/build.rs b/src/librustc_binaryen/build.rs
deleted file mode 100644
index f23ff3cee555b..0000000000000
--- a/src/librustc_binaryen/build.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-extern crate cc;
-extern crate cmake;
-
-use std::env;
-
-use cmake::Config;
-
-fn main() {
-    let target = env::var("TARGET").unwrap();
-
-    // Bring in `__emutls_get_address` which is apparently needed for now
-    if target.contains("pc-windows-gnu") {
-        println!("cargo:rustc-link-lib=gcc_eh");
-        println!("cargo:rustc-link-lib=pthread");
-    }
-
-    Config::new("../binaryen")
-        .define("BUILD_STATIC_LIB", "ON")
-        .build_target("binaryen")
-        .build();
-
-    // I couldn't figure out how to link just one of these, so link everything.
-    println!("cargo:rustc-link-lib=static=asmjs");
-    println!("cargo:rustc-link-lib=static=binaryen");
-    println!("cargo:rustc-link-lib=static=cfg");
-    println!("cargo:rustc-link-lib=static=emscripten-optimizer");
-    println!("cargo:rustc-link-lib=static=ir");
-    println!("cargo:rustc-link-lib=static=passes");
-    println!("cargo:rustc-link-lib=static=support");
-    println!("cargo:rustc-link-lib=static=wasm");
-
-    let out_dir = env::var("OUT_DIR").unwrap();
-    println!("cargo:rustc-link-search=native={}/build/lib", out_dir);
-
-    // Add in our own little shim along with some extra files that weren't
-    // included in the main build.
-    let mut cfg = cc::Build::new();
-    cfg.file("BinaryenWrapper.cpp")
-        .file("../binaryen/src/wasm-linker.cpp")
-        .file("../binaryen/src/wasm-emscripten.cpp")
-        .include("../binaryen/src")
-        .cpp_link_stdlib(None)
-        .warnings(false)
-        .cpp(true);
-
-    if !target.contains("msvc") {
-        cfg.flag("-std=c++11");
-    }
-    cfg.compile("binaryen_wrapper");
-}
diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs
deleted file mode 100644
index 36174e11ba04a..0000000000000
--- a/src/librustc_binaryen/lib.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-//! Rustc bindings to the binaryen project.
-//!
-//! This crate is a small shim around the binaryen project which provides us the
-//! ability to take LLVM's output and generate a wasm module. Specifically this
-//! only supports one operation, creating a module from LLVM's assembly format
-//! and then serializing that module to a wasm module.
-
-extern crate libc;
-
-use std::slice;
-use std::ffi::{CString, CStr};
-
-/// In-memory representation of a serialized wasm module.
-pub struct Module {
-    ptr: *mut BinaryenRustModule,
-}
-
-impl Module {
-    /// Creates a new wasm module from the LLVM-assembly provided (in a C string
-    /// format).
-    ///
-    /// The actual module creation can be tweaked through the various options in
-    /// `ModuleOptions` as well. Any errors are just returned as a bland string.
-    pub fn new(assembly: &CStr, opts: &ModuleOptions) -> Result<Module, String> {
-        unsafe {
-            let ptr = BinaryenRustModuleCreate(opts.ptr, assembly.as_ptr());
-            if ptr.is_null() {
-                Err(format!("failed to create binaryen module"))
-            } else {
-                Ok(Module { ptr })
-            }
-        }
-    }
-
-    /// Returns the data of the serialized wasm module. This is a `foo.wasm`
-    /// file contents.
-    pub fn data(&self) -> &[u8] {
-        unsafe {
-            let ptr = BinaryenRustModulePtr(self.ptr);
-            let len = BinaryenRustModuleLen(self.ptr);
-            slice::from_raw_parts(ptr, len)
-        }
-    }
-
-    /// Returns the data of the source map JSON.
-    pub fn source_map(&self) -> &[u8] {
-        unsafe {
-            let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
-            let len = BinaryenRustModuleSourceMapLen(self.ptr);
-            slice::from_raw_parts(ptr, len)
-        }
-    }
-}
-
-impl Drop for Module {
-    fn drop(&mut self) {
-        unsafe {
-            BinaryenRustModuleFree(self.ptr);
-        }
-    }
-}
-
-pub struct ModuleOptions {
-    ptr: *mut BinaryenRustModuleOptions,
-}
-
-impl ModuleOptions {
-    pub fn new() -> ModuleOptions {
-        unsafe {
-            let ptr = BinaryenRustModuleOptionsCreate();
-            ModuleOptions { ptr }
-        }
-    }
-
-    /// Turns on or off debug info.
-    ///
-    /// From what I can tell this just creates a "names" section of the wasm
-    /// module which contains a table of the original function names.
-    pub fn debuginfo(&mut self, debug: bool) -> &mut Self {
-        unsafe {
-            BinaryenRustModuleOptionsSetDebugInfo(self.ptr, debug);
-        }
-        self
-    }
-
-    /// Configures a `start` function for the module, to be executed when it's
-    /// loaded.
-    pub fn start(&mut self, func: &str) -> &mut Self {
-        let func = CString::new(func).unwrap();
-        unsafe {
-            BinaryenRustModuleOptionsSetStart(self.ptr, func.as_ptr());
-        }
-        self
-    }
-
-    /// Configures a `sourceMappingURL` custom section value for the module.
-    pub fn source_map_url(&mut self, url: &str) -> &mut Self {
-        let url = CString::new(url).unwrap();
-        unsafe {
-            BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
-        }
-        self
-    }
-
-    /// Configures how much stack is initially allocated for the module. 1MB is
-    /// probably good enough for now.
-    pub fn stack(&mut self, amt: u64) -> &mut Self {
-        unsafe {
-            BinaryenRustModuleOptionsSetStackAllocation(self.ptr, amt);
-        }
-        self
-    }
-
-    /// Flags whether the initial memory should be imported or exported. So far
-    /// we export it by default.
-    pub fn import_memory(&mut self, import: bool) -> &mut Self {
-        unsafe {
-            BinaryenRustModuleOptionsSetImportMemory(self.ptr, import);
-        }
-        self
-    }
-}
-
-impl Drop for ModuleOptions {
-    fn drop(&mut self) {
-        unsafe {
-            BinaryenRustModuleOptionsFree(self.ptr);
-        }
-    }
-}
-
-enum BinaryenRustModule {}
-enum BinaryenRustModuleOptions {}
-
-extern {
-    fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions,
-                                assembly: *const libc::c_char)
-        -> *mut BinaryenRustModule;
-    fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
-    fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
-    fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
-    fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
-    fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
-
-    fn BinaryenRustModuleOptionsCreate()
-        -> *mut BinaryenRustModuleOptions;
-    fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions,
-                                             debuginfo: bool);
-    fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
-                                         start: *const libc::c_char);
-    fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
-                                                sourceMapUrl: *const libc::c_char);
-    fn BinaryenRustModuleOptionsSetStackAllocation(
-        module: *mut BinaryenRustModuleOptions,
-        stack: u64,
-    );
-    fn BinaryenRustModuleOptionsSetImportMemory(
-        module: *mut BinaryenRustModuleOptions,
-        import: bool,
-    );
-    fn BinaryenRustModuleOptionsFree(module: *mut BinaryenRustModuleOptions);
-}
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 54e3f544acb68..ccfeec124711c 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -94,6 +94,10 @@ fn main() {
         optional_components.push("hexagon");
     }
 
+    if major > 5 {
+        optional_components.push("riscv");
+    }
+
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
     let required_components = &["ipo",
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 8dcf7444dd18f..8ed7303be440b 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -357,6 +357,12 @@ pub fn initialize_available_targets() {
                  LLVMInitializeMSP430Target,
                  LLVMInitializeMSP430TargetMC,
                  LLVMInitializeMSP430AsmPrinter);
+    init_target!(llvm_component = "riscv",
+                 LLVMInitializeRISCVTargetInfo,
+                 LLVMInitializeRISCVTarget,
+                 LLVMInitializeRISCVTargetMC,
+                 LLVMInitializeRISCVAsmPrinter,
+                 LLVMInitializeRISCVAsmParser);
     init_target!(llvm_component = "sparc",
                  LLVMInitializeSparcTargetInfo,
                  LLVMInitializeSparcTarget,
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 500c4fdf4e8dd..805d2086ee4f6 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -11,6 +11,7 @@ test = false
 
 [dependencies]
 bitflags = "1.0"
+cc = "1.0.1"
 flate2 = "1.0"
 jobserver = "0.1.5"
 libc = "0.2"
@@ -21,7 +22,6 @@ rustc-demangle = "0.1.4"
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_back = { path = "../librustc_back" }
-rustc_binaryen = { path = "../librustc_binaryen" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
@@ -35,9 +35,6 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 tempdir = "0.3"
 
-[target."cfg(windows)".dependencies]
-cc = "1.0.1"
-
 [features]
 # Used to communicate the feature to `rustc_back` in the same manner that the
 # `rustc` driver script communicate this.
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index ee0f2415bd808..ccce660962859 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -25,6 +25,7 @@ use cabi_mips;
 use cabi_mips64;
 use cabi_asmjs;
 use cabi_msp430;
+use cabi_riscv;
 use cabi_sparc;
 use cabi_sparc64;
 use cabi_nvptx;
@@ -955,6 +956,7 @@ impl<'a, 'tcx> FnType<'tcx> {
             "nvptx" => cabi_nvptx::compute_abi_info(self),
             "nvptx64" => cabi_nvptx64::compute_abi_info(self),
             "hexagon" => cabi_hexagon::compute_abi_info(self),
+            "riscv" => cabi_riscv::compute_abi_info(self),
             a => cx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
         }
 
diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs
index 0bccef1e62a8e..ecf7bf5036e08 100644
--- a/src/librustc_trans/back/command.rs
+++ b/src/librustc_trans/back/command.rs
@@ -17,6 +17,8 @@ use std::io;
 use std::mem;
 use std::process::{self, Output};
 
+use rustc_back::LldFlavor;
+
 #[derive(Clone)]
 pub struct Command {
     program: Program,
@@ -28,6 +30,7 @@ pub struct Command {
 enum Program {
     Normal(OsString),
     CmdBatScript(OsString),
+    Lld(OsString, LldFlavor)
 }
 
 impl Command {
@@ -39,6 +42,10 @@ impl Command {
         Command::_new(Program::CmdBatScript(program.as_ref().to_owned()))
     }
 
+    pub fn lld<P: AsRef<OsStr>>(program: P, flavor: LldFlavor) -> Command {
+        Command::_new(Program::Lld(program.as_ref().to_owned(), flavor))
+    }
+
     fn _new(program: Program) -> Command {
         Command {
             program,
@@ -74,17 +81,6 @@ impl Command {
         self
     }
 
-    pub fn envs<I, K, V>(&mut self, envs: I) -> &mut Command
-        where I: IntoIterator<Item=(K, V)>,
-              K: AsRef<OsStr>,
-              V: AsRef<OsStr>
-    {
-        for (key, value) in envs {
-            self._env(key.as_ref(), value.as_ref());
-        }
-        self
-    }
-
     fn _env(&mut self, key: &OsStr, value: &OsStr) {
         self.env.push((key.to_owned(), value.to_owned()));
     }
@@ -101,6 +97,16 @@ impl Command {
                 c.arg("/c").arg(p);
                 c
             }
+            Program::Lld(ref p, flavor) => {
+                let mut c = process::Command::new(p);
+                c.arg("-flavor").arg(match flavor {
+                    LldFlavor::Wasm => "wasm",
+                    LldFlavor::Ld => "gnu",
+                    LldFlavor::Link => "link",
+                    LldFlavor::Ld64 => "darwin",
+                });
+                c
+            }
         };
         ret.args(&self.args);
         ret.envs(self.env.clone());
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index d7c75dea8d04e..7bbc59e175b77 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cc::windows_registry;
 use super::archive::{ArchiveBuilder, ArchiveConfig};
 use super::bytecode::RLIB_BYTECODE_EXTENSION;
 use super::linker::Linker;
@@ -15,6 +16,7 @@ use super::command::Command;
 use super::rpath::RPathConfig;
 use super::rpath;
 use metadata::METADATA_FILENAME;
+use rustc_back::LinkerFlavor;
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
 use rustc::session::config::{RUST_CGU_EXT, Lto};
 use rustc::session::filesearch;
@@ -27,7 +29,7 @@ use rustc::util::common::time;
 use rustc::util::fs::fix_windows_verbatim_for_gcc;
 use rustc::hir::def_id::CrateNum;
 use tempdir::TempDir;
-use rustc_back::{PanicStrategy, RelroLevel, LinkerFlavor};
+use rustc_back::{PanicStrategy, RelroLevel};
 use context::get_reloc_model;
 use llvm;
 
@@ -57,9 +59,7 @@ pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_o
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
 // toolchain
-pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString)>) {
-    let envs = vec![("PATH".into(), command_path(sess))];
-
+pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
     // If our linker looks like a batch script on Windows then to execute this
     // we'll need to spawn `cmd` explicitly. This is primarily done to handle
     // emscripten where the linker is `emcc.bat` and needs to be spawned as
@@ -74,45 +74,41 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command, Vec<(OsString, OsString)
                 return Command::bat_script(linker)
             }
         }
-        Command::new(linker)
+        match sess.linker_flavor() {
+            LinkerFlavor::Lld(f) => Command::lld(linker, f),
+            _ => Command::new(linker),
+
+        }
     };
 
-    if let Some(ref linker) = sess.opts.cg.linker {
-        (linker.clone(), cmd(linker), envs)
-    } else if sess.target.target.options.is_like_msvc {
-        let (cmd, envs) = msvc_link_exe_cmd(sess);
-        (PathBuf::from("link.exe"), cmd, envs)
-    } else {
-        let linker = PathBuf::from(&sess.target.target.options.linker);
-        let cmd = cmd(&linker);
-        (linker, cmd, envs)
-    }
-}
+    let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple, "link.exe");
 
-#[cfg(windows)]
-pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
-    use cc::windows_registry;
+    let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s)
+        .or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref()))
+        .unwrap_or(match sess.linker_flavor() {
+            LinkerFlavor::Msvc => {
+                msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref())
+            }
+            LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(),
+            LinkerFlavor::Em => "emcc".as_ref(),
+            LinkerFlavor::Gcc => "gcc".as_ref(),
+            LinkerFlavor::Ld => "ld".as_ref(),
+            LinkerFlavor::Lld(_) => "lld".as_ref(),
+        });
 
-    let target = &sess.opts.target_triple;
-    let tool = windows_registry::find_tool(target, "link.exe");
+    let mut cmd = cmd(linker_path);
 
-    if let Some(tool) = tool {
-        let mut cmd = Command::new(tool.path());
-        cmd.args(tool.args());
-        for &(ref k, ref v) in tool.env() {
-            cmd.env(k, v);
+    if sess.target.target.options.is_like_msvc {
+        if let Some(ref tool) = msvc_tool {
+            cmd.args(tool.args());
+            for &(ref k, ref v) in tool.env() {
+                cmd.env(k, v);
+            }
         }
-        let envs = tool.env().to_vec();
-        (cmd, envs)
-    } else {
-        debug!("Failed to locate linker.");
-        (Command::new("link.exe"), vec![])
     }
-}
+    cmd.env("PATH", command_path(sess));
 
-#[cfg(not(windows))]
-pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
-    (Command::new("link.exe"), vec![])
+    (linker_path.to_path_buf(), cmd)
 }
 
 fn command_path(sess: &Session) -> OsString {
@@ -612,15 +608,8 @@ fn link_natively(sess: &Session,
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let flavor = sess.linker_flavor();
 
-    // The "binaryen linker" is massively special, so skip everything below.
-    if flavor == LinkerFlavor::Binaryen {
-        return link_binaryen(sess, crate_type, out_filename, trans, tmpdir);
-    }
-
     // The invocations of cc share some flags across platforms
-    let (pname, mut cmd, envs) = get_linker(sess);
-    // This will set PATH on windows
-    cmd.envs(envs);
+    let (pname, mut cmd) = get_linker(sess);
 
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
@@ -1473,33 +1462,6 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
     }
 }
 
-/// For now "linking with binaryen" is just "move the one module we generated in
-/// the backend to the final output"
-///
-/// That is, all the heavy lifting happens during the `back::write` phase. Here
-/// we just clean up after that.
-///
-/// Note that this is super temporary and "will not survive the night", this is
-/// guaranteed to get removed as soon as a linker for wasm exists. This should
-/// not be used for anything other than wasm.
-fn link_binaryen(sess: &Session,
-                 _crate_type: config::CrateType,
-                 out_filename: &Path,
-                 trans: &CrateTranslation,
-                 _tmpdir: &Path) {
-    assert!(trans.allocator_module.is_none());
-    assert_eq!(trans.modules.len(), 1);
-
-    let object = trans.modules[0].object.as_ref().expect("object must exist");
-    let res = fs::hard_link(object, out_filename)
-        .or_else(|_| fs::copy(object, out_filename).map(|_| ()));
-    if let Err(e) = res {
-        sess.fatal(&format!("failed to create `{}`: {}",
-                            out_filename.display(),
-                            e));
-    }
-}
-
 fn is_full_lto_enabled(sess: &Session) -> bool {
     match sess.lto() {
         Lto::Yes |
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 7e7811c56c74e..a3ff39a47a299 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -23,7 +23,7 @@ use rustc::middle::dependency_format::Linkage;
 use rustc::session::Session;
 use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
 use rustc::ty::TyCtxt;
-use rustc_back::LinkerFlavor;
+use rustc_back::{LinkerFlavor, LldFlavor};
 use serialize::{json, Encoder};
 
 /// For all the linkers we support, and information they might
@@ -45,6 +45,7 @@ impl LinkerInfo {
                          cmd: Command,
                          sess: &'a Session) -> Box<Linker+'a> {
         match sess.linker_flavor() {
+            LinkerFlavor::Lld(LldFlavor::Link) |
             LinkerFlavor::Msvc => {
                 Box::new(MsvcLinker {
                     cmd,
@@ -68,6 +69,9 @@ impl LinkerInfo {
                     is_ld: false,
                 }) as Box<Linker>
             }
+
+            LinkerFlavor::Lld(LldFlavor::Ld) |
+            LinkerFlavor::Lld(LldFlavor::Ld64) |
             LinkerFlavor::Ld => {
                 Box::new(GccLinker {
                     cmd,
@@ -77,8 +81,11 @@ impl LinkerInfo {
                     is_ld: true,
                 }) as Box<Linker>
             }
-            LinkerFlavor::Binaryen => {
-                panic!("can't instantiate binaryen linker")
+
+            LinkerFlavor::Lld(LldFlavor::Wasm) => {
+                Box::new(WasmLd {
+                    cmd,
+                }) as Box<Linker>
             }
         }
     }
@@ -785,3 +792,111 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
 
     symbols
 }
+
+pub struct WasmLd {
+    cmd: Command,
+}
+
+impl Linker for WasmLd {
+    fn link_dylib(&mut self, lib: &str) {
+        self.cmd.arg("-l").arg(lib);
+    }
+
+    fn link_staticlib(&mut self, lib: &str) {
+        self.cmd.arg("-l").arg(lib);
+    }
+
+    fn link_rlib(&mut self, lib: &Path) {
+        self.cmd.arg(lib);
+    }
+
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+
+    fn framework_path(&mut self, _path: &Path) {
+        panic!("frameworks not supported")
+    }
+
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn position_independent_executable(&mut self) {
+    }
+
+    fn partial_relro(&mut self) {
+    }
+
+    fn full_relro(&mut self) {
+    }
+
+    fn build_static_executable(&mut self) {
+    }
+
+    fn args(&mut self, args: &[String]) {
+        self.cmd.args(args);
+    }
+
+    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+        self.cmd.arg("-l").arg(lib);
+    }
+
+    fn link_framework(&mut self, _framework: &str) {
+        panic!("frameworks not supported")
+    }
+
+    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
+        self.cmd.arg("-l").arg(lib);
+    }
+
+    fn link_whole_rlib(&mut self, lib: &Path) {
+        self.cmd.arg(lib);
+    }
+
+    fn gc_sections(&mut self, _keep_metadata: bool) {
+    }
+
+    fn optimize(&mut self) {
+    }
+
+    fn debuginfo(&mut self) {
+    }
+
+    fn no_default_libraries(&mut self) {
+    }
+
+    fn build_dylib(&mut self, _out_filename: &Path) {
+    }
+
+    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {
+    }
+
+    fn subsystem(&mut self, _subsystem: &str) {
+    }
+
+    fn no_position_independent_executable(&mut self) {
+    }
+
+    fn finalize(&mut self) -> Command {
+        self.cmd.arg("--threads");
+
+        // FIXME we probably shouldn't pass this but instead pass an explicit
+        // whitelist of symbols we'll allow to be undefined. Unfortunately
+        // though we can't handle symbols like `log10` that LLVM injects at a
+        // super late date without actually parsing object files. For now let's
+        // stick to this and hopefully fix it before stabilization happens.
+        self.cmd.arg("--allow-undefined");
+
+        // For now we just never have an entry symbol
+        self.cmd.arg("--no-entry");
+
+        let mut cmd = Command::new("");
+        ::std::mem::swap(&mut cmd, &mut self.cmd);
+        cmd
+    }
+}
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index 989ef8a953746..6aac6ceeca1d4 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -21,7 +21,6 @@ use rustc::ty::TyCtxt;
 use rustc::ty::maps::Providers;
 use rustc::util::nodemap::FxHashMap;
 use rustc_allocator::ALLOCATOR_METHODS;
-use rustc_back::LinkerFlavor;
 use syntax::attr;
 
 pub type ExportedSymbols = FxHashMap<
@@ -156,26 +155,12 @@ pub fn provide_extern(providers: &mut Providers) {
         let special_runtime_crate =
             tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
 
-        // Dealing with compiler-builtins and wasm right now is super janky.
-        // There's no linker! As a result we need all of the compiler-builtins
-        // exported symbols to make their way through all the way to the end of
-        // compilation. We want to make sure that LLVM doesn't remove them as
-        // well because we may or may not need them in the final output
-        // artifact. For now just force them to always get exported at the C
-        // layer, and we'll worry about gc'ing them later.
-        let compiler_builtins_and_binaryen =
-            tcx.is_compiler_builtins(cnum) &&
-            tcx.sess.linker_flavor() == LinkerFlavor::Binaryen;
-
         let mut crate_exports: Vec<_> = tcx
             .exported_symbol_ids(cnum)
             .iter()
             .map(|&def_id| {
                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                let export_level = if compiler_builtins_and_binaryen &&
-                                      tcx.contains_extern_indicator(def_id) {
-                    SymbolExportLevel::C
-                } else if special_runtime_crate {
+                let export_level = if special_runtime_crate {
                     // We can probably do better here by just ensuring that
                     // it has hidden visibility rather than public
                     // visibility, as this is primarily here to ensure it's
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index af5178eb565db..78b26a37485ef 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -23,7 +23,6 @@ use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePass
                              AllPasses, Sanitizer, Lto};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
-use rustc_back::LinkerFlavor;
 use time_graph::{self, TimeGraph, Timeline};
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
@@ -344,9 +343,7 @@ pub struct CodegenContext {
     pub tm_factory: Arc<Fn() -> Result<TargetMachineRef, String> + Send + Sync>,
     pub msvc_imps_needed: bool,
     pub target_pointer_width: String,
-    binaryen_linker: bool,
     debuginfo: config::DebugInfoLevel,
-    wasm_import_memory: bool,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -639,13 +636,6 @@ unsafe fn codegen(cgcx: &CodegenContext,
         f(cpm)
     }
 
-    // If we're going to generate wasm code from the assembly that llvm
-    // generates then we'll be transitively affecting a ton of options below.
-    // This only happens on the wasm target now.
-    let asm2wasm = cgcx.binaryen_linker &&
-        !cgcx.crate_types.contains(&config::CrateTypeRlib) &&
-        mtrans.kind == ModuleKind::Regular;
-
     // 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;
@@ -654,10 +644,10 @@ unsafe fn codegen(cgcx: &CodegenContext,
     // 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 && !asm2wasm);
-    let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm;
-    let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm && !asm_to_obj;
-    let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm;
+    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);
@@ -736,13 +726,13 @@ unsafe fn codegen(cgcx: &CodegenContext,
             timeline.record("ir");
         }
 
-        if config.emit_asm || (asm2wasm && config.emit_obj) || asm_to_obj {
+        if config.emit_asm || asm_to_obj {
             let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
 
             // 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 && !asm2wasm {
+            let llmod = if config.emit_obj {
                 llvm::LLVMCloneModule(llmod)
             } else {
                 llmod
@@ -751,24 +741,13 @@ unsafe fn codegen(cgcx: &CodegenContext,
                 write_output_file(diag_handler, tm, cpm, llmod, &path,
                                   llvm::FileType::AssemblyFile)
             })?;
-            if config.emit_obj && !asm2wasm {
+            if config.emit_obj {
                 llvm::LLVMDisposeModule(llmod);
             }
             timeline.record("asm");
         }
 
-        if asm2wasm && config.emit_obj {
-            let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
-            let suffix = ".wasm.map"; // FIXME use target suffix
-            let map = cgcx.output_filenames.path(OutputType::Exe)
-                .with_extension(&suffix[1..]);
-            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
-            timeline.record("binaryen");
-
-            if !config.emit_asm {
-                drop(fs::remove_file(&assembly));
-            }
-        } else if write_obj {
+        if write_obj {
             with_codegen(tm, llmod, config.no_builtins, |cpm| {
                 write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
                                   llvm::FileType::ObjectFile)
@@ -808,49 +787,6 @@ unsafe fn codegen(cgcx: &CodegenContext,
                                    &cgcx.output_filenames))
 }
 
-/// Translates the LLVM-generated `assembly` on the filesystem into a wasm
-/// module using binaryen, placing the output at `object`.
-///
-/// In this case the "object" is actually a full and complete wasm module. We
-/// won't actually be doing anything else to the output for now. This is all
-/// pretty janky and will get removed as soon as a linker for wasm exists.
-fn binaryen_assemble(cgcx: &CodegenContext,
-                     handler: &Handler,
-                     assembly: &Path,
-                     object: &Path,
-                     map: &Path) {
-    use rustc_binaryen::{Module, ModuleOptions};
-
-    let input = fs::read(&assembly).and_then(|contents| {
-        Ok(CString::new(contents)?)
-    });
-    let mut options = ModuleOptions::new();
-    if cgcx.debuginfo != config::NoDebugInfo {
-        options.debuginfo(true);
-        let map_file_name = map.file_name().unwrap();
-        options.source_map_url(map_file_name.to_str().unwrap());
-    }
-
-    options.stack(1024 * 1024);
-    options.import_memory(cgcx.wasm_import_memory);
-    let assembled = input.and_then(|input| {
-        Module::new(&input, &options)
-            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
-    });
-    let err = assembled.and_then(|binary| {
-        fs::write(&object, binary.data()).and_then(|()| {
-            if cgcx.debuginfo != config::NoDebugInfo {
-                fs::write(map, binary.source_map())
-            } else {
-                Ok(())
-            }
-        })
-    });
-    if let Err(e) = err {
-        handler.err(&format!("failed to run binaryen assembler: {}", e));
-    }
-}
-
 pub(crate) struct CompiledModules {
     pub modules: Vec<CompiledModule>,
     pub metadata_module: CompiledModule,
@@ -1431,12 +1367,9 @@ fn start_executing_work(tcx: TyCtxt,
         each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
     }));
 
-    let wasm_import_memory =
-        attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
-
     let assembler_cmd = if modules_config.no_integrated_as {
         // HACK: currently we use linker (gcc) as our assembler
-        let (name, mut cmd, _) = get_linker(sess);
+        let (name, mut cmd) = get_linker(sess);
         cmd.args(&sess.target.target.options.asm_args);
         Some(Arc::new(AssemblerCommand {
             name,
@@ -1471,9 +1404,7 @@ fn start_executing_work(tcx: TyCtxt,
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
-        binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
         debuginfo: tcx.sess.opts.debuginfo,
-        wasm_import_memory,
         assembler_cmd,
     };
 
diff --git a/src/librustc_trans/cabi_riscv.rs b/src/librustc_trans/cabi_riscv.rs
new file mode 100644
index 0000000000000..72563f611c3a5
--- /dev/null
+++ b/src/librustc_trans/cabi_riscv.rs
@@ -0,0 +1,61 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+// Reference: RISC-V ELF psABI specification
+// https://github.com/riscv/riscv-elf-psabi-doc
+
+use abi::{ArgType, FnType, LayoutExt};
+
+// Procedure Calling Convention
+//
+// Scalars wider than 2✕XLEN are passed by reference and are replaced in the
+// argument list with the address.
+//
+// Scalars that are at most XLEN bits wide are passed in a single argument
+// register, or on the stack by value if none is available. When passed in
+// registers, scalars narrower than XLEN bits are widened according to the
+// sign of their type up to 32 bits, then sign-extended to XLEN bits.
+//
+// Aggregates larger than 2✕XLEN bits are passed by reference and are replaced
+// in the argument list with the address, as are C++ aggregates with nontrivial
+// copy constructors, destructors, or vtables.
+//
+
+// 32-bit Architecture
+const XLEN: u64 = 32;
+
+fn classify_ret_ty(ret: &mut ArgType) {
+    if ret.layout.is_aggregate() && ret.layout.size.bits() > 2 * XLEN {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(XLEN);
+    }
+}
+
+fn classify_arg_ty(arg: &mut ArgType) {
+    if arg.layout.is_aggregate() && arg.layout.size.bits() > 2 * XLEN {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(XLEN);
+    }
+}
+
+pub fn compute_abi_info(fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6c281ab5e7a40..cb89e5a13540e 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -49,7 +49,6 @@ extern crate rustc_mir;
 extern crate rustc_allocator;
 extern crate rustc_apfloat;
 extern crate rustc_back;
-extern crate rustc_binaryen;
 extern crate rustc_const_math;
 extern crate rustc_data_structures;
 extern crate rustc_demangle;
@@ -63,7 +62,6 @@ extern crate rustc_trans_utils;
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
 extern crate serialize;
-#[cfg(windows)]
 extern crate cc; // Used to locate MSVC
 extern crate tempdir;
 
@@ -119,6 +117,7 @@ mod cabi_nvptx;
 mod cabi_nvptx64;
 mod cabi_powerpc;
 mod cabi_powerpc64;
+mod cabi_riscv;
 mod cabi_s390x;
 mod cabi_sparc;
 mod cabi_sparc64;
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index c4946b6b2824d..5cf2c16fb682f 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -929,6 +929,11 @@ mod arch {
     pub const ARCH: &'static str = "mips64";
 }
 
+#[cfg(target_arch = "riscv")]
+mod arch {
+    pub const ARCH: &'static str = "riscv";
+}
+
 #[cfg(target_arch = "powerpc")]
 mod arch {
     pub const ARCH: &'static str = "powerpc";
diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs
index bb1830a147e43..12f022139c6d7 100644
--- a/src/libstd/os/linux/raw.rs
+++ b/src/libstd/os/linux/raw.rs
@@ -92,7 +92,9 @@ mod arch {
     }
 }
 
-#[cfg(target_arch = "mips")]
+#[cfg(any(target_arch = "mips",
+          all(target_arch = "riscv",
+              target_pointer_width = "32")))]
 mod arch {
     use os::raw::{c_long, c_ulong};
 
@@ -159,7 +161,9 @@ mod arch {
 
 #[cfg(any(target_arch = "mips64",
           target_arch = "s390x",
-          target_arch = "sparc64"))]
+          target_arch = "sparc64",
+          all(target_arch = "riscv",
+              target_pointer_width = "64")))]
 mod arch {
     pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1ebf52e9fe8c0..849401ff498fa 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -414,9 +414,6 @@ declare_features! (
     // Allow trait methods with arbitrary self types
     (active, arbitrary_self_types, "1.23.0", Some(44874)),
 
-    // #![wasm_import_memory] attribute
-    (active, wasm_import_memory, "1.22.0", None),
-
     // `crate` in paths
     (active, crate_in_paths, "1.23.0", Some(45477)),
 
@@ -982,11 +979,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                                         never be stable",
                                                        cfg_fn!(rustc_attrs))),
 
-    ("wasm_import_memory", Whitelisted, Gated(Stability::Unstable,
-                                 "wasm_import_memory",
-                                 "wasm_import_memory attribute is currently unstable",
-                                 cfg_fn!(wasm_import_memory))),
-
     ("rustc_args_required_const", Whitelisted, Gated(Stability::Unstable,
                                  "rustc_attrs",
                                  "never will be stable",
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
index e6fff7963f79c..9c62109eb37a0 100644
--- a/src/libunwind/libunwind.rs
+++ b/src/libunwind/libunwind.rs
@@ -59,6 +59,9 @@ pub const unwinder_private_data_size: usize = 2;
 #[cfg(target_arch = "mips64")]
 pub const unwinder_private_data_size: usize = 2;
 
+#[cfg(target_arch = "riscv")]
+pub const unwinder_private_data_size: usize = 2;
+
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
 pub const unwinder_private_data_size: usize = 2;
 
diff --git a/src/llvm b/src/llvm
index 9f81beaf32608..8669a3f6b88c9 160000
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 9f81beaf32608fbe1fe0f2a82f974e800e9d8c62
+Subproject commit 8669a3f6b88c98cf8c16b58a8d14fc173e8a8567
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 06d1301d70003..504b5a61bc8c0 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -167,6 +167,12 @@ bool LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
 #define SUBTARGET_MSP430
 #endif
 
+#ifdef LLVM_COMPONENT_RISCV
+#define SUBTARGET_RISCV SUBTARGET(RISCV)
+#else
+#define SUBTARGET_RISCV
+#endif
+
 #ifdef LLVM_COMPONENT_SPARC
 #define SUBTARGET_SPARC SUBTARGET(Sparc)
 #else
@@ -188,7 +194,8 @@ bool LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
   SUBTARGET_SYSTEMZ                                                            \
   SUBTARGET_MSP430                                                             \
   SUBTARGET_SPARC                                                              \
-  SUBTARGET_HEXAGON
+  SUBTARGET_HEXAGON                                                            \
+  SUBTARGET_RISCV                                                              \
 
 #define SUBTARGET(x)                                                           \
   namespace llvm {                                                             \
diff --git a/src/test/run-pass/issue-15487.rs b/src/test/run-pass/issue-15487.rs
index cc5db0af88bea..3616ab9e6c730 100644
--- a/src/test/run-pass/issue-15487.rs
+++ b/src/test/run-pass/issue-15487.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // ignore-windows
+// ignore-wasm32-bare no libs to link
 
 #![feature(link_args)]
 
diff --git a/src/test/ui/feature-gate-wasm_import_memory.rs b/src/test/ui/feature-gate-wasm_import_memory.rs
deleted file mode 100644
index a010ebb3551d0..0000000000000
--- a/src/test/ui/feature-gate-wasm_import_memory.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-#![wasm_import_memory] //~ ERROR: currently unstable
-
-fn main() {}
-
diff --git a/src/test/ui/feature-gate-wasm_import_memory.stderr b/src/test/ui/feature-gate-wasm_import_memory.stderr
deleted file mode 100644
index 10190ef93f0d9..0000000000000
--- a/src/test/ui/feature-gate-wasm_import_memory.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error[E0658]: wasm_import_memory attribute is currently unstable
-  --> $DIR/feature-gate-wasm_import_memory.rs:11:1
-   |
-11 | #![wasm_import_memory] //~ ERROR: currently unstable
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(wasm_import_memory)] to the crate attributes to enable
-
-error: aborting due to previous error
-
diff --git a/src/tools/lld b/src/tools/lld
new file mode 160000
index 0000000000000..66430983d600b
--- /dev/null
+++ b/src/tools/lld
@@ -0,0 +1 @@
+Subproject commit 66430983d600ba76310c595b1bc100f77b46a46e
diff --git a/src/tools/miri b/src/tools/miri
deleted file mode 160000
index 61833b9aeab8b..0000000000000
--- a/src/tools/miri
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 4d89008d5ca54..615e624fb86bc 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -50,7 +50,6 @@ pub mod unstable_book;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
-        "src/binaryen",
         "src/dlmalloc",
         "src/jemalloc",
         "src/llvm",
@@ -68,6 +67,7 @@ fn filter_dirs(path: &Path) -> bool {
         "src/tools/rust-installer",
         "src/tools/rustfmt",
         "src/tools/miri",
+        "src/tools/lld",
         "src/librustc/mir/interpret",
         "src/librustc_mir/interpret",
         "src/target",
