Skip to content

Commit afa7252

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent 35d0f9d commit afa7252

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
@@ -19,6 +19,9 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
1919
codegen_llvm_intrinsic_signature_mismatch =
2020
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
2121
22+
codegen_llvm_intrinsic_wrong_arch =
23+
Intrinsic `{$name}` cannot be used with target arch `{$target_arch}`
24+
2225
codegen_llvm_invalid_intrinsic =
2326
Invalid LLVM Intrinsic `{$name}`
2427

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
@@ -182,3 +182,12 @@ pub(crate) struct DeprecatedIntrinsicWithReplacement<'a> {
182182
#[primary_span]
183183
pub span: Option<Span>,
184184
}
185+
186+
#[derive(Diagnostic)]
187+
#[diag(codegen_llvm_intrinsic_wrong_arch)]
188+
pub(crate) struct IntrinsicWrongArch<'a> {
189+
pub name: &'a str,
190+
pub target_arch: &'a str,
191+
#[primary_span]
192+
pub span: Option<Span>,
193+
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,7 @@ unsafe extern "C" {
12721272
NewFn: &mut Option<&'a Value>,
12731273
CanUpgradeDebugIntrinsicsToRecords: bool,
12741274
) -> bool;
1275+
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
12751276

12761277
// Operations on parameters
12771278
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
@@ -308,6 +308,10 @@ impl Intrinsic {
308308
unsafe { LLVMIntrinsicIsOverloaded(self.id).is_true() }
309309
}
310310

311+
pub(crate) fn is_target_specific(self) -> bool {
312+
unsafe { LLVMRustIsTargetIntrinsic(self.id) }
313+
}
314+
311315
pub(crate) fn get_type<'ll>(self, llcx: &'ll Context, type_params: &[&'ll Type]) -> &'ll Type {
312316
unsafe { LLVMIntrinsicGetType(llcx, self.id, type_params.as_ptr(), type_params.len()) }
313317
}

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

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

1917+
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
1918+
#if LLVM_VERSION_GE(20, 1)
1919+
return Intrinsic::isTargetIntrinsic(ID);
1920+
#else
1921+
return Function::isTargetIntrinsic(ID);
1922+
#endif
1923+
}
1924+
19171925
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
19181926
auto *CB = unwrap<CallBase>(CallSite);
19191927
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)