Skip to content

Commit 825eb47

Browse files
committed
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.
1 parent 3503f56 commit 825eb47

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

src/librustc_codegen_llvm/context.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_session::Session;
2222
use rustc_span::source_map::{Span, DUMMY_SP};
2323
use rustc_span::symbol::Symbol;
2424
use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
25-
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
25+
use rustc_target::spec::{CodeModel, HasTargetSpec, RelocModel, Target, TlsModel};
2626

2727
use std::cell::{Cell, RefCell};
2828
use std::ffi::CStr;
@@ -99,6 +99,16 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
9999
}
100100
}
101101

102+
fn to_llvm_code_model(code_model: CodeModel) -> llvm::CodeModel {
103+
match code_model {
104+
CodeModel::Tiny => llvm::CodeModel::Tiny,
105+
CodeModel::Small => llvm::CodeModel::Small,
106+
CodeModel::Kernel => llvm::CodeModel::Kernel,
107+
CodeModel::Medium => llvm::CodeModel::Medium,
108+
CodeModel::Large => llvm::CodeModel::Large,
109+
}
110+
}
111+
102112
fn strip_function_ptr_alignment(data_layout: String) -> String {
103113
// FIXME: Make this more general.
104114
data_layout.replace("-Fi8-", "-")
@@ -181,6 +191,10 @@ pub unsafe fn create_module(
181191
}
182192
}
183193

194+
if let Some(code_model) = sess.code_model() {
195+
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(code_model));
196+
}
197+
184198
// If skipping the PLT is enabled, we need to add some module metadata
185199
// to ensure intrinsic calls don't use it.
186200
if !sess.needs_plt() {

src/librustc_codegen_llvm/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,7 @@ extern "C" {
21292129
pub fn LLVMRustUnsetComdat(V: &Value);
21302130
pub fn LLVMRustSetModulePICLevel(M: &Module);
21312131
pub fn LLVMRustSetModulePIELevel(M: &Module);
2132+
pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel);
21322133
pub fn LLVMRustModuleBufferCreate(M: &Module) -> &'static mut ModuleBuffer;
21332134
pub fn LLVMRustModuleBufferPtr(p: &ModuleBuffer) -> *const u8;
21342135
pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;

src/rustllvm/PassWrapper.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,20 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
11631163
unwrap(M)->setPIELevel(PIELevel::Level::Large);
11641164
}
11651165

1166+
// Linking object files with different code models is undefined behavior
1167+
// because the compiler would have to generate additional code (to span
1168+
// longer jumps) if a larger code model is used with a smaller one.
1169+
// Therefore we will treat attempts to mix code models as an error.
1170+
//
1171+
// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323.
1172+
extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
1173+
LLVMRustCodeModel Model) {
1174+
auto CM = fromRust(Model);
1175+
if (!CM.hasValue())
1176+
return;
1177+
unwrap(M)->setCodeModel(*CM);
1178+
}
1179+
11661180
// Here you'll find an implementation of ThinLTO as used by the Rust compiler
11671181
// right now. This ThinLTO support is only enabled on "recent ish" versions of
11681182
// LLVM, and otherwise it's just blanket rejected from other compilers.

src/test/codegen/codemodels.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// revisions: NOMODEL MODEL-TINY MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE
2+
//[NOMODEL] compile-flags:
3+
//[MODEL-TINY] compile-flags: --target=riscv32i-unknown-none-elf -C code-model=tiny
4+
//[MODEL-SMALL] compile-flags: -C code-model=small
5+
//[MODEL-KERNEL] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=kernel
6+
//[MODEL-MEDIUM] compile-flags: --target=x86_64-unknown-linux-gnu -C code-model=medium
7+
//[MODEL-LARGE] compile-flags: -C code-model=large
8+
9+
#![crate_type = "lib"]
10+
11+
// MODEL-TINY: !llvm.module.flags = !{{{.*}}}
12+
// MODEL-TINY: !(([0-9]+)) = !(i32 1, !"Code-Model", i32 0)
13+
// MODEL-SMALL: !llvm.module.flags = !{{{.*}}}
14+
// MODEL-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1}
15+
// MODEL-KERNEL: !llvm.module.flags = !{{{.*}}}
16+
// MODEL-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2}
17+
// MODEL-MEDIUM: !llvm.module.flags = !{{{.*}}}
18+
// MODEL-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3}
19+
// MODEL-LARGE: !llvm.module.flags = !{{{.*}}}
20+
// MODEL-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4}
21+
// NOMODEL-NOT: Code Model

0 commit comments

Comments
 (0)