mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Add target arch verification for LLVM intrinsics
This commit is contained in:
@@ -231,3 +231,12 @@ pub(crate) struct UnknownIntrinsic<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("intrinsic `{$name}` cannot be used with target arch `{$target_arch}`")]
|
||||
pub(crate) struct IntrinsicWrongArch<'a> {
|
||||
pub name: &'a str,
|
||||
pub target_arch: &'a str,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
|
||||
use rustc_target::callconv::PassMode;
|
||||
use rustc_target::spec::Os;
|
||||
use rustc_target::spec::{Arch, Os};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::abi::FnAbiLlvmExt;
|
||||
@@ -37,8 +37,8 @@
|
||||
use crate::context::CodegenCx;
|
||||
use crate::declare::declare_raw_fn;
|
||||
use crate::errors::{
|
||||
AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, OffloadWithoutEnable,
|
||||
OffloadWithoutFatLTO, UnknownIntrinsic,
|
||||
AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
|
||||
OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
|
||||
};
|
||||
use crate::llvm::{self, Type, Value};
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
@@ -965,6 +965,26 @@ fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
|
||||
Some(match rust_arch {
|
||||
Arch::AArch64 | Arch::Arm64EC => "aarch64",
|
||||
Arch::AmdGpu => "amdgcn",
|
||||
Arch::Arm => "arm",
|
||||
Arch::Bpf => "bpf",
|
||||
Arch::Hexagon => "hexagon",
|
||||
Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
|
||||
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
|
||||
Arch::Nvptx64 => "nvvm",
|
||||
Arch::PowerPC | Arch::PowerPC64 => "ppc",
|
||||
Arch::RiscV32 | Arch::RiscV64 => "riscv",
|
||||
Arch::S390x => "s390",
|
||||
Arch::SpirV => "spv",
|
||||
Arch::Wasm32 | Arch::Wasm64 => "wasm",
|
||||
Arch::X86 | Arch::X86_64 => "x86",
|
||||
_ => return None, // fallback for unknown archs
|
||||
})
|
||||
}
|
||||
|
||||
fn intrinsic_fn<'ll, 'tcx>(
|
||||
bx: &Builder<'_, 'll, 'tcx>,
|
||||
name: &str,
|
||||
@@ -978,6 +998,23 @@ fn intrinsic_fn<'ll, 'tcx>(
|
||||
|
||||
let intrinsic = llvm::Intrinsic::lookup(name.as_bytes());
|
||||
|
||||
if let Some(intrinsic) = intrinsic
|
||||
&& intrinsic.is_target_specific()
|
||||
{
|
||||
let (llvm_arch, _) = name[5..].split_once('.').unwrap();
|
||||
let rust_arch = &tcx.sess.target.arch;
|
||||
|
||||
if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
|
||||
&& llvm_arch != correct_llvm_arch
|
||||
{
|
||||
tcx.dcx().emit_fatal(IntrinsicWrongArch {
|
||||
name,
|
||||
target_arch: rust_arch.desc(),
|
||||
span: tcx.def_span(instance.def_id()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(intrinsic) = intrinsic
|
||||
&& !intrinsic.is_overloaded()
|
||||
{
|
||||
|
||||
@@ -1097,6 +1097,7 @@ pub(crate) fn LLVMRustUpgradeIntrinsicFunction<'a>(
|
||||
Fn: &'a Value,
|
||||
NewFn: &mut Option<&'a Value>,
|
||||
) -> bool;
|
||||
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
|
||||
|
||||
// Operations on parameters
|
||||
pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
|
||||
|
||||
@@ -327,6 +327,10 @@ pub(crate) fn is_overloaded(self) -> bool {
|
||||
unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() }
|
||||
}
|
||||
|
||||
pub(crate) fn is_target_specific(self) -> bool {
|
||||
unsafe { LLVMRustIsTargetIntrinsic(self.id) }
|
||||
}
|
||||
|
||||
pub(crate) fn get_declaration<'ll>(
|
||||
self,
|
||||
llmod: &'ll Module,
|
||||
|
||||
@@ -1825,6 +1825,10 @@ extern "C" bool LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn,
|
||||
return CanUpgrade;
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
|
||||
return Intrinsic::isTargetIntrinsic(ID);
|
||||
}
|
||||
|
||||
// Statically assert that the fixed metadata kind IDs declared in
|
||||
// `metadata_kind.rs` match the ones actually used by LLVM.
|
||||
#define FIXED_MD_KIND(VARIANT, VALUE) \
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//@ build-fail
|
||||
//@ ignore-s390x
|
||||
//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`"
|
||||
//@ ignore-backends: gcc
|
||||
|
||||
#![feature(link_llvm_intrinsics, abi_unadjusted)]
|
||||
|
||||
extern "unadjusted" {
|
||||
#[link_name = "llvm.s390.sfpc"]
|
||||
fn foo(a: i32);
|
||||
//~^ ERROR: intrinsic `llvm.s390.sfpc` cannot be used with target arch
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
foo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
error: intrinsic `llvm.s390.sfpc` cannot be used with target arch `TARGET_ARCH`
|
||||
--> $DIR/incorrect-arch-intrinsic.rs:10:5
|
||||
|
|
||||
LL | fn foo(a: i32);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Reference in New Issue
Block a user