Skip to content

Commit 360f534

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent b3f8fb1 commit 360f534

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
@@ -13,6 +13,9 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
1313
codegen_llvm_intrinsic_signature_mismatch =
1414
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
1515
16+
codegen_llvm_intrinsic_wrong_arch =
17+
Intrinsic `{$name}` cannot be used with target arch `{$target_arch}`
18+
1619
1720
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
1821
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: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,36 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
178178
signature.fn_ty(),
179179
);
180180

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

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
@@ -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
@@ -1909,6 +1909,14 @@ LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn, LLVMValueRef *NewFn,
19091909
return CanUpgrade;
19101910
}
19111911

1912+
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
1913+
#if LLVM_VERSION_GE(20, 1)
1914+
return Intrinsic::isTargetIntrinsic(ID);
1915+
#else
1916+
return Function::isTargetIntrinsic(ID);
1917+
#endif
1918+
}
1919+
19121920
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
19131921
auto *CB = unwrap<CallBase>(CallSite);
19141922
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)