Skip to content

Commit b9ab03c

Browse files
committed
Support GPR pair in RISC-V inline assembly
1 parent 08f833a commit b9ab03c

15 files changed

Lines changed: 460 additions & 112 deletions

File tree

compiler/rustc_codegen_gcc/src/asm.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
723723
unreachable!("clobber-only")
724724
}
725725
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
726+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg_pair) => "R",
726727
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
727728
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
728729
unreachable!("clobber-only")
@@ -807,6 +808,13 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
807808
unreachable!("clobber-only")
808809
}
809810
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
811+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg_pair) => {
812+
if cx.tcx.sess.asm_arch.unwrap() == InlineAsmArch::RiscV64 {
813+
cx.type_i128()
814+
} else {
815+
cx.type_i64()
816+
}
817+
}
810818
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
811819
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
812820
unreachable!("clobber-only")
@@ -983,6 +991,7 @@ fn modifier_to_gcc(
983991
}
984992
InlineAsmRegClass::PowerPC(_) => None,
985993
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
994+
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg_pair)
986995
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
987996
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
988997
unreachable!("clobber-only")

compiler/rustc_codegen_llvm/src/asm.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
669669
unreachable!("clobber-only")
670670
}
671671
RiscV(RiscVInlineAsmRegClass::reg) => "r",
672+
RiscV(RiscVInlineAsmRegClass::reg_pair) => "R",
672673
RiscV(RiscVInlineAsmRegClass::freg) => "f",
673674
RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"),
674675
X86(X86InlineAsmRegClass::reg) => "r",
@@ -757,7 +758,9 @@ fn modifier_to_llvm(
757758
if modifier.is_none() { Some('x') } else { modifier }
758759
}
759760
PowerPC(_) => None,
760-
RiscV(RiscVInlineAsmRegClass::reg) | RiscV(RiscVInlineAsmRegClass::freg) => None,
761+
RiscV(RiscVInlineAsmRegClass::reg)
762+
| RiscV(RiscVInlineAsmRegClass::reg_pair)
763+
| RiscV(RiscVInlineAsmRegClass::freg) => None,
761764
RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"),
762765
X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
763766
None if arch == InlineAsmArch::X86_64 => Some('q'),
@@ -850,6 +853,13 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
850853
unreachable!("clobber-only")
851854
}
852855
RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
856+
RiscV(RiscVInlineAsmRegClass::reg_pair) => {
857+
if cx.tcx.sess.asm_arch.unwrap() == InlineAsmArch::RiscV64 {
858+
cx.type_i128()
859+
} else {
860+
cx.type_i64()
861+
}
862+
}
853863
RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
854864
RiscV(RiscVInlineAsmRegClass::vreg) => unreachable!("clobber-only"),
855865
X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),

