about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-11-25 07:01:37 +0100
committerGitHub <noreply@github.com>2024-11-25 07:01:37 +0100
commit3f86eddf837191f61ab9ca203b5742278f98d758 (patch)
treea9d1ecc598cb4033263ae97e45ade1bd2f135744
parentc5230d1148995a30ad5fd56aacffe3576fc0e95f (diff)
parentc024d8ccdfb462f4e99b54e6c8456fbc4d745752 (diff)
downloadrust-3f86eddf837191f61ab9ca203b5742278f98d758.tar.gz
rust-3f86eddf837191f61ab9ca203b5742278f98d758.zip
Rollup merge of #131664 - taiki-e:s390x-asm-vreg-inout, r=Amanieu
Support input/output in vector registers of s390x inline assembly (under asm_experimental_reg feature)

This extends currently clobber-only vector registers (`vreg`) support to allow passing `#[repr(simd)]` types, floats (f32/f64/f128), and integers (i32/i64/i128) as input/output.

This is unstable and gated under new `#![feature(asm_experimental_reg)]` (tracking issue: https://github.com/rust-lang/rust/issues/133416). If the feature is not enabled, only clober is supported as before.

| Architecture | Register class | Target feature | Allowed types |
| ------------ | -------------- | -------------- | -------------- |
| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |

This matches the list of types that are supported by the vector registers in LLVM:
https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td#L301-L313

In addition to `core::simd` types and floats listed above, custom `#[repr(simd)]` types of the same size and type are also allowed. All allowed types other than i32/f32/i64/f64/i128, and relevant target features are currently unstable.

Currently there is no SIMD type for s390x in `core::arch`, but this is tracked in https://github.com/rust-lang/rust/issues/130869.

cc https://github.com/rust-lang/rust/issues/130869 about vector facility support in s390x
cc https://github.com/rust-lang/rust/issues/125398 & https://github.com/rust-lang/rust/issues/116909 about f128 support in asm

`@rustbot` label +O-SystemZ +A-inline-assembly
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl2
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs32
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs10
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl3
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs38
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs8
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs13
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs13
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-reg.md40
-rw-r--r--tests/assembly/asm/s390x-types.rs199
-rw-r--r--tests/auxiliary/minicore.rs1
-rw-r--r--tests/ui/asm/s390x/bad-reg.rs78
-rw-r--r--tests/ui/asm/s390x/bad-reg.s390x.stderr192
-rw-r--r--tests/ui/asm/s390x/bad-reg.s390x_vector.stderr328
-rw-r--r--tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr489
-rw-r--r--tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs23
-rw-r--r--tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr23
22 files changed, 1379 insertions, 143 deletions
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 93e1e25384e..a4dbf981115 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 520274278a1..ff803e50997 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
@@ -324,11 +326,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 70176754f33..7bc500b1814 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 6b067b35e71..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
@@ -683,9 +683,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
-            InlineAsmRegClass::S390x(
-                S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
-            ) => {
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
                 unreachable!("clobber-only")
             }
             InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
@@ -766,7 +765,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
         ) => cx.type_i32(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
-        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 07473190d6f..6ee80c08d4a 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
@@ -686,7 +686,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             S390x(S390xInlineAsmRegClass::reg) => "r",
             S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             S390x(S390xInlineAsmRegClass::freg) => "f",
-            S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+            S390x(S390xInlineAsmRegClass::vreg) => "v",
+            S390x(S390xInlineAsmRegClass::areg) => {
                 unreachable!("clobber-only")
             }
             Sparc(SparcInlineAsmRegClass::reg) => "r",
@@ -852,7 +853,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
         S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
         S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
-        S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+        S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
+        S390x(S390xInlineAsmRegClass::areg) => {
             unreachable!("clobber-only")
         }
         Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 6a231397615..aa2e451ef39 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 using `label` operands in inline assembly together with output operands.
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index f5ccf8c9dff..49b4a1fabec 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -431,6 +431,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 f5ca3c49475..0b2e9ed6052 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1708,3 +1708,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 0e4d937d6fd..46e245fb71f 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_goto_with_outputs,
         asm_sym,
@@ -2140,6 +2141,7 @@ symbols! {
         vec_pop,
         vec_with_capacity,
         vecdeque_iter,
+        vector,
         version,
         vfp2,
         vis,
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 9b31190a72b..410590b722b 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -38,11 +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 => &[],
+            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 => &[],
         }
     }
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md
new file mode 100644
index 00000000000..a251573d276
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md
@@ -0,0 +1,40 @@
+# `asm_experimental_arch`
+
+The tracking issue for this feature is: [#133416]
+
+[#133416]: https://github.com/rust-lang/rust/issues/133416
+
+------------------------
+
+This tracks support for additional registers in architectures where inline assembly is already stable.
+
+## Register classes
+
+| Architecture | Register class | Registers | LLVM constraint code |
+| ------------ | -------------- | --------- | -------------------- |
+| s390x | `vreg` | `v[0-31]` | `v` |
+
+> **Notes**:
+> - s390x `vreg` is clobber-only in stable.
+
+## Register class supported types
+
+| Architecture | Register class | Target feature | Allowed types |
+| ------------ | -------------- | -------------- | ------------- |
+| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
+
+## Register aliases
+
+| Architecture | Base register | Aliases |
+| ------------ | ------------- | ------- |
+
+## Unsupported registers
+
+| Architecture | Unsupported register | Reason |
+| ------------ | -------------------- | ------ |
+
+## Template modifiers
+
+| Architecture | Register class | Modifier | Example output | LLVM modifier |
+| ------------ | -------------- | -------- | -------------- | ------------- |
+| s390x | `vreg` | None | `%v0` | None |
diff --git a/tests/assembly/asm/s390x-types.rs b/tests/assembly/asm/s390x-types.rs
index b1522198a08..3da22d6c77b 100644
--- a/tests/assembly/asm/s390x-types.rs
+++ b/tests/assembly/asm/s390x-types.rs
@@ -1,10 +1,13 @@
-//@ revisions: s390x
+//@ revisions: s390x s390x_vector
 //@ assembly-output: emit-asm
 //@[s390x] compile-flags: --target s390x-unknown-linux-gnu
 //@[s390x] needs-llvm-components: systemz
+//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
+//@[s390x_vector] needs-llvm-components: systemz
 //@ compile-flags: -Zmerge-functions=disabled
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, f128)]
+#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
@@ -27,16 +30,39 @@ trait Sized {}
 #[lang = "copy"]
 trait Copy {}
 
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
 type ptr = *const i32;
 
