about summary refs log tree commit diff
path: root/src/librustc_codegen_utils
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 /src/librustc_codegen_utils
parent4f0ca9248f93162201ea88a99594deedf0ebd897 (diff)
downloadrust-6ceb1637b2500f384015578a5a6f556bcc992052.tar.gz
rust-6ceb1637b2500f384015578a5a6f556bcc992052.zip
Move some functions out of rustc_codegen_llvm and fix metadata_only backend
Diffstat (limited to 'src/librustc_codegen_utils')
-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.rs278
4 files changed, 408 insertions, 5 deletions
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_utils/time_graph.rs b/src/librustc_codegen_utils/time_graph.rs
new file mode 100644
index 00000000000..a8502682a80
--- /dev/null
+++ b/src/librustc_codegen_utils/time_graph.rs
@@ -0,0 +1,278 @@
+// 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.
+
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::prelude::*;
+use std::marker::PhantomData;
+use std::mem;
+use std::sync::{Arc, Mutex};
+use std::time::Instant;
+
+const OUTPUT_WIDTH_IN_PX: u64 = 1000;
+const TIME_LINE_HEIGHT_IN_PX: u64 = 20;
+const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 30;
+
+#[derive(Clone)]
+struct Timing {
+    start: Instant,
+    end: Instant,
+    work_package_kind: WorkPackageKind,
+    name: String,
+    events: Vec<(String, Instant)>,
+}
+
+#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
+pub struct TimelineId(pub usize);
+
+#[derive(Clone)]
+struct PerThread {
+    timings: Vec<Timing>,
+    open_work_package: Option<(Instant, WorkPackageKind, String)>,
+}
+
+#[derive(Clone)]
+pub struct TimeGraph {
+    data: Arc<Mutex<HashMap<TimelineId, PerThread>>>,
+}
+
+#[derive(Clone, Copy)]
+pub struct WorkPackageKind(pub &'static [&'static str]);
+
+pub struct Timeline {
+    token: Option<RaiiToken>,
+}
+
+struct RaiiToken {
+    graph: TimeGraph,
+    timeline: TimelineId,
+    events: Vec<(String, Instant)>,
+    // The token must not be Send:
+    _marker: PhantomData<*const ()>
+}
+
+
+impl Drop for RaiiToken {
+    fn drop(&mut self) {
+        self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new()));
+    }
+}
+
+impl TimeGraph {
+    pub fn new() -> TimeGraph {
+        TimeGraph {
+            data: Arc::new(Mutex::new(HashMap::new()))
+        }
+    }
+
+    pub fn start(&self,
+                 timeline: TimelineId,
+                 work_package_kind: WorkPackageKind,
+                 name: &str) -> Timeline {
+        {
+            let mut table = self.data.lock().unwrap();
+
+            let data = table.entry(timeline).or_insert(PerThread {
+                timings: Vec::new(),
+                open_work_package: None,
+            });
+
+            assert!(data.open_work_package.is_none());
+            data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string()));
+        }
+
+        Timeline {
+            token: Some(RaiiToken {
+                graph: self.clone(),
+                timeline,
+                events: Vec::new(),
+                _marker: PhantomData,
+            }),
+        }
+    }
+
+    fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) {
+        let end = Instant::now();
+
+        let mut table = self.data.lock().unwrap();
+        let data = table.get_mut(&timeline).unwrap();
+
+        if let Some((start, work_package_kind, name)) = data.open_work_package.take() {
+            data.timings.push(Timing {
+                start,
+                end,
+                work_package_kind,
+                name,
+                events,
+            });
+        } else {
+            bug!("end timing without start?")
+        }
+    }
+
+    pub fn dump(&self, output_filename: &str) {
+        let table = self.data.lock().unwrap();
+
+        for data in table.values() {
+            assert!(data.open_work_package.is_none());
+        }
+
+        let mut threads: Vec<PerThread> =
+            table.values().map(|data| data.clone()).collect();
+
+        threads.sort_by_key(|timeline| timeline.timings[0].start);
+
+        let earliest_instant = threads[0].timings[0].start;
+        let latest_instant = threads.iter()
+                                       .map(|timeline| timeline.timings
+                                                               .last()
+                                                               .unwrap()
+                                                               .end)
+                                       .max()
+                                       .unwrap();
+        let max_distance = distance(earliest_instant, latest_instant);
+
+        let mut file = File::create(format!("{}.html", output_filename)).unwrap();
+
+        writeln!(file, "
+            <html>
+            <head>
+                <style>
+                    #threads a {{
+                        position: absolute;
+                        overflow: hidden;
+                    }}
+                    #threads {{
+                        height: {total_height}px;
+                        width: {width}px;
+                    }}
+
+                    .timeline {{
+                        display: none;
+                        width: {width}px;
+                        position: relative;
+                    }}
+
+                    .timeline:target {{
+                        display: block;
+                    }}
+
+                    .event {{
+                        position: absolute;
+                    }}
+                </style>
+            </head>
+            <body>
+                <div id='threads'>
+        ",
+            total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX,
+            width = OUTPUT_WIDTH_IN_PX,
+        ).unwrap();
+
+        let mut color = 0;
+        for (line_index, thread) in threads.iter().enumerate() {
+            let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
+
+            for span in &thread.timings {
+                let start = distance(earliest_instant, span.start);
+                let end = distance(earliest_instant, span.end);
+
+                let start = normalize(start, max_distance, OUTPUT_WIDTH_IN_PX);
+                let end = normalize(end, max_distance, OUTPUT_WIDTH_IN_PX);
+
+                let colors = span.work_package_kind.0;
+
+                writeln!(file, "<a href='#timing{}'
+                                   style='top:{}px; \
+                                          left:{}px; \
+                                          width:{}px; \
+                                          height:{}px; \
+                                          background:{};'>{}</a>",
+                    color,
+                    line_top,
+                    start,
+                    end - start,
+                    TIME_LINE_HEIGHT_IN_PX,
+                    colors[color % colors.len()],
+                    span.name,
+                    ).unwrap();
+
+                color += 1;
+            }
+        }
+
+        writeln!(file, "
+            </div>
+        ").unwrap();
+
+        let mut idx = 0;
+        for thread in threads.iter() {
+            for timing in &thread.timings {
+                let colors = timing.work_package_kind.0;
+                let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len();
+                writeln!(file, "<div class='timeline'
+                                     id='timing{}'
+                                     style='background:{};height:{}px;'>",
+                         idx,
+                         colors[idx % colors.len()],
+                         height).unwrap();
+                idx += 1;
+                let max = distance(timing.start, timing.end);
+                for (i, &(ref event, time)) in timing.events.iter().enumerate() {
+                    let i = i as u64;
+                    let time = distance(timing.start, time);
+                    let at = normalize(time, max, OUTPUT_WIDTH_IN_PX);
+                    writeln!(file, "<span class='event'
+                                          style='left:{}px;\
+                                                 top:{}px;'>{}</span>",
+                             at,
+                             TIME_LINE_HEIGHT_IN_PX * i,
+                             event).unwrap();
+                }
+                writeln!(file, "</div>").unwrap();
+            }
+        }
+
+        writeln!(file, "
+            </body>
+            </html>
+        ").unwrap();
+    }
+}
+
+impl Timeline {
+    pub fn noop() -> Timeline {
+        Timeline { token: None }
+    }
+
+    /// Record an event which happened at this moment on this timeline.
+    ///
+    /// Events are displayed in the eventual HTML output where you can click on
+    /// a particular timeline and it'll expand to all of the events that
+    /// happened on that timeline. This can then be used to drill into a
+    /// particular timeline and see what events are happening and taking the
+    /// most time.
+    pub fn record(&mut self, name: &str) {
+        if let Some(ref mut token) = self.token {
+            token.events.push((name.to_string(), Instant::now()));
+        }
+    }
+}
+
+fn distance(zero: Instant, x: Instant) -> u64 {
+
+    let duration = x.duration_since(zero);
+    (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div
+}
+
+fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 {
+    (max_pixels * distance) / max
+}
+