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

NVPTX support for new asm! #72439

Merged
merged 10 commits into from
May 30, 2020
11 changes: 11 additions & 0 deletions src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,17 @@ Here is the list of currently supported register classes:
| ARM | `qreg` | `q[0-15]` | `w` |
| ARM | `qreg_low8` | `q[0-7]` | `t` |
| ARM | `qreg_low4` | `q[0-3]` | `x` |
| NVPTX | `reg16` | None\* | `h` |
| NVPTX | `reg32` | None\* | `r` |
| 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` |

> **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 #3: NVPTX doesn't have a fixed register set, so named registers are not supported.

Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).

Expand All @@ -495,6 +500,9 @@ Each register class has constraints on which value types they can be used with.
| ARM | `sreg` | `vfp2` | `i32`, `f32` |
| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
| NVPTX | `reg16` | None | `i8`, `i16` |
| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
| RISC-V | `freg` | `f` | `f32` |
Expand Down Expand Up @@ -610,6 +618,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
| ARM | `dreg` | None | `d0` | `P` |
| ARM | `qreg` | None | `q0` | `q` |
| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
| NVPTX | `reg16` | None | `rs0` | None |
| NVPTX | `reg32` | None | `r0` | None |
| NVPTX | `reg64` | None | `rd0` | None |
| RISC-V | `reg` | None | `x1` | None |
| RISC-V | `freg` | None | `f0` | None |

Expand Down
8 changes: 8 additions & 0 deletions src/librustc_codegen_llvm/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
]);
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
InlineAsmArch::Nvptx64 => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
Expand Down Expand Up @@ -410,6 +411,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
Expand Down Expand Up @@ -452,6 +456,7 @@ fn modifier_to_llvm(
modifier
}
}
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
Expand Down Expand Up @@ -502,6 +507,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
cx.type_vector(cx.type_i64(), 2)
}
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
Expand Down
29 changes: 26 additions & 3 deletions src/librustc_target/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ macro_rules! def_regs {
#error = [$($bad_reg:literal),+] => $error:literal,
)*
}) => {
#[allow(unreachable_code)]
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
#[allow(non_camel_case_types)]
pub enum $arch_reg {
Expand Down Expand Up @@ -102,19 +103,20 @@ macro_rules! def_regs {
pub(super) fn fill_reg_map(
_arch: super::InlineAsmArch,
mut _has_feature: impl FnMut(&str) -> bool,
map: &mut rustc_data_structures::fx::FxHashMap<
_map: &mut rustc_data_structures::fx::FxHashMap<
super::InlineAsmRegClass,
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
>,
) {
#[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass};
$(
if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
$(
if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
)*
Expand Down Expand Up @@ -146,11 +148,13 @@ macro_rules! types {

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

pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};

Expand All @@ -162,6 +166,7 @@ pub enum InlineAsmArch {
AArch64,
RiscV32,
RiscV64,
Nvptx64,
}

impl FromStr for InlineAsmArch {
Expand All @@ -175,6 +180,7 @@ impl FromStr for InlineAsmArch {
"aarch64" => Ok(Self::AArch64),
"riscv32" => Ok(Self::RiscV32),
"riscv64" => Ok(Self::RiscV64),
"nvptx64" => Ok(Self::Nvptx64),
_ => Err(()),
}
}
Expand All @@ -196,6 +202,7 @@ pub enum InlineAsmReg {
Arm(ArmInlineAsmReg),
AArch64(AArch64InlineAsmReg),
RiscV(RiscVInlineAsmReg),
Nvptx(NvptxInlineAsmReg),
}

impl InlineAsmReg {
Expand Down Expand Up @@ -236,6 +243,9 @@ impl InlineAsmReg {
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
}
InlineAsmArch::Nvptx64 => {
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
}
})
}

Expand Down Expand Up @@ -281,6 +291,7 @@ pub enum InlineAsmRegClass {
Arm(ArmInlineAsmRegClass),
AArch64(AArch64InlineAsmRegClass),
RiscV(RiscVInlineAsmRegClass),
Nvptx(NvptxInlineAsmRegClass),
}

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

Expand All @@ -302,6 +314,7 @@ impl InlineAsmRegClass {
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),
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
}
}

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

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

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

Expand All @@ -367,6 +383,7 @@ impl InlineAsmRegClass {
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
})
})
}
Expand All @@ -379,6 +396,7 @@ impl InlineAsmRegClass {
Self::Arm(r) => r.valid_modifiers(arch),
Self::AArch64(r) => r.valid_modifiers(arch),
Self::RiscV(r) => r.valid_modifiers(arch),
Self::Nvptx(r) => r.valid_modifiers(arch),
}
}
}
Expand Down Expand Up @@ -518,5 +536,10 @@ pub fn allocatable_registers(
riscv::fill_reg_map(arch, has_feature, &mut map);
map
}
InlineAsmArch::Nvptx64 => {
let mut map = nvptx::regclass_map();
nvptx::fill_reg_map(arch, has_feature, &mut map);
map
}
}
}
49 changes: 49 additions & 0 deletions src/librustc_target/asm/nvptx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;

def_reg_class! {
Nvptx NvptxInlineAsmRegClass {
reg16,
reg32,
reg64,
}
}

impl NvptxInlineAsmRegClass {
pub fn valid_modifiers(self, _arch: 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::reg16 => types! { _: I8, I16; },
Self::reg32 => types! { _: I8, I16, I32, F32; },
Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; },
}
}
}

def_regs! {
// Registers in PTX are declared in the assembly.
// There are no predefined registers that one can use.
Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {}
westernmagic marked this conversation as resolved.
Show resolved Hide resolved
}
Loading