about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-04-29 00:45:58 +0100
committerAmanieu d'Antras <amanieu@gmail.com>2020-05-18 14:41:32 +0100
commit7dfa486d4a18b7a6e514e589771f52c43eff4f3b (patch)
tree6e9ac7f1c742cc946353074a940341798f47e681
parent93e2946d0c0cccd69ee03390adca7ec4f71a2113 (diff)
downloadrust-7dfa486d4a18b7a6e514e589771f52c43eff4f3b.tar.gz
rust-7dfa486d4a18b7a6e514e589771f52c43eff4f3b.zip
Add support for high byte registers on x86
-rw-r--r--src/librustc_codegen_llvm/asm.rs3
-rw-r--r--src/librustc_passes/intrinsicck.rs24
-rw-r--r--src/librustc_target/asm/aarch64.rs18
-rw-r--r--src/librustc_target/asm/arm.rs6
-rw-r--r--src/librustc_target/asm/mod.rs17
-rw-r--r--src/librustc_target/asm/riscv.rs6
-rw-r--r--src/librustc_target/asm/x86.rs141
-rw-r--r--src/test/assembly/asm/x86-types.rs20
-rw-r--r--src/test/ui/asm/bad-reg.rs4
-rw-r--r--src/test/ui/asm/bad-reg.stderr36
-rw-r--r--src/test/ui/asm/type-check-3.rs15
-rw-r--r--src/test/ui/asm/type-check-3.stderr31
12 files changed, 198 insertions, 123 deletions
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 21322511c99..20abfbcf405 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -409,6 +409,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
             InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "r",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
             | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
@@ -459,6 +460,7 @@ fn modifier_to_llvm(
             Some('r') => Some('q'),
             _ => unreachable!(),
         },
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None,
         InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg)
         | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg)
         | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) {
@@ -499,6 +501,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
index b98ed99d04e..9e144f86cd8 100644
--- a/src/librustc_passes/intrinsicck.rs
+++ b/src/librustc_passes/intrinsicck.rs
@@ -268,6 +268,12 @@ impl ExprVisitor<'tcx> {
                     reg_class.name(),
                     supported_tys.join(", "),
                 ));
+                if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
+                    err.help(&format!(
+                        "consider using the `{}` register class instead",
+                        suggest.name()
+                    ));
+                }
                 err.emit();
                 return Some(asm_ty);
             }
@@ -298,7 +304,7 @@ impl ExprVisitor<'tcx> {
         }
 
         // Check whether a modifier is suggested for using this type.
