Skip to content

Commit e994a7c

Browse files
committed
Add target arch verification for LLVM intrinsics
1 parent d88e935 commit e994a7c

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
@@ -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: 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
@@ -1140,6 +1140,7 @@ unsafe extern "C" {
11401140
NewFn: &mut Option<&'a Value>,
11411141
CanUpgradeDebugIntrinsicsToRecords: bool,
11421142
) -> bool;
1143+
pub(crate) fn LLVMRustIsTargetIntrinsic(ID: NonZero<c_uint>) -> bool;
11431144

11441145
// Operations on parameters
11451146
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
@@ -1777,6 +1777,14 @@ LLVMRustUpgradeIntrinsicFunction(LLVMValueRef Fn, LLVMValueRef *NewFn,
17771777
return CanUpgrade;
17781778
}
17791779

1780+
extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) {
1781+
#if LLVM_VERSION_GE(20, 1)
1782+
return Intrinsic::isTargetIntrinsic(ID);
1783+
#else
1784+
return Function::isTargetIntrinsic(ID);
1785+
#endif
1786+
}
1787+
17801788
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
17811789
auto *CB = unwrap<CallBase>(CallSite);
17821790
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)