Skip to content

Commit 8d22850

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent c464998 commit 8d22850

File tree

8 files changed

+75
-1
lines changed

8 files changed

+75
-1
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
2828
codegen_llvm_intrinsic_signature_mismatch =
2929
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
3030
31+
codegen_llvm_intrinsic_wrong_arch =
32+
Intrinsic `{$name}` cannot be used with target arch "{$target_arch}"
33+
3134
codegen_llvm_invalid_intrinsic =
3235
Invalid LLVM Intrinsic `{$name}`
3336

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
@@ -244,3 +244,12 @@ pub(crate) struct DeprecatedIntrinsicWithReplacement<'a> {
244244
#[primary_span]
245245
pub span: Option<Span>,
246246
}
247+
248+
#[derive(Diagnostic)]
249+
#[diag(codegen_llvm_intrinsic_wrong_arch)]
250+
pub(crate) struct IntrinsicWrongArch<'a> {
251+
pub name: &'a str,
252+
pub target_arch: &'a str,
253+
#[primary_span]
254+
pub span: Option<Span>,
255+
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,7 @@ unsafe extern "C" {
12141214
NewFn: &mut Option<&'a Value>,
12151215
CanUpgradeDebugIntrinsicsToRecords: bool,
12161216
) -> bool;
1217+
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
12171218

12181219
// Operations on parameters
12191220
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
@@ -346,6 +346,10 @@ impl Intrinsic {
346346
pub(crate) fn is_overloaded(self) -> bool {
347347
unsafe { LLVMIntrinsicIsOverloaded(self.id) == True }
348348
}
349+
350+
pub(crate) fn is_target_specific(self) -> bool {
351+
unsafe { LLVMRustIsTargetIntrinsic(self.id) }
352+
}
349353
}
350354

351355
/// Safe wrapper for `LLVMSetValueName2` from a byte slice

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

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

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

0 commit comments

Comments
 (0)