From 8357e573466d583991edd28e52433417b49dc4ae Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Fri, 12 Mar 2021 08:35:13 +0900 Subject: [PATCH 1/2] 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. This patch is based on https://github.com/rust-lang/rust/pull/74002 --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/context.rs | 8 ++++++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 8 ++++++++ src/test/codegen/codemodels.rs | 18 ++++++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/codemodels.rs diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c224da7885bd0..4b7bcf0550131 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -140,7 +140,7 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { } } -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/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 9f6a2ae3ca1b7..21473f3b1143c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/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; @@ -181,6 +182,13 @@ 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 // to ensure intrinsic calls don't use it. if !sess.needs_plt() { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e6d60044c84b4..82cd1be3b3b45 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2326,6 +2326,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/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 2f28162f908ac..c067d7de3c518 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1260,6 +1260,14 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { unwrap(M)->setPIELevel(PIELevel::Level::Large); } +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..6e6dd56ba276e --- /dev/null +++ b/src/test/codegen/codemodels.rs @@ -0,0 +1,18 @@ +// 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: -C code-model=medium +//[MODEL-LARGE] compile-flags: -C code-model=large + +#![crate_type = "lib"] + +// 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 71418384d7d37b37eef250291ea8015667a81f17 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Fri, 12 Mar 2021 19:46:17 +0900 Subject: [PATCH 2/2] Use only x86_64 flag --- src/test/codegen/codemodels.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/codegen/codemodels.rs b/src/test/codegen/codemodels.rs index 6e6dd56ba276e..2328f5feb4e1c 100644 --- a/src/test/codegen/codemodels.rs +++ b/src/test/codegen/codemodels.rs @@ -1,7 +1,9 @@ +// only-x86_64 + // 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-KERNEL] compile-flags: -C code-model=kernel //[MODEL-MEDIUM] compile-flags: -C code-model=medium //[MODEL-LARGE] compile-flags: -C code-model=large