about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2018-06-15 19:02:41 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2018-07-07 10:47:22 +0200
commit6ceb1637b2500f384015578a5a6f556bcc992052 (patch)
treef19b7aa29e17b30195a6018ce817456f3d00c925
parent4f0ca9248f93162201ea88a99594deedf0ebd897 (diff)
downloadrust-6ceb1637b2500f384015578a5a6f556bcc992052.tar.gz
rust-6ceb1637b2500f384015578a5a6f556bcc992052.zip
Move some functions out of rustc_codegen_llvm and fix metadata_only backend
-rw-r--r--src/bootstrap/bin/rustc.rs4
-rw-r--r--src/bootstrap/compile.rs16
-rw-r--r--src/librustc_codegen_llvm/base.rs7
-rw-r--r--src/librustc_codegen_llvm/common.rs104
-rw-r--r--src/librustc_codegen_llvm/lib.rs4
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs118
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs2
-rw-r--r--src/librustc_codegen_utils/codegen_backend.rs16
-rw-r--r--src/librustc_codegen_utils/lib.rs2
-rw-r--r--src/librustc_codegen_utils/llvm_target_features.rs117
-rw-r--r--src/librustc_codegen_utils/time_graph.rs (renamed from src/librustc_codegen_llvm/time_graph.rs)0
-rw-r--r--src/librustc_driver/lib.rs14
12 files changed, 265 insertions, 139 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 4607ca5cf9f..d38ffe431e0 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -114,6 +114,10 @@ fn main() {
 
     cmd.env("RUSTC_BREAK_ON_ICE", "1");
 
+    if args.iter().find(|s| **s == OsString::from("___")).is_some() {
+        cmd.arg("-Zcodegen-backend=metadata_only");
+    }
+
     if let Some(target) = target {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option.
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 298bd58c6cd..e23566d52f0 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -182,11 +182,13 @@ pub fn std_cargo(builder: &Builder,
             // missing
             // We also only build the runtimes when --enable-sanitizers (or its
             // config.toml equivalent) is used
-            let llvm_config = builder.ensure(native::Llvm {
-                target: builder.config.build,
-                emscripten: false,
-            });
-            cargo.env("LLVM_CONFIG", llvm_config);
+            if !builder.config.rust_codegen_backends.is_empty() {
+                let llvm_config = builder.ensure(native::Llvm {
+                    target: builder.config.build,
+                    emscripten: false,
+                });
+                cargo.env("LLVM_CONFIG", llvm_config);
+            }
         }
 
         cargo.arg("--features").arg(features)
@@ -675,7 +677,9 @@ impl Step for CodegenBackend {
             .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
         rustc_cargo_env(builder, &mut cargo);
 
-        features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
+        if !backend.is_empty() {
+            features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
+        }
 
         let tmp_stamp = builder.cargo_out(compiler, Mode::Codegen, target)
             .join(".tmp.stamp");
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index a4709739a23..53c70eb42ce 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -56,6 +56,7 @@ use builder::{Builder, MemFlags};
 use callee;
 use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
 use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
+use rustc_mir::monomorphize::item::DefPathBasedNames;
 use common::{self, C_struct_in_context, C_array, val_ty};
 use consts;
 use context::{self, CodegenCx};
@@ -67,7 +68,7 @@ use monomorphize::Instance;
 use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
 use rustc_codegen_utils::symbol_names_test;
 use time_graph;
-use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames};
+use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt};
 use type_::Type;
 use type_of::LayoutLlvmExt;
 use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
@@ -92,8 +93,6 @@ use syntax::ast;
 
 use mir::operand::OperandValue;
 
-pub use rustc_codegen_utils::check_for_rustc_errors_attr;
-
 pub struct StatRecorder<'a, 'tcx: 'a> {
     cx: &'a CodegenCx<'a, 'tcx>,
     name: Option<String>,
@@ -715,7 +714,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              rx: mpsc::Receiver<Box<Any + Send>>)
                              -> OngoingCodegen {
 
-    check_for_rustc_errors_attr(tcx);
+    ::rustc_codegen_utils::check_for_rustc_errors_attr(tcx);
 
     if let Some(true) = tcx.sess.opts.debugging_opts.thinlto {
         if unsafe { !llvm::LLVMRustThinLTOAvailable() } {
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 7e55642814b..099d717e3c0 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -12,9 +12,7 @@
 
 //! Code that is useful in various codegen modules.
 
-use llvm;
-use llvm::{ValueRef, ContextRef, TypeKind};
-use llvm::{True, False, Bool, OperandBundleDef};
+use llvm::{self, ValueRef, ContextRef, TypeKind, True, False, Bool, OperandBundleDef};
 use rustc::hir::def_id::DefId;
 use rustc::middle::lang_items::LangItem;
 use abi;
@@ -29,6 +27,8 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{HasDataLayout, LayoutOf};
 use rustc::hir;
 
+use meth;
+
 use libc::{c_uint, c_char};
 use std::iter;
 
@@ -448,3 +448,101 @@ pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
     }
 }
+
+pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
+                                       -> (ValueRef, ValueRef) {
+    debug!("calculate size of DST: {}; with lost info: {:?}",
+           t, Value(info));
+    if bx.cx.type_is_sized(t) {
+        let (size, align) = bx.cx.size_and_align_of(t);
+        debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}",
+               t, Value(info), size, align);
+        let size = C_usize(bx.cx, size.bytes());
+        let align = C_usize(bx.cx, align.abi());
+        return (size, align);
+    }
+    assert!(!info.is_null());
+    match t.sty {
+        ty::TyDynamic(..) => {
+            // load size/align from vtable
+            (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info))
+        }
+        ty::TySlice(_) | ty::TyStr => {
+            let unit = t.sequence_element_type(bx.tcx());
+            // The info in this case is the length of the str, so the size is that
+            // times the unit size.
+            let (size, align) = bx.cx.size_and_align_of(unit);
+            (bx.mul(info, C_usize(bx.cx, size.bytes())),
+             C_usize(bx.cx, align.abi()))
+        }
+        _ => {
+            let cx = bx.cx;
+            // First get the size of all statically known fields.
+            // Don't use size_of because it also rounds up to alignment, which we
+            // want to avoid, as the unsized field's alignment could be smaller.
+            assert!(!t.is_simd());
+            let layout = cx.layout_of(t);
+            debug!("DST {} layout: {:?}", t, layout);
+
+            let i = layout.fields.count() - 1;
+            let sized_size = layout.fields.offset(i).bytes();
+            let sized_align = layout.align.abi();
+            debug!("DST {} statically sized prefix size: {} align: {}",
+                   t, sized_size, sized_align);
+            let sized_size = C_usize(cx, sized_size);
+            let sized_align = C_usize(cx, sized_align);
+
+            // Recurse to get the size of the dynamically sized field (must be
+            // the last field).
+            let field_ty = layout.field(cx, i).ty;
+            let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info);
+
+            // FIXME (#26403, #27023): We should be adding padding
+            // to `sized_size` (to accommodate the `unsized_align`
+            // required of the unsized field that follows) before
+            // summing it with `sized_size`. (Note that since #26403
+            // is unfixed, we do not yet add the necessary padding
+            // here. But this is where the add would go.)
+
+            // Return the sum of sizes and max of aligns.
+            let size = bx.add(sized_size, unsized_size);
+
+            // Packed types ignore the alignment of their fields.
+            if let ty::TyAdt(def, _) = t.sty {
+                if def.repr.packed() {
+                    unsized_align = sized_align;
+                }
+            }
+
+            // Choose max of two known alignments (combined value must
+            // be aligned according to more restrictive of the two).
+            let align = match (const_to_opt_u128(sized_align, false),
+                               const_to_opt_u128(unsized_align, false)) {
+                (Some(sized_align), Some(unsized_align)) => {
+                    // If both alignments are constant, (the sized_align should always be), then
+                    // pick the correct alignment statically.
+                    C_usize(cx, ::std::cmp::max(sized_align, unsized_align) as u64)
+                }
+                _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align),
+                                sized_align,
+                                unsized_align)
+            };
+
+            // Issue #27023: must add any necessary padding to `size`
+            // (to make it a multiple of `align`) before returning it.
+            //
+            // Namely, the returned size should be, in C notation:
+            //
+            //   `size + ((size & (align-1)) ? align : 0)`
+            //
+            // emulated via the semi-standard fast bit trick:
+            //
+            //   `(size + (align-1)) & -align`
+
+            let addend = bx.sub(align, C_usize(bx.cx, 1));
+            let size = bx.and(bx.add(size, addend), bx.neg(align));
+
+            (size, align)
+        }
+    }
+}
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index b11b0c7abe8..eee4e5f8f7a 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -79,6 +79,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc_mir::monomorphize;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_codegen_utils::time_graph;
 
 mod diagnostics;
 
