Auto merge of #131341 - taiki-e:ppc-clobber-abi, r=bzEq,workingjubilee

Support clobber_abi and vector registers (clobber-only) in PowerPC inline assembly

This supports `clobber_abi` which is one of the requirements of stabilization mentioned in #93335.

This basically does a similar thing I did in https://github.com/rust-lang/rust/pull/130630 to implement `clobber_abi` for s390x, but for powerpc/powerpc64/powerpc64le.
- This also supports vector registers (as `vreg`) as clobber-only, which need to support clobbering of them to implement `clobber_abi`.
- `vreg` should be able to accept `#[repr(simd)]` types as input/output if the unstable `altivec` target feature is enabled, but `core::arch::{powerpc,powerpc64}` vector types, `#[repr(simd)]`, and `core::simd` are all unstable, so the fact that this is currently a clobber-only should not be considered a blocker of clobber_abi implementation or stabilization. So I have not implemented it in this PR.
  - See https://github.com/rust-lang/rust/pull/131551 (which is based on this PR) for a PR to implement this.
  - (I'm not sticking to whether that PR should be a separate PR or part of this PR, so I can merge that PR into this PR if needed.)

Refs:
- PPC32 SysV: Section "Function Calling Sequence" in [System V Application Binary Interface PowerPC Processor Supplement](https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf)
- PPC64 ELFv1: Section 3.2 "Function Calling Sequence" in [64-bit PowerPC ELF Application Binary Interface Supplement](https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-CALL)
- PPC64 ELFv2: Section 2.2 "Function Calling Sequence" in [64-Bit ELF V2 ABI Specification](https://openpowerfoundation.org/specifications/64bitelfabi/)
- AIX: [Register usage and conventions](https://www.ibm.com/docs/en/aix/7.3?topic=overview-register-usage-conventions), [Special registers in the PowerPC®](https://www.ibm.com/docs/en/aix/7.3?topic=overview-special-registers-in-powerpc), [AIX vector programming](https://www.ibm.com/docs/en/aix/7.3?topic=concepts-aix-vector-programming)
- Register definition in LLVM: https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/PowerPC/PPCRegisterInfo.td#L189

If I understand the above four ABI documentations correctly, except for the PPC32 SysV's VR (Vector Registers) and 32-bit AIX (currently not supported by rustc)'s r13, there does not appear to be important differences in terms of implementing `clobber_abi`:
- The above four ABIs are consistent about FPR (0-13: volatile, 14-31: nonvolatile), CR (0-1,5-7: volatile, 2-4: nonvolatile), XER (volatile), and CTR (volatile).
- As for GPR, only the registers we are treating as reserved are slightly different
  - r0, r3-r12 are volatile
  - r1(sp, reserved), r14-31 are nonvolatile
  - r2(reserved) is TOC pointer in PPC64 ELF/AIX, system-reserved register in PPC32 SysV (AFAIK used as thread pointer in Linux/BSDs)
  - r13(reserved for non-32-bit-AIX) is thread pointer in PPC64 ELF, small data area pointer register in PPC32 SysV, "reserved under 64-bit environment; not restored across system calls[^r13]" in AIX)
- As for FPSCR, volatile in PPC64 ELFv1/AIX, some fields are volatile only in certain situations (rest are volatile) in PPC32 SysV/PPC64 ELFv2.
- As for VR (Vector Registers), it is not mentioned in PPC32 SysV, v0-v19 are volatile in both in PPC64 ELF/AIX, v20-v31 are nonvolatile in PPC64 ELF, reserved or nonvolatile depending on the ABI ([vec-extabi vs vec-default in LLVM](https://reviews.llvm.org/D89684), we are [using vec-extabi](https://github.com/rust-lang/rust/pull/131341#discussion_r1797693299)) in AIX:
  > When the default Vector enabled mode is used, these registers are reserved and must not be used.
  > In the extended ABI vector enabled mode, these registers are nonvolatile and their values are preserved across function calls

  I left [FIXME comment about PPC32 SysV](https://github.com/rust-lang/rust/pull/131341#discussion_r1790496095) and added ABI check for AIX.
- As for VRSAVE, it is not mentioned in PPC32 SysV, nonvolatile in PPC64 ELFv1, reserved in PPC64 ELFv2/AIX
- As for VSCR, it is not mentioned in PPC32 SysV/PPC64 ELFv1, some fields are volatile only in certain situations (rest are volatile) in PPC64 ELFv2, volatile in AIX

We are currently treating r1-r2, r13 (non-32-bit-AIX), r29-r31, LR, CTR, and VRSAVE as reserved.
We are currently not processing anything about FPSCR and VSCR, but I feel those are things that should be processed by `preserves_flags` rather than `clobber_abi` if we need to do something about them. (However, PPCRegisterInfo.td in LLVM does not seem to define anything about them.)

Replaces #111335 and #124279

cc `@ecnelises` `@bzEq` `@lu-zero`

r? `@Amanieu`

`@rustbot` label +O-PowerPC +A-inline-assembly

[^r13]: callee-saved, according to [LLVM](6a6af0246b/llvm/lib/Target/PowerPC/PPCCallingConv.td (L322)) and [GCC](a9173a50e7/gcc/config/rs6000/rs6000.h (L859)).
This commit is contained in:
bors 2024-11-05 03:13:47 +00:00
commit 96477c55bc
11 changed files with 1332 additions and 18 deletions

View File

@ -654,7 +654,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
unreachable!("clobber-only") unreachable!("clobber-only")
} }
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
@ -729,7 +730,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
unreachable!("clobber-only") unreachable!("clobber-only")
} }
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),

