Skip to content

Commit ab82ad9

Browse files
committed
Feature gate fp, and other registers. Add Xtensa to asm! documentation.
1 parent 4e1bfd7 commit ab82ad9

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

compiler/rustc_target/src/asm/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ impl fmt::Display for InlineAsmRegOrRegClass {
593593
/// Set of types which can be used with a particular register class.
594594
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
595595
pub enum InlineAsmType {
596+
I1,
596597
I8,
597598
I16,
598599
I32,
@@ -616,6 +617,7 @@ impl InlineAsmType {
616617

617618
pub fn size(self) -> Size {
618619
Size::from_bytes(match self {
620+
Self::I1 => return Size::from_bits(1),
619621
Self::I8 => 1,
620622
Self::I16 => 2,
621623
Self::I32 => 4,
@@ -637,6 +639,7 @@ impl InlineAsmType {
637639
impl fmt::Display for InlineAsmType {
638640
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639641
match *self {
642+
Self::I1 => f.write_str("i1"),
640643
Self::I8 => f.write_str("i8"),
641644
Self::I16 => f.write_str("i16"),
642645
Self::I32 => f.write_str("i32"),

compiler/rustc_target/src/asm/xtensa.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ impl XtensaInlineAsmRegClass {
3737
_arch: InlineAsmArch,
3838
) -> &'static [(InlineAsmType, Option<&'static str>)] {
3939
match self {
40-
Self::reg | Self::breg => types! { _: I8, I16, I32; },
41-
Self::freg => types! { "fp":F32; }, // TODO how does the dfpaccel feature interact F64 types? // _:F64;
40+
Self::reg => types! { _: I8, I16, I32; },
41+
Self::breg => types! { "bool": I1; },
42+
Self::freg => types! { "fp":F32; "dfpaccel":F64; },
4243
}
4344
}
4445
}
@@ -101,31 +102,57 @@ fn has_gpio_out(
101102
}
102103
}
103104

105+
fn frame_pointer_is_a7(
106+
_arch: InlineAsmArch,
107+
mut has_feature: impl FnMut(&str) -> bool,
108+
_target: &Target,
109+
) -> bool {
110+
has_feature("windowed")
111+
}
112+
113+
fn frame_pointer_a7(
114+
arch: InlineAsmArch,
115+
has_feature: impl FnMut(&str) -> bool,
116+
target: &Target,
117+
) -> Result<(), &'static str> {
118+
if frame_pointer_is_a7(arch, has_feature, target) {
119+
Err("the frame pointer (a7) cannot be used as an operand for inline asm")
120+
} else {
121+
Ok(())
122+
}
123+
}
104124

125+
fn frame_pointer_a15(
126+
arch: InlineAsmArch,
127+
has_feature: impl FnMut(&str) -> bool,
128+
target: &Target,
129+
) -> Result<(), &'static str> {
130+
if !frame_pointer_is_a7(arch, has_feature, target) {
131+
Err("the frame pointer (a15) cannot be used as an operand for inline asm")
132+
} else {
133+
Ok(())
134+
}
135+
}
105136

106137
def_regs! {
107138
Xtensa XtensaInlineAsmReg XtensaInlineAsmRegClass {
108-
a0: reg = ["a0"],
109-
sp: reg = ["sp", "a1"],
110139
a2: reg = ["a2"],
111140
a3: reg = ["a3"],
112141
a4: reg = ["a4"],
113142
a5: reg = ["a5"],
114143
a6: reg = ["a6"],
115-
a7: reg = ["a7"],
144+
a7: reg = ["a7"] % frame_pointer_a7,
116145
a8: reg = ["a8"],
117146
a9: reg = ["a9"],
118147
a10: reg = ["a10"],
119148
a11: reg = ["a11"],
120149
a12: reg = ["a12"],
121150
a13: reg = ["a13"],
122151
a14: reg = ["a14"],
123-
a15: reg = ["a15"],
124-
sar: reg = ["sar"], // TODO what feature enables this, if any?
125-
ddr: reg = ["ddr"], // TODO what feature enables this, if any?
126-
ps: reg = ["ps"], // TODO what feature enables this, if any?
127-
configid0: reg = ["configid0"], // TODO what feature enables this, if any?
128-
configid1: reg = ["configid1"], // TODO what feature enables this, if any?
152+
a15: reg = ["a15"] % frame_pointer_a15,
153+
sar: reg = ["sar"],
154+
configid0: reg = ["configid0"],
155+
configid1: reg = ["configid1"],
129156
lbeg: reg = ["lbeg"] % has_loop,
130157
lend: reg = ["lend"] % has_loop,
131158
lcount: reg = ["lcount"] % has_loop,
@@ -139,6 +166,7 @@ def_regs! {
139166
m3: reg = ["m3"] % has_mac16,
140167
windowbase: reg = ["windowbase"] % has_windowed,
141168
windowstart: reg = ["windowstart"] % has_windowed,
169+
ddr: reg = ["ddr"] % has_debug,
142170
ibreakenable: reg = ["ibreakenable"] % has_debug,
143171
ibreaka0: reg = ["ibreaka0"] % has_debug,
144172
ibreaka1: reg = ["ibreaka1"] % has_debug,
@@ -151,6 +179,7 @@ def_regs! {
151179
debugcause: reg = ["debugcause"] % has_debug,
152180
memctl: reg = ["memctl"] % has_memctl,
153181
atomctl: reg = ["atomctl"] % has_atomctl,
182+
ps: reg = ["ps"] % has_exception,
154183
epc1: reg = ["epc1"] % has_exception,
155184
epc2: reg = ["epc2"] % has_exception,
156185
epc3: reg = ["epc3"] % has_exception,
@@ -229,6 +258,9 @@ def_regs! {
229258
b13: breg = ["b13"] % has_bool,
230259
b14: breg = ["b14"] % has_bool,
231260
b15: breg = ["b15"] % has_bool,
261+
262+
#error = ["a0"] => "a0 is used internally by LLVM and cannot be used as an operand for inline asm",
263+
#error = ["sp", "a1"] => "sp is used internally by LLVM and cannot be used as an operand for inline asm",
232264
}
233265
}
234266

src/doc/unstable-book/src/library-features/asm.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Inline assembly is currently supported on the following architectures:
3030
- Hexagon
3131
- MIPS32r2 and MIPS64r2
3232
- wasm32
33+
- Xtensa
3334
- BPF
3435

3536
## Basic usage
@@ -461,7 +462,7 @@ options := "options(" option *["," option] [","] ")"
461462
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
462463
```
463464

464-
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.
465+
The macro will initially be supported only on ARM, AArch64, Hexagon, PowerPC, Xtensa, 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.
465466

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

@@ -571,8 +572,25 @@ Here is the list of currently supported register classes:
571572
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
572573
| PowerPC | `freg` | `f[0-31]` | `f` |
573574
| wasm32 | `local` | None\* | `r` |
575+
| Xtensa | `reg` | `a[0-15]` | `r` |
576+
| Xtensa | `freg` | `f[0-15]` | `f` |
577+
| Xtensa | `breg` | `b[0-15]` | `b` |
574578
| BPF | `reg` | `r[0-10]` | `r` |
575579
| BPF | `wreg` | `w[0-10]` | `w` |
580+
| Xtensa | `reg` | `a[0-15]`, `lbeg`, `lend`, `lcount` | `r` |
581+
| Xtensa | `reg` | `sar`, `br`, `litbase`, `scompare1` | `r` |
582+
| Xtensa | `reg` | `acclo`, `acchi`, `m0`, `m1`, `m2`, `m3` | `r` |
583+
| Xtensa | `reg` | `windowbase`, `windowstart`, `ibreakenable`, `memctl`, `atomctl`, `ddr` | `r` |
584+
| Xtensa | `reg` | `ibreaka0`, `ibreaka1`, `dbreaka0`, `dbreaka1`, `dbreakc0`, `dbreakc1`, `configid[0-1]` | `r` |
585+
| Xtensa | `reg` | `epc[1-7]`, `depc`, `eps[2-7]` | `r` |
586+
| Xtensa | `reg` | `excsave[1-7]`, `cpenable`, `interrupt`, `intclear`, `intenable` | `r` |
587+
| Xtensa | `reg` | `ps`, `vecbase`, `exccause`, `debugcause`, `ccount` | `r` |
588+
| Xtensa | `reg` | `prid`, `icount`, `icountlevel`, `excvaddr`, `ccompare[0-2]` | `r` |
589+
| Xtensa | `reg` | `excsave[1-7]`, `cpenable`, `interrupt`, `intclear`, `intenable` | `r` |
590+
| Xtensa | `reg` | `misc[0-3]`, `gpio_out`, `expstate`, `threadptr` | `r` |
591+
| Xtensa | `reg` | `fcr`, `fsr`, `f64r_lo`, `f64r_hi`, `f64s` | `r` |
592+
| Xtensa | `breg` | `b[0-15]` | `b` |
593+
| Xtensa | `freg` | `f[0-15]` | `f` |
576594

577595
> **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.
578596
>
@@ -620,6 +638,9 @@ Each register class has constraints on which value types they can be used with.
620638
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
621639
| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
622640
| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
641+
| Xtensa | `reg` | None | `i8`, `i16`, `i32` |
642+
| Xtensa | `breg` | None | None |
643+
| Xtensa | `freg` | None | `f32` |
623644

624645
> **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).
625646
@@ -680,6 +701,7 @@ Some registers have multiple names. These are all treated by the compiler as ide
680701
| Hexagon | `r30` | `fr` |
681702
| Hexagon | `r31` | `lr` |
682703
| BPF | `r[0-10]` | `w[0-10]` |
704+
| Xtensa | `a1` | `sp` |
683705

684706
Some registers cannot be used for input or output operands:
685707

@@ -703,6 +725,7 @@ Some registers cannot be used for input or output operands:
703725
| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
704726
| RISC-V | `x0` | This is a constant zero register which can't be modified. |
705727
| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
728+
| Xtensa | `a7` or `a15` | On Xtensa the frame pointer can be either `a7` or `a15` depending on whether the target supports the windowed ABI. The frame pointer cannot be used as an input or output. |
706729
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
707730

708731
In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
@@ -760,6 +783,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
760783
| PowerPC | `reg` | None | `0` | None |
761784
| PowerPC | `reg_nonzero` | None | `3` | `b` |
762785
| PowerPC | `freg` | None | `0` | None |
786+
| Xtensa | `reg` | None | `a0` | None |
787+
| Xtensa | `breg` | None | `b0` | None |
788+
| Xtensa | `freg` | None | `f0` | None |
763789

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

0 commit comments

Comments
 (0)