Skip to content

Commit d6177d6

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent c0b64d0 commit d6177d6

File tree

8 files changed

+88
-1
lines changed

8 files changed

+88
-1
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
1212
codegen_llvm_intrinsic_signature_mismatch =
1313
intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
1414
15+
codegen_llvm_intrinsic_wrong_arch =
16+
intrinsic `{$name}` cannot be used with target arch `{$target_arch}`
17+
1518
1619
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
1720
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc_middle::ty::{Instance, Ty};
2020
use rustc_sanitizers::{cfi, kcfi};
2121
use rustc_session::lint::builtin::{DEPRECATED_LLVM_INTRINSIC, UNKNOWN_LLVM_INTRINSIC};
2222
use rustc_target::callconv::FnAbi;
23+
use rustc_target::spec::Arch;
2324
use smallvec::SmallVec;
2425
use tracing::debug;
2526

@@ -100,6 +101,26 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
100101
}
101102
}
102103

104+
fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
105+
Some(match rust_arch {
106+
Arch::AArch64 | Arch::Arm64EC => "aarch64",
107+
Arch::AmdGpu => "amdgcn",
108+
Arch::Arm => "arm",
109+
Arch::Bpf => "bpf",
110+
Arch::Hexagon => "hexagon",
111+
Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
112+
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
113+
Arch::Nvptx64 => "nvvm",
114+
Arch::PowerPC | Arch::PowerPC64 | Arch::PowerPC64LE => "ppc",
115+
Arch::RiscV32 | Arch::RiscV64 => "riscv",
116+
Arch::S390x => "s390",
117+
Arch::SpirV => "spv",
118+
Arch::Wasm32 | Arch::Wasm64 => "wasm",
119+
Arch::X86 | Arch::X86_64 => "x86",
120+
_ => return None, // fallback for unknown archs
121+
})
122+
}
123+
103124
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
104125
/// Declare a C ABI function.
105126
///
@@ -176,7 +197,22 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
176197
signature.fn_ty(),
177198
);
178199

179-
if signature.intrinsic().is_none() {
200+
if let Some(intrinsic) = signature.intrinsic()
201+
&& intrinsic.is_target_specific()
202+
{
203+
let (llvm_arch, _) = name[5..].split_once('.').unwrap();
204+
let rust_arch = &self.tcx.sess.target.arch;
205+
206+
if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
207+
&& llvm_arch != correct_llvm_arch
208+
{
209+
self.tcx.dcx().emit_fatal(errors::IntrinsicWrongArch {
210+
name,
211+
target_arch: rust_arch.desc(),
212+
span: span(),
213+
});
214+
}
215+
} else {
180216
// Don't apply any attributes to intrinsics, they will be applied by AutoUpgrade
181217
fn_abi.apply_attrs_llfn(self, llfn, instance);
182218
}

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,12 @@ pub(crate) struct IntrinsicSignatureMismatch<'a> {
157157
#[primary_span]
158158
pub span: Option<Span>,
159159
}
160+
161+
#[derive(Diagnostic)]
162+
#[diag(codegen_llvm_intrinsic_wrong_arch)]
163+
pub(crate) struct IntrinsicWrongArch<'a> {
164+
pub name: &'a str,
165+
pub target_arch: &'a str,
166+
#[primary_span]
167+
pub span: Option<Span>,
168+
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ unsafe extern "C" {
11561156
NewFn: &mut Option<&'a Value>,
11571157
CanUpgradeDebugIntrinsicsToRecords: bool,
11581158
) -> bool;
1159+
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
11591160

11601161
// Operations on parameters
11611162
pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;

compiler/rustc_codegen_llvm/src/llvm/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ impl Intrinsic {
315315
unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() }
316316
}
317317

318+
pub(crate) fn is_target_specific(self) -> bool {
319+
unsafe { LLVMRustIsTargetIntrinsic(self.id) }
320+
}
321+
318322
pub(crate) fn get_type<'ll>(self, llcx: &'ll Context, type_params: &[&'ll Type]) -> &'ll Type {
319323
unsafe { LLVMIntrinsicGetType(llcx, self.id, type_params.as_ptr(), type_params.len()) }
320324
}

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,6 +1659,14 @@ LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn, LLVMValueRef *NewFn,
16591659
return CanUpgrade;
16601660
}
16611661

1662+
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
1663+
#if LLVM_VERSION_GE(20, 1)
1664+
return Intrinsic::isTargetIntrinsic(ID);
1665+
#else
1666+
return Function::isTargetIntrinsic(ID);
1667+
#endif
1668+
}
1669+
16621670
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
16631671
auto *CB = unwrap<CallBase>(CallSite);
16641672
switch (CB->getIntrinsicID()) {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ build-fail
2+
//@ ignore-s390x
3+
//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`"
4+
//@ ignore-backends: gcc
5+
6+
#![feature(link_llvm_intrinsics, abi_unadjusted)]
7+
8+
extern "unadjusted" {
9+
#[link_name = "llvm.s390.sfpc"]
10+
fn foo(a: i32);
11+
//~^ ERROR: intrinsic `llvm.s390.sfpc` cannot be used with target arch
12+
}
13+
14+
pub fn main() {
15+
unsafe {
16+
foo(0);
17+
}
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: intrinsic `llvm.s390.sfpc` cannot be used with target arch `TARGET_ARCH`
2+
--> $DIR/incorrect-arch-intrinsic.rs:10:5
3+
|
4+
LL | fn foo(a: i32);
5+
| ^^^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)