Skip to content
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

Add asm!() support for hexagon #73214

Merged
merged 1 commit into from
Jun 20, 2020
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
13 changes: 10 additions & 3 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ options := "options(" option *["," option] [","] ")"
asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
```

The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.

[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax

Expand All @@ -386,7 +386,7 @@ As with format strings, named arguments must appear after positional arguments.

The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.

The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.

[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795

Expand Down Expand Up @@ -473,6 +473,7 @@ Here is the list of currently supported register classes:
| NVPTX | `reg64` | None\* | `l` |
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
| RISC-V | `freg` | `f[0-31]` | `f` |
| Hexagon | `reg` | `r[0-28]` | `r` |

> **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.
>
Expand Down Expand Up @@ -507,6 +508,7 @@ Each register class has constraints on which value types they can be used with.
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
| RISC-V | `freg` | `f` | `f32` |
| RISC-V | `freg` | `d` | `f64` |
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |

> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).

Expand Down Expand Up @@ -563,13 +565,16 @@ Some registers have multiple names. These are all treated by the compiler as ide
| RISC-V | `f[10-17]` | `fa[0-7]` |
| RISC-V | `f[18-27]` | `fs[2-11]` |
| RISC-V | `f[28-31]` | `ft[8-11]` |
| Hexagon | `r29` | `sp` |
| Hexagon | `r30` | `fr` |
| Hexagon | `r31` | `lr` |

Some registers cannot be used for input or output operands:

| Architecture | Unsupported register | Reason |
| ------------ | -------------------- | ------ |
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. |
| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All registers can be used as inputs on Hexagon, that is the architecture doesn't not differentiate between r0 and r29 or r30, except for a small set of instructions which require fewer bits to encode registers. As a matter of fact, most loads/stores to stack are done via r29 or r30 (i.e. sp or fp), and a return from a function that does not allocate stack space is done via jumpr r31.

All of these registers can also be modified, but that's typically a bad idea.

| x86 | `k0` | This is a constant zero register which can't be modified. |
| x86 | `ip` | This is the program counter, not a real register. |
| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
Expand All @@ -578,6 +583,7 @@ Some registers cannot be used for input or output operands:
| ARM | `pc` | This is the program counter, not a real register. |
| RISC-V | `x0` | This is a constant zero register which can't be modified. |
| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add sp, lr and fr as aliases for x29, x30 and x31 in the register names tables.


## Template modifiers

Expand Down Expand Up @@ -623,6 +629,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
| NVPTX | `reg64` | None | `rd0` | None |
| RISC-V | `reg` | None | `x1` | None |
| RISC-V | `freg` | None | `f0` | None |
| Hexagon | `reg` | None | `r0` | None |

> Notes:
> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_codegen_llvm/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::Hexagon => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
Expand Down Expand Up @@ -427,6 +428,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
Expand Down Expand Up @@ -472,6 +474,7 @@ fn modifier_to_llvm(
modifier
}
}
InlineAsmRegClass::Hexagon(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
Expand Down Expand Up @@ -523,6 +526,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
cx.type_vector(cx.type_i64(), 2)
}
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
Expand Down
93 changes: 93 additions & 0 deletions src/librustc_target/asm/hexagon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
use std::fmt;

def_reg_class! {
Hexagon HexagonInlineAsmRegClass {
reg,
androm3da marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl HexagonInlineAsmRegClass {
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
&[]
}

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)> {
None
}

pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
None
}

pub fn supported_types(
self,
_arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<&'static str>)] {
match self {
Self::reg => types! { _: I8, I16, I32, F32; },
}
}
}

def_regs! {
Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass {
r0: reg = ["r0"],
r1: reg = ["r1"],
r2: reg = ["r2"],
r3: reg = ["r3"],
r4: reg = ["r4"],
r5: reg = ["r5"],
r6: reg = ["r6"],
r7: reg = ["r7"],
r8: reg = ["r8"],
r9: reg = ["r9"],
r10: reg = ["r10"],
r11: reg = ["r11"],
r12: reg = ["r12"],
r13: reg = ["r13"],
r14: reg = ["r14"],
r15: reg = ["r15"],
r16: reg = ["r16"],
r17: reg = ["r17"],
r18: reg = ["r18"],
r19: reg = ["r19"],
r20: reg = ["r20"],
r21: reg = ["r21"],
r22: reg = ["r22"],
r23: reg = ["r23"],
r24: reg = ["r24"],
r25: reg = ["r25"],
r26: reg = ["r26"],
r27: reg = ["r27"],
r28: reg = ["r28"],
#error = ["r29", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r30", "fr"] =>
"the frame register cannot be used as an operand for inline asm",
#error = ["r31", "lr"] =>
"the link register cannot be used as an operand for inline asm",
}
}

impl HexagonInlineAsmReg {
pub fn emit(
self,
out: &mut dyn fmt::Write,
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
out.write_str(self.name())
}

pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
}
27 changes: 27 additions & 0 deletions src/librustc_target/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,14 @@ macro_rules! types {

mod aarch64;
mod arm;
mod hexagon;
mod nvptx;
mod riscv;
mod x86;

pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
Expand All @@ -167,6 +169,7 @@ pub enum InlineAsmArch {
RiscV32,
RiscV64,
Nvptx64,
Hexagon,
}

impl FromStr for InlineAsmArch {
Expand All @@ -181,6 +184,7 @@ impl FromStr for InlineAsmArch {
"riscv32" => Ok(Self::RiscV32),
"riscv64" => Ok(Self::RiscV64),
"nvptx64" => Ok(Self::Nvptx64),
"hexagon" => Ok(Self::Hexagon),
_ => Err(()),
}
}
Expand All @@ -203,6 +207,7 @@ pub enum InlineAsmReg {
AArch64(AArch64InlineAsmReg),
RiscV(RiscVInlineAsmReg),
Nvptx(NvptxInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
}

impl InlineAsmReg {
Expand All @@ -212,6 +217,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.name(),
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
Self::Hexagon(r) => r.name(),
}
}

Expand All @@ -221,6 +227,7 @@ impl InlineAsmReg {
Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
}
}

Expand All @@ -246,6 +253,9 @@ impl InlineAsmReg {
InlineAsmArch::Nvptx64 => {
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
}
InlineAsmArch::Hexagon => {
Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?)
}
})
}

Expand All @@ -262,6 +272,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.emit(out, arch, modifier),
Self::AArch64(r) => r.emit(out, arch, modifier),
Self::RiscV(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
}
}

Expand All @@ -271,6 +282,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
Self::AArch64(_) => cb(self),
Self::RiscV(_) => cb(self),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
}
}
}
Expand All @@ -292,6 +304,7 @@ pub enum InlineAsmRegClass {
AArch64(AArch64InlineAsmRegClass),
RiscV(RiscVInlineAsmRegClass),
Nvptx(NvptxInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
}

impl InlineAsmRegClass {
Expand All @@ -302,6 +315,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
Self::Nvptx(r) => r.name(),
Self::Hexagon(r) => r.name(),
}
}

Expand All @@ -315,6 +329,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
}
}

Expand All @@ -335,6 +350,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.suggest_modifier(arch, ty),
Self::RiscV(r) => r.suggest_modifier(arch, ty),
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
}
}

Expand All @@ -351,6 +367,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.default_modifier(arch),
Self::RiscV(r) => r.default_modifier(arch),
Self::Nvptx(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
}
}

Expand All @@ -366,6 +383,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.supported_types(arch),
Self::RiscV(r) => r.supported_types(arch),
Self::Nvptx(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
}
}

Expand All @@ -384,6 +402,9 @@ impl InlineAsmRegClass {
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Hexagon => {
Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
}
})
})
}
Expand All @@ -397,6 +418,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.valid_modifiers(arch),
Self::RiscV(r) => r.valid_modifiers(arch),
Self::Nvptx(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
}
}
}
Expand Down Expand Up @@ -541,5 +563,10 @@ pub fn allocatable_registers(
nvptx::fill_reg_map(arch, has_feature, &mut map);
map
}
InlineAsmArch::Hexagon => {
let mut map = hexagon::regclass_map();
hexagon::fill_reg_map(arch, has_feature, &mut map);
map
}
}
}
Loading