Skip to content

Commit f19c48e

Browse files
committed
Set target-abi module flag for RISC-V targets
Fixes cross-language LTO on RISC-V targets (Fixes rust-lang#121924)
1 parent f65f84f commit f19c48e

File tree

10 files changed

+115
-21
lines changed

10 files changed

+115
-21
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ pub(crate) fn run_pass_manager(
608608
"LTOPostLink".as_ptr().cast(),
609609
11,
610610
) {
611-
llvm::LLVMRustAddModuleFlag(
611+
llvm::LLVMRustAddModuleFlagU32(
612612
module.module_llvm.llmod(),
613613
llvm::LLVMModFlagBehavior::Error,
614614
c"LTOPostLink".as_ptr().cast(),

compiler/rustc_codegen_llvm/src/context.rs

+33-15
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use libc::c_uint;
3535
use std::borrow::Borrow;
3636
use std::cell::{Cell, RefCell};
3737
use std::ffi::CStr;
38+
use std::ffi::CString;
3839
use std::str;
3940

4041
/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
@@ -180,13 +181,13 @@ pub unsafe fn create_module<'ll>(
180181
// to ensure intrinsic calls don't use it.
181182
if !sess.needs_plt() {
182183
let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
183-
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
184+
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
184185
}
185186

186187
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
187188
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
188189
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
189-
llvm::LLVMRustAddModuleFlag(
190+
llvm::LLVMRustAddModuleFlagU32(
190191
llmod,
191192
llvm::LLVMModFlagBehavior::Override,
192193
canonical_jump_tables,
@@ -197,7 +198,7 @@ pub unsafe fn create_module<'ll>(
197198
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
198199
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
199200
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
200-
llvm::LLVMRustAddModuleFlag(
201+
llvm::LLVMRustAddModuleFlagU32(
201202
llmod,
202203
llvm::LLVMModFlagBehavior::Override,
203204
enable_split_lto_unit,
@@ -208,7 +209,7 @@ pub unsafe fn create_module<'ll>(
208209
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
209210
if sess.is_sanitizer_kcfi_enabled() {
210211
let kcfi = c"kcfi".as_ptr().cast();
211-
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
212+
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
212213
}
213214

214215
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
@@ -217,7 +218,7 @@ pub unsafe fn create_module<'ll>(
217218
CFGuard::Disabled => {}
218219
CFGuard::NoChecks => {
219220
// Set `cfguard=1` module flag to emit metadata only.
220-
llvm::LLVMRustAddModuleFlag(
221+
llvm::LLVMRustAddModuleFlagU32(
221222
llmod,
222223
llvm::LLVMModFlagBehavior::Warning,
223224
c"cfguard".as_ptr() as *const _,
@@ -226,7 +227,7 @@ pub unsafe fn create_module<'ll>(
226227
}
227228
CFGuard::Checks => {
228229
// Set `cfguard=2` module flag to emit metadata and checks.
229-
llvm::LLVMRustAddModuleFlag(
230+
llvm::LLVMRustAddModuleFlagU32(
230231
llmod,
231232
llvm::LLVMModFlagBehavior::Warning,
232233
c"cfguard".as_ptr() as *const _,
@@ -238,26 +239,26 @@ pub unsafe fn create_module<'ll>(
238239

239240
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
240241
if sess.target.arch == "aarch64" {
241-
llvm::LLVMRustAddModuleFlag(
242+
llvm::LLVMRustAddModuleFlagU32(
242243
llmod,
243244
llvm::LLVMModFlagBehavior::Min,
244245
c"branch-target-enforcement".as_ptr().cast(),
245246
bti.into(),
246247
);
247-
llvm::LLVMRustAddModuleFlag(
248+
llvm::LLVMRustAddModuleFlagU32(
248249
llmod,
249250
llvm::LLVMModFlagBehavior::Min,
250251
c"sign-return-address".as_ptr().cast(),
251252
pac_ret.is_some().into(),
252253
);
253254
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
254-
llvm::LLVMRustAddModuleFlag(
255+
llvm::LLVMRustAddModuleFlagU32(
255256
llmod,
256257
llvm::LLVMModFlagBehavior::Min,
257258
c"sign-return-address-all".as_ptr().cast(),
258259
pac_opts.leaf.into(),
259260
);
260-
llvm::LLVMRustAddModuleFlag(
261+
llvm::LLVMRustAddModuleFlagU32(
261262
llmod,
262263
llvm::LLVMModFlagBehavior::Min,
263264
c"sign-return-address-with-bkey".as_ptr().cast(),
@@ -273,15 +274,15 @@ pub unsafe fn create_module<'ll>(
273274

274275
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
275276
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
276-
llvm::LLVMRustAddModuleFlag(
277+
llvm::LLVMRustAddModuleFlagU32(
277278
llmod,
278279
llvm::LLVMModFlagBehavior::Override,
279280
c"cf-protection-branch".as_ptr().cast(),
280281
1,
281282
)
282283
}
283284
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
284-
llvm::LLVMRustAddModuleFlag(
285+
llvm::LLVMRustAddModuleFlagU32(
285286
llmod,
286287
llvm::LLVMModFlagBehavior::Override,
287288
c"cf-protection-return".as_ptr().cast(),
@@ -290,7 +291,7 @@ pub unsafe fn create_module<'ll>(
290291
}
291292

292293
if sess.opts.unstable_opts.virtual_function_elimination {
293-
llvm::LLVMRustAddModuleFlag(
294+
llvm::LLVMRustAddModuleFlagU32(
294295
llmod,
295296
llvm::LLVMModFlagBehavior::Error,
296297
c"Virtual Function Elim".as_ptr().cast(),
@@ -300,7 +301,7 @@ pub unsafe fn create_module<'ll>(
300301

301302
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
302303
if sess.opts.unstable_opts.ehcont_guard {
303-
llvm::LLVMRustAddModuleFlag(
304+
llvm::LLVMRustAddModuleFlagU32(
304305
llmod,
305306
llvm::LLVMModFlagBehavior::Warning,
306307
c"ehcontguard".as_ptr() as *const _,
@@ -326,6 +327,23 @@ pub unsafe fn create_module<'ll>(
326327
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
327328
);
328329

330+
// Emit RISC-V specific target-abi metadata
331+
// to workaround lld as the LTO plugin not
332+
// correctly setting target-abi for the LTO object
333+
// FIXME: https://github.com/llvm/llvm-project/issues/50591
334+
// If llvm_abiname is empty, emit nothing.
335+
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64")
336+
&& !sess.target.options.llvm_abiname.is_empty()
337+
{
338+
let llvm_abiname = CString::new(sess.target.options.llvm_abiname.as_ref()).unwrap();
339+
llvm::LLVMRustAddModuleFlagString(
340+
llmod,
341+
llvm::LLVMModFlagBehavior::Error,
342+
c"target-abi".as_ptr() as *const _,
343+
llvm_abiname.as_ptr() as *const _,
344+
);
345+
}
346+
329347
// Add module flags specified via -Z llvm_module_flag
330348
for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
331349
let key = format!("{key}\0");
@@ -341,7 +359,7 @@ pub unsafe fn create_module<'ll>(
341359
// We already checked this during option parsing
342360
_ => unreachable!(),
343361
};
344-
llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value)
362+
llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value)
345363
}
346364

347365
llmod

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,15 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
110110
.unstable_opts
111111
.dwarf_version
112112
.unwrap_or(sess.target.default_dwarf_version);
113-
llvm::LLVMRustAddModuleFlag(
113+
llvm::LLVMRustAddModuleFlagU32(
114114
self.llmod,
115115
llvm::LLVMModFlagBehavior::Warning,
116116
c"Dwarf Version".as_ptr().cast(),
117117
dwarf_version,
118118
);
119119
} else {
120120
// Indicate that we want CodeView debug information on MSVC
121-
llvm::LLVMRustAddModuleFlag(
121+
llvm::LLVMRustAddModuleFlagU32(
122122
self.llmod,
123123
llvm::LLVMModFlagBehavior::Warning,
124124
c"CodeView".as_ptr().cast(),
@@ -127,7 +127,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
127127
}
128128

129129
// Prevent bitcode readers from deleting the debug info.
130-
llvm::LLVMRustAddModuleFlag(
130+
llvm::LLVMRustAddModuleFlagU32(
131131
self.llmod,
132132
llvm::LLVMModFlagBehavior::Warning,
133133
c"Debug Info Version".as_ptr().cast(),

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1801,12 +1801,20 @@ extern "C" {
18011801
///
18021802
/// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
18031803
/// "compatible" means depends on the merge behaviors involved.
1804-
pub fn LLVMRustAddModuleFlag(
1804+
pub fn LLVMRustAddModuleFlagU32(
18051805
M: &Module,
18061806
merge_behavior: LLVMModFlagBehavior,
18071807
name: *const c_char,
18081808
value: u32,
18091809
);
1810+
1811+
pub fn LLVMRustAddModuleFlagString(
1812+
M: &Module,
1813+
merge_behavior: LLVMModFlagBehavior,
1814+
name: *const c_char,
1815+
value: *const c_char,
1816+
);
1817+
18101818
pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
18111819

18121820
pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -817,14 +817,23 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
817817

818818
extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
819819

820-
extern "C" void LLVMRustAddModuleFlag(
820+
extern "C" void LLVMRustAddModuleFlagU32(
821821
LLVMModuleRef M,
822822
Module::ModFlagBehavior MergeBehavior,
823823
const char *Name,
824824
uint32_t Value) {
825825
unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
826826
}
827827

828+
extern "C" void LLVMRustAddModuleFlagString(
829+
LLVMModuleRef M,
830+
Module::ModFlagBehavior MergeBehavior,
831+
const char *Name,
832+
const char *Value) {
833+
llvm::LLVMContext &Ctx = unwrap(M)->getContext();
834+
unwrap(M)->addModuleFlag(MergeBehavior, Name, llvm::MDString::get(Ctx, Value));
835+
}
836+
828837
extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name,
829838
size_t Len) {
830839
return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr;

src/tools/tidy/src/allowed_run_make_makefiles.txt

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ run-make/crate-hash-rustc-version/Makefile
3636
run-make/crate-name-priority/Makefile
3737
run-make/cross-lang-lto-clang/Makefile
3838
run-make/cross-lang-lto-pgo-smoketest/Makefile
39+
run-make/cross-lang-lto-riscv-abi/Makefile
3940
run-make/cross-lang-lto-upstream-rlibs/Makefile
4041
run-make/cross-lang-lto/Makefile
4142
run-make/debug-assertions/Makefile

tests/codegen/riscv-target-abi.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ revisions:riscv64gc riscv32gc riscv32imac
2+
3+
//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu
4+
//@[riscv64gc] needs-llvm-components: riscv
5+
// riscv64gc: !{i32 1, !"target-abi", !"lp64d"}
6+
7+
//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl
8+
//@[riscv32gc] needs-llvm-components: riscv
9+
// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"}
10+
11+
//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
12+
//@[riscv32imac] needs-llvm-components: riscv
13+
// riscv32imac-NOT: !"target-abi"
14+
15+
#![feature(no_core, lang_items)]
16+
#![crate_type = "lib"]
17+
#![no_core]
18+
19+
#[lang = "sized"]
20+
trait Sized {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# needs-matching-clang
2+
3+
# This test makes sure that cross-language LTO works on riscv targets
4+
5+
include ../tools.mk
6+
7+
all: riscv64gc-unknown-linux-gnu riscv32imac-unknown-none-elf riscv32gc-unknown-linux-gnu
8+
9+
define check-target =
10+
@echo "Testing target $(1)"
11+
$(RUSTC) --target $(1) -Clinker-plugin-lto=on -Cpanic=abort --crate-type=rlib -o $(TMPDIR)/libriscv-xlto.a ./riscv-xlto.rs
12+
$(CLANG) -target $(2) -march=$(3) -mabi=$(4) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lriscv-xlto -nostdlib -o $(TMPDIR)/riscv-xlto ./cstart.c
13+
file $(TMPDIR)/riscv-xlto | $(CGREP) "$(5)"
14+
endef
15+
16+
17+
riscv64gc-unknown-linux-gnu:
18+
@$(call check-target,$@,riscv64-linux-gnu,rv64gc,lp64d,double-float ABI)
19+
20+
riscv32imac-unknown-none-elf:
21+
@$(call check-target,$@,riscv32-unknown-elf,rv32imac,ilp32,soft-float ABI)
22+
23+
riscv32gc-unknown-linux-gnu:
24+
@$(call check-target,$@,riscv32-linux-gnu,rv32gc,ilp32d,double-float ABI)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern void hello();
2+
3+
void _start() {
4+
hello();
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![allow(internal_features)]
2+
#![feature(no_core, lang_items)]
3+
#![no_core]
4+
5+
#[lang = "sized"]
6+
trait Sized {}
7+
8+
#[no_mangle]
9+
pub fn hello() {}

0 commit comments

Comments
 (0)