diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2018-06-15 19:02:41 +0200 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2018-07-07 10:47:22 +0200 |
| commit | 6ceb1637b2500f384015578a5a6f556bcc992052 (patch) | |
| tree | f19b7aa29e17b30195a6018ce817456f3d00c925 /src/librustc_codegen_utils | |
| parent | 4f0ca9248f93162201ea88a99594deedf0ebd897 (diff) | |
| download | rust-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.rs | 16 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/lib.rs | 2 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/llvm_target_features.rs | 117 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/time_graph.rs | 278 |
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 +} + |
