Skip to content

Disallow the use of high byte registes as operands on x86_64 #83853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions compiler/rustc_target/src/asm/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ fn frame_pointer_r11(
_arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool,
target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
if !frame_pointer_is_r7(has_feature, target) {
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
Expand All @@ -81,7 +80,6 @@ fn frame_pointer_r7(
_arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool,
target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
if frame_pointer_is_r7(has_feature, target) {
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_target/src/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ macro_rules! def_regs {
match name {
$(
$($alias)|* | $reg_name => {
$($filter(_arch, &mut _has_feature, _target, false)?;)?
$($filter(_arch, &mut _has_feature, _target)?;)?
Ok(Self::$reg)
}
)*
Expand All @@ -114,7 +114,7 @@ macro_rules! def_regs {
#[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass};
$(
if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_target/src/asm/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ fn not_e(
_arch: InlineAsmArch,
mut has_feature: impl FnMut(&str) -> bool,
_target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
if has_feature("e") {
Err("register can't be used with the `e` target feature")
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_target/src/asm/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ fn x86_64_only(
arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool,
_target: &Target,
_allocating: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86 => Err("register is only available on x86_64"),
Expand All @@ -146,13 +145,9 @@ fn high_byte(
arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool,
_target: &Target,
allocating: bool,
) -> Result<(), &'static str> {
match arch {
InlineAsmArch::X86_64 if allocating => {
// The error message isn't actually used...
Err("high byte registers are not allocated by reg_byte")
}
InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
_ => Ok(()),
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ Here is the list of currently supported register classes:
| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
| x86-64 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b`, `ah`\*, `bh`\*, `ch`\*, `dh`\* | `q` |
| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` |
| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
Expand Down Expand Up @@ -526,7 +526,7 @@ Here is the list of currently supported register classes:

> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
>
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class.
>
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
>
Expand Down
9 changes: 5 additions & 4 deletions src/test/assembly/asm/x86-types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,10 +748,11 @@ check_reg!(eax_f64 f64 "eax" "mov");
// CHECK: #NO_APP
check_reg!(eax_ptr ptr "eax" "mov");

// CHECK-LABEL: ah_byte:
// CHECK: #APP
// CHECK: mov ah, ah
// CHECK: #NO_APP
// i686-LABEL: ah_byte:
// i686: #APP
// i686: mov ah, ah
// i686: #NO_APP
#[cfg(i686)]
check_reg!(ah_byte i8 "ah" "mov");

// CHECK-LABEL: xmm0_i32:
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/asm/bad-reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ fn main() {
//~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands
asm!("", in("k0") foo);
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
asm!("", in("ah") foo);
//~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand

// Explicit register conflicts
// (except in/lateout which don't conflict)
Expand Down
20 changes: 13 additions & 7 deletions src/test/ui/asm/bad-reg.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -94,49 +94,55 @@ error: invalid register `k0`: the k0 AVX mask register cannot be used as an oper
LL | asm!("", in("k0") foo);
| ^^^^^^^^^^^^

error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", in("ah") foo);
| ^^^^^^^^^^^^

error: register `al` conflicts with register `ax`
--> $DIR/bad-reg.rs:44:33
--> $DIR/bad-reg.rs:46:33
|
LL | asm!("", in("eax") foo, in("al") bar);
| ------------- ^^^^^^^^^^^^ register `al`
| |
| register `ax`

error: register `ax` conflicts with register `ax`
--> $DIR/bad-reg.rs:46:33
--> $DIR/bad-reg.rs:48:33
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ------------- ^^^^^^^^^^^^^^ register `ax`
| |
| register `ax`
|
help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:46:18
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ^^^^^^^^^^^^^

error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:49:34
--> $DIR/bad-reg.rs:51:34
|
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
| |
| register `xmm0`

error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:51:34
--> $DIR/bad-reg.rs:53:34
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
| |
| register `xmm0`
|
help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:51:18
--> $DIR/bad-reg.rs:53:18
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| ^^^^^^^^^^^^^^

error: aborting due to 18 previous errors
error: aborting due to 19 previous errors