From a5372be2a15f7ec0c06855e209936e44bd42f482 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 25 Nov 2025 13:30:09 +0530 Subject: [PATCH] Add target arch verification for LLVM intrinsics --- compiler/rustc_codegen_llvm/src/errors.rs | 9 ++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 43 +++++++++++++++++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_llvm/src/llvm/mod.rs | 4 ++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 ++ tests/ui/codegen/incorrect-arch-intrinsic.rs | 18 ++++++++ .../codegen/incorrect-arch-intrinsic.stderr | 8 ++++ 7 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 tests/ui/codegen/incorrect-arch-intrinsic.rs create mode 100644 tests/ui/codegen/incorrect-arch-intrinsic.stderr diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 259aa20b9e38..8921395ab76c 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2655b45d6e94..4c66c4ef8bdd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -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() { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3b81fde64059..7edbaf5a5f33 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1097,6 +1097,7 @@ pub(crate) fn LLVMRustUpgradeIntrinsicFunction<'a>( Fn: &'a Value, NewFn: &mut Option<&'a Value>, ) -> bool; + pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero) -> bool; // Operations on parameters pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 84d7e8165fe0..2ec19b1795b5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -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, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 30410a4d26fc..c310e580af55 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -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) \ diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.rs b/tests/ui/codegen/incorrect-arch-intrinsic.rs new file mode 100644 index 000000000000..9576cb8f8131 --- /dev/null +++ b/tests/ui/codegen/incorrect-arch-intrinsic.rs @@ -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); + } +} diff --git a/tests/ui/codegen/incorrect-arch-intrinsic.stderr b/tests/ui/codegen/incorrect-arch-intrinsic.stderr new file mode 100644 index 000000000000..5b44419aa741 --- /dev/null +++ b/tests/ui/codegen/incorrect-arch-intrinsic.stderr @@ -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 +