+#[repr(simd)]
+pub struct i8x16([i8; 16]);
+#[repr(simd)]
+pub struct i16x8([i16; 8]);
+#[repr(simd)]
+pub struct i32x4([i32; 4]);
+#[repr(simd)]
+pub struct i64x2([i64; 2]);
+#[repr(simd)]
+pub struct f32x4([f32; 4]);
+#[repr(simd)]
+pub struct f64x2([f64; 2]);
+
 impl Copy for i8 {}
 impl Copy for u8 {}
 impl Copy for i16 {}
 impl Copy for i32 {}
 impl Copy for i64 {}
+impl Copy for i128 {}
 impl Copy for f32 {}
 impl Copy for f64 {}
+impl Copy for f128 {}
 impl Copy for ptr {}
+impl Copy for i8x16 {}
+impl Copy for i16x8 {}
+impl Copy for i32x4 {}
+impl Copy for i64x2 {}
+impl Copy for f32x4 {}
+impl Copy for f64x2 {}
 
 extern "C" {
     fn extern_func();
@@ -65,7 +91,6 @@ macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => {
 // CHECK: #APP
 // CHECK: brasl %r14, extern_func
 // CHECK: #NO_APP
-#[cfg(s390x)]
 #[no_mangle]
 pub unsafe fn sym_fn_32() {
     asm!("brasl %r14, {}", sym extern_func);
@@ -146,6 +171,90 @@ check!(reg_f64, f64, freg, "ldr");
 // CHECK: #NO_APP
 check!(reg_ptr, ptr, reg, "lgr");
 
+// s390x_vector-LABEL: vreg_i8x16:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i8x16, i8x16, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i16x8:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i16x8, i16x8, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i32x4:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i32x4, i32x4, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i64x2:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i64x2, i64x2, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_f32x4:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_f32x4, f32x4, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_f64x2:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_f64x2, f64x2, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i32:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i32, i32, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i64:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i64, i64, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_i128:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_i128, i128, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_f32:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_f32, f32, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_f64:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_f64, f64, vreg, "vlr");
+
+// s390x_vector-LABEL: vreg_f128:
+// s390x_vector: #APP
+// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}}
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check!(vreg_f128, f128, vreg, "vlr");
+
 // CHECK-LABEL: r0_i8:
 // CHECK: #APP
 // CHECK: lr %r0, %r0
@@ -181,3 +290,87 @@ check_reg!(f0_f32, f32, "f0", "ler");
 // CHECK: ldr %f0, %f0
 // CHECK: #NO_APP
 check_reg!(f0_f64, f64, "f0", "ldr");
+
+// s390x_vector-LABEL: v0_i8x16:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i8x16, i8x16, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i16x8:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i16x8, i16x8, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i32x4:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i32x4, i32x4, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i64x2:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i64x2, i64x2, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_f32x4:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_f32x4, f32x4, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_f64x2:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_f64x2, f64x2, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i32:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i32, i32, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i64:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i64, i64, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_i128:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_i128, i128, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_f32:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_f32, f32, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_f64:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_f64, f64, "v0", "vlr");
+
+// s390x_vector-LABEL: v0_f128:
+// s390x_vector: #APP
+// s390x_vector: vlr %v0, %v0
+// s390x_vector: #NO_APP
+#[cfg(s390x_vector)]
+check_reg!(v0_f128, f128, "v0", "vlr");
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 1e9f2ee59b4..c4317752920 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -45,6 +45,7 @@ impl_marker_trait!(
 impl<'a, T: ?Sized> Copy for &'a T {}
 impl<T: ?Sized> Copy for *const T {}
 impl<T: ?Sized> Copy for *mut T {}
+impl<T: Copy, const N: usize> Copy for [T; N] {}
 
 #[lang = "phantom_data"]
 pub struct PhantomData<T: ?Sized>;
diff --git a/tests/ui/asm/s390x/bad-reg.rs b/tests/ui/asm/s390x/bad-reg.rs
index 6de43fdfe5e..144215b1a3d 100644
--- a/tests/ui/asm/s390x/bad-reg.rs
+++ b/tests/ui/asm/s390x/bad-reg.rs
@@ -1,19 +1,31 @@
 //@ add-core-stubs
 //@ needs-asm-support
-//@ revisions: s390x
+//@ revisions: s390x s390x_vector s390x_vector_stable
 //@[s390x] compile-flags: --target s390x-unknown-linux-gnu
 //@[s390x] needs-llvm-components: systemz
+//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
+//@[s390x_vector] needs-llvm-components: systemz
+//@[s390x_vector_stable] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
+//@[s390x_vector_stable] needs-llvm-components: systemz
 
 #![crate_type = "rlib"]
-#![feature(no_core, rustc_attrs)]
-#![feature(asm_experimental_arch)]
+#![feature(no_core, rustc_attrs, repr_simd)]
+#![cfg_attr(not(s390x_vector_stable), feature(asm_experimental_reg))]
 #![no_core]
+#![allow(non_camel_case_types)]
 
 extern crate minicore;
 use minicore::*;
 
+#[repr(simd)]
+pub struct i64x2([i64; 2]);
+
+impl Copy for i64x2 {}
+
 fn f() {
     let mut x = 0;
+    let mut b = 0u8;
+    let mut v = i64x2([0; 2]);
     unsafe {
         // Unsupported registers
         asm!("", out("r11") _);
@@ -57,6 +69,51 @@ fn f() {
         asm!("", out("a1") _);
         //~^ ERROR invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
 
+        // vreg
+        asm!("", out("v0") _); // always ok
+        asm!("", in("v0") v); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
+        asm!("", out("v0") v); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
+        asm!("", in("v0") x); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
+        asm!("", out("v0") x); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
+        asm!("", in("v0") b);
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
+        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
+        asm!("", out("v0") b);
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
+        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
+        asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
+        asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
+        asm!("/* {} */", in(vreg) b);
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
+        //[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+        //[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
+        asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
+        //[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
+        //[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
+
         // Clobber-only registers
         // areg
         asm!("", out("a2") _); // ok
@@ -72,21 +129,6 @@ fn f() {
         asm!("/* {} */", out(areg) _);
         //~^ ERROR can only be used as a clobber
 
-        // vreg
-        asm!("", out("v0") _); // ok
-        // FIXME: will be supported in https://github.com/rust-lang/rust/pull/131664
-        asm!("", in("v0") x);
-        //~^ ERROR can only be used as a clobber
-        //~| ERROR type `i32` cannot be used with this register class
-        asm!("", out("v0") x);
-        //~^ ERROR can only be used as a clobber
-        //~| ERROR type `i32` cannot be used with this register class
-        asm!("/* {} */", in(vreg) x);
-        //~^ ERROR can only be used as a clobber
-        //~| ERROR type `i32` cannot be used with this register class
-        asm!("/* {} */", out(vreg) _);
-        //~^ ERROR can only be used as a clobber
-
         // Overlapping registers
         // vreg/freg
         asm!("", out("v0") _, out("f0") _);
diff --git a/tests/ui/asm/s390x/bad-reg.s390x.stderr b/tests/ui/asm/s390x/bad-reg.s390x.stderr
index 460d7c15de1..238419b376b 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x.stderr
@@ -1,173 +1,149 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:19:18
+  --> $DIR/bad-reg.rs:31:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:21:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:23:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:25:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:27:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:29:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:45:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:47:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:51:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:59:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:61:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:51:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:53:18
+  --> $DIR/bad-reg.rs:65:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:55:18
+  --> $DIR/bad-reg.rs:67:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:69:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:63:18
+  --> $DIR/bad-reg.rs:120:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:123:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:69:26
+  --> $DIR/bad-reg.rs:126:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:72:26
+  --> $DIR/bad-reg.rs:129:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
-error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:78:18
-   |
-LL |         asm!("", in("v0") x);
-   |                  ^^^^^^^^^^
-
-error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:81:18
-   |
-LL |         asm!("", out("v0") x);
-   |                  ^^^^^^^^^^^
-
-error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:84:26
-   |
-LL |         asm!("/* {} */", in(vreg) x);
-   |                          ^^^^^^^^^^
-
-error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:87:26
-   |
-LL |         asm!("/* {} */", out(vreg) _);
-   |                          ^^^^^^^^^^^
-
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:92:31
+  --> $DIR/bad-reg.rs:134:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -175,7 +151,7 @@ LL |         asm!("", out("v0") _, out("f0") _);
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:94:31
+  --> $DIR/bad-reg.rs:136:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -183,7 +159,7 @@ LL |         asm!("", out("v1") _, out("f1") _);
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:96:31
+  --> $DIR/bad-reg.rs:138:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -191,7 +167,7 @@ LL |         asm!("", out("v2") _, out("f2") _);
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:98:31
+  --> $DIR/bad-reg.rs:140:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -199,7 +175,7 @@ LL |         asm!("", out("v3") _, out("f3") _);
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:100:31
+  --> $DIR/bad-reg.rs:142:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -207,7 +183,7 @@ LL |         asm!("", out("v4") _, out("f4") _);
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:102:31
+  --> $DIR/bad-reg.rs:144:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -215,7 +191,7 @@ LL |         asm!("", out("v5") _, out("f5") _);
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:104:31
+  --> $DIR/bad-reg.rs:146:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -223,7 +199,7 @@ LL |         asm!("", out("v6") _, out("f6") _);
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:106:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -231,7 +207,7 @@ LL |         asm!("", out("v7") _, out("f7") _);
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:108:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -239,7 +215,7 @@ LL |         asm!("", out("v8") _, out("f8") _);
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:110:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -247,7 +223,7 @@ LL |         asm!("", out("v9") _, out("f9") _);
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:112:32
+  --> $DIR/bad-reg.rs:154:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -255,7 +231,7 @@ LL |         asm!("", out("v10") _, out("f10") _);
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:114:32
+  --> $DIR/bad-reg.rs:156:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -263,7 +239,7 @@ LL |         asm!("", out("v11") _, out("f11") _);
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:116:32
+  --> $DIR/bad-reg.rs:158:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -271,7 +247,7 @@ LL |         asm!("", out("v12") _, out("f12") _);
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:118:32
+  --> $DIR/bad-reg.rs:160:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -279,7 +255,7 @@ LL |         asm!("", out("v13") _, out("f13") _);
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:120:32
+  --> $DIR/bad-reg.rs:162:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -287,7 +263,7 @@ LL |         asm!("", out("v14") _, out("f14") _);
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:122:32
+  --> $DIR/bad-reg.rs:164:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -295,58 +271,94 @@ LL |         asm!("", out("v15") _, out("f15") _);
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:125:32
+  --> $DIR/bad-reg.rs:167:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:63:27
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:74:18
    |
-LL |         asm!("", in("a2") x);
-   |                           ^
+LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:78:18
    |
-   = note: register class `areg` supports these types: 
+LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^^
 
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:66:28
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:82:18
    |
-LL |         asm!("", out("a2") x);
-   |                            ^
+LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:86:18
    |
-   = note: register class `areg` supports these types: 
+LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^^
 
-error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:69:35
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:90:18
    |
-LL |         asm!("/* {} */", in(areg) x);
-   |                                   ^
+LL |         asm!("", in("v0") b);
+   |                  ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:95:18
    |
-   = note: register class `areg` supports these types: 
+LL |         asm!("", out("v0") b);
+   |                  ^^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:100:26
+   |
+LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:104:26
+   |
+LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:108:26
+   |
+LL |         asm!("/* {} */", in(vreg) b);
+   |                          ^^^^^^^^^^
+
+error: register class `vreg` requires the `vector` target feature
+  --> $DIR/bad-reg.rs:113:26
+   |
+LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:27
+  --> $DIR/bad-reg.rs:120:27
    |
-LL |         asm!("", in("v0") x);
+LL |         asm!("", in("a2") x);
    |                           ^
    |
-   = note: register class `vreg` supports these types: 
+   = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:81:28
+  --> $DIR/bad-reg.rs:123:28
    |
-LL |         asm!("", out("v0") x);
+LL |         asm!("", out("a2") x);
    |                            ^
    |
-   = note: register class `vreg` supports these types: 
+   = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:84:35
+  --> $DIR/bad-reg.rs:126:35
    |
-LL |         asm!("/* {} */", in(vreg) x);
+LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
    |
-   = note: register class `vreg` supports these types: 
+   = note: register class `areg` supports these types: 
 
-error: aborting due to 51 previous errors
+error: aborting due to 54 previous errors
 
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
new file mode 100644
index 00000000000..897f872ae72
--- /dev/null
+++ b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
@@ -0,0 +1,328 @@
+error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:31:18
+   |
+LL |         asm!("", out("r11") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:33:18
+   |
+LL |         asm!("", out("r15") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:35:18
+   |
+LL |         asm!("", out("c0") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:37:18
+   |
+LL |         asm!("", out("c1") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:39:18
+   |
+LL |         asm!("", out("c2") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:41:18
+   |
+LL |         asm!("", out("c3") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:43:18
+   |
+LL |         asm!("", out("c4") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:45:18
+   |
+LL |         asm!("", out("c5") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:47:18
+   |
+LL |         asm!("", out("c6") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:49:18
+   |
+LL |         asm!("", out("c7") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:51:18
+   |
+LL |         asm!("", out("c8") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:53:18
+   |
+LL |         asm!("", out("c9") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:55:18
+   |
+LL |         asm!("", out("c10") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:57:18
+   |
+LL |         asm!("", out("c11") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:59:18
+   |
+LL |         asm!("", out("c12") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:61:18
+   |
+LL |         asm!("", out("c13") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:63:18
+   |
+LL |         asm!("", out("c14") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:65:18
+   |
+LL |         asm!("", out("c15") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:67:18
+   |
+LL |         asm!("", out("a0") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:69:18
+   |
+LL |         asm!("", out("a1") _);
+   |                  ^^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:120:18
+   |
+LL |         asm!("", in("a2") x);
+   |                  ^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:123:18
+   |
+LL |         asm!("", out("a2") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:126:26
+   |
+LL |         asm!("/* {} */", in(areg) x);
+   |                          ^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:129:26
+   |
+LL |         asm!("/* {} */", out(areg) _);
+   |                          ^^^^^^^^^^^
+
+error: register `f0` conflicts with register `v0`
+  --> $DIR/bad-reg.rs:134:31
+   |
+LL |         asm!("", out("v0") _, out("f0") _);
+   |                  -----------  ^^^^^^^^^^^ register `f0`
+   |                  |
+   |                  register `v0`
+
+error: register `f1` conflicts with register `v1`
+  --> $DIR/bad-reg.rs:136:31
+   |
+LL |         asm!("", out("v1") _, out("f1") _);
+   |                  -----------  ^^^^^^^^^^^ register `f1`
+   |                  |
+   |                  register `v1`
+
+error: register `f2` conflicts with register `v2`
+  --> $DIR/bad-reg.rs:138:31
+   |
+LL |         asm!("", out("v2") _, out("f2") _);
+   |                  -----------  ^^^^^^^^^^^ register `f2`
+   |                  |
+   |                  register `v2`
+
+error: register `f3` conflicts with register `v3`
+  --> $DIR/bad-reg.rs:140:31
+   |
+LL |         asm!("", out("v3") _, out("f3") _);
+   |                  -----------  ^^^^^^^^^^^ register `f3`
+   |                  |
+   |                  register `v3`
+
+error: register `f4` conflicts with register `v4`
+  --> $DIR/bad-reg.rs:142:31
+   |
+LL |         asm!("", out("v4") _, out("f4") _);
+   |                  -----------  ^^^^^^^^^^^ register `f4`
+   |                  |
+   |                  register `v4`
+
+error: register `f5` conflicts with register `v5`
+  --> $DIR/bad-reg.rs:144:31
+   |
+LL |         asm!("", out("v5") _, out("f5") _);
+   |                  -----------  ^^^^^^^^^^^ register `f5`
+   |                  |
+   |                  register `v5`
+
+error: register `f6` conflicts with register `v6`
+  --> $DIR/bad-reg.rs:146:31
+   |
+LL |         asm!("", out("v6") _, out("f6") _);
+   |                  -----------  ^^^^^^^^^^^ register `f6`
+   |                  |
+   |                  register `v6`
+
+error: register `f7` conflicts with register `v7`
+  --> $DIR/bad-reg.rs:148:31
+   |
+LL |         asm!("", out("v7") _, out("f7") _);
+   |                  -----------  ^^^^^^^^^^^ register `f7`
+   |                  |
+   |                  register `v7`
+
+error: register `f8` conflicts with register `v8`
+  --> $DIR/bad-reg.rs:150:31
+   |
+LL |         asm!("", out("v8") _, out("f8") _);
+   |                  -----------  ^^^^^^^^^^^ register `f8`
+   |                  |
+   |                  register `v8`
+
+error: register `f9` conflicts with register `v9`
+  --> $DIR/bad-reg.rs:152:31
+   |
+LL |         asm!("", out("v9") _, out("f9") _);
+   |                  -----------  ^^^^^^^^^^^ register `f9`
+   |                  |
+   |                  register `v9`
+
+error: register `f10` conflicts with register `v10`
+  --> $DIR/bad-reg.rs:154:32
+   |
+LL |         asm!("", out("v10") _, out("f10") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f10`
+   |                  |
+   |                  register `v10`
+
+error: register `f11` conflicts with register `v11`
+  --> $DIR/bad-reg.rs:156:32
+   |
+LL |         asm!("", out("v11") _, out("f11") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f11`
+   |                  |
+   |                  register `v11`
+
+error: register `f12` conflicts with register `v12`
+  --> $DIR/bad-reg.rs:158:32
+   |
+LL |         asm!("", out("v12") _, out("f12") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f12`
+   |                  |
+   |                  register `v12`
+
+error: register `f13` conflicts with register `v13`
+  --> $DIR/bad-reg.rs:160:32
+   |
+LL |         asm!("", out("v13") _, out("f13") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f13`
+   |                  |
+   |                  register `v13`
+
+error: register `f14` conflicts with register `v14`
+  --> $DIR/bad-reg.rs:162:32
+   |
+LL |         asm!("", out("v14") _, out("f14") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f14`
+   |                  |
+   |                  register `v14`
+
+error: register `f15` conflicts with register `v15`
+  --> $DIR/bad-reg.rs:164:32
+   |
+LL |         asm!("", out("v15") _, out("f15") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f15`
+   |                  |
+   |                  register `v15`
+
+error: invalid register `f16`: unknown register
+  --> $DIR/bad-reg.rs:167:32
+   |
+LL |         asm!("", out("v16") _, out("f16") _);
+   |                                ^^^^^^^^^^^^
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:90:27
+   |
+LL |         asm!("", in("v0") b);
+   |                           ^
+   |
+   = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:95:28
+   |
+LL |         asm!("", out("v0") b);
+   |                            ^
+   |
+   = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:108:35
+   |
+LL |         asm!("/* {} */", in(vreg) b);
+   |                                   ^
+   |
+   = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:120:27
+   |
+LL |         asm!("", in("a2") x);
+   |                           ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:123:28
+   |
+LL |         asm!("", out("a2") x);
+   |                            ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:126:35
+   |
+LL |         asm!("/* {} */", in(areg) x);
+   |                                   ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: aborting due to 47 previous errors
+
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
new file mode 100644
index 00000000000..e2b3eeef4e9
--- /dev/null
+++ b/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
@@ -0,0 +1,489 @@
+error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:31:18
+   |
+LL |         asm!("", out("r11") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:33:18
+   |
+LL |         asm!("", out("r15") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:35:18
+   |
+LL |         asm!("", out("c0") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:37:18
+   |
+LL |         asm!("", out("c1") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:39:18
+   |
+LL |         asm!("", out("c2") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:41:18
+   |
+LL |         asm!("", out("c3") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:43:18
+   |
+LL |         asm!("", out("c4") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:45:18
+   |
+LL |         asm!("", out("c5") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:47:18
+   |
+LL |         asm!("", out("c6") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:49:18
+   |
+LL |         asm!("", out("c7") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:51:18
+   |
+LL |         asm!("", out("c8") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:53:18
+   |
+LL |         asm!("", out("c9") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:55:18
+   |
+LL |         asm!("", out("c10") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:57:18
+   |
+LL |         asm!("", out("c11") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:59:18
+   |
+LL |         asm!("", out("c12") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:61:18
+   |
+LL |         asm!("", out("c13") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:63:18
+   |
+LL |         asm!("", out("c14") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:65:18
+   |
+LL |         asm!("", out("c15") _);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:67:18
+   |
+LL |         asm!("", out("a0") _);
+   |                  ^^^^^^^^^^^
+
+error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
+  --> $DIR/bad-reg.rs:69:18
+   |
+LL |         asm!("", out("a1") _);
+   |                  ^^^^^^^^^^^
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:74:18
+   |
+LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:78:18
+   |
+LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:82:18
+   |
+LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:86:18
+   |
+LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
+   |                  ^^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:90:18
+   |
+LL |         asm!("", in("v0") b);
+   |                  ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:95:18
+   |
+LL |         asm!("", out("v0") b);
+   |                  ^^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:100:26
+   |
+LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:104:26
+   |
+LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:108:26
+   |
+LL |         asm!("/* {} */", in(vreg) b);
+   |                          ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/bad-reg.rs:113:26
+   |
+LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
+   |                          ^^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:120:18
+   |
+LL |         asm!("", in("a2") x);
+   |                  ^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:123:18
+   |
+LL |         asm!("", out("a2") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:126:26
+   |
+LL |         asm!("/* {} */", in(areg) x);
+   |                          ^^^^^^^^^^
+
+error: register class `areg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:129:26
+   |
+LL |         asm!("/* {} */", out(areg) _);
+   |                          ^^^^^^^^^^^
+
+error: register `f0` conflicts with register `v0`
+  --> $DIR/bad-reg.rs:134:31
+   |
+LL |         asm!("", out("v0") _, out("f0") _);
+   |                  -----------  ^^^^^^^^^^^ register `f0`
+   |                  |
+   |                  register `v0`
+
+error: register `f1` conflicts with register `v1`
+  --> $DIR/bad-reg.rs:136:31
+   |
+LL |         asm!("", out("v1") _, out("f1") _);
+   |                  -----------  ^^^^^^^^^^^ register `f1`
+   |                  |
+   |                  register `v1`
+
+error: register `f2` conflicts with register `v2`
+  --> $DIR/bad-reg.rs:138:31
+   |
+LL |         asm!("", out("v2") _, out("f2") _);
+   |                  -----------  ^^^^^^^^^^^ register `f2`
+   |                  |
+   |                  register `v2`
+
+error: register `f3` conflicts with register `v3`
+  --> $DIR/bad-reg.rs:140:31
+   |
+LL |         asm!("", out("v3") _, out("f3") _);
+   |                  -----------  ^^^^^^^^^^^ register `f3`
+   |                  |
+   |                  register `v3`
+
+error: register `f4` conflicts with register `v4`
+  --> $DIR/bad-reg.rs:142:31
+   |
+LL |         asm!("", out("v4") _, out("f4") _);
+   |                  -----------  ^^^^^^^^^^^ register `f4`
+   |                  |
+   |                  register `v4`
+
+error: register `f5` conflicts with register `v5`
+  --> $DIR/bad-reg.rs:144:31
+   |
+LL |         asm!("", out("v5") _, out("f5") _);
+   |                  -----------  ^^^^^^^^^^^ register `f5`
+   |                  |
+   |                  register `v5`
+
+error: register `f6` conflicts with register `v6`
+  --> $DIR/bad-reg.rs:146:31
+   |
+LL |         asm!("", out("v6") _, out("f6") _);
+   |                  -----------  ^^^^^^^^^^^ register `f6`
+   |                  |
+   |                  register `v6`
+
+error: register `f7` conflicts with register `v7`
+  --> $DIR/bad-reg.rs:148:31
+   |
+LL |         asm!("", out("v7") _, out("f7") _);
+   |                  -----------  ^^^^^^^^^^^ register `f7`
+   |                  |
+   |                  register `v7`
+
+error: register `f8` conflicts with register `v8`
+  --> $DIR/bad-reg.rs:150:31
+   |
+LL |         asm!("", out("v8") _, out("f8") _);
+   |                  -----------  ^^^^^^^^^^^ register `f8`
+   |                  |
+   |                  register `v8`
+
+error: register `f9` conflicts with register `v9`
+  --> $DIR/bad-reg.rs:152:31
+   |
+LL |         asm!("", out("v9") _, out("f9") _);
+   |                  -----------  ^^^^^^^^^^^ register `f9`
+   |                  |
+   |                  register `v9`
+
+error: register `f10` conflicts with register `v10`
+  --> $DIR/bad-reg.rs:154:32
+   |
+LL |         asm!("", out("v10") _, out("f10") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f10`
+   |                  |
+   |                  register `v10`
+
+error: register `f11` conflicts with register `v11`
+  --> $DIR/bad-reg.rs:156:32
+   |
+LL |         asm!("", out("v11") _, out("f11") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f11`
+   |                  |
+   |                  register `v11`
+
+error: register `f12` conflicts with register `v12`
+  --> $DIR/bad-reg.rs:158:32
+   |
+LL |         asm!("", out("v12") _, out("f12") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f12`
+   |                  |
+   |                  register `v12`
+
+error: register `f13` conflicts with register `v13`
+  --> $DIR/bad-reg.rs:160:32
+   |
+LL |         asm!("", out("v13") _, out("f13") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f13`
+   |                  |
+   |                  register `v13`
+
+error: register `f14` conflicts with register `v14`
+  --> $DIR/bad-reg.rs:162:32
+   |
+LL |         asm!("", out("v14") _, out("f14") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f14`
+   |                  |
+   |                  register `v14`
+
+error: register `f15` conflicts with register `v15`
+  --> $DIR/bad-reg.rs:164:32
+   |
+LL |         asm!("", out("v15") _, out("f15") _);
+   |                  ------------  ^^^^^^^^^^^^ register `f15`
+   |                  |
+   |                  register `v15`
+
+error: invalid register `f16`: unknown register
+  --> $DIR/bad-reg.rs:167:32
+   |
+LL |         asm!("", out("v16") _, out("f16") _);
+   |                                ^^^^^^^^^^^^
+
+error[E0658]: type `i64x2` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:74:27
+   |
+LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
+   |                           ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: type `i64x2` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:78:28
+   |
+LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
+   |                            ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: type `i32` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:82:27
+   |
+LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
+   |                           ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: type `i32` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:86:28
+   |
+LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
+   |                            ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:90:27
+   |
+LL |         asm!("", in("v0") b);
+   |                           ^
+   |
+   = note: register class `vreg` supports these types: 
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:95:28
+   |
+LL |         asm!("", out("v0") b);
+   |                            ^
+   |
+   = note: register class `vreg` supports these types: 
+
+error[E0658]: type `i64x2` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:100:35
+   |
+LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
+   |                                   ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: type `i32` cannot be used with this register class in stable
+  --> $DIR/bad-reg.rs:104:35
+   |
+LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
+   |                                   ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/bad-reg.rs:108:35
+   |
+LL |         asm!("/* {} */", in(vreg) b);
+   |                                   ^
+   |
+   = note: register class `vreg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:120:27
+   |
+LL |         asm!("", in("a2") x);
+   |                           ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:123:28
+   |
+LL |         asm!("", out("a2") x);
+   |                            ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:126:35
+   |
+LL |         asm!("/* {} */", in(areg) x);
+   |                                   ^
+   |
+   = note: register class `areg` supports these types: 
+
+error: aborting due to 63 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
new file mode 100644
index 00000000000..7aec7455b2e
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
@@ -0,0 +1,23 @@
+//@ needs-asm-support
+//@ compile-flags: --target s390x-unknown-linux-gnu
+//@ needs-llvm-components: systemz
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+unsafe fn main() {
+    asm!("", in("v0") 0);
+    //~^ ERROR register class `vreg` can only be used as a clobber in stable
+    //~| ERROR type `i32` cannot be used with this register class
+}
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
new file mode 100644
index 00000000000..0791ce4543c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
@@ -0,0 +1,23 @@
+error[E0658]: register class `vreg` can only be used as a clobber in stable
+  --> $DIR/feature-gate-asm_experimental_reg.rs:20:14
+   |
+LL |     asm!("", in("v0") 0);
+   |              ^^^^^^^^^^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: type `i32` cannot be used with this register class in stable
+  --> $DIR/feature-gate-asm_experimental_reg.rs:20:23
+   |
+LL |     asm!("", in("v0") 0);
+   |                       ^
+   |
+   = note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
+   = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.