@@ -114,7 +115,6 @@ mod llvm_util;
 mod metadata;
 mod meth;
 mod mir;
-mod time_graph;
 mod mono_item;
 mod type_;
 mod type_of;
@@ -368,7 +368,7 @@ struct CodegenResults {
     crate_info: CrateInfo,
 }
 
-// Misc info we load from metadata to persist beyond the tcx
+/// Misc info we load from metadata to persist beyond the tcx
 struct CrateInfo {
     panic_runtime: Option<CrateNum>,
     compiler_builtins: Option<CrateNum>,
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 87ee9ef5adb..b63b43c9c73 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -20,6 +20,8 @@ use syntax::feature_gate::UnstableFeatures;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Once;
 
+pub use rustc_codegen_utils::llvm_target_features::*;
+
 static POISONED: AtomicBool = AtomicBool::new(false);
 static INIT: Once = Once::new();
 
@@ -79,108 +81,6 @@ unsafe fn configure_llvm(sess: &Session) {
                                  llvm_args.as_ptr());
 }
 
-// WARNING: the features after applying `to_llvm_feature` must be known
-// to LLVM or the feature detection code will walk past the end of the feature
-// array, leading to crashes.
-
-const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("mclass", Some("arm_target_feature")),
-    ("neon", Some("arm_target_feature")),
-    ("v7", Some("arm_target_feature")),
-    ("vfp2", Some("arm_target_feature")),
-    ("vfp3", Some("arm_target_feature")),
-    ("vfp4", Some("arm_target_feature")),
-];
-
-const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("fp", Some("aarch64_target_feature")),
-    ("neon", Some("aarch64_target_feature")),
-    ("sve", Some("aarch64_target_feature")),
-    ("crc", Some("aarch64_target_feature")),
-    ("crypto", Some("aarch64_target_feature")),
-    ("ras", Some("aarch64_target_feature")),
-    ("lse", Some("aarch64_target_feature")),
-    ("rdm", Some("aarch64_target_feature")),
-    ("fp16", Some("aarch64_target_feature")),
-    ("rcpc", Some("aarch64_target_feature")),
-    ("dotprod", Some("aarch64_target_feature")),
-    ("v8.1a", Some("aarch64_target_feature")),
-    ("v8.2a", Some("aarch64_target_feature")),
-    ("v8.3a", Some("aarch64_target_feature")),
-];
-
-const X86_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("aes", None),
-    ("avx", None),
-    ("avx2", None),
-    ("avx512bw", Some("avx512_target_feature")),
-    ("avx512cd", Some("avx512_target_feature")),
-    ("avx512dq", Some("avx512_target_feature")),
-    ("avx512er", Some("avx512_target_feature")),
-    ("avx512f", Some("avx512_target_feature")),
-    ("avx512ifma", Some("avx512_target_feature")),
-    ("avx512pf", Some("avx512_target_feature")),
-    ("avx512vbmi", Some("avx512_target_feature")),
-    ("avx512vl", Some("avx512_target_feature")),
-    ("avx512vpopcntdq", Some("avx512_target_feature")),
-    ("bmi1", None),
-    ("bmi2", None),
-    ("fma", None),
-    ("fxsr", None),
-    ("lzcnt", None),
-    ("mmx", Some("mmx_target_feature")),
-    ("pclmulqdq", None),
-    ("popcnt", None),
-    ("rdrand", None),
-    ("rdseed", None),
-    ("sha", None),
-    ("sse", None),
-    ("sse2", None),
-    ("sse3", None),
-    ("sse4.1", None),
-    ("sse4.2", None),
-    ("sse4a", Some("sse4a_target_feature")),
-    ("ssse3", None),
-    ("tbm", Some("tbm_target_feature")),
-    ("xsave", None),
-    ("xsavec", None),
-    ("xsaveopt", None),
-    ("xsaves", None),
-];
-
-const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("hvx", Some("hexagon_target_feature")),
-    ("hvx-double", Some("hexagon_target_feature")),
-];
-
-const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("altivec", Some("powerpc_target_feature")),
-    ("power8-altivec", Some("powerpc_target_feature")),
-    ("power9-altivec", Some("powerpc_target_feature")),
-    ("power8-vector", Some("powerpc_target_feature")),
-    ("power9-vector", Some("powerpc_target_feature")),
-    ("vsx", Some("powerpc_target_feature")),
-];
-
-const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("fp64", Some("mips_target_feature")),
-    ("msa", Some("mips_target_feature")),
-];
-
-/// When rustdoc is running, provide a list of all known features so that all their respective
-/// primtives may be documented.
-///
-/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
-/// iterator!
-pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
-    ARM_WHITELIST.iter().cloned()
-        .chain(AARCH64_WHITELIST.iter().cloned())
-        .chain(X86_WHITELIST.iter().cloned())
-        .chain(HEXAGON_WHITELIST.iter().cloned())
-        .chain(POWERPC_WHITELIST.iter().cloned())
-        .chain(MIPS_WHITELIST.iter().cloned())
-}
-
 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
     let arch = if sess.target.target.arch == "x86_64" {
         "x86"
@@ -216,20 +116,6 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
         .map(|feature| Symbol::intern(feature)).collect()
 }
 
