mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Set target-abi module flag for RISC-V targets
Fixes cross-language LTO on RISC-V targets (Fixes #121924)
This commit is contained in:
parent
f65f84feb0
commit
f19c48e7a8
@ -608,7 +608,7 @@ pub(crate) fn run_pass_manager(
|
||||
"LTOPostLink".as_ptr().cast(),
|
||||
11,
|
||||
) {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
module.module_llvm.llmod(),
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"LTOPostLink".as_ptr().cast(),
|
||||
|
@ -35,6 +35,7 @@ use libc::c_uint;
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::str;
|
||||
|
||||
/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
|
||||
@ -180,13 +181,13 @@ pub unsafe fn create_module<'ll>(
|
||||
// to ensure intrinsic calls don't use it.
|
||||
if !sess.needs_plt() {
|
||||
let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
}
|
||||
|
||||
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
|
||||
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
@ -197,7 +198,7 @@ pub unsafe fn create_module<'ll>(
|
||||
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
|
||||
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
|
||||
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
@ -208,7 +209,7 @@ pub unsafe fn create_module<'ll>(
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi = c"kcfi".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
}
|
||||
|
||||
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
|
||||
@ -217,7 +218,7 @@ pub unsafe fn create_module<'ll>(
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
// Set `cfguard=1` module flag to emit metadata only.
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
@ -226,7 +227,7 @@ pub unsafe fn create_module<'ll>(
|
||||
}
|
||||
CFGuard::Checks => {
|
||||
// Set `cfguard=2` module flag to emit metadata and checks.
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
@ -238,26 +239,26 @@ pub unsafe fn create_module<'ll>(
|
||||
|
||||
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
||||
if sess.target.arch == "aarch64" {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"branch-target-enforcement".as_ptr().cast(),
|
||||
bti.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address".as_ptr().cast(),
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-all".as_ptr().cast(),
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-with-bkey".as_ptr().cast(),
|
||||
@ -273,7 +274,7 @@ pub unsafe fn create_module<'ll>(
|
||||
|
||||
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
|
||||
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-branch".as_ptr().cast(),
|
||||
@ -281,7 +282,7 @@ pub unsafe fn create_module<'ll>(
|
||||
)
|
||||
}
|
||||
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-return".as_ptr().cast(),
|
||||
@ -290,7 +291,7 @@ pub unsafe fn create_module<'ll>(
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"Virtual Function Elim".as_ptr().cast(),
|
||||
@ -300,7 +301,7 @@ pub unsafe fn create_module<'ll>(
|
||||
|
||||
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
|
||||
if sess.opts.unstable_opts.ehcont_guard {
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"ehcontguard".as_ptr() as *const _,
|
||||
@ -326,6 +327,23 @@ pub unsafe fn create_module<'ll>(
|
||||
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
|
||||
);
|
||||
|
||||
// Emit RISC-V specific target-abi metadata
|
||||
// to workaround lld as the LTO plugin not
|
||||
// correctly setting target-abi for the LTO object
|
||||
// FIXME: https://github.com/llvm/llvm-project/issues/50591
|
||||
// If llvm_abiname is empty, emit nothing.
|
||||
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64")
|
||||
&& !sess.target.options.llvm_abiname.is_empty()
|
||||
{
|
||||
let llvm_abiname = CString::new(sess.target.options.llvm_abiname.as_ref()).unwrap();
|
||||
llvm::LLVMRustAddModuleFlagString(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"target-abi".as_ptr() as *const _,
|
||||
llvm_abiname.as_ptr() as *const _,
|
||||
);
|
||||
}
|
||||
|
||||
// Add module flags specified via -Z llvm_module_flag
|
||||
for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
|
||||
let key = format!("{key}\0");
|
||||
@ -341,7 +359,7 @@ pub unsafe fn create_module<'ll>(
|
||||
// We already checked this during option parsing
|
||||
_ => unreachable!(),
|
||||
};
|
||||
llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value)
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value)
|
||||
}
|
||||
|
||||
llmod
|
||||
|
@ -110,7 +110,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
||||
.unstable_opts
|
||||
.dwarf_version
|
||||
.unwrap_or(sess.target.default_dwarf_version);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"Dwarf Version".as_ptr().cast(),
|
||||
@ -118,7 +118,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
||||
);
|
||||
} else {
|
||||
// Indicate that we want CodeView debug information on MSVC
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"CodeView".as_ptr().cast(),
|
||||
@ -127,7 +127,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
||||
}
|
||||
|
||||
// Prevent bitcode readers from deleting the debug info.
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"Debug Info Version".as_ptr().cast(),
|
||||
|
@ -1801,12 +1801,20 @@ extern "C" {
|
||||
///
|
||||
/// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
|
||||
/// "compatible" means depends on the merge behaviors involved.
|
||||
pub fn LLVMRustAddModuleFlag(
|
||||
pub fn LLVMRustAddModuleFlagU32(
|
||||
M: &Module,
|
||||
merge_behavior: LLVMModFlagBehavior,
|
||||
name: *const c_char,
|
||||
value: u32,
|
||||
);
|
||||
|
||||
pub fn LLVMRustAddModuleFlagString(
|
||||
M: &Module,
|
||||
merge_behavior: LLVMModFlagBehavior,
|
||||
name: *const c_char,
|
||||
value: *const c_char,
|
||||
);
|
||||
|
||||
pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
|
||||
|
||||
pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
|
||||
|
@ -817,7 +817,7 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
|
||||
|
||||
extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
|
||||
|
||||
extern "C" void LLVMRustAddModuleFlag(
|
||||
extern "C" void LLVMRustAddModuleFlagU32(
|
||||
LLVMModuleRef M,
|
||||
Module::ModFlagBehavior MergeBehavior,
|
||||
const char *Name,
|
||||
@ -825,6 +825,15 @@ extern "C" void LLVMRustAddModuleFlag(
|
||||
unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustAddModuleFlagString(
|
||||
LLVMModuleRef M,
|
||||
Module::ModFlagBehavior MergeBehavior,
|
||||
const char *Name,
|
||||
const char *Value) {
|
||||
llvm::LLVMContext &Ctx = unwrap(M)->getContext();
|
||||
unwrap(M)->addModuleFlag(MergeBehavior, Name, llvm::MDString::get(Ctx, Value));
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name,
|
||||
size_t Len) {
|
||||
return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr;
|
||||
|
@ -36,6 +36,7 @@ run-make/crate-hash-rustc-version/Makefile
|
||||
run-make/crate-name-priority/Makefile
|
||||
run-make/cross-lang-lto-clang/Makefile
|
||||
run-make/cross-lang-lto-pgo-smoketest/Makefile
|
||||
run-make/cross-lang-lto-riscv-abi/Makefile
|
||||
run-make/cross-lang-lto-upstream-rlibs/Makefile
|
||||
run-make/cross-lang-lto/Makefile
|
||||
run-make/debug-assertions/Makefile
|
||||
|
20
tests/codegen/riscv-target-abi.rs
Normal file
20
tests/codegen/riscv-target-abi.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//@ revisions:riscv64gc riscv32gc riscv32imac
|
||||
|
||||
//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu
|
||||
//@[riscv64gc] needs-llvm-components: riscv
|
||||
// riscv64gc: !{i32 1, !"target-abi", !"lp64d"}
|
||||
|
||||
//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl
|
||||
//@[riscv32gc] needs-llvm-components: riscv
|
||||
// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"}
|
||||
|
||||
//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
|
||||
//@[riscv32imac] needs-llvm-components: riscv
|
||||
// riscv32imac-NOT: !"target-abi"
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![crate_type = "lib"]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
24
tests/run-make/cross-lang-lto-riscv-abi/Makefile
Normal file
24
tests/run-make/cross-lang-lto-riscv-abi/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
# needs-matching-clang
|
||||
|
||||
# This test makes sure that cross-language LTO works on riscv targets
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
all: riscv64gc-unknown-linux-gnu riscv32imac-unknown-none-elf riscv32gc-unknown-linux-gnu
|
||||
|
||||
define check-target =
|
||||
@echo "Testing target $(1)"
|
||||
$(RUSTC) --target $(1) -Clinker-plugin-lto=on -Cpanic=abort --crate-type=rlib -o $(TMPDIR)/libriscv-xlto.a ./riscv-xlto.rs
|
||||
$(CLANG) -target $(2) -march=$(3) -mabi=$(4) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lriscv-xlto -nostdlib -o $(TMPDIR)/riscv-xlto ./cstart.c
|
||||
file $(TMPDIR)/riscv-xlto | $(CGREP) "$(5)"
|
||||
endef
|
||||
|
||||
|
||||
riscv64gc-unknown-linux-gnu:
|
||||
@$(call check-target,$@,riscv64-linux-gnu,rv64gc,lp64d,double-float ABI)
|
||||
|
||||
riscv32imac-unknown-none-elf:
|
||||
@$(call check-target,$@,riscv32-unknown-elf,rv32imac,ilp32,soft-float ABI)
|
||||
|
||||
riscv32gc-unknown-linux-gnu:
|
||||
@$(call check-target,$@,riscv32-linux-gnu,rv32gc,ilp32d,double-float ABI)
|
5
tests/run-make/cross-lang-lto-riscv-abi/cstart.c
Normal file
5
tests/run-make/cross-lang-lto-riscv-abi/cstart.c
Normal file
@ -0,0 +1,5 @@
|
||||
extern void hello();
|
||||
|
||||
void _start() {
|
||||
hello();
|
||||
}
|
9
tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
Normal file
9
tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn hello() {}
|
Loading…
Reference in New Issue
Block a user