Skip to content

Commit b3f8fb1

Browse files
committed
Refactor emitting errors to declare.rs, and use fluently-generated error messages
Create lints for deprecated and invalid intrinsics
1 parent 3db5e31 commit b3f8fb1

13 files changed

+221
-105
lines changed

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z au
33
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
44
55
6+
67
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
78
89
codegen_llvm_from_llvm_diag = {$message}
910
1011
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
1112
13+
codegen_llvm_intrinsic_signature_mismatch =
14+
Intrinsic signature mismatch for `{$name}`: expected signature `{$llvm_fn_ty}`, found `{$rust_fn_ty}`
15+
16+
1217
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
1318
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
1419

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -310,33 +310,42 @@ impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
310310
}
311311

312312
pub(crate) enum FunctionSignature<'ll> {
313-
/// The signature is obtained directly from LLVM, and **may not match the Rust signature**
314-
Intrinsic(&'ll Type),
313+
/// This is an LLVM intrinsic, the signature is obtained directly from LLVM, and **may not match the Rust signature**
314+
LLVMSignature(llvm::Intrinsic, &'ll Type),
315+
/// This is an LLVM intrinsic, but the signature is just the Rust signature.
316+
/// FIXME: this should ideally not exist, we should be using the LLVM signature for all LLVM intrinsics
317+
RustSignature(llvm::Intrinsic, &'ll Type),
315318
/// The name starts with `llvm.`, but can't obtain the intrinsic ID. May be invalid or upgradable
316-
MaybeInvalidIntrinsic(&'ll Type),
319+
MaybeInvalid(&'ll Type),
317320
/// Just the Rust signature
318-
Rust(&'ll Type),
321+
NotIntrinsic(&'ll Type),
319322
}
320323

321324
impl<'ll> FunctionSignature<'ll> {
322325
pub(crate) fn fn_ty(&self) -> &'ll Type {
323326
match self {
324-
FunctionSignature::Intrinsic(fn_ty)
325-
| FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
326-
| FunctionSignature::Rust(fn_ty) => fn_ty,
327+
FunctionSignature::LLVMSignature(_, fn_ty)
328+
| FunctionSignature::RustSignature(_, fn_ty)
329+
| FunctionSignature::MaybeInvalid(fn_ty)
330+
| FunctionSignature::NotIntrinsic(fn_ty) => fn_ty,
331+
}
332+
}
333+
334+
pub(crate) fn intrinsic(&self) -> Option<llvm::Intrinsic> {
335+
match self {
336+
FunctionSignature::RustSignature(intrinsic, _)
337+
| FunctionSignature::LLVMSignature(intrinsic, _) => Some(*intrinsic),
338+
_ => None,
327339
}
328340
}
329341
}
330342

331343
pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
332344
fn llvm_return_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
333345
fn llvm_argument_types(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<&'ll Type>;
334-
fn llvm_type(
335-
&self,
336-
cx: &CodegenCx<'ll, 'tcx>,
337-
name: &[u8],
338-
do_verify: bool,
339-
) -> FunctionSignature<'ll>;
346+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll>;
347+
/// The normal Rust signature for this
348+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
340349
/// **If this function is an LLVM intrinsic** checks if the LLVM signature provided matches with this
341350
fn verify_intrinsic_signature(&self, cx: &CodegenCx<'ll, 'tcx>, llvm_ty: &'ll Type) -> bool;
342351

@@ -482,51 +491,35 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
482491
.all(|(rust_ty, llvm_ty)| cx.equate_ty(rust_ty, llvm_ty))
483492
}
484493

485-
fn llvm_type(
486-
&self,
487-
cx: &CodegenCx<'ll, 'tcx>,
488-
name: &[u8],
489-
do_verify: bool,
490-
) -> FunctionSignature<'ll> {
491-
let mut maybe_invalid = false;
494+
fn rust_signature(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
495+
let return_ty = self.llvm_return_type(cx);
496+
let argument_tys = self.llvm_argument_types(cx);
497+
498+
if self.c_variadic {
499+
cx.type_variadic_func(&argument_tys, return_ty)
500+
} else {
501+
cx.type_func(&argument_tys, return_ty)
502+
}
503+
}
492504

505+
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>, name: &[u8]) -> FunctionSignature<'ll> {
493506
if name.starts_with(b"llvm.") {
494507
if let Some(intrinsic) = llvm::Intrinsic::lookup(name) {
495508
if !intrinsic.is_overloaded() {
496509
// FIXME: also do this for overloaded intrinsics
497-
let llvm_fn_ty = intrinsic.get_type(cx.llcx, &[]);
498-
if do_verify {
499-
if !self.verify_intrinsic_signature(cx, llvm_fn_ty) {
500-
cx.tcx.dcx().fatal(format!(
501-
"Intrinsic signature mismatch for `{}`: expected signature `{llvm_fn_ty:?}`",
502-
str::from_utf8(name).unwrap()
503-
));
504-
}
505-
}
506-
return FunctionSignature::Intrinsic(llvm_fn_ty);
510+
FunctionSignature::LLVMSignature(intrinsic, intrinsic.get_type(cx.llcx, &[]))
511+
} else {
512+
FunctionSignature::RustSignature(intrinsic, self.rust_signature(cx))
507513
}
508514
} else {
509515
// it's one of 2 cases,
510516
// - either the base name is invalid
511517
// - it has been superseded by something else, so the intrinsic was removed entirely
512518
// to check for upgrades, we need the `llfn`, so we defer it for now
513-
maybe_invalid = true;
519+
FunctionSignature::MaybeInvalid(self.rust_signature(cx))
514520
}
515-
}
516-
517-
let return_ty = self.llvm_return_type(cx);
518-
let argument_tys = self.llvm_argument_types(cx);
519-
520-
let fn_ty = if self.c_variadic {
521-
cx.type_variadic_func(&argument_tys, return_ty)
522521
} else {
523-
cx.type_func(&argument_tys, return_ty)
524-
};
525-
526-
if maybe_invalid {
527-
FunctionSignature::MaybeInvalidIntrinsic(fn_ty)
528-
} else {
529-
FunctionSignature::Rust(fn_ty)
522+
FunctionSignature::NotIntrinsic(self.rust_signature(cx))
530523
}
531524
}
532525

@@ -684,15 +677,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
684677
callsite: &'ll Value,
685678
llfn: &'ll Value,
686679
) {
687-
// if we are using the LLVM signature, use the LLVM attributes otherwise it might be problematic
688-
let name = llvm::get_value_name(llfn);
689-
if name.starts_with(b"llvm.")
690-
&& let Some(intrinsic) = llvm::Intrinsic::lookup(&name)
691-
{
692-
// FIXME: also do this for overloaded intrinsics
693-
if !intrinsic.is_overloaded() {
694-
return;
695-
}
680+
// Don't apply any attributes to LLVM intrinsics, they will be applied by AutoUpgrade
681+
if llvm::get_value_name(llfn).starts_with(b"llvm.") {
682+
return;
696683
}
697684

698685
let mut func_attrs = SmallVec::<[_; 2]>::new();

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
1818
use rustc_data_structures::fx::FxIndexSet;
1919
use rustc_middle::ty::{Instance, Ty};
2020
use rustc_sanitizers::{cfi, kcfi};
21+
use rustc_session::lint::builtin::{DEPRECATED_LLVM_INTRINSIC, UNKNOWN_LLVM_INTRINSIC};
2122
use rustc_target::callconv::FnAbi;
2223
use smallvec::SmallVec;
2324
use tracing::debug;
@@ -29,7 +30,7 @@ use crate::llvm::AttributePlace::Function;
2930
use crate::llvm::Visibility;
3031
use crate::type_::Type;
3132
use crate::value::Value;
32-
use crate::{attributes, llvm};
33+
use crate::{attributes, errors, llvm};
3334

3435
/// Declare a function with a SimpleCx.
3536
///
@@ -150,52 +151,69 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
150151
) -> &'ll Value {
151152
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
152153

153-
let signature = fn_abi.llvm_type(self, name.as_bytes(), true);
154-
let llfn;
155-
156-
if let FunctionSignature::Intrinsic(fn_ty) = signature {
157-
// intrinsics have a specified set of attributes, so we don't use the `FnAbi` set for them
158-
llfn = declare_simple_fn(
159-
self,
160-
name,
161-
fn_abi.llvm_cconv(self),
162-
llvm::UnnamedAddr::Global,
163-
llvm::Visibility::Default,
164-
fn_ty,
165-
);
166-
} else {
167-
// Function addresses in Rust are never significant, allowing functions to
168-
// be merged.
169-
llfn = declare_raw_fn(
170-
self,
171-
name,
172-
fn_abi.llvm_cconv(self),
173-
llvm::UnnamedAddr::Global,
174-
llvm::Visibility::Default,
175-
signature.fn_ty(),
176-
);
154+
let signature = fn_abi.llvm_type(self, name.as_bytes());
155+
156+
let span = || instance.map(|instance| self.tcx.def_span(instance.def_id()));
157+
158+
if let FunctionSignature::LLVMSignature(_, llvm_fn_ty) = signature {
159+
// check if the intrinsic signatures match
160+
if !fn_abi.verify_intrinsic_signature(self, llvm_fn_ty) {
161+
self.tcx.dcx().emit_fatal(errors::IntrinsicSignatureMismatch {
162+
name,
163+
llvm_fn_ty: &format!("{llvm_fn_ty:?}"),
164+
rust_fn_ty: &format!("{:?}", fn_abi.rust_signature(self)),
165+
span: span(),
166+
});
167+
}
168+
}
169+
170+
// Function addresses in Rust are never significant, allowing functions to
171+
// be merged.
172+
let llfn = declare_raw_fn(
173+
self,
174+
name,
175+
fn_abi.llvm_cconv(self),
176+
llvm::UnnamedAddr::Global,
177+
llvm::Visibility::Default,
178+
signature.fn_ty(),
179+
);
180+
181+
if signature.intrinsic().is_none() {
182+
// Don't apply any attributes to intrinsics, they will be applied by AutoUpgrade
177183
fn_abi.apply_attrs_llfn(self, llfn, instance);
178184
}
179185

180-
if let FunctionSignature::MaybeInvalidIntrinsic(..) = signature {
186+
if let FunctionSignature::MaybeInvalid(..) = signature {
181187
let mut new_llfn = None;
182188
let can_upgrade =
183189
unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn, false) };
184190

185-
if can_upgrade {
186-
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
187-
if let Some(new_llfn) = new_llfn {
188-
self.tcx.dcx().note(format!(
189-
"Using deprecated intrinsic `{name}`, `{}` can be used instead",
190-
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
191-
));
191+
// we can emit diagnostics for local crates only
192+
if let Some(instance) = instance
193+
&& let Some(local_def_id) = instance.def_id().as_local()
194+
{
195+
let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
196+
let span = self.tcx.def_span(local_def_id);
197+
198+
if can_upgrade {
199+
// not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
200+
let msg = if let Some(new_llfn) = new_llfn {
201+
format!(
202+
"Using deprecated intrinsic `{name}`, `{}` can be used instead",
203+
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
204+
)
205+
} else {
206+
format!("Using deprecated intrinsic `{name}`")
207+
};
208+
self.tcx.node_lint(DEPRECATED_LLVM_INTRINSIC, hir_id, |d| {
209+
d.primary_message(msg).span(span);
210+
});
192211
} else {
193-
self.tcx.dcx().note(format!(
194-
"Using deprecated intrinsic `{name}`, consider using other intrinsics/instructions"
195-
));
212+
// This is either plain wrong, or this can be caused by incompatible LLVM versions, we let the user decide
213+
self.tcx.node_lint(UNKNOWN_LLVM_INTRINSIC, hir_id, |d| {
214+
d.primary_message(format!("Invalid LLVM Intrinsic `{name}`")).span(span);
215+
});
196216
}
197-
} else {
198-
self.tcx.dcx().fatal(format!("Invalid LLVM intrinsic: `{name}`"))
199217
}
200218
}
201219

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,13 @@ pub(crate) struct FixedX18InvalidArch<'a> {
147147
#[derive(Diagnostic)]
148148
#[diag(codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0)]
149149
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
150+
151+
#[derive(Diagnostic)]
152+
#[diag(codegen_llvm_intrinsic_signature_mismatch)]
153+
pub(crate) struct IntrinsicSignatureMismatch<'a> {
154+
pub name: &'a str,
155+
pub llvm_fn_ty: &'a str,
156+
pub rust_fn_ty: &'a str,
157+
#[primary_span]
158+
pub span: Option<Span>,
159+
}

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ fn gen_fn<'a, 'll, 'tcx>(
10661066
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
10671067
) -> (&'ll Type, &'ll Value) {
10681068
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
1069-
let llty = fn_abi.llvm_type(cx, name.as_bytes(), true).fn_ty();
1069+
let llty = fn_abi.llvm_type(cx, name.as_bytes()).fn_ty();
10701070
let llfn = cx.declare_fn(name, fn_abi, None);
10711071
cx.set_frame_pointer_type(llfn);
10721072
cx.apply_target_cpu_attr(llfn);

compiler/rustc_codegen_llvm/src/type_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
311311
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
312312
fn_ptr: &'ll Value,
313313
) -> &'ll Type {
314-
fn_abi.llvm_type(self, &llvm::get_value_name(fn_ptr), false).fn_ty()
314+
fn_abi.llvm_type(self, &llvm::get_value_name(fn_ptr)).fn_ty()
315315
}
316316
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
317317
fn_abi.ptr_to_llvm_type(self)

0 commit comments

Comments
 (0)