View File

@ -638,7 +638,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
PowerPC(PowerPCInlineAsmRegClass::reg) => "r", PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
PowerPC(PowerPCInlineAsmRegClass::freg) => "f", PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { PowerPC(PowerPCInlineAsmRegClass::cr)
| PowerPC(PowerPCInlineAsmRegClass::xer)
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
unreachable!("clobber-only") unreachable!("clobber-only")
} }
RiscV(RiscVInlineAsmRegClass::reg) => "r", RiscV(RiscVInlineAsmRegClass::reg) => "r",
@ -800,7 +802,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { PowerPC(PowerPCInlineAsmRegClass::cr)
| PowerPC(PowerPCInlineAsmRegClass::xer)
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
unreachable!("clobber-only") unreachable!("clobber-only")
} }
RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),

View File

@ -893,6 +893,7 @@ pub enum InlineAsmClobberAbi {
Arm64EC, Arm64EC,
RiscV, RiscV,
LoongArch, LoongArch,
PowerPC,
S390x, S390x,
Msp430, Msp430,
} }
@ -944,6 +945,10 @@ impl InlineAsmClobberAbi {
"C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
_ => Err(&["C", "system"]), _ => Err(&["C", "system"]),
}, },
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name {
"C" | "system" => Ok(InlineAsmClobberAbi::PowerPC),
_ => Err(&["C", "system"]),
},
InlineAsmArch::S390x => match name { InlineAsmArch::S390x => match name {
"C" | "system" => Ok(InlineAsmClobberAbi::S390x), "C" | "system" => Ok(InlineAsmClobberAbi::S390x),
_ => Err(&["C", "system"]), _ => Err(&["C", "system"]),
@ -1121,6 +1126,31 @@ impl InlineAsmClobberAbi {
f16, f17, f18, f19, f20, f21, f22, f23, f16, f17, f18, f19, f20, f21, f22, f23,
} }
}, },
InlineAsmClobberAbi::PowerPC => clobbered_regs! {
PowerPC PowerPCInlineAsmReg {
// r0, r3-r12
r0,
r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12,
// f0-f13
f0, f1, f2, f3, f4, f5, f6, f7,
f8, f9, f10, f11, f12, f13,
// v0-v19
// FIXME: PPC32 SysV ABI does not mention vector registers processing.
// https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14,
v15, v16, v17, v18, v19,
// cr0-cr1, cr5-cr7, xer
cr0, cr1,
cr5, cr6, cr7,
xer,
// lr and ctr are reserved
}
},
InlineAsmClobberAbi::S390x => clobbered_regs! { InlineAsmClobberAbi::S390x => clobbered_regs! {
S390x S390xInlineAsmReg { S390x S390xInlineAsmReg {
r0, r1, r2, r3, r4, r5, r0, r1, r2, r3, r4, r5,

View File

@ -1,14 +1,17 @@
use std::fmt; use std::fmt;
use rustc_data_structures::fx::FxIndexSet;
use rustc_span::Symbol; use rustc_span::Symbol;
use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
use crate::spec::{RelocModel, Target};
def_reg_class! { def_reg_class! {
PowerPC PowerPCInlineAsmRegClass { PowerPC PowerPCInlineAsmRegClass {
reg, reg,
reg_nonzero, reg_nonzero,
freg, freg,
vreg,
cr, cr,
xer, xer,
} }
@ -48,11 +51,44 @@ impl PowerPCInlineAsmRegClass {
} }
} }
Self::freg => types! { _: F32, F64; }, Self::freg => types! { _: F32, F64; },
Self::vreg => &[],
Self::cr | Self::xer => &[], Self::cr | Self::xer => &[],
} }
} }
} }
fn reserved_r13(
arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxIndexSet<Symbol>,
target: &Target,
_is_clobber: bool,
) -> Result<(), &'static str> {
if target.is_like_aix && arch == InlineAsmArch::PowerPC {
Ok(())
} else {
Err("r13 is a reserved register on this target")
}
}
fn reserved_v20to31(
_arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxIndexSet<Symbol>,
target: &Target,
_is_clobber: bool,
) -> Result<(), &'static str> {
if target.is_like_aix {
match &*target.options.abi {
"vec-default" => Err("v20-v31 are reserved on vec-default ABI"),
"vec-extabi" => Ok(()),
_ => unreachable!("unrecognized AIX ABI"),
}
} else {
Ok(())
}
}
def_regs! { def_regs! {
PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass { PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass {
r0: reg = ["r0", "0"], r0: reg = ["r0", "0"],
@ -66,6 +102,7 @@ def_regs! {
r10: reg, reg_nonzero = ["r10", "10"], r10: reg, reg_nonzero = ["r10", "10"],
r11: reg, reg_nonzero = ["r11", "11"], r11: reg, reg_nonzero = ["r11", "11"],
r12: reg, reg_nonzero = ["r12", "12"], r12: reg, reg_nonzero = ["r12", "12"],
r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13,
r14: reg, reg_nonzero = ["r14", "14"], r14: reg, reg_nonzero = ["r14", "14"],
r15: reg, reg_nonzero = ["r15", "15"], r15: reg, reg_nonzero = ["r15", "15"],
r16: reg, reg_nonzero = ["r16", "16"], r16: reg, reg_nonzero = ["r16", "16"],
@ -113,6 +150,38 @@ def_regs! {
f29: freg = ["f29", "fr29"], f29: freg = ["f29", "fr29"],
f30: freg = ["f30", "fr30"], f30: freg = ["f30", "fr30"],
f31: freg = ["f31", "fr31"], f31: freg = ["f31", "fr31"],
v0: vreg = ["v0"],
v1: vreg = ["v1"],
v2: vreg = ["v2"],
v3: vreg = ["v3"],
v4: vreg = ["v4"],
v5: vreg = ["v5"],
v6: vreg = ["v6"],
v7: vreg = ["v7"],
v8: vreg = ["v8"],
v9: vreg = ["v9"],
v10: vreg = ["v10"],
v11: vreg = ["v11"],
v12: vreg = ["v12"],
v13: vreg = ["v13"],
v14: vreg = ["v14"],
v15: vreg = ["v15"],
v16: vreg = ["v16"],
v17: vreg = ["v17"],
v18: vreg = ["v18"],
v19: vreg = ["v19"],
v20: vreg = ["v20"] % reserved_v20to31,
v21: vreg = ["v21"] % reserved_v20to31,
v22: vreg = ["v22"] % reserved_v20to31,
v23: vreg = ["v23"] % reserved_v20to31,
v24: vreg = ["v24"] % reserved_v20to31,
v25: vreg = ["v25"] % reserved_v20to31,
v26: vreg = ["v26"] % reserved_v20to31,
v27: vreg = ["v27"] % reserved_v20to31,
v28: vreg = ["v28"] % reserved_v20to31,
v29: vreg = ["v29"] % reserved_v20to31,
v30: vreg = ["v30"] % reserved_v20to31,
v31: vreg = ["v31"] % reserved_v20to31,
cr: cr = ["cr"], cr: cr = ["cr"],
cr0: cr = ["cr0"], cr0: cr = ["cr0"],
cr1: cr = ["cr1"], cr1: cr = ["cr1"],
@ -127,8 +196,6 @@ def_regs! {
"the stack pointer cannot be used as an operand for inline asm", "the stack pointer cannot be used as an operand for inline asm",
#error = ["r2", "2"] => #error = ["r2", "2"] =>
"r2 is a system reserved register and cannot be used as an operand for inline asm", "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"] => #error = ["r29", "29"] =>
"r29 is used internally by LLVM and cannot be used as an operand for inline asm", "r29 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r30", "30"] => #error = ["r30", "30"] =>
@ -163,13 +230,17 @@ impl PowerPCInlineAsmReg {
// Strip off the leading prefix. // Strip off the leading prefix.
do_emit! { do_emit! {
(r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
(r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15"); (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15");
(r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23"); (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
(r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"); (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28");
(f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7"); (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
(f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15"); (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
(f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23"); (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
(f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31"); (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
(v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7");
(v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15");
(v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23");
(v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
(cr, "cr"); (cr, "cr");
(cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
(xer, "xer"); (xer, "xer");
@ -201,5 +272,6 @@ impl PowerPCInlineAsmReg {
reg_conflicts! { reg_conflicts! {
cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7; cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
} }
// f0-f31 (vsr0-vsr31) and v0-v31 (vsr32-vsr63) do not conflict.
} }
} }

View File

@ -31,9 +31,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg32` | None\* | `r` |
| NVPTX | `reg64` | None\* | `l` | | NVPTX | `reg64` | None\* | `l` |
| Hexagon | `reg` | `r[0-28]` | `r` | | Hexagon | `reg` | `r[0-28]` | `r` |
| PowerPC | `reg` | `r[0-31]` | `r` | | PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` |
| PowerPC | `reg_nonzero` | `r[1-31]` | `b` | | PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` |
| PowerPC | `freg` | `f[0-31]` | `f` | | PowerPC | `freg` | `f[0-31]` | `f` |
| PowerPC | `vreg` | `v[0-31]` | Only clobbers |
| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | | PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
| PowerPC | `xer` | `xer` | Only clobbers | | PowerPC | `xer` | `xer` | Only clobbers |
| wasm32 | `local` | None\* | `r` | | wasm32 | `local` | None\* | `r` |
@ -76,9 +77,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
| PowerPC | `reg` | None | `i8`, `i16`, `i32` | | PowerPC | `reg` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) |
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | | PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) |
| PowerPC | `freg` | None | `f32`, `f64` | | PowerPC | `freg` | None | `f32`, `f64` |
| PowerPC | `vreg` | N/A | Only clobbers |
| PowerPC | `cr` | N/A | Only clobbers | | PowerPC | `cr` | N/A | Only clobbers |
| PowerPC | `xer` | N/A | Only clobbers | | PowerPC | `xer` | N/A | Only clobbers |
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
@ -105,6 +107,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| Hexagon | `r29` | `sp` | | Hexagon | `r29` | `sp` |
| Hexagon | `r30` | `fr` | | Hexagon | `r30` | `fr` |
| Hexagon | `r31` | `lr` | | Hexagon | `r31` | `lr` |
| PowerPC | `r1` | `sp` |
| PowerPC | `r31` | `fp` |
| PowerPC | `r[0-31]` | `[0-31]` |
| PowerPC | `f[0-31]` | `fr[0-31]`|
| BPF | `r[0-10]` | `w[0-10]` | | BPF | `r[0-10]` | `w[0-10]` |
| AVR | `XH` | `r27` | | AVR | `XH` | `r27` |
| AVR | `XL` | `r26` | | AVR | `XL` | `r26` |
@ -145,14 +151,18 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| Architecture | Unsupported register | Reason | | Architecture | Unsupported register | Reason |
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. |
| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | | All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. |
| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. |
| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
| MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$1` or `$at` | Reserved for assembler. |
| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | | MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
| MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
| PowerPC | `r2`, `r13` | These are system reserved registers. |
| PowerPC | `lr` | The link register cannot be used as an input or output. |
| PowerPC | `ctr` | The counter register cannot be used as an input or output. |
| PowerPC | `vrsave` | The vrsave register cannot be used as an input or output. |
| AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. |
|MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. |
| M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. |

View File

@ -1,10 +1,12 @@
//@ revisions: powerpc powerpc64 powerpc64le //@ revisions: powerpc powerpc64 powerpc64le aix64
//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
//@[powerpc] needs-llvm-components: powerpc //@[powerpc] needs-llvm-components: powerpc
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
//@[powerpc64] needs-llvm-components: powerpc //@[powerpc64] needs-llvm-components: powerpc
//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu //@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu
//@[powerpc64le] needs-llvm-components: powerpc //@[powerpc64le] needs-llvm-components: powerpc
//@[aix64] compile-flags: --target powerpc64-ibm-aix
//@[aix64] needs-llvm-components: powerpc
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] #![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
@ -22,26 +24,40 @@ macro_rules! asm {
// CHECK: call void asm sideeffect "", "~{cr}"() // CHECK: call void asm sideeffect "", "~{cr}"()
#[no_mangle] #[no_mangle]
pub unsafe fn cr_clobber() { pub unsafe fn cr_clobber() {
asm!("", out("cr") _, options(nostack, nomem)); asm!("", out("cr") _, options(nostack, nomem, preserves_flags));
} }
// CHECK-LABEL: @cr0_clobber // CHECK-LABEL: @cr0_clobber
// CHECK: call void asm sideeffect "", "~{cr0}"() // CHECK: call void asm sideeffect "", "~{cr0}"()
#[no_mangle] #[no_mangle]
pub unsafe fn cr0_clobber() { pub unsafe fn cr0_clobber() {
asm!("", out("cr0") _, options(nostack, nomem)); asm!("", out("cr0") _, options(nostack, nomem, preserves_flags));
} }
// CHECK-LABEL: @cr5_clobber // CHECK-LABEL: @cr5_clobber
// CHECK: call void asm sideeffect "", "~{cr5}"() // CHECK: call void asm sideeffect "", "~{cr5}"()
#[no_mangle] #[no_mangle]
pub unsafe fn cr5_clobber() { pub unsafe fn cr5_clobber() {
asm!("", out("cr5") _, options(nostack, nomem)); asm!("", out("cr5") _, options(nostack, nomem, preserves_flags));
} }
// CHECK-LABEL: @xer_clobber // CHECK-LABEL: @xer_clobber
// CHECK: call void asm sideeffect "", "~{xer}"() // CHECK: call void asm sideeffect "", "~{xer}"()
#[no_mangle] #[no_mangle]
pub unsafe fn xer_clobber() { pub unsafe fn xer_clobber() {
asm!("", out("xer") _, options(nostack, nomem)); asm!("", out("xer") _, options(nostack, nomem, preserves_flags));
}
// CHECK-LABEL: @v0_clobber
// CHECK: call void asm sideeffect "", "~{v0}"()
#[no_mangle]
pub unsafe fn v0_clobber() {
asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
}
// CHECK-LABEL: @clobber_abi
// CHECK: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
#[no_mangle]
pub unsafe fn clobber_abi() {
asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
} }

View File

@ -0,0 +1,264 @@
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("sp") _);
| ^^^^^^^^^^^
error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("r2") _);
| ^^^^^^^^^^^
error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("r29") _);
| ^^^^^^^^^^^^
error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("r30") _);
| ^^^^^^^^^^^^
error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("fp") _);
| ^^^^^^^^^^^
error: invalid register `lr`: the link register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("lr") _);
| ^^^^^^^^^^^
error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("ctr") _);
| ^^^^^^^^^^^^
error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("vrsave") _);
| ^^^^^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", in("cr") x);
| ^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:69:18
|
LL | asm!("", out("cr") x);
| ^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:72:26
|
LL | asm!("/* {} */", in(cr) x);
| ^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:75:26
|
LL | asm!("/* {} */", out(cr) _);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:79:18
|
LL | asm!("", in("xer") x);
| ^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", out("xer") x);
| ^^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:85:26
|
LL | asm!("/* {} */", in(xer) x);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:88:26
|
LL | asm!("/* {} */", out(xer) _);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:93:18
|
LL | asm!("", in("v0") x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:96:18
|
LL | asm!("", out("v0") x);
| ^^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:99:26
|
LL | asm!("/* {} */", in(vreg) x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:102:26
|
LL | asm!("/* {} */", out(vreg) _);
| ^^^^^^^^^^^
error: register `cr0` conflicts with register `cr`
--> $DIR/bad-reg.rs:106:31
|
LL | asm!("", out("cr") _, out("cr0") _);
| ----------- ^^^^^^^^^^^^ register `cr0`
| |
| register `cr`
error: register `cr1` conflicts with register `cr`
--> $DIR/bad-reg.rs:108:31
|
LL | asm!("", out("cr") _, out("cr1") _);
| ----------- ^^^^^^^^^^^^ register `cr1`
| |
| register `cr`
error: register `cr2` conflicts with register `cr`
--> $DIR/bad-reg.rs:110:31
|
LL | asm!("", out("cr") _, out("cr2") _);
| ----------- ^^^^^^^^^^^^ register `cr2`
| |
| register `cr`
error: register `cr3` conflicts with register `cr`
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("cr") _, out("cr3") _);
| ----------- ^^^^^^^^^^^^ register `cr3`
| |
| register `cr`
error: register `cr4` conflicts with register `cr`
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("cr") _, out("cr4") _);
| ----------- ^^^^^^^^^^^^ register `cr4`
| |
| register `cr`
error: register `cr5` conflicts with register `cr`
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("cr") _, out("cr5") _);
| ----------- ^^^^^^^^^^^^ register `cr5`
| |
| register `cr`
error: register `cr6` conflicts with register `cr`
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("cr") _, out("cr6") _);
| ----------- ^^^^^^^^^^^^ register `cr6`
| |
| register `cr`
error: register `cr7` conflicts with register `cr`
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("cr") _, out("cr7") _);
| ----------- ^^^^^^^^^^^^ register `cr7`
| |
| register `cr`
error: cannot use register `r13`: r13 is a reserved register on this target
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("r13") _);
| ^^^^^^^^^^^^
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:66:27
|
LL | asm!("", in("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:69:28
|
LL | asm!("", out("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:72:33
|
LL | asm!("/* {} */", in(cr) x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:79:28
|
LL | asm!("", in("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:82:29
|
LL | asm!("", out("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:85:34
|
LL | asm!("/* {} */", in(xer) x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:93:27
|
LL | asm!("", in("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:96:28
|
LL | asm!("", out("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:99:35
|
LL | asm!("/* {} */", in(vreg) x);
| ^
|
= note: register class `vreg` supports these types:
error: aborting due to 38 previous errors

View File

@ -0,0 +1,264 @@
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("sp") _);
| ^^^^^^^^^^^
error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("r2") _);
| ^^^^^^^^^^^
error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("r29") _);
| ^^^^^^^^^^^^
error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("r30") _);
| ^^^^^^^^^^^^
error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("fp") _);
| ^^^^^^^^^^^
error: invalid register `lr`: the link register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("lr") _);
| ^^^^^^^^^^^
error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("ctr") _);
| ^^^^^^^^^^^^
error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("vrsave") _);
| ^^^^^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", in("cr") x);
| ^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:69:18
|
LL | asm!("", out("cr") x);
| ^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:72:26
|
LL | asm!("/* {} */", in(cr) x);
| ^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:75:26
|
LL | asm!("/* {} */", out(cr) _);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:79:18
|
LL | asm!("", in("xer") x);
| ^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", out("xer") x);
| ^^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:85:26
|
LL | asm!("/* {} */", in(xer) x);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:88:26
|
LL | asm!("/* {} */", out(xer) _);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:93:18
|
LL | asm!("", in("v0") x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:96:18
|
LL | asm!("", out("v0") x);
| ^^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:99:26
|
LL | asm!("/* {} */", in(vreg) x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:102:26
|
LL | asm!("/* {} */", out(vreg) _);
| ^^^^^^^^^^^
error: register `cr0` conflicts with register `cr`
--> $DIR/bad-reg.rs:106:31
|
LL | asm!("", out("cr") _, out("cr0") _);
| ----------- ^^^^^^^^^^^^ register `cr0`
| |
| register `cr`
error: register `cr1` conflicts with register `cr`
--> $DIR/bad-reg.rs:108:31
|
LL | asm!("", out("cr") _, out("cr1") _);
| ----------- ^^^^^^^^^^^^ register `cr1`
| |
| register `cr`
error: register `cr2` conflicts with register `cr`
--> $DIR/bad-reg.rs:110:31
|
LL | asm!("", out("cr") _, out("cr2") _);
| ----------- ^^^^^^^^^^^^ register `cr2`
| |
| register `cr`
error: register `cr3` conflicts with register `cr`
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("cr") _, out("cr3") _);
| ----------- ^^^^^^^^^^^^ register `cr3`
| |
| register `cr`
error: register `cr4` conflicts with register `cr`
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("cr") _, out("cr4") _);
| ----------- ^^^^^^^^^^^^ register `cr4`
| |
| register `cr`
error: register `cr5` conflicts with register `cr`
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("cr") _, out("cr5") _);
| ----------- ^^^^^^^^^^^^ register `cr5`
| |
| register `cr`
error: register `cr6` conflicts with register `cr`
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("cr") _, out("cr6") _);
| ----------- ^^^^^^^^^^^^ register `cr6`
| |
| register `cr`
error: register `cr7` conflicts with register `cr`
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("cr") _, out("cr7") _);
| ----------- ^^^^^^^^^^^^ register `cr7`
| |
| register `cr`
error: cannot use register `r13`: r13 is a reserved register on this target
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("r13") _);
| ^^^^^^^^^^^^
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:66:27
|
LL | asm!("", in("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:69:28
|
LL | asm!("", out("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:72:33
|
LL | asm!("/* {} */", in(cr) x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:79:28
|
LL | asm!("", in("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:82:29
|
LL | asm!("", out("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:85:34
|
LL | asm!("/* {} */", in(xer) x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:93:27
|
LL | asm!("", in("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:96:28
|
LL | asm!("", out("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:99:35
|
LL | asm!("/* {} */", in(vreg) x);
| ^
|
= note: register class `vreg` supports these types:
error: aborting due to 38 previous errors

View File

@ -0,0 +1,264 @@
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("sp") _);
| ^^^^^^^^^^^
error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("r2") _);
| ^^^^^^^^^^^
error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("r29") _);
| ^^^^^^^^^^^^
error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("r30") _);
| ^^^^^^^^^^^^
error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("fp") _);
| ^^^^^^^^^^^
error: invalid register `lr`: the link register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("lr") _);
| ^^^^^^^^^^^
error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("ctr") _);
| ^^^^^^^^^^^^
error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("vrsave") _);
| ^^^^^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", in("cr") x);
| ^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:69:18
|
LL | asm!("", out("cr") x);
| ^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:72:26
|
LL | asm!("/* {} */", in(cr) x);
| ^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:75:26
|
LL | asm!("/* {} */", out(cr) _);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:79:18
|
LL | asm!("", in("xer") x);
| ^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", out("xer") x);
| ^^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:85:26
|
LL | asm!("/* {} */", in(xer) x);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:88:26
|
LL | asm!("/* {} */", out(xer) _);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:93:18
|
LL | asm!("", in("v0") x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:96:18
|
LL | asm!("", out("v0") x);
| ^^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:99:26
|
LL | asm!("/* {} */", in(vreg) x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:102:26
|
LL | asm!("/* {} */", out(vreg) _);
| ^^^^^^^^^^^
error: register `cr0` conflicts with register `cr`
--> $DIR/bad-reg.rs:106:31
|
LL | asm!("", out("cr") _, out("cr0") _);
| ----------- ^^^^^^^^^^^^ register `cr0`
| |
| register `cr`
error: register `cr1` conflicts with register `cr`
--> $DIR/bad-reg.rs:108:31
|
LL | asm!("", out("cr") _, out("cr1") _);
| ----------- ^^^^^^^^^^^^ register `cr1`
| |
| register `cr`
error: register `cr2` conflicts with register `cr`
--> $DIR/bad-reg.rs:110:31
|
LL | asm!("", out("cr") _, out("cr2") _);
| ----------- ^^^^^^^^^^^^ register `cr2`
| |
| register `cr`
error: register `cr3` conflicts with register `cr`
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("cr") _, out("cr3") _);
| ----------- ^^^^^^^^^^^^ register `cr3`
| |
| register `cr`
error: register `cr4` conflicts with register `cr`
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("cr") _, out("cr4") _);
| ----------- ^^^^^^^^^^^^ register `cr4`
| |
| register `cr`
error: register `cr5` conflicts with register `cr`
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("cr") _, out("cr5") _);
| ----------- ^^^^^^^^^^^^ register `cr5`
| |
| register `cr`
error: register `cr6` conflicts with register `cr`
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("cr") _, out("cr6") _);
| ----------- ^^^^^^^^^^^^ register `cr6`
| |
| register `cr`
error: register `cr7` conflicts with register `cr`
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("cr") _, out("cr7") _);
| ----------- ^^^^^^^^^^^^ register `cr7`
| |
| register `cr`
error: cannot use register `r13`: r13 is a reserved register on this target
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("r13") _);
| ^^^^^^^^^^^^
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:66:27
|
LL | asm!("", in("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:69:28
|
LL | asm!("", out("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:72:33
|
LL | asm!("/* {} */", in(cr) x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:79:28
|
LL | asm!("", in("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:82:29
|
LL | asm!("", out("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:85:34
|
LL | asm!("/* {} */", in(xer) x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:93:27
|
LL | asm!("", in("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:96:28
|
LL | asm!("", out("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:99:35
|
LL | asm!("/* {} */", in(vreg) x);
| ^
|
= note: register class `vreg` supports these types:
error: aborting due to 38 previous errors

View File

@ -0,0 +1,264 @@
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("sp") _);
| ^^^^^^^^^^^
error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("r2") _);
| ^^^^^^^^^^^
error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("r29") _);
| ^^^^^^^^^^^^
error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("r30") _);
| ^^^^^^^^^^^^
error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("fp") _);
| ^^^^^^^^^^^
error: invalid register `lr`: the link register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("lr") _);
| ^^^^^^^^^^^
error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("ctr") _);
| ^^^^^^^^^^^^
error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("vrsave") _);
| ^^^^^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", in("cr") x);
| ^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:69:18
|
LL | asm!("", out("cr") x);
| ^^^^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:72:26
|
LL | asm!("/* {} */", in(cr) x);
| ^^^^^^^^
error: register class `cr` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:75:26
|
LL | asm!("/* {} */", out(cr) _);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:79:18
|
LL | asm!("", in("xer") x);
| ^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", out("xer") x);
| ^^^^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:85:26
|
LL | asm!("/* {} */", in(xer) x);
| ^^^^^^^^^
error: register class `xer` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:88:26
|
LL | asm!("/* {} */", out(xer) _);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:93:18
|
LL | asm!("", in("v0") x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:96:18
|
LL | asm!("", out("v0") x);
| ^^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:99:26
|
LL | asm!("/* {} */", in(vreg) x);
| ^^^^^^^^^^
error: register class `vreg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:102:26
|
LL | asm!("/* {} */", out(vreg) _);
| ^^^^^^^^^^^
error: register `cr0` conflicts with register `cr`
--> $DIR/bad-reg.rs:106:31
|
LL | asm!("", out("cr") _, out("cr0") _);
| ----------- ^^^^^^^^^^^^ register `cr0`
| |
| register `cr`
error: register `cr1` conflicts with register `cr`
--> $DIR/bad-reg.rs:108:31
|
LL | asm!("", out("cr") _, out("cr1") _);
| ----------- ^^^^^^^^^^^^ register `cr1`
| |
| register `cr`
error: register `cr2` conflicts with register `cr`
--> $DIR/bad-reg.rs:110:31
|
LL | asm!("", out("cr") _, out("cr2") _);
| ----------- ^^^^^^^^^^^^ register `cr2`
| |
| register `cr`
error: register `cr3` conflicts with register `cr`
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("cr") _, out("cr3") _);
| ----------- ^^^^^^^^^^^^ register `cr3`
| |
| register `cr`
error: register `cr4` conflicts with register `cr`
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("cr") _, out("cr4") _);
| ----------- ^^^^^^^^^^^^ register `cr4`
| |
| register `cr`
error: register `cr5` conflicts with register `cr`
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("cr") _, out("cr5") _);
| ----------- ^^^^^^^^^^^^ register `cr5`
| |
| register `cr`
error: register `cr6` conflicts with register `cr`
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("cr") _, out("cr6") _);
| ----------- ^^^^^^^^^^^^ register `cr6`
| |
| register `cr`
error: register `cr7` conflicts with register `cr`
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("cr") _, out("cr7") _);
| ----------- ^^^^^^^^^^^^ register `cr7`
| |
| register `cr`
error: cannot use register `r13`: r13 is a reserved register on this target
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("r13") _);
| ^^^^^^^^^^^^
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:66:27
|
LL | asm!("", in("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:69:28
|
LL | asm!("", out("cr") x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:72:33
|
LL | asm!("/* {} */", in(cr) x);
| ^
|
= note: register class `cr` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:79:28
|
LL | asm!("", in("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:82:29
|
LL | asm!("", out("xer") x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:85:34
|
LL | asm!("/* {} */", in(xer) x);
| ^
|
= note: register class `xer` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:93:27
|
LL | asm!("", in("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:96:28
|
LL | asm!("", out("v0") x);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:99:35
|
LL | asm!("/* {} */", in(vreg) x);
| ^
|
= note: register class `vreg` supports these types:
error: aborting due to 38 previous errors

View File

@ -0,0 +1,124 @@
//@ revisions: powerpc powerpc64 powerpc64le aix64
//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
//@[powerpc] needs-llvm-components: powerpc
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
//@[powerpc64] needs-llvm-components: powerpc
//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu
//@[powerpc64le] needs-llvm-components: powerpc
//@[aix64] compile-flags: --target powerpc64-ibm-aix
//@[aix64] needs-llvm-components: powerpc
//@ needs-asm-support
#![crate_type = "rlib"]
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
#![no_core]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
impl Copy for i32 {}
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
fn f() {
let mut x = 0;
unsafe {
// Unsupported registers
asm!("", out("sp") _);
//~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
asm!("", out("r2") _);
//~^ ERROR invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
asm!("", out("r13") _);
//~^ ERROR cannot use register `r13`: r13 is a reserved register on this target
asm!("", out("r29") _);
//~^ ERROR invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
asm!("", out("r30") _);
//~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
asm!("", out("fp") _);
//~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
asm!("", out("lr") _);
//~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm
asm!("", out("ctr") _);
//~^ ERROR invalid register `ctr`: the counter register cannot be used as an operand for inline asm
asm!("", out("vrsave") _);
//~^ ERROR invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
asm!("", out("v20") _);
asm!("", out("v21") _);
asm!("", out("v22") _);
asm!("", out("v23") _);
asm!("", out("v24") _);
asm!("", out("v25") _);
asm!("", out("v26") _);
asm!("", out("v27") _);
asm!("", out("v28") _);
asm!("", out("v29") _);
asm!("", out("v30") _);
asm!("", out("v31") _);
// Clobber-only registers
// cr
asm!("", out("cr") _); // ok
asm!("", in("cr") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("", out("cr") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", in(cr) x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", out(cr) _);
//~^ ERROR can only be used as a clobber
// xer
asm!("", out("xer") _); // ok
asm!("", in("xer") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("", out("xer") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", in(xer) x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", out(xer) _);
//~^ ERROR can only be used as a clobber
// vreg
asm!("", out("v0") _); // ok
// FIXME: will be supported in the subsequent patch: https://github.com/rust-lang/rust/pull/131551
asm!("", in("v0") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("", out("v0") x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", in(vreg) x);
//~^ ERROR can only be used as a clobber
//~| ERROR type `i32` cannot be used with this register class
asm!("/* {} */", out(vreg) _);
//~^ ERROR can only be used as a clobber
// Overlapping-only registers
asm!("", out("cr") _, out("cr0") _);
//~^ ERROR register `cr0` conflicts with register `cr`
asm!("", out("cr") _, out("cr1") _);
//~^ ERROR register `cr1` conflicts with register `cr`
asm!("", out("cr") _, out("cr2") _);
//~^ ERROR register `cr2` conflicts with register `cr`
asm!("", out("cr") _, out("cr3") _);
//~^ ERROR register `cr3` conflicts with register `cr`
asm!("", out("cr") _, out("cr4") _);
//~^ ERROR register `cr4` conflicts with register `cr`
asm!("", out("cr") _, out("cr5") _);
//~^ ERROR register `cr5` conflicts with register `cr`
asm!("", out("cr") _, out("cr6") _);
//~^ ERROR register `cr6` conflicts with register `cr`
asm!("", out("cr") _, out("cr7") _);
//~^ ERROR register `cr7` conflicts with register `cr`
asm!("", out("f0") _, out("v0") _); // ok
}
}