From 55a94bdc384673fe2ae7bc2b0275a5777c830b52 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 7 May 2020 03:34:27 +0300 Subject: [PATCH 1/2] rustc_target: Stop using "string typing" for code models Introduce `enum CodeModel` instead. --- src/librustc_codegen_llvm/back/write.rs | 35 +++++------- src/librustc_codegen_llvm/lib.rs | 2 +- src/librustc_codegen_llvm/llvm/ffi.rs | 4 +- src/librustc_interface/tests.rs | 4 +- src/librustc_session/config.rs | 7 +-- src/librustc_session/options.rs | 17 ++++-- src/librustc_session/session.rs | 7 ++- src/librustc_target/spec/mod.rs | 54 ++++++++++++++++++- .../spec/riscv64gc_unknown_linux_gnu.rs | 4 +- .../spec/riscv64gc_unknown_none_elf.rs | 4 +- .../spec/riscv64imac_unknown_none_elf.rs | 4 +- .../spec/x86_64_linux_kernel.rs | 4 +- .../spec/x86_64_unknown_uefi.rs | 4 +- src/rustllvm/PassWrapper.cpp | 12 +++-- 14 files changed, 107 insertions(+), 55 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index dd9ada0b95daa..500311f9054c3 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -24,7 +24,7 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath}; use rustc_session::Session; -use rustc_target::spec::RelocModel; +use rustc_target::spec::{CodeModel, RelocModel}; use libc::{c_char, c_int, c_uint, c_void, size_t}; use std::ffi::CString; @@ -35,13 +35,6 @@ use std::slice; use std::str; use std::sync::Arc; -pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[ - ("small", llvm::CodeModel::Small), - ("kernel", llvm::CodeModel::Kernel), - ("medium", llvm::CodeModel::Medium), - ("large", llvm::CodeModel::Large), -]; - pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), @@ -114,6 +107,17 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { } } +fn to_llvm_code_model(code_model: Option) -> llvm::CodeModel { + match code_model { + Some(CodeModel::Tiny) => llvm::CodeModel::Tiny, + Some(CodeModel::Small) => llvm::CodeModel::Small, + Some(CodeModel::Kernel) => llvm::CodeModel::Kernel, + Some(CodeModel::Medium) => llvm::CodeModel::Medium, + Some(CodeModel::Large) => llvm::CodeModel::Large, + None => llvm::CodeModel::None, + } +} + pub fn target_machine_factory( sess: &Session, optlvl: config::OptLevel, @@ -126,20 +130,7 @@ pub fn target_machine_factory( let ffunction_sections = sess.target.target.options.function_sections; let fdata_sections = ffunction_sections; - let code_model_arg = - sess.opts.cg.code_model.as_ref().or(sess.target.target.options.code_model.as_ref()); - - let code_model = match code_model_arg { - Some(s) => match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid code model", code_model_arg)); - sess.abort_if_errors(); - bug!(); - } - }, - None => llvm::CodeModel::None, - }; + let code_model = to_llvm_code_model(sess.code_model()); let features = attributes::llvm_target_features(sess).collect::>(); let mut singlethread = sess.target.target.options.singlethread; diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 63af60e14db4f..6afd4278451f7 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -208,7 +208,7 @@ impl CodegenBackend for LlvmCodegenBackend { } PrintRequest::CodeModels => { println!("Available code models:"); - for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter() { + for name in &["small", "kernel", "medium", "large"] { println!(" {}", name); } println!(); diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 0d466c2cd745a..01cdd263d7ab1 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -458,9 +458,7 @@ pub enum RelocModel { #[derive(Copy, Clone)] #[repr(C)] pub enum CodeModel { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, + Tiny, Small, Kernel, Medium, diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 68b749e10844b..5e17660f4c60e 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -15,7 +15,7 @@ use rustc_session::{build_session, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; -use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy}; +use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -411,7 +411,7 @@ fn test_codegen_options_tracking_hash() { // Make sure that changing a [TRACKED] option changes the hash. // This list is in alphabetical order. - tracked!(code_model, Some(String::from("code model"))); + tracked!(code_model, Some(CodeModel::Large)); tracked!(debug_assertions, Some(true)); tracked!(debuginfo, 0xdeadbeef); tracked!(embed_bitcode, false); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 402ed054be460..5f34a39db05ce 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1324,10 +1324,6 @@ fn collect_print_requests( prints.push(PrintRequest::TargetFeatures); cg.target_feature = String::new(); } - if cg.code_model.as_ref().map_or(false, |s| s == "help") { - prints.push(PrintRequest::CodeModels); - cg.code_model = None; - } prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s { "crate-name" => PrintRequest::CrateName, @@ -2010,7 +2006,7 @@ crate mod dep_tracking { use crate::utils::NativeLibraryKind; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; - use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel}; + use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel}; use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; @@ -2060,6 +2056,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index be1c358d58e0f..0421d209c34e5 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -5,9 +5,8 @@ use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLibraryKind; -use rustc_target::spec::TargetTriple; -use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy}; -use rustc_target::spec::{RelocModel, RelroLevel, TlsModel}; +use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; +use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel}; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; @@ -269,6 +268,8 @@ macro_rules! options { pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; + pub const parse_code_model: &str = + "one of supported code models (`rustc --print code-models`)"; pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)"; } @@ -620,6 +621,14 @@ macro_rules! options { true } + fn parse_code_model(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(|s| CodeModel::from_str(s).ok()) { + Some(code_model) => *slot = Some(code_model), + _ => return false, + } + true + } + fn parse_tls_model(slot: &mut Option, v: Option<&str>) -> bool { match v.and_then(|s| TlsModel::from_str(s).ok()) { Some(tls_model) => *slot = Some(tls_model), @@ -662,7 +671,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing"), - code_model: Option = (None, parse_opt_string, [TRACKED], + code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option = (None, parse_opt_uint, [UNTRACKED], "divide crate into N units to optimize in parallel"), diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index b39b15dc24428..c55456bf5232c 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -23,7 +23,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported use rustc_span::edition::Edition; use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::{SourceFileHashAlgorithm, Symbol}; -use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple, TlsModel}; +use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::{Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; @@ -625,6 +626,10 @@ impl Session { self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model) } + pub fn code_model(&self) -> Option { + self.opts.cg.code_model.or(self.target.target.options.code_model) + } + pub fn tls_model(&self) -> TlsModel { self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model) } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index c7b2023ddca04..49b33059b6345 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -305,6 +305,43 @@ impl ToJson for RelocModel { } } +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum CodeModel { + Tiny, + Small, + Kernel, + Medium, + Large, +} + +impl FromStr for CodeModel { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + // "tiny" => CodeModel::Tiny, // Not exposed to users right now. + "small" => CodeModel::Small, + "kernel" => CodeModel::Kernel, + "medium" => CodeModel::Medium, + "large" => CodeModel::Large, + _ => return Err(()), + }) + } +} + +impl ToJson for CodeModel { + fn to_json(&self) -> Json { + match *self { + CodeModel::Tiny => "tiny", + CodeModel::Small => "small", + CodeModel::Kernel => "kernel", + CodeModel::Medium => "medium", + CodeModel::Large => "large", + } + .to_json() + } +} + #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TlsModel { GeneralDynamic, @@ -699,7 +736,8 @@ pub struct TargetOptions { /// -relocation-model=$relocation_model`. Defaults to `Pic`. pub relocation_model: RelocModel, /// Code model to use. Corresponds to `llc -code-model=$code_model`. - pub code_model: Option, + /// Defaults to `None` which means "inherited from the base LLVM target". + pub code_model: Option, /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. pub tls_model: TlsModel, @@ -1114,6 +1152,18 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, CodeModel) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { + match s.parse::() { + Ok(code_model) => base.options.$key_name = Some(code_model), + _ => return Some(Err(format!("'{}' is not a valid code model. \ + Run `rustc --print code-models` to \ + see the list of supported values.", s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, TlsModel) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { @@ -1266,7 +1316,7 @@ impl Target { key!(only_cdylib, bool); key!(executables, bool); key!(relocation_model, RelocModel)?; - key!(code_model, optional); + key!(code_model, CodeModel)?; key!(tls_model, TlsModel)?; key!(disable_redzone, bool); key!(eliminate_frame_pointer, bool); diff --git a/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs b/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs index 638e6770ebf8c..715449d74ce22 100644 --- a/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { @@ -14,7 +14,7 @@ pub fn target() -> TargetResult { linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::riscv_base::abi_blacklist(), - code_model: Some("medium".to_string()), + code_model: Some(CodeModel::Medium), cpu: "generic-rv64".to_string(), features: "+m,+a,+f,+d,+c".to_string(), llvm_abiname: "lp64d".to_string(), diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs index 9dbbcb1f4bd6e..7376a14e951f5 100644 --- a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel}; +use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel}; use crate::spec::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -23,7 +23,7 @@ pub fn target() -> TargetResult { executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, - code_model: Some("medium".to_string()), + code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), eliminate_frame_pointer: false, diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs index 7e9390561a700..a3b0eb5334f40 100644 --- a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs @@ -1,5 +1,5 @@ +use crate::spec::{CodeModel, Target, TargetOptions, TargetResult}; use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel}; -use crate::spec::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { @@ -23,7 +23,7 @@ pub fn target() -> TargetResult { executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, - code_model: Some("medium".to_string()), + code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), eliminate_frame_pointer: false, diff --git a/src/librustc_target/spec/x86_64_linux_kernel.rs b/src/librustc_target/spec/x86_64_linux_kernel.rs index 89070c99e3941..65bb97d84aae9 100644 --- a/src/librustc_target/spec/x86_64_linux_kernel.rs +++ b/src/librustc_target/spec/x86_64_linux_kernel.rs @@ -1,7 +1,7 @@ // This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for // generic Linux kernel options. -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_kernel_base::opts(); @@ -10,7 +10,7 @@ pub fn target() -> TargetResult { base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .to_string(); - base.code_model = Some("kernel".to_string()); + base.code_model = Some(CodeModel::Kernel); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/src/librustc_target/spec/x86_64_unknown_uefi.rs index 12edc29330a49..849227a574aeb 100644 --- a/src/librustc_target/spec/x86_64_unknown_uefi.rs +++ b/src/librustc_target/spec/x86_64_unknown_uefi.rs @@ -5,7 +5,7 @@ // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features. -use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult}; +use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::uefi_msvc_base::opts(); @@ -26,7 +26,7 @@ pub fn target() -> TargetResult { // UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell // LLVM to expect code to reference any address in the address-space. The "large" code-model // places no locality-restrictions, so it fits well here. - base.code_model = Some("large".to_string()); + base.code_model = Some(CodeModel::Large); Ok(Target { llvm_target: "x86_64-unknown-windows".to_string(), diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 84bde9a52f7ce..e7cd81ea68ef0 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -274,7 +274,7 @@ extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, } enum class LLVMRustCodeModel { - Other, + Tiny, Small, Kernel, Medium, @@ -282,8 +282,10 @@ enum class LLVMRustCodeModel { None, }; -static CodeModel::Model fromRust(LLVMRustCodeModel Model) { +static Optional fromRust(LLVMRustCodeModel Model) { switch (Model) { + case LLVMRustCodeModel::Tiny: + return CodeModel::Tiny; case LLVMRustCodeModel::Small: return CodeModel::Small; case LLVMRustCodeModel::Kernel: @@ -292,6 +294,8 @@ static CodeModel::Model fromRust(LLVMRustCodeModel Model) { return CodeModel::Medium; case LLVMRustCodeModel::Large: return CodeModel::Large; + case LLVMRustCodeModel::None: + return None; default: report_fatal_error("Bad CodeModel."); } @@ -452,6 +456,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); + auto CM = fromRust(RustCM); std::string Error; Triple Trip(Triple::normalize(TripleStr)); @@ -490,9 +495,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; - Optional CM; - if (RustCM != LLVMRustCodeModel::None) - CM = fromRust(RustCM); TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); return wrap(TM); From 59187f97713b8c9d54a4697dfe736037ddc22f8a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 16 May 2020 12:02:16 +0300 Subject: [PATCH 2/2] rustc-book: Document `-C code-model` --- src/doc/rustc/src/codegen-options/index.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index dbe281be7df74..66dcb8163f6af 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -9,9 +9,25 @@ This option is deprecated and does nothing. ## code-model -This option lets you choose which code model to use. +This option lets you choose which code model to use. \ +Code models put constraints on address ranges that the program and its symbols may use. \ +With smaller address ranges machine instructions +may be able to use use more compact addressing modes. -To find the valid options for this flag, run `rustc --print code-models`. +The specific ranges depend on target architectures and addressing modes available to them. \ +For x86 more detailed description of its code models can be found in +[System V Application Binary Interface](https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf) +specification. + +Supported values for this option are: + + +- `small` - Small code model. This is the default model for majority of supported targets. +- `kernel` - Kernel code model. +- `medium` - Medium code model. +- `large` - Large code model. + +Supported values can also be discovered by running `rustc --print code-models`. ## codegen-units