-        if let Some((suggested_modifier, suggested_result, switch_reg_class)) =
+        if let Some((suggested_modifier, suggested_result)) =
             reg_class.suggest_modifier(asm_arch, asm_ty)
         {
             // Search for any use of this operand without a modifier and emit
@@ -323,18 +329,10 @@ impl ExprVisitor<'tcx> {
                         let msg = "formatting may not be suitable for sub-register argument";
                         let mut err = lint.build(msg);
                         err.span_label(expr.span, "for this argument");
-                        if let Some(switch_reg_class) = switch_reg_class {
-                            err.help(&format!(
-                                "use the `{}` modifier with the `{}` register class \
-                                 to have the register formatted as `{}`",
-                                suggested_modifier, switch_reg_class, suggested_result,
-                            ));
-                        } else {
-                            err.help(&format!(
-                                "use the `{}` modifier to have the register formatted as `{}`",
-                                suggested_modifier, suggested_result,
-                            ));
-                        }
+                        err.help(&format!(
+                            "use the `{}` modifier to have the register formatted as `{}`",
+                            suggested_modifier, suggested_result,
+                        ));
                         err.help(&format!(
                             "or use the `{}` modifier to keep the default formatting of `{}`",
                             default_modifier, default_result,
diff --git a/src/librustc_target/asm/aarch64.rs b/src/librustc_target/asm/aarch64.rs
index 16bc5d670d8..e7c9edea765 100644
--- a/src/librustc_target/asm/aarch64.rs
+++ b/src/librustc_target/asm/aarch64.rs
@@ -18,22 +18,26 @@ impl AArch64InlineAsmRegClass {
         }
     }
 
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
     pub fn suggest_modifier(
         self,
         _arch: InlineAsmArch,
         ty: InlineAsmType,
-    ) -> Option<(char, &'static str, Option<&'static str>)> {
+    ) -> Option<(char, &'static str)> {
         match self {
             Self::reg => match ty.size().bits() {
                 64 => None,
-                _ => Some(('w', "w0", None)),
+                _ => Some(('w', "w0")),
             },
             Self::vreg | Self::vreg_low16 => match ty.size().bits() {
-                8 => Some(('b', "b0", None)),
-                16 => Some(('h', "h0", None)),
-                32 => Some(('s', "s0", None)),
-                64 => Some(('d', "d0", None)),
-                128 => Some(('q', "q0", None)),
+                8 => Some(('b', "b0")),
+                16 => Some(('h', "h0")),
+                32 => Some(('s', "s0")),
+                64 => Some(('d', "d0")),
+                128 => Some(('q', "q0")),
                 _ => None,
             },
         }
diff --git a/src/librustc_target/asm/arm.rs b/src/librustc_target/asm/arm.rs
index 0ceb15e297f..1798b2a0949 100644
--- a/src/librustc_target/asm/arm.rs
+++ b/src/librustc_target/asm/arm.rs
@@ -25,11 +25,15 @@ impl ArmInlineAsmRegClass {
         }
     }
 
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
     pub fn suggest_modifier(
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str, Option<&'static str>)> {
+    ) -> Option<(char, &'static str)> {
         None
     }
 
diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs
index dda6e7cd5cd..f1e8457cacc 100644
--- a/src/librustc_target/asm/mod.rs
+++ b/src/librustc_target/asm/mod.rs
@@ -291,9 +291,20 @@ impl InlineAsmRegClass {
         }
     }
 
+    /// Returns a suggested register class to use for this type. This is called
+    /// after type checking via `supported_types` fails to give a better error
+    /// message to the user.
+    pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
+        match self {
+            Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
+            Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
+            Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
+            Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
+        }
+    }
+
     /// Returns a suggested template modifier to use for this type and an
-    /// example of a  register named formatted with it. Optionally also returns
-    /// the name of a different register class to use instead.
+    /// example of a  register named formatted with it.
     ///
     /// Such suggestions are useful if a type smaller than the full register
     /// size is used and a modifier can be used to point to the subregister of
@@ -302,7 +313,7 @@ impl InlineAsmRegClass {
         self,
         arch: InlineAsmArch,
         ty: InlineAsmType,
-    ) -> Option<(char, &'static str, Option<&'static str>)> {
+    ) -> Option<(char, &'static str)> {
         match self {
             Self::X86(r) => r.suggest_modifier(arch, ty),
             Self::Arm(r) => r.suggest_modifier(arch, ty),
diff --git a/src/librustc_target/asm/riscv.rs b/src/librustc_target/asm/riscv.rs
index f9b132c2087..7da30cc8875 100644
--- a/src/librustc_target/asm/riscv.rs
+++ b/src/librustc_target/asm/riscv.rs
@@ -14,11 +14,15 @@ impl RiscVInlineAsmRegClass {
         &[]
     }
 
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
     pub fn suggest_modifier(
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str, Option<&'static str>)> {
+    ) -> Option<(char, &'static str)> {
         None
     }
 
diff --git a/src/librustc_target/asm/x86.rs b/src/librustc_target/asm/x86.rs
index d10bcb40ba0..6eb99b0180f 100644
--- a/src/librustc_target/asm/x86.rs
+++ b/src/librustc_target/asm/x86.rs
@@ -6,6 +6,7 @@ def_reg_class! {
     X86 X86InlineAsmRegClass {
         reg,
         reg_abcd,
+        reg_byte,
         xmm_reg,
         ymm_reg,
         zmm_reg,
@@ -30,46 +31,45 @@ impl X86InlineAsmRegClass {
                     &['l', 'h', 'x', 'e']
                 }
             }
+            Self::reg_byte => &[],
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
             Self::kreg => &[],
         }
     }
 
+    pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
+        match self {
+            Self::reg | Self::reg_abcd if ty.size().bits() == 8 => Some(Self::reg_byte),
+            _ => None,
+        }
+    }
+
     pub fn suggest_modifier(
         self,
         arch: InlineAsmArch,
         ty: InlineAsmType,
-    ) -> Option<(char, &'static str, Option<&'static str>)> {
+    ) -> Option<(char, &'static str)> {
         match self {
             Self::reg => match ty.size().bits() {
-                8 => {
-                    if arch == InlineAsmArch::X86_64 {
-                        Some(('l', "al", None))
-                    } else {
-                        // Low byte registers require reg_abcd on x86 so we emit
-                        // a suggestion to use that register class instead.
-                        Some(('l', "al", Some("reg_abcd")))
-                    }
-                }
-                16 => Some(('x', "ax", None)),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)),
+                16 => Some(('x', "ax")),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
                 _ => None,
             },
             Self::reg_abcd => match ty.size().bits() {
-                8 => Some(('l', "al", None)),
-                16 => Some(('x', "ax", None)),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)),
+                16 => Some(('x', "ax")),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
                 _ => None,
             },
