Skip to content

Add asm!() support for PowerPC #84732

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
May 13, 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
8 changes: 8 additions & 0 deletions compiler/rustc_codegen_llvm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::PowerPC => {}
InlineAsmArch::Hexagon => {}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::SpirV => {}
Expand Down Expand Up @@ -540,6 +541,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
Expand Down Expand Up @@ -590,6 +594,7 @@ fn modifier_to_llvm(
InlineAsmRegClass::Hexagon(_) => None,
InlineAsmRegClass::Mips(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::PowerPC(_) => None,
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
Expand Down Expand Up @@ -651,6 +656,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ symbols! {
reg64,
reg_abcd,
reg_byte,
reg_nonzero,
reg_thumb,
register_attr,
register_tool,
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_target/src/asm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ mod arm;
mod hexagon;
mod mips;
mod nvptx;
mod powerpc;
mod riscv;
mod spirv;
mod wasm;
Expand All @@ -164,6 +165,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
Expand All @@ -181,6 +183,7 @@ pub enum InlineAsmArch {
Hexagon,
Mips,
Mips64,
PowerPC,
SpirV,
Wasm32,
}
Expand All @@ -197,6 +200,7 @@ impl FromStr for InlineAsmArch {
"riscv32" => Ok(Self::RiscV32),
"riscv64" => Ok(Self::RiscV64),
"nvptx64" => Ok(Self::Nvptx64),
"powerpc" => Ok(Self::PowerPC),
"hexagon" => Ok(Self::Hexagon),
"mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64),
Expand Down Expand Up @@ -225,6 +229,7 @@ pub enum InlineAsmReg {
AArch64(AArch64InlineAsmReg),
RiscV(RiscVInlineAsmReg),
Nvptx(NvptxInlineAsmReg),
PowerPC(PowerPCInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
Mips(MipsInlineAsmReg),
SpirV(SpirVInlineAsmReg),
Expand All @@ -240,6 +245,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.name(),
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
Self::Err => "<reg>",
Expand All @@ -252,6 +258,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::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
Expand Down Expand Up @@ -283,6 +290,9 @@ impl InlineAsmReg {
InlineAsmArch::Nvptx64 => {
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::PowerPC => {
Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::Hexagon => {
Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
Expand Down Expand Up @@ -311,6 +321,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::PowerPC(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
Expand All @@ -323,6 +334,7 @@ impl InlineAsmReg {
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
Self::AArch64(_) => cb(self),
Self::RiscV(_) => cb(self),
Self::PowerPC(_) => cb(self),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::Mips(_) => cb(self),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
Expand All @@ -348,6 +360,7 @@ pub enum InlineAsmRegClass {
AArch64(AArch64InlineAsmRegClass),
RiscV(RiscVInlineAsmRegClass),
Nvptx(NvptxInlineAsmRegClass),
PowerPC(PowerPCInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
Mips(MipsInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
Expand All @@ -364,6 +377,7 @@ impl InlineAsmRegClass {
Self::AArch64(r) => r.name(),
Self::RiscV(r) => r.name(),
Self::Nvptx(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
Self::SpirV(r) => r.name(),
Expand All @@ -382,6 +396,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::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
Expand All @@ -407,6 +422,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::PowerPC(r) => r.suggest_modifier(arch, ty),
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
Expand All @@ -428,6 +444,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::PowerPC(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
Expand All @@ -448,6 +465,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::PowerPC(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
Expand All @@ -467,6 +485,7 @@ impl InlineAsmRegClass {
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::PowerPC => Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
Expand All @@ -485,6 +504,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::PowerPC(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
Expand Down Expand Up @@ -633,6 +653,11 @@ pub fn allocatable_registers(
nvptx::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::PowerPC => {
let mut map = powerpc::regclass_map();
powerpc::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::Hexagon => {
let mut map = hexagon::regclass_map();
hexagon::fill_reg_map(arch, has_feature, target, &mut map);
Expand Down
146 changes: 146 additions & 0 deletions compiler/rustc_target/src/asm/powerpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
use std::fmt;

def_reg_class! {
PowerPC PowerPCInlineAsmRegClass {
reg,
reg_nonzero,
freg,
}
}

impl PowerPCInlineAsmRegClass {
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 | Self::reg_nonzero => types! { _: I8, I16, I32; },
Self::freg => types! { _: F32, F64; },
}
}
}

def_regs! {
PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
r0: reg = ["r0", "0"],
r3: reg, reg_nonzero = ["r3", "3"],
r4: reg, reg_nonzero = ["r4", "4"],
r5: reg, reg_nonzero = ["r5", "5"],
r6: reg, reg_nonzero = ["r6", "6"],
r7: reg, reg_nonzero = ["r7", "7"],
r8: reg, reg_nonzero = ["r8", "8"],
r9: reg, reg_nonzero = ["r9", "9"],
r10: reg, reg_nonzero = ["r10", "10"],
r11: reg, reg_nonzero = ["r11", "11"],
r12: reg, reg_nonzero = ["r12", "12"],
r14: reg, reg_nonzero = ["r14", "14"],
r15: reg, reg_nonzero = ["r15", "15"],
r16: reg, reg_nonzero = ["r16", "16"],
r17: reg, reg_nonzero = ["r17", "17"],
r18: reg, reg_nonzero = ["r18", "18"],
r19: reg, reg_nonzero = ["r19", "19"],
r20: reg, reg_nonzero = ["r20", "20"],
r21: reg, reg_nonzero = ["r21", "21"],
r22: reg, reg_nonzero = ["r22", "22"],
r23: reg, reg_nonzero = ["r23", "23"],
r24: reg, reg_nonzero = ["r24", "24"],
r25: reg, reg_nonzero = ["r25", "25"],
r26: reg, reg_nonzero = ["r26", "26"],
r27: reg, reg_nonzero = ["r27", "27"],
r28: reg, reg_nonzero = ["r28", "28"],
f0: freg = ["f0", "fr0"],
f1: freg = ["f1", "fr1"],
f2: freg = ["f2", "fr2"],
f3: freg = ["f3", "fr3"],
f4: freg = ["f4", "fr4"],
f5: freg = ["f5", "fr5"],
f6: freg = ["f6", "fr6"],
f7: freg = ["f7", "fr7"],
f8: freg = ["f8", "fr8"],
f9: freg = ["f9", "fr9"],
f10: freg = ["f10", "fr10"],
f11: freg = ["f11", "fr11"],
f12: freg = ["f12", "fr12"],
f13: freg = ["f13", "fr13"],
f14: freg = ["f14", "fr14"],
f15: freg = ["f15", "fr15"],
f16: freg = ["f16", "fr16"],
f17: freg = ["f17", "fr17"],
f18: freg = ["f18", "fr18"],
f19: freg = ["f19", "fr19"],
f20: freg = ["f20", "fr20"],
f21: freg = ["f21", "fr21"],
f22: freg = ["f22", "fr22"],
f23: freg = ["f23", "fr23"],
f24: freg = ["f24", "fr24"],
f25: freg = ["f25", "fr25"],
f26: freg = ["f26", "fr26"],
f27: freg = ["f27", "fr27"],
f28: freg = ["f28", "fr28"],
f29: freg = ["f29", "fr29"],
f30: freg = ["f30", "fr30"],
f31: freg = ["f31", "fr31"],
#error = ["r1", "1", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r2", "2"] =>
"r2 is a system reserved register and cannot be used as an operand for inline asm",
#error = ["r13", "13"] =>
"r13 is a system reserved register and cannot be used as an operand for inline asm",
#error = ["r29", "29"] =>
"r29 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r30", "30"] =>
"r30 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r31", "31", "fp"] =>
"the frame pointer cannot be used as an operand for inline asm",
#error = ["lr"] =>
"the link register cannot be used as an operand for inline asm",
#error = ["ctr"] =>
"the counter register cannot be used as an operand for inline asm",
#error = ["vrsave"] =>
"the vrsave register cannot be used as an operand for inline asm",
}
}

impl PowerPCInlineAsmReg {
pub fn emit(
self,
out: &mut dyn fmt::Write,
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
// Strip off the leading prefix.
if self as u32 <= Self::r28 as u32 {
let index = self as u32 - Self::r28 as u32;
write!(out, "{}", index)
} else if self as u32 >= Self::f0 as u32 && self as u32 <= Self::f31 as u32 {
let index = self as u32 - Self::f31 as u32;
write!(out, "{}", index)
} else {
unreachable!()
}
}

pub fn overlapping_regs(self, mut _cb: impl FnMut(PowerPCInlineAsmReg)) {}
}
12 changes: 11 additions & 1 deletion src/doc/unstable-book/src/library-features/asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Inline assembly is currently supported on the following architectures:
- AArch64
- RISC-V
- NVPTX
- PowerPC
- Hexagon
- MIPS32r2 and MIPS64r2
- wasm32
Expand Down Expand Up @@ -459,7 +460,7 @@ options := "options(" option *["," option] [","] ")"
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
```

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.
The macro will initially be supported only on ARM, AArch64, Hexagon, PowerPC, 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 Down Expand Up @@ -565,6 +566,9 @@ Here is the list of currently supported register classes:
| 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` |
| PowerPC | `reg` | `r[0-31]` | `r` |
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
| PowerPC | `freg` | `f[0-31]` | `f` |
| wasm32 | `local` | None\* | `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 @@ -607,6 +611,9 @@ Each register class has constraints on which value types they can be used with.
| RISC-V | `freg` | `f` | `f32` |
| RISC-V | `freg` | `d` | `f64` |
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
| PowerPC | `freg` | None | `f32`, `f64` |
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |

> **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 @@ -744,6 +751,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
| RISC-V | `reg` | None | `x1` | None |
| RISC-V | `freg` | None | `f0` | None |
| Hexagon | `reg` | None | `r0` | None |
| PowerPC | `reg` | None | `0` | None |
| PowerPC | `reg_nonzero` | None | `3` | `b` |
| PowerPC | `freg` | None | `0` | None |

> Notes:
> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
Expand Down
Loading