From 825eb478c5fee6edefc8e032298ac5317e2f09ca Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sat, 4 Jul 2020 00:23:54 +0900 Subject: [PATCH 1/5] Add support for storing code model to LLVM module IR This patch avoids undefined behavior by linking different object files. Also this would it could be propagated properly to LTO. See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. --- src/librustc_codegen_llvm/context.rs | 16 +++++++++++++++- src/librustc_codegen_llvm/llvm/ffi.rs | 1 + src/rustllvm/PassWrapper.cpp | 14 ++++++++++++++ src/test/codegen/codemodels.rs | 21 +++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/codemodels.rs diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index e9a001bab7540..42120c5ee6906 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -22,7 +22,7 @@ use rustc_session::Session; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::Symbol; use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; +use rustc_target::spec::{CodeModel, HasTargetSpec, RelocModel, Target, TlsModel}; use std::cell::{Cell, RefCell}; use std::ffi::CStr; @@ -99,6 +99,16 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { } } +fn to_llvm_code_model(code_model: CodeModel) -> llvm::CodeModel { + match code_model { + CodeModel::Tiny => llvm::CodeModel::Tiny, + CodeModel::Small => llvm::CodeModel::Small, + CodeModel::Kernel => llvm::CodeModel::Kernel, + CodeModel::Medium => llvm::CodeModel::Medium, + CodeModel::Large => llvm::CodeModel::Large, + } +} + fn strip_function_ptr_alignment(data_layout: String) -> String { // FIXME: Make this more general. data_layout.replace("-Fi8-", "-") @@ -181,6 +191,10 @@ pub unsafe fn create_module( } } + if let Some(code_model) = sess.code_model() { + llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(code_model)); + } + // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 7beb4fc897472..c7ebd3f0684fa 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -2129,6 +2129,7 @@ extern "C" { pub fn LLVMRustUnsetComdat(V: &Value); pub fn LLVMRustSetModulePICLevel(M: &Module); pub fn LLVMRustSetModulePIELevel(M: &Module); + pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel); pub fn LLVMRustModuleBufferCreate(M: &Module) -> &'static mut ModuleBuffer; pub fn LLVMRustModuleBufferPtr(p: &ModuleBuffer) -> *const u8; pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 41b14714842fd..c719f02b771f8 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -1163,6 +1163,20 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { unwrap(M)->setPIELevel(PIELevel::Level::Large); } +// Linking object files with different code models is undefined behavior +// because the compiler would have to generate additional code (to span +// longer jumps) if a larger code model is used with a smaller one. +// Therefore we will treat attempts to mix code models as an error. +// +// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. +extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M, + LLVMRustCodeModel Model) { + auto CM = fromRust(Model); + if (!CM.hasValue()) + return; + unwrap(M)->setCodeModel(*CM); +} + // Here you'll find an implementation of ThinLTO as used by the Rust compiler // right now. This ThinLTO support is only enabled on "recent ish" versions of // LLVM, and otherwise it's just blanket rejected from other compilers. diff --git a/src/test/codegen/codemodels.rs b/src/test/codegen/codemodels.rs new file mode 100644 index 0000000000000..7edbf0ea6f6aa --- /dev/null +++ b/src/test/codegen/codemodels.rs @@ -0,0 +1,21 @@ +// revisions: NOMODEL MODEL-TINY MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE +//[NOMODEL] compile-flags: +//[MODEL-TINY] compile-flags: --target=riscv32i-unknown-none-elf -C code-model=tiny +//[MODEL-SMALL] compile-flags: -C code-model=small +//[MODEL-KERNEL] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=kernel +//[MODEL-MEDIUM] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=medium +//[MODEL-LARGE] compile-flags: -C code-model=large + +#![crate_type = "lib"] + +// MODEL-TINY: !llvm.module.flags = !{{{.*}}} +// MODEL-TINY: !(([0-9]+)) = !(i32 1, !"Code-Model", i32 0) +// MODEL-SMALL: !llvm.module.flags = !{{{.*}}} +// MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1} +// MODEL-KERNEL: !llvm.module.flags = !{{{.*}}} +// MODEL-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2} +// MODEL-MEDIUM: !llvm.module.flags = !{{{.*}}} +// MODEL-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3} +// MODEL-LARGE: !llvm.module.flags = !{{{.*}}} +// MODEL-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4} +// NOMODEL-NOT: Code Model From b99a08a3a561c06c0a9ff1a432602d174d0e1c7f Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sat, 4 Jul 2020 02:10:18 +0900 Subject: [PATCH 2/5] Remove code-model=tiny from module IR test --- src/test/codegen/codemodels.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/codegen/codemodels.rs b/src/test/codegen/codemodels.rs index 7edbf0ea6f6aa..e3c258f864c61 100644 --- a/src/test/codegen/codemodels.rs +++ b/src/test/codegen/codemodels.rs @@ -1,6 +1,5 @@ -// revisions: NOMODEL MODEL-TINY MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE +// revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE //[NOMODEL] compile-flags: -//[MODEL-TINY] compile-flags: --target=riscv32i-unknown-none-elf -C code-model=tiny //[MODEL-SMALL] compile-flags: -C code-model=small //[MODEL-KERNEL] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=kernel //[MODEL-MEDIUM] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=medium @@ -8,8 +7,6 @@ #![crate_type = "lib"] -// MODEL-TINY: !llvm.module.flags = !{{{.*}}} -// MODEL-TINY: !(([0-9]+)) = !(i32 1, !"Code-Model", i32 0) // MODEL-SMALL: !llvm.module.flags = !{{{.*}}} // MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1} // MODEL-KERNEL: !llvm.module.flags = !{{{.*}}} From 4a89c9fdedd8dc5ce59f55b4aa7b370183a01f74 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sat, 4 Jul 2020 04:57:59 +0900 Subject: [PATCH 3/5] Remove duplicated to_llvm_code_model function --- src/librustc_codegen_llvm/back/write.rs | 2 +- src/librustc_codegen_llvm/context.rs | 17 +++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 54271d3dd0491..180f3f2e2cf5c 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -108,7 +108,7 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { } } -fn to_llvm_code_model(code_model: Option) -> llvm::CodeModel { +pub 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, diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 42120c5ee6906..7c48c50ab2e45 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,4 +1,5 @@ use crate::attributes; +use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::coverageinfo; use crate::debuginfo; @@ -22,7 +23,7 @@ use rustc_session::Session; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::Symbol; use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{CodeModel, HasTargetSpec, RelocModel, Target, TlsModel}; +use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use std::cell::{Cell, RefCell}; use std::ffi::CStr; @@ -99,16 +100,6 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { } } -fn to_llvm_code_model(code_model: CodeModel) -> llvm::CodeModel { - match code_model { - CodeModel::Tiny => llvm::CodeModel::Tiny, - CodeModel::Small => llvm::CodeModel::Small, - CodeModel::Kernel => llvm::CodeModel::Kernel, - CodeModel::Medium => llvm::CodeModel::Medium, - CodeModel::Large => llvm::CodeModel::Large, - } -} - fn strip_function_ptr_alignment(data_layout: String) -> String { // FIXME: Make this more general. data_layout.replace("-Fi8-", "-") @@ -191,9 +182,7 @@ pub unsafe fn create_module( } } - if let Some(code_model) = sess.code_model() { - llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(code_model)); - } + llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. From 67a5e2b1a006c624d1fe41c627b3e0c612e8daf3 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sat, 4 Jul 2020 23:02:07 +0900 Subject: [PATCH 4/5] Fix for reviews --- src/librustc_codegen_llvm/back/write.rs | 2 +- src/librustc_codegen_llvm/context.rs | 5 +++++ src/rustllvm/PassWrapper.cpp | 6 ------ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 180f3f2e2cf5c..af87651833d88 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -108,7 +108,7 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { } } -pub fn to_llvm_code_model(code_model: Option) -> llvm::CodeModel { +pub(crate) 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, diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 7c48c50ab2e45..d7ab1e2327519 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -182,6 +182,11 @@ pub unsafe fn create_module( } } + // Linking object files with different code models is undefined behavior + // because the compiler would have to generate additional code (to span + // longer jumps) if a larger code model is used with a smaller one. + // + // See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); // If skipping the PLT is enabled, we need to add some module metadata diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index c719f02b771f8..3ad3c5353b7b0 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -1163,12 +1163,6 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { unwrap(M)->setPIELevel(PIELevel::Level::Large); } -// Linking object files with different code models is undefined behavior -// because the compiler would have to generate additional code (to span -// longer jumps) if a larger code model is used with a smaller one. -// Therefore we will treat attempts to mix code models as an error. -// -// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M, LLVMRustCodeModel Model) { auto CM = fromRust(Model); From 5c24a94f0ce455b4758e8f0d4ec2472235bb75a3 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 6 Jul 2020 05:54:11 +0900 Subject: [PATCH 5/5] Remove target flag from code model test --- src/test/codegen/codemodels.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/codemodels.rs b/src/test/codegen/codemodels.rs index e3c258f864c61..d6cb73b8b8a16 100644 --- a/src/test/codegen/codemodels.rs +++ b/src/test/codegen/codemodels.rs @@ -1,8 +1,8 @@ // revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE //[NOMODEL] compile-flags: //[MODEL-SMALL] compile-flags: -C code-model=small -//[MODEL-KERNEL] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=kernel -//[MODEL-MEDIUM] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=medium +//[MODEL-KERNEL] compile-flags: -C code-model=kernel +//[MODEL-MEDIUM] compile-flags: -C code-model=medium //[MODEL-LARGE] compile-flags: -C code-model=large #![crate_type = "lib"]