+            Self::reg_byte => None,
             Self::xmm_reg => None,
             Self::ymm_reg => match ty.size().bits() {
                 256 => None,
-                _ => Some(('x', "xmm0", None)),
+                _ => Some(('x', "xmm0")),
             },
             Self::zmm_reg => match ty.size().bits() {
                 512 => None,
-                256 => Some(('y', "ymm0", None)),
-                _ => Some(('x', "xmm0", None)),
+                256 => Some(('y', "ymm0")),
+                _ => Some(('x', "xmm0")),
             },
             Self::kreg => None,
         }
@@ -84,6 +84,7 @@ impl X86InlineAsmRegClass {
                     Some(('e', "eax"))
                 }
             }
+            Self::reg_byte => None,
             Self::xmm_reg => Some(('x', "xmm0")),
             Self::ymm_reg => Some(('y', "ymm0")),
             Self::zmm_reg => Some(('z', "zmm0")),
@@ -98,11 +99,12 @@ impl X86InlineAsmRegClass {
         match self {
             Self::reg | Self::reg_abcd => {
                 if arch == InlineAsmArch::X86_64 {
-                    types! { _: I8, I16, I32, I64, F32, F64; }
+                    types! { _: I16, I32, I64, F32, F64; }
                 } else {
-                    types! { _: I8, I16, I32, F32; }
+                    types! { _: I16, I32, F32; }
                 }
             }
+            Self::reg_byte => types! { _: I8; },
             Self::xmm_reg => types! {
                 "sse": I32, I64, F32, F64,
                   VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
@@ -139,20 +141,38 @@ fn x86_64_only(
 
 def_regs! {
     X86 X86InlineAsmReg X86InlineAsmRegClass {
-        ax: reg, reg_abcd = ["ax", "al", "eax", "rax"],
-        bx: reg, reg_abcd = ["bx", "bl", "ebx", "rbx"],
-        cx: reg, reg_abcd = ["cx", "cl", "ecx", "rcx"],
-        dx: reg, reg_abcd = ["dx", "dl", "edx", "rdx"],
-        si: reg = ["si", "sil", "esi", "rsi"],
-        di: reg = ["di", "dil", "edi", "rdi"],
-        r8: reg = ["r8", "r8b", "r8w", "r8d"] % x86_64_only,
-        r9: reg = ["r9", "r9b", "r9w", "r9d"] % x86_64_only,
-        r10: reg = ["r10", "r10b", "r10w", "r10d"] % x86_64_only,
-        r11: reg = ["r11", "r11b", "r11w", "r11d"] % x86_64_only,
-        r12: reg = ["r12", "r12b", "r12w", "r12d"] % x86_64_only,
-        r13: reg = ["r13", "r13b", "r13w", "r13d"] % x86_64_only,
-        r14: reg = ["r14", "r14b", "r14w", "r14d"] % x86_64_only,
-        r15: reg = ["r15", "r15b", "r15w", "r15d"] % x86_64_only,
+        ax: reg, reg_abcd = ["ax", "eax", "rax"],
+        bx: reg, reg_abcd = ["bx", "ebx", "rbx"],
+        cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
+        dx: reg, reg_abcd = ["dx", "edx", "rdx"],
+        si: reg = ["si", "esi", "rsi"],
+        di: reg = ["di", "edi", "rdi"],
+        r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
+        r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
+        r10: reg = ["r10", "r10w", "r10d"] % x86_64_only,
+        r11: reg = ["r11", "r11w", "r11d"] % x86_64_only,
+        r12: reg = ["r12", "r12w", "r12d"] % x86_64_only,
+        r13: reg = ["r13", "r13w", "r13d"] % x86_64_only,
+        r14: reg = ["r14", "r14w", "r14d"] % x86_64_only,
+        r15: reg = ["r15", "r15w", "r15d"] % x86_64_only,
+        al: reg_byte = ["al"],
+        ah: reg_byte = ["ah"],
+        bl: reg_byte = ["bl"],
+        bh: reg_byte = ["bh"],
+        cl: reg_byte = ["cl"],
+        ch: reg_byte = ["ch"],
+        dl: reg_byte = ["dl"],
+        dh: reg_byte = ["dh"],
+        sil: reg_byte = ["sil"] % x86_64_only,
+        dil: reg_byte = ["dil"] % x86_64_only,
+        r8b: reg_byte = ["r8b"] % x86_64_only,
+        r9b: reg_byte = ["r9b"] % x86_64_only,
+        r10b: reg_byte = ["r10b"] % x86_64_only,
+        r11b: reg_byte = ["r11b"] % x86_64_only,
+        r12b: reg_byte = ["r12b"] % x86_64_only,
+        r13b: reg_byte = ["r13b"] % x86_64_only,
+        r14b: reg_byte = ["r14b"] % x86_64_only,
+        r15b: reg_byte = ["r15b"] % x86_64_only,
         xmm0: xmm_reg = ["xmm0"],
         xmm1: xmm_reg = ["xmm1"],
         xmm2: xmm_reg = ["xmm2"],
@@ -224,8 +244,6 @@ def_regs! {
         k5: kreg = ["k5"],
         k6: kreg = ["k6"],
         k7: kreg = ["k7"],
-        #error = ["ah", "bh", "ch", "dh"] =>
-            "high byte registers are not currently supported as operands for inline asm",
         #error = ["bp", "bpl", "ebp", "rbp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "spl", "esp", "rsp"] =>
@@ -281,6 +299,8 @@ impl X86InlineAsmReg {
                 'r' => write!(out, "r{}", index),
                 _ => unreachable!(),
             }
+        } else if self as u32 <= Self::r15b as u32 {
+            out.write_str(self.name())
         } else if self as u32 <= Self::xmm15 as u32 {
             let prefix = modifier.unwrap_or('x');
             let index = self as u32 - Self::xmm0 as u32;
@@ -301,9 +321,40 @@ impl X86InlineAsmReg {
 
     pub fn overlapping_regs(self, mut cb: impl FnMut(X86InlineAsmReg)) {
         macro_rules! reg_conflicts {
-            ($($x:ident : $y:ident : $z:ident,)*) => {
+            (
+                $(
+                    $w:ident : $l:ident $h:ident
+                ),*;
+                $(
+                    $w2:ident : $l2:ident
+                ),*;
+                $(
+                    $x:ident : $y:ident : $z:ident
+                ),*;
+            ) => {
                 match self {
                     $(
+                        Self::$w => {
+                            cb(Self::$w);
+                            cb(Self::$l);
+                            cb(Self::$h);
+                        }
+                        Self::$l => {
+                            cb(Self::$w);
+                            cb(Self::$l);
+                        }
+                        Self::$h => {
+                            cb(Self::$w);
+                            cb(Self::$h);
+                        }
+                    )*
+                    $(
+                        Self::$w2 | Self::$l2 => {
+                            cb(Self::$w2);
+                            cb(Self::$l2);
+                        }
+                    )*
+                    $(
                         Self::$x | Self::$y | Self::$z => {
                             cb(Self::$x);
                             cb(Self::$y);
@@ -324,6 +375,20 @@ impl X86InlineAsmReg {
         // registers are only available with AVX-512, so we just specify them
         // as aliases directly.
         reg_conflicts! {
+            ax : al ah,
+            bx : bl bh,
+            cx : cl ch,
+            dx : dl dh;
+            si : sil,
+            di : dil,
+            r8 : r8b,
+            r9 : r9b,
+            r10 : r10b,
+            r11 : r11b,
+            r12 : r12b,
+            r13 : r13b,
+            r14 : r14b,
+            r15 : r15b;
             xmm0 : ymm0 : zmm0,
             xmm1 : ymm1 : zmm1,
             xmm2 : ymm2 : zmm2,
@@ -339,7 +404,7 @@ impl X86InlineAsmReg {
             xmm12 : ymm12 : zmm12,
             xmm13 : ymm13 : zmm13,
             xmm14 : ymm14 : zmm14,
-            xmm15 : ymm15 : zmm15,
+            xmm15 : ymm15 : zmm15;
         }
     }
 }
diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs
index d2819ac88e7..508d6801580 100644
--- a/src/test/assembly/asm/x86-types.rs
+++ b/src/test/assembly/asm/x86-types.rs
@@ -266,13 +266,6 @@ macro_rules! check {
     };
 }
 
-// CHECK-LABEL: reg_i8:
-// CHECK: #APP
-// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}}
-// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}}
-// CHECK: #NO_APP
-check!(reg_i8 i8 reg "mov");
-
 // CHECK-LABEL: reg_i16:
 // CHECK: #APP
 // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}}
@@ -315,13 +308,6 @@ check!(reg_f64 f64 reg "mov");
 // CHECK: #NO_APP
 check!(reg_ptr ptr reg "mov");
 
-// CHECK-LABEL: reg_abcd_i8:
-// CHECK: #APP
-// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}}
-// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}}
-// CHECK: #NO_APP
-check!(reg_abcd_i8 i8 reg_abcd "mov");
-
 // CHECK-LABEL: reg_abcd_i16:
 // CHECK: #APP
 // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}}
@@ -364,6 +350,12 @@ check!(reg_abcd_f64 f64 reg_abcd "mov");
 // CHECK: #NO_APP
 check!(reg_abcd_ptr ptr reg_abcd "mov");
 
+// CHECK-LABEL: reg_byte:
+// CHECK: #APP
+// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_byte i8 reg_byte "mov");
+
 // CHECK-LABEL: xmm_reg_i32:
 // CHECK: #APP
 // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}}
diff --git a/src/test/ui/asm/bad-reg.rs b/src/test/ui/asm/bad-reg.rs
index ed7faa4b156..016ea9329c4 100644
--- a/src/test/ui/asm/bad-reg.rs
+++ b/src/test/ui/asm/bad-reg.rs
@@ -25,8 +25,6 @@ fn main() {
         //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
         asm!("", in("zmm0") foo);
         //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
-        asm!("", in("ah") foo);
-        //~^ ERROR invalid register `ah`: high byte registers are not currently supported
         asm!("", in("ebp") foo);
         //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand
         asm!("", in("rsp") foo);
@@ -44,7 +42,7 @@ fn main() {
         // (except in/lateout which don't conflict)
 
         asm!("", in("eax") foo, in("al") bar);
-        //~^ ERROR register `ax` conflicts with register `ax`
+        //~^ ERROR register `al` conflicts with register `ax`
         asm!("", in("rax") foo, out("rax") bar);
         //~^ ERROR register `ax` conflicts with register `ax`
         asm!("", in("al") foo, lateout("al") bar);
diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/bad-reg.stderr
index a9d872dae41..a1423f0e9c1 100644
--- a/src/test/ui/asm/bad-reg.stderr
+++ b/src/test/ui/asm/bad-reg.stderr
@@ -58,58 +58,52 @@ error: register class `zmm_reg` requires the `avx512f` target feature
 LL |         asm!("", in("zmm0") foo);
    |                  ^^^^^^^^^^^^^^
 
-error: invalid register `ah`: high byte registers are not currently supported as operands for inline asm
-  --> $DIR/bad-reg.rs:28:18
-   |
-LL |         asm!("", in("ah") foo);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:30:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", in("ebp") foo);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", in("rsp") foo);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", in("ip") foo);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `st(2)`: x87 registers are not currently supported as operands for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", in("st(2)") foo);
    |                  ^^^^^^^^^^^^^^^
 
 error: invalid register `mm0`: MMX registers are not currently supported as operands for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", in("mm0") foo);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", in("k0") foo);
    |                  ^^^^^^^^^^^^
 
-error: register `ax` conflicts with register `ax`
-  --> $DIR/bad-reg.rs:46:33
+error: register `al` conflicts with register `ax`
+  --> $DIR/bad-reg.rs:44:33
    |
 LL |         asm!("", in("eax") foo, in("al") bar);
-   |                  -------------  ^^^^^^^^^^^^ register `ax`
+   |                  -------------  ^^^^^^^^^^^^ register `al`
    |                  |
    |                  register `ax`
 
 error: register `ax` conflicts with register `ax`
-  --> $DIR/bad-reg.rs:48:33
+  --> $DIR/bad-reg.rs:46:33
    |
 LL |         asm!("", in("rax") foo, out("rax") bar);
    |                  -------------  ^^^^^^^^^^^^^^ register `ax`
@@ -117,13 +111,13 @@ LL |         asm!("", in("rax") foo, out("rax") bar);
    |                  register `ax`
    |
 help: use `lateout` instead of `out` to avoid conflict
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", in("rax") foo, out("rax") bar);
    |                  ^^^^^^^^^^^^^
 
 error: register `ymm0` conflicts with register `xmm0`
-  --> $DIR/bad-reg.rs:51:34
+  --> $DIR/bad-reg.rs:49:34
    |
 LL |         asm!("", in("xmm0") foo, in("ymm0") bar);
    |                  --------------  ^^^^^^^^^^^^^^ register `ymm0`
@@ -131,7 +125,7 @@ LL |         asm!("", in("xmm0") foo, in("ymm0") bar);
    |                  register `xmm0`
 
 error: register `ymm0` conflicts with register `xmm0`
-  --> $DIR/bad-reg.rs:53:34
+  --> $DIR/bad-reg.rs:51:34
    |
 LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
    |                  --------------  ^^^^^^^^^^^^^^^ register `ymm0`
@@ -139,10 +133,10 @@ LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
    |                  register `xmm0`
    |
 help: use `lateout` instead of `out` to avoid conflict
-  --> $DIR/bad-reg.rs:53:18
+  --> $DIR/bad-reg.rs:51:18
    |
 LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
    |                  ^^^^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs
index 750d28026d7..5de15fe4906 100644
--- a/src/test/ui/asm/type-check-3.rs
+++ b/src/test/ui/asm/type-check-3.rs
@@ -29,7 +29,7 @@ fn main() {
 
         // Template modifier suggestions for sub-registers
 
-        asm!("{0} {0}", in(reg) 0i8);
+        asm!("{0} {0}", in(reg) 0i16);
         //~^ WARN formatting may not be suitable for sub-register argument
         asm!("{0} {0:x}", in(reg) 0i16);
         //~^ WARN formatting may not be suitable for sub-register argument
@@ -39,23 +39,26 @@ fn main() {
         asm!("{}", in(ymm_reg) 0i64);
         //~^ WARN formatting may not be suitable for sub-register argument
         asm!("{}", in(ymm_reg) _mm256_setzero_ps());
-        asm!("{:l}", in(reg) 0i8);
         asm!("{:l}", in(reg) 0i16);
         asm!("{:l}", in(reg) 0i32);
         asm!("{:l}", in(reg) 0i64);
         asm!("{:x}", in(ymm_reg) 0i64);
         asm!("{:x}", in(ymm_reg) _mm256_setzero_ps());
 
+        // Suggest different register class for type
+
+        asm!("{}", in(reg) 0i8);
+        //~^ ERROR type `i8` cannot be used with this register class
+        asm!("{}", in(reg_byte) 0i8);
+
         // Split inout operands must have compatible types
 
-        let mut val_i8: i8;
+        let mut val_i16: i16;
         let mut val_f32: f32;
         let mut val_u32: u32;
         let mut val_u64: u64;
         let mut val_ptr: *mut u8;
-        asm!("{:r}", inout(reg) 0u8 => val_i8);
-        asm!("{:r}", inout(reg) 0u16 => val_i8);
-        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:r}", inout(reg) 0u16 => val_i16);
         asm!("{:r}", inout(reg) 0u32 => val_f32);
         //~^ ERROR incompatible types for asm inout argument
         asm!("{:r}", inout(reg) 0u32 => val_ptr);
diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr
index ccc795d1013..01dbe78db88 100644
--- a/src/test/ui/asm/type-check-3.stderr
+++ b/src/test/ui/asm/type-check-3.stderr
@@ -4,7 +4,7 @@ error: type `i128` cannot be used with this register class
 LL |         asm!("{}", in(reg) 0i128);
    |                            ^^^^^
    |
-   = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
 
 error: type `std::arch::x86_64::__m128` cannot be used with this register class
   --> $DIR/type-check-3.rs:14:28
@@ -12,7 +12,7 @@ error: type `std::arch::x86_64::__m128` cannot be used with this register class
 LL |         asm!("{}", in(reg) _mm_setzero_ps());
    |                            ^^^^^^^^^^^^^^^^
    |
-   = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
 
 error: type `std::arch::x86_64::__m256` cannot be used with this register class
   --> $DIR/type-check-3.rs:16:28
@@ -20,7 +20,7 @@ error: type `std::arch::x86_64::__m256` cannot be used with this register class
 LL |         asm!("{}", in(reg) _mm256_setzero_ps());
    |                            ^^^^^^^^^^^^^^^^^^^
    |
-   = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
 
 error: type `u8` cannot be used with this register class
   --> $DIR/type-check-3.rs:18:32
@@ -41,11 +41,11 @@ LL |         asm!("{}", in(kreg) 0u64);
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:32:15
    |
-LL |         asm!("{0} {0}", in(reg) 0i8);
-   |               ^^^ ^^^           --- for this argument
+LL |         asm!("{0} {0}", in(reg) 0i16);
+   |               ^^^ ^^^           ---- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `l` modifier to have the register formatted as `al`
+   = help: use the `x` modifier to have the register formatted as `ax`
    = help: or use the `r` modifier to keep the default formatting of `rax`
 
 warning: formatting may not be suitable for sub-register argument
@@ -75,18 +75,17 @@ LL |         asm!("{}", in(ymm_reg) 0i64);
    = help: use the `x` modifier to have the register formatted as `xmm0`
    = help: or use the `y` modifier to keep the default formatting of `ymm0`
 
-error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:57:33
+error: type `i8` cannot be used with this register class
+  --> $DIR/type-check-3.rs:50:28
    |
-LL |         asm!("{:r}", inout(reg) 0u16 => val_i8);
-   |                                 ^^^^    ^^^^^^ type `i8`
-   |                                 |
-   |                                 type `u16`
+LL |         asm!("{}", in(reg) 0i8);
+   |                            ^^^
    |
-   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+   = help: consider using the `reg_byte` register class instead
 
 error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:59:33
+  --> $DIR/type-check-3.rs:62:33
    |
 LL |         asm!("{:r}", inout(reg) 0u32 => val_f32);
    |                                 ^^^^    ^^^^^^^ type `f32`
@@ -96,7 +95,7 @@ LL |         asm!("{:r}", inout(reg) 0u32 => val_f32);
    = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
 
 error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:61:33
+  --> $DIR/type-check-3.rs:64:33
    |
 LL |         asm!("{:r}", inout(reg) 0u32 => val_ptr);
    |                                 ^^^^    ^^^^^^^ type `*mut u8`
@@ -106,7 +105,7 @@ LL |         asm!("{:r}", inout(reg) 0u32 => val_ptr);
    = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
 
 error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:63:33
+  --> $DIR/type-check-3.rs:66:33
    |
 LL |         asm!("{:r}", inout(reg) main => val_u32);
    |                                 ^^^^    ^^^^^^^ type `u32`