compiler/rustc_target/src/asm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ impl InlineAsmRegClass {
617617
Self::X86(r) => r.supported_types(arch),
618618
Self::Arm(r) => r.supported_types(arch),
619619
Self::AArch64(r) => r.supported_types(arch),
620-
Self::RiscV(r) => r.supported_types(arch),
620+
Self::RiscV(r) => r.supported_types(arch, allow_experimental_reg),
621621
Self::Nvptx(r) => r.supported_types(arch),
622622
Self::PowerPC(r) => r.supported_types(arch),
623623
Self::Hexagon(r) => r.supported_types(arch),

compiler/rustc_target/src/asm/riscv.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::spec::{RelocModel, Target};
99
def_reg_class! {
1010
RiscV RiscVInlineAsmRegClass {
1111
reg,
12+
reg_pair,
1213
freg,
1314
vreg,
1415
}
@@ -38,6 +39,7 @@ impl RiscVInlineAsmRegClass {
3839
pub fn supported_types(
3940
self,
4041
arch: InlineAsmArch,
42+
allow_experimental_reg: bool,
4143
) -> &'static [(InlineAsmType, Option<Symbol>)] {
4244
match self {
4345
Self::reg => {
@@ -47,6 +49,18 @@ impl RiscVInlineAsmRegClass {
4749
types! { _: I8, I16, I32, F16, F32; }
4850
}
4951
}
52+
Self::reg_pair => {
53+
if allow_experimental_reg {
54+
// register pair support is unstable.
55+
if arch == InlineAsmArch::RiscV64 {
56+
types! { _: I128; }
57+
} else {
58+
types! { _: I64; }
59+
}
60+
} else {
61+
&[]
62+
}
63+
}
5064
// FIXME(f16_f128): Add `q: F128;` once LLVM support the `Q` extension.
5165
Self::freg => types! { f: F16, F32; d: F64; },
5266
Self::vreg => &[],

src/doc/unstable-book/src/language-features/asm-experimental-reg.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This tracks support for additional registers in architectures where inline assem
1313
| Architecture | Register class | Registers | LLVM constraint code |
1414
| ------------ | -------------- | --------- | -------------------- |
1515
| s390x | `vreg` | `v[0-31]` | `v` |
16+
| RISC-V | `reg_pair` | | `R` |
1617

1718
> **Notes**:
1819
> - s390x `vreg` is clobber-only in stable.
@@ -22,6 +23,8 @@ This tracks support for additional registers in architectures where inline assem
2223
| Architecture | Register class | Target feature | Allowed types |
2324
| ------------ | -------------- | -------------- | ------------- |
2425
| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
26+
| RISC-V32 | `reg_pair` | | `i64` |
27+
| RISC-V64 | `reg_pair` | | `i128` |
2528

2629
## Register aliases
2730

@@ -38,3 +41,4 @@ This tracks support for additional registers in architectures where inline assem
3841
| Architecture | Register class | Modifier | Example output | LLVM modifier |
3942
| ------------ | -------------- | -------- | -------------- | ------------- |
4043
| s390x | `vreg` | None | `%v0` | None |
44+
| RISC-V | `reg_pair` | None | `a0` | None |

tests/assembly-llvm/asm/riscv-types.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//@ compile-flags: -C target-feature=+d
3131
//@ compile-flags: -Zmerge-functions=disabled
3232

33-
#![feature(no_core, f16)]
33+
#![feature(no_core, f16, asm_experimental_reg)]
3434
#![crate_type = "rlib"]
3535
#![no_core]
3636
#![allow(asm_sub_register)]
@@ -136,6 +136,20 @@ check!(reg_f64 f64 reg "mv");
136136
// CHECK: #NO_APP
137137
check!(reg_ptr ptr reg "mv");
138138

139+
// riscv32-LABEL: reg_pair_i64:
140+
// riscv32: #APP
141+
// riscv32: mv {{[a-z0-9]+[02468]}}, {{[a-z0-9]+[02468]}}
142+
// riscv32: #NO_APP
143+
#[cfg(riscv32)]
144+
check!(reg_pair_i64 i64 reg_pair "mv");
145+
146+
// riscv64-LABEL: reg_pair_i128:
147+
// riscv64: #APP
148+
// riscv64: mv {{[a-z0-9]+[02468]}}, {{[a-z0-9]+[02468]}}
149+
// riscv64: #NO_APP
150+
#[cfg(riscv64)]
151+
check!(reg_pair_i128 i128 reg_pair "mv");
152+
139153
// CHECK-LABEL: freg_f16:
140154
// zfhmin-NOT: or
141155
// CHECK: #APP

tests/ui/asm/riscv/bad-reg.riscv32e.stderr

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,201 @@
11
error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
2-
--> $DIR/bad-reg.rs:33:18
2+
--> $DIR/bad-reg.rs:42:18
33
|
44
LL | asm!("", out("s1") _);
55
| ^^^^^^^^^^^
66

77
error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
8-
--> $DIR/bad-reg.rs:35:18
8+
--> $DIR/bad-reg.rs:44:18
99
|
1010
LL | asm!("", out("fp") _);
1111
| ^^^^^^^^^^^
1212

1313
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
14-
--> $DIR/bad-reg.rs:37:18
14+
--> $DIR/bad-reg.rs:46:18
1515
|
1616
LL | asm!("", out("sp") _);
1717
| ^^^^^^^^^^^
1818

1919
error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
20-
--> $DIR/bad-reg.rs:39:18
20+
--> $DIR/bad-reg.rs:48:18
2121
|
2222
LL | asm!("", out("gp") _);
2323
| ^^^^^^^^^^^
2424

2525
error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
26-
--> $DIR/bad-reg.rs:41:18
26+
--> $DIR/bad-reg.rs:50:18
2727
|
2828
LL | asm!("", out("tp") _);
2929
| ^^^^^^^^^^^
3030

3131
error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
32-
--> $DIR/bad-reg.rs:43:18
32+
--> $DIR/bad-reg.rs:52:18
3333
|
3434
LL | asm!("", out("zero") _);
3535
| ^^^^^^^^^^^^^
3636

3737
error: register class `vreg` can only be used as a clobber, not as an input or output
38-
--> $DIR/bad-reg.rs:94:18
38+
--> $DIR/bad-reg.rs:117:18
3939
|
4040
LL | asm!("", in("v0") x);
4141
| ^^^^^^^^^^
4242

4343
error: register class `vreg` can only be used as a clobber, not as an input or output
44-
--> $DIR/bad-reg.rs:97:18
44+
--> $DIR/bad-reg.rs:120:18
4545
|
4646
LL | asm!("", out("v0") x);
4747
| ^^^^^^^^^^^
4848

4949
error: register class `vreg` can only be used as a clobber, not as an input or output
50-
--> $DIR/bad-reg.rs:100:26
50+
--> $DIR/bad-reg.rs:123:26
5151
|
5252
LL | asm!("/* {} */", in(vreg) x);
5353
| ^^^^^^^^^^
5454

5555
error: register class `vreg` can only be used as a clobber, not as an input or output
56-
--> $DIR/bad-reg.rs:103:26
56+
--> $DIR/bad-reg.rs:126:26
5757
|
5858
LL | asm!("/* {} */", out(vreg) _);
5959
| ^^^^^^^^^^^
6060

6161
error: cannot use register `x16`: register can't be used with the `e` target feature
62-
--> $DIR/bad-reg.rs:46:18
62+
--> $DIR/bad-reg.rs:55:18
6363
|
6464
LL | asm!("", out("x16") _);
6565
| ^^^^^^^^^^^^
6666

6767
error: cannot use register `x17`: register can't be used with the `e` target feature
68-
--> $DIR/bad-reg.rs:48:18
68+
--> $DIR/bad-reg.rs:57:18
6969
|
7070
LL | asm!("", out("x17") _);
7171
| ^^^^^^^^^^^^
7272

7373
error: cannot use register `x18`: register can't be used with the `e` target feature
74-
--> $DIR/bad-reg.rs:50:18
74+
--> $DIR/bad-reg.rs:59:18
7575
|
7676
LL | asm!("", out("x18") _);
7777
| ^^^^^^^^^^^^
7878

7979
error: cannot use register `x19`: register can't be used with the `e` target feature
80-
--> $DIR/bad-reg.rs:52:18
80+
--> $DIR/bad-reg.rs:61:18
8181
|
8282
LL | asm!("", out("x19") _);
8383
| ^^^^^^^^^^^^
8484

8585
error: cannot use register `x20`: register can't be used with the `e` target feature
86-
--> $DIR/bad-reg.rs:54:18
86+
--> $DIR/bad-reg.rs:63:18
8787
|
8888
LL | asm!("", out("x20") _);
8989
| ^^^^^^^^^^^^
9090

9191
error: cannot use register `x21`: register can't be used with the `e` target feature
92-
--> $DIR/bad-reg.rs:56:18
92+
--> $DIR/bad-reg.rs:65:18
9393
|
9494
LL | asm!("", out("x21") _);
9595
| ^^^^^^^^^^^^
9696

9797
error: cannot use register `x22`: register can't be used with the `e` target feature
98-
--> $DIR/bad-reg.rs:58:18
98+
--> $DIR/bad-reg.rs:67:18
9999
|
100100
LL | asm!("", out("x22") _);
101101
| ^^^^^^^^^^^^
102102

103103
error: cannot use register `x23`: register can't be used with the `e` target feature
104-
--> $DIR/bad-reg.rs:60:18
104+
--> $DIR/bad-reg.rs:69:18
105105
|
106106
LL | asm!("", out("x23") _);
107107
| ^^^^^^^^^^^^
108108

109109
error: cannot use register `x24`: register can't be used with the `e` target feature
110-
--> $DIR/bad-reg.rs:62:18
110+
--> $DIR/bad-reg.rs:71:18
111111
|
112112
LL | asm!("", out("x24") _);
113113
| ^^^^^^^^^^^^
114114

115115
error: cannot use register `x25`: register can't be used with the `e` target feature
116-
--> $DIR/bad-reg.rs:64:18
116+
--> $DIR/bad-reg.rs:73:18
117117
|
118118
LL | asm!("", out("x25") _);
119119
| ^^^^^^^^^^^^
120120

121121
error: cannot use register `x26`: register can't be used with the `e` target feature
122-
--> $DIR/bad-reg.rs:66:18
122+
--> $DIR/bad-reg.rs:75:18
123123
|
124124
LL | asm!("", out("x26") _);
125125
| ^^^^^^^^^^^^
126126

127127
error: cannot use register `x27`: register can't be used with the `e` target feature
128-
--> $DIR/bad-reg.rs:68:18
128+
--> $DIR/bad-reg.rs:77:18
129129
|
130130
LL | asm!("", out("x27") _);
131131
| ^^^^^^^^^^^^
132132

133133
error: cannot use register `x28`: register can't be used with the `e` target feature
134-
--> $DIR/bad-reg.rs:70:18
134+
--> $DIR/bad-reg.rs:79:18
135135
|
136136
LL | asm!("", out("x28") _);
137137
| ^^^^^^^^^^^^
138138

139139
error: cannot use register `x29`: register can't be used with the `e` target feature
140-
--> $DIR/bad-reg.rs:72:18
140+
--> $DIR/bad-reg.rs:81:18
141141
|
142142
LL | asm!("", out("x29") _);
143143
| ^^^^^^^^^^^^
144144

145145
error: cannot use register `x30`: register can't be used with the `e` target feature
146-
--> $DIR/bad-reg.rs:74:18
146+
--> $DIR/bad-reg.rs:83:18
147147
|
148148
LL | asm!("", out("x30") _);
149149
| ^^^^^^^^^^^^
150150

151151
error: cannot use register `x31`: register can't be used with the `e` target feature
152-
--> $DIR/bad-reg.rs:76:18
152+
--> $DIR/bad-reg.rs:85:18
153153
|
154154
LL | asm!("", out("x31") _);
155155
| ^^^^^^^^^^^^
156156

157157
error: register class `freg` requires at least one of the following target features: d, f
158-
--> $DIR/bad-reg.rs:80:26
158+
--> $DIR/bad-reg.rs:103:26
159159
|
160160
LL | asm!("/* {} */", in(freg) f);
161161
| ^^^^^^^^^^
162162

163163
error: register class `freg` requires at least one of the following target features: d, f
164-
--> $DIR/bad-reg.rs:82:26
164+
--> $DIR/bad-reg.rs:105:26
165165
|
166166
LL | asm!("/* {} */", out(freg) _);
167167
| ^^^^^^^^^^^
168168

169169
error: register class `freg` requires at least one of the following target features: d, f
170-
--> $DIR/bad-reg.rs:84:26
170+
--> $DIR/bad-reg.rs:107:26
171171
|
172172
LL | asm!("/* {} */", in(freg) d);
173173
| ^^^^^^^^^^
174174

175175
error: register class `freg` requires at least one of the following target features: d, f
176-
--> $DIR/bad-reg.rs:87:26
176+
--> $DIR/bad-reg.rs:110:26
177177
|
178178
LL | asm!("/* {} */", out(freg) d);
179179
| ^^^^^^^^^^^
180180

181181
error: type `i32` cannot be used with this register class
182-
--> $DIR/bad-reg.rs:94:27
182+
--> $DIR/bad-reg.rs:117:27
183183
|
184184
LL | asm!("", in("v0") x);
185185
| ^
186186
|
187187
= note: register class `vreg` supports these types:
188188

189189
error: type `i32` cannot be used with this register class
190-
--> $DIR/bad-reg.rs:97:28
190+
--> $DIR/bad-reg.rs:120:28
191191
|
192192
LL | asm!("", out("v0") x);
193193
| ^
194194
|
195195
= note: register class `vreg` supports these types:
196196

197197
error: type `i32` cannot be used with this register class
198-
--> $DIR/bad-reg.rs:100:35
198+
--> $DIR/bad-reg.rs:123:35
199199
|
200200
LL | asm!("/* {} */", in(vreg) x);
201201
| ^

0 commit comments

Comments
 (0)