diff options
| author | Taiki Endo <te316e89@gmail.com> | 2024-11-24 21:42:22 +0900 |
|---|---|---|
| committer | Taiki Endo <te316e89@gmail.com> | 2024-11-24 21:42:22 +0900 |
| commit | c024d8ccdfb462f4e99b54e6c8456fbc4d745752 (patch) | |
| tree | 746d303b898bf928538b56a2d50b1b5c05ed28a5 /compiler | |
| parent | 2c8f6de1babfd5cce9badd8ff85c0652377edd75 (diff) | |
Make s390x non-clobber-only vector register support unstable
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_lowering/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/asm.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/inline_asm.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_gcc/src/asm.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/asm.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/unstable.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsicck.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_target/src/asm/mod.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_target/src/asm/s390x.rs | 16 |
13 files changed, 108 insertions, 29 deletions
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index f704320c71d..5095b454fa4 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -152,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}` ast_lowering_register_class_only_clobber = register class `{$reg_class_name}` can only be used as a clobber, not as an input or output +ast_lowering_register_class_only_clobber_stable = + register class `{$reg_class_name}` can only be used as a clobber in stable ast_lowering_register_conflict = register `{$reg1_name}` conflicts with register `{$reg2_name}` diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 215e6d84d0f..3d75a63abda 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -17,7 +17,8 @@ use super::errors::{ InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister, - InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict, + InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable, + RegisterConflict, }; use crate::{ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, @@ -61,6 +62,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } } + let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) && !self.tcx.sess.opts.actually_rustdoc @@ -333,11 +335,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // means that we disallow passing a value in/out of the asm and // require that the operand name an explicit register, not a // register class. - if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { - self.dcx().emit_err(RegisterClassOnlyClobber { - op_span: op_sp, - reg_class_name: reg_class.name(), - }); + if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg) + && !op.is_clobber() + { + if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true) + { + // always clobber-only + self.dcx().emit_err(RegisterClassOnlyClobber { + op_span: op_sp, + reg_class_name: reg_class.name(), + }); + } else { + // clobber-only in stable + self.tcx + .sess + .create_feature_err( + RegisterClassOnlyClobberStable { + op_span: op_sp, + reg_class_name: reg_class.name(), + }, + sym::asm_experimental_reg, + ) + .emit(); + } continue; } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index e6a3f939f2d..447af57354f 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -280,6 +280,14 @@ pub(crate) struct RegisterClassOnlyClobber { } #[derive(Diagnostic)] +#[diag(ast_lowering_register_class_only_clobber_stable)] +pub(crate) struct RegisterClassOnlyClobberStable { + #[primary_span] + pub op_span: Span, + pub reg_class_name: Symbol, +} + +#[derive(Diagnostic)] #[diag(ast_lowering_register_conflict)] pub(crate) struct RegisterConflict<'a> { #[primary_span] diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 0df1a30fc0a..a2fb711b9e1 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -462,8 +462,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut slots_output = vec![None; self.operands.len()]; let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { - let reg_size = - reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap(); + let reg_size = reg_class + .supported_types(self.arch, true) + .iter() + .map(|(ty, _)| ty.size()) + .max() + .unwrap(); let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap(); let offset = slot_size.align_to(align); *slot_size = offset + reg_size; diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 279b4d1d20c..ab4fdb78bb0 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -186,7 +186,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // `clobber_abi` can add lots of clobbers that are not supported by the target, // such as AVX-512 registers, so we just ignore unsupported registers let is_target_supported = - reg.reg_class().supported_types(asm_arch).iter().any( + reg.reg_class().supported_types(asm_arch, true).iter().any( |&(_, feature)| { if let Some(feature) = feature { self.tcx diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 2568c5ea5b5..ee6c768b724 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -45,7 +45,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { match *op { InlineAsmOperandRef::Out { reg, late, place } => { let is_target_supported = |reg_class: InlineAsmRegClass| { - for &(_, feature) in reg_class.supported_types(asm_arch) { + for &(_, feature) in reg_class.supported_types(asm_arch, true) { if let Some(feature) = feature { if self .tcx @@ -85,7 +85,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } continue; } else if !is_target_supported(reg.reg_class()) - || reg.reg_class().is_clobber_only(asm_arch) + || reg.reg_class().is_clobber_only(asm_arch, true) { // We turn discarded outputs into clobber constraints // if the target feature needed by the register class is diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e3dc73c1401..3b93c29e548 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -376,6 +376,8 @@ declare_features! ( (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), + /// Enables experimental register support in inline assembly. + (unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)), /// Allows using `label` operands in inline assembly. (unstable, asm_goto, "1.78.0", Some(119364)), /// Allows the `may_unwind` option in inline assembly. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 64a30e633cf..6cc1d9ed8f4 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -424,6 +424,9 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` +hir_analysis_register_type_unstable = + type `{$ty}` cannot be used with this register class in stable + hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}` hir_analysis_return_type_notation_equality_bound = diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index dfddf93a5c2..b96469f503c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -7,12 +7,14 @@ use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; -use rustc_span::Symbol; use rustc_span::def_id::LocalDefId; +use rustc_span::{Symbol, sym}; use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, }; +use crate::errors::RegisterTypeUnstable; + pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, @@ -218,17 +220,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check the type against the list of types supported by the selected // register class. let asm_arch = self.tcx.sess.asm_arch.unwrap(); + let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); let reg_class = reg.reg_class(); - let supported_tys = reg_class.supported_types(asm_arch); + let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg); let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else { - let msg = format!("type `{ty}` cannot be used with this register class"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect(); - err.note(format!( - "register class `{}` supports these types: {}", - reg_class.name(), - supported_tys.join(", "), - )); + let mut err = if !allow_experimental_reg + && reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty) + { + self.tcx.sess.create_feature_err( + RegisterTypeUnstable { span: expr.span, ty }, + sym::asm_experimental_reg, + ) + } else { + let msg = format!("type `{ty}` cannot be used with this register class"); + let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); + let supported_tys: Vec<_> = + supported_tys.iter().map(|(t, _)| t.to_string()).collect(); + err.note(format!( + "register class `{}` supports these types: {}", + reg_class.name(), + supported_tys.join(", "), + )); + err + }; if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) { err.help(format!("consider using the `{}` register class instead", suggest.name())); } @@ -313,6 +327,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { self.tcx.dcx().delayed_bug("target architecture does not support asm"); return; }; + let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { // Validate register classes against currently enabled target // features. We check that at least one type is available for @@ -352,7 +367,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let InlineAsmRegClass::Err = reg_class { continue; } - for &(_, feature) in reg_class.supported_types(asm_arch) { + for &(_, feature) in reg_class.supported_types(asm_arch, allow_experimental_reg) + { match feature { Some(feature) => { if target_features.contains(&feature) { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 07d3273b09c..897ee58baab 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1685,3 +1685,11 @@ pub(crate) struct CmseEntryGeneric { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_register_type_unstable)] +pub(crate) struct RegisterTypeUnstable<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b0086928231..a051ab62638 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -416,6 +416,7 @@ symbols! { asm, asm_const, asm_experimental_arch, + asm_experimental_reg, asm_goto, asm_sym, asm_unwind, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 10778e9acf1..db8d23776e5 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -604,9 +604,13 @@ impl InlineAsmRegClass { /// Returns a list of supported types for this register class, each with an /// options target feature required to use this type. + /// + /// At the codegen stage, it is fine to always pass true for `allow_experimental_reg`, + /// since all the stability checking will have been done in prior stages. pub fn supported_types( self, arch: InlineAsmArch, + allow_experimental_reg: bool, ) -> &'static [(InlineAsmType, Option<Symbol>)] { match self { Self::X86(r) => r.supported_types(arch), @@ -618,7 +622,7 @@ impl InlineAsmRegClass { Self::Hexagon(r) => r.supported_types(arch), Self::LoongArch(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), - Self::S390x(r) => r.supported_types(arch), + Self::S390x(r) => r.supported_types(arch, allow_experimental_reg), Self::Sparc(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch), @@ -696,8 +700,11 @@ impl InlineAsmRegClass { /// Returns whether registers in this class can only be used as clobbers /// and not as inputs/outputs. - pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool { - self.supported_types(arch).is_empty() + /// + /// At the codegen stage, it is fine to always pass true for `allow_experimental_reg`, + /// since all the stability checking will have been done in prior stages. + pub fn is_clobber_only(self, arch: InlineAsmArch, allow_experimental_reg: bool) -> bool { + self.supported_types(arch, allow_experimental_reg).is_empty() } } diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 426417e5bac..410590b722b 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -38,14 +38,22 @@ impl S390xInlineAsmRegClass { pub fn supported_types( self, _arch: InlineAsmArch, + allow_experimental_reg: bool, ) -> &'static [(InlineAsmType, Option<Symbol>)] { match self { Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; }, Self::freg => types! { _: F32, F64; }, - Self::vreg => types! { - vector: I32, F32, I64, F64, I128, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); - }, + Self::vreg => { + if allow_experimental_reg { + // non-clobber-only vector register support is unstable. + types! { + vector: I32, F32, I64, F64, I128, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + } + } else { + &[] + } + } Self::areg => &[], } } |