-pub fn target_feature_whitelist(sess: &Session)
-    -> &'static [(&'static str, Option<&'static str>)]
-{
-    match &*sess.target.target.arch {
-        "arm" => ARM_WHITELIST,
-        "aarch64" => AARCH64_WHITELIST,
-        "x86" | "x86_64" => X86_WHITELIST,
-        "hexagon" => HEXAGON_WHITELIST,
-        "mips" | "mips64" => MIPS_WHITELIST,
-        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
-        _ => &[],
-    }
-}
-
 pub fn print_version() {
     // Can be called without initializing LLVM
     unsafe {
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index c4a23ac653c..61f4bc3e6bc 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -33,7 +33,7 @@ use std::fmt;
 
 pub use rustc::mir::mono::MonoItem;
 
-pub use rustc_mir::monomorphize::item::*;
+use rustc_mir::monomorphize::item::*;
 pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt;
 
 pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs
index 8ba6f30cf16..8b52d61fd9e 100644
--- a/src/librustc_codegen_utils/codegen_backend.rs
+++ b/src/librustc_codegen_utils/codegen_backend.rs
@@ -26,7 +26,7 @@ use std::io::prelude::*;
 use std::io::{self, Cursor};
 use std::fs::File;
 use std::path::Path;
-use std::sync::mpsc;
+use std::sync::{mpsc, Arc};
 
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::sync::Lrc;
@@ -44,7 +44,6 @@ use rustc::middle::cstore::EncodedMetadata;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::dep_graph::DepGraph;
 use rustc_target::spec::Target;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_mir::monomorphize::collector;
 use link::{build_link_meta, out_filename};
 
@@ -203,10 +202,17 @@ impl CodegenBackend for MetadataOnlyCodegenBackend {
         ::symbol_names::provide(providers);
 
         providers.target_features_whitelist = |_tcx, _cnum| {
-            Lrc::new(FxHashMap()) // Just a dummy
+            Lrc::new(::llvm_target_features::all_known_features()
+                .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
+                .collect())
         };
+        providers.is_reachable_non_generic = |_tcx, _defid| true;
+        providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new());
+        providers.wasm_custom_sections = |_tcx, _crate| Lrc::new(Vec::new());
+    }
+    fn provide_extern(&self, providers: &mut Providers) {
+        providers.is_reachable_non_generic = |_tcx, _defid| true;
     }
-    fn provide_extern(&self, _providers: &mut Providers) {}
 
     fn codegen_crate<'a, 'tcx>(
         &self,
@@ -225,7 +231,7 @@ impl CodegenBackend for MetadataOnlyCodegenBackend {
                 collector::MonoItemCollectionMode::Eager
             ).0.iter()
         );
-        ::rustc::middle::dependency_format::calculate(tcx);
+        //::rustc::middle::dependency_format::calculate(tcx);
         let _ = tcx.link_args(LOCAL_CRATE);
         let _ = tcx.native_libraries(LOCAL_CRATE);
         for mono_item in
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index d09e8f4845e..058e4b7841f 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -47,6 +47,8 @@ pub mod link;
 pub mod codegen_backend;
 pub mod symbol_names;
 pub mod symbol_names_test;
+pub mod time_graph;
+pub mod llvm_target_features;
 
 /// check for the #[rustc_error] annotation, which forces an
 /// error in codegen. This is used to write compile-fail tests
diff --git a/src/librustc_codegen_utils/llvm_target_features.rs b/src/librustc_codegen_utils/llvm_target_features.rs
new file mode 100644
index 00000000000..82cd397be23
--- /dev/null
+++ b/src/librustc_codegen_utils/llvm_target_features.rs
@@ -0,0 +1,117 @@
+use rustc::session::Session;
+
+// WARNING: the features after applying `to_llvm_feature` must be known
+// to LLVM or the feature detection code will walk past the end of the feature
+// array, leading to crashes.
+
+const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("mclass", Some("arm_target_feature")),
+    ("neon", Some("arm_target_feature")),
+    ("v7", Some("arm_target_feature")),
+    ("vfp2", Some("arm_target_feature")),
+    ("vfp3", Some("arm_target_feature")),
+    ("vfp4", Some("arm_target_feature")),
+];
+
+const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("fp", Some("aarch64_target_feature")),
+    ("neon", Some("aarch64_target_feature")),
+    ("sve", Some("aarch64_target_feature")),
+    ("crc", Some("aarch64_target_feature")),
+    ("crypto", Some("aarch64_target_feature")),
+    ("ras", Some("aarch64_target_feature")),
+    ("lse", Some("aarch64_target_feature")),
+    ("rdm", Some("aarch64_target_feature")),
+    ("fp16", Some("aarch64_target_feature")),
+    ("rcpc", Some("aarch64_target_feature")),
+    ("dotprod", Some("aarch64_target_feature")),
+    ("v8.1a", Some("aarch64_target_feature")),
+    ("v8.2a", Some("aarch64_target_feature")),
+    ("v8.3a", Some("aarch64_target_feature")),
+];
+
+const X86_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("aes", None),
+    ("avx", None),
+    ("avx2", None),
+    ("avx512bw", Some("avx512_target_feature")),
+    ("avx512cd", Some("avx512_target_feature")),
+    ("avx512dq", Some("avx512_target_feature")),
+    ("avx512er", Some("avx512_target_feature")),
+    ("avx512f", Some("avx512_target_feature")),
+    ("avx512ifma", Some("avx512_target_feature")),
+    ("avx512pf", Some("avx512_target_feature")),
+    ("avx512vbmi", Some("avx512_target_feature")),
+    ("avx512vl", Some("avx512_target_feature")),
+    ("avx512vpopcntdq", Some("avx512_target_feature")),
+    ("bmi1", None),
+    ("bmi2", None),
+    ("fma", None),
+    ("fxsr", None),
+    ("lzcnt", None),
+    ("mmx", Some("mmx_target_feature")),
+    ("pclmulqdq", None),
+    ("popcnt", None),
+    ("rdrand", None),
+    ("rdseed", None),
+    ("sha", None),
+    ("sse", None),
+    ("sse2", None),
+    ("sse3", None),
+    ("sse4.1", None),
+    ("sse4.2", None),
+    ("sse4a", Some("sse4a_target_feature")),
+    ("ssse3", None),
+    ("tbm", Some("tbm_target_feature")),
+    ("xsave", None),
+    ("xsavec", None),
+    ("xsaveopt", None),
+    ("xsaves", None),
+];
+
+const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("hvx", Some("hexagon_target_feature")),
+    ("hvx-double", Some("hexagon_target_feature")),
+];
+
+const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("altivec", Some("powerpc_target_feature")),
+    ("power8-altivec", Some("powerpc_target_feature")),
+    ("power9-altivec", Some("powerpc_target_feature")),
+    ("power8-vector", Some("powerpc_target_feature")),
+    ("power9-vector", Some("powerpc_target_feature")),
+    ("vsx", Some("powerpc_target_feature")),
+];
+
+const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("fp64", Some("mips_target_feature")),
+    ("msa", Some("mips_target_feature")),
+];
+
+/// When rustdoc is running, provide a list of all known features so that all their respective
+/// primtives may be documented.
+///
+/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
+/// iterator!
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
+    ARM_WHITELIST.iter().cloned()
+        .chain(AARCH64_WHITELIST.iter().cloned())
+        .chain(X86_WHITELIST.iter().cloned())
+        .chain(HEXAGON_WHITELIST.iter().cloned())
+        .chain(POWERPC_WHITELIST.iter().cloned())
+        .chain(MIPS_WHITELIST.iter().cloned())
+}
+
+pub fn target_feature_whitelist(sess: &Session)
+    -> &'static [(&'static str, Option<&'static str>)]
+{
+    match &*sess.target.target.arch {
+        "arm" => ARM_WHITELIST,
+        "aarch64" => AARCH64_WHITELIST,
+        "x86" | "x86_64" => X86_WHITELIST,
+        "hexagon" => HEXAGON_WHITELIST,
+        "mips" | "mips64" => MIPS_WHITELIST,
+        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
+        _ => &[],
+    }
+}
diff --git a/src/librustc_codegen_llvm/time_graph.rs b/src/librustc_codegen_utils/time_graph.rs
index a8502682a80..a8502682a80 100644
--- a/src/librustc_codegen_llvm/time_graph.rs
+++ b/src/librustc_codegen_utils/time_graph.rs
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 84f7b35d21f..321d398b521 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -375,10 +375,20 @@ fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<CodegenBackend> {
     match file {
         Some(ref s) => return load_backend_from_dylib(s),
         None => {
-            let err = format!("failed to load default codegen backend for `{}`, \
+            if !::rustc::session::config::nightly_options::is_nightly_build() {
+                let err = format!("failed to load default codegen backend for `{}`, \
                                no appropriate codegen dylib found in `{}`",
                                backend_name, sysroot.display());
-            early_error(ErrorOutputType::default(), &err);
+                early_error(ErrorOutputType::default(), &err);
+            } else {
+                let warn = format!("no codegen-backend `{}`, \
+                               no appropriate dylib in `{}`. \
+                               Falling back to metadata_only codegen backend. \
+                               **This is suitable for dev purposes only**",
+                               backend_name, sysroot.display());
+                early_warn(ErrorOutputType::default(), &warn);
+                return rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::new;
+            }
         }
     }