Add target arch verification for LLVM intrinsics

This commit is contained in:
sayantn
2025-11-25 13:30:09 +05:30
parent c21f4ee437
commit a5372be2a1
7 changed files with 84 additions and 3 deletions
@@ -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,
}
+40 -3
View File
@@ -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