Skip to content

Commit 618d826

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent ea47331 commit 618d826

File tree

8 files changed

+80
-1
lines changed

8 files changed

+80
-1
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
2323
codegen_llvm_intrinsic_signature_mismatch =
2424
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
2525
26+
codegen_llvm_intrinsic_wrong_arch =
27+
Intrinsic `{$name}` cannot be used with target arch `{$target_arch}`
28+
2629
codegen_llvm_invalid_intrinsic =
2730
Invalid LLVM Intrinsic `{$name}`
2831

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,36 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
177177
signature.fn_ty(),
178178
);
179179

180-
if signature.intrinsic().is_none() {
180+
if let Some(intrinsic) = signature.intrinsic() {
181+
if intrinsic.is_target_specific() {
182+
let (llvm_arch, _) = name[5..].split_once('.').unwrap();
183+
let target_arch = self.tcx.sess.target.arch.as_ref();
184+
185+
let is_correct_arch = match llvm_arch {
186+
"aarch64" => matches!(target_arch, "aarch64" | "arm64ec"),
187+
"amdgcn" => target_arch == "amdgpu",
188+
"arm" | "bpf" | "hexagon" => target_arch == llvm_arch,
189+
"loongarch" => matches!(target_arch, "loongarch32" | "loongarch64"),
190+
"mips" => target_arch.starts_with("mips"),
191+
"nvvm" => target_arch == "nvptx64",
192+
"ppc" => matches!(target_arch, "powerpc" | "powerpc64"),
193+
"riscv" => matches!(target_arch, "riscv32" | "riscv64"),
194+
"s390" => target_arch == "s390x",
195+
"spv" => target_arch == "spirv",
196+
"wasm" => matches!(target_arch, "wasm32" | "wasm64"),
197+
"x86" => matches!(target_arch, "x86" | "x86_64"),
198+
_ => true, // fallback for unknown archs
199+
};
200+
201+
if !is_correct_arch {
202+
self.tcx.dcx().emit_fatal(errors::IntrinsicWrongArch {
203+
name,
204+
target_arch,
205+
span: span(),
206+
});
207+
}
208+
}
209+
} else {
181210
// Don't apply any attributes to intrinsics, they will be applied by AutoUpgrade
182211
fn_abi.apply_attrs_llfn(self, llfn, instance);
183212
}

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,12 @@ pub(crate) struct DeprecatedIntrinsicWithReplacement<'a> {
227227
#[primary_span]
228228
pub span: Option<Span>,
229229
}
230+
231+
#[derive(Diagnostic)]
232+
#[diag(codegen_llvm_intrinsic_wrong_arch)]
233+
pub(crate) struct IntrinsicWrongArch<'a> {
234+
pub name: &'a str,
235+
pub target_arch: &'a str,
236+
#[primary_span]
237+
pub span: Option<Span>,
238+
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ unsafe extern "C" {
12241224
NewFn: &mut Option<&'a Value>,
12251225
CanUpgradeDebugIntrinsicsToRecords: bool,
12261226
) -> bool;
1227+
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
12271228

12281229
// Operations on parameters
12291230
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
@@ -347,6 +347,10 @@ impl Intrinsic {
347347
unsafe { LLVMIntrinsicIsOverloaded(self.id) == True }
348348
}
349349

350+
pub(crate) fn is_target_specific(self) -> bool {
351+
unsafe { LLVMRustIsTargetIntrinsic(self.id) }
352+
}
353+
350354
pub(crate) fn overloaded_name<'ll>(
351355
self,
352356
llmod: &'ll Module,

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,6 +1913,14 @@ LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn, LLVMValueRef *NewFn,
19131913
return CanUpgrade;
19141914
}
19151915

1916+
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
1917+
#if LLVM_VERSION_GE(20, 1)
1918+
return Intrinsic::isTargetIntrinsic(ID);
1919+
#else
1920+
return Function::isTargetIntrinsic(ID);
1921+
#endif
1922+
}
1923+
19161924
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
19171925
auto *CB = unwrap<CallBase>(CallSite);
19181926
switch (CB->getIntrinsicID()) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ build-fail
2+
//@ ignore-s390x
3+
//@ normalize-stderr: "target arch `(.*)`" -> "target arch `TARGET_ARCH`"
4+
5+
#![feature(link_llvm_intrinsics, abi_unadjusted)]
6+
7+
extern "unadjusted" {
8+
#[link_name = "llvm.s390.sfpc"]
9+
fn foo(a: i32);
10+
//~^ ERROR: Intrinsic `llvm.s390.sfpc` cannot be used with target arch
11+
}
12+
13+
pub fn main() {
14+
unsafe {
15+
foo(0);
16+
}
17+
}
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:9:5
3+
|
4+
LL | fn foo(a: i32);
5+
| ^^^^^^^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)