Skip to content

Commit 9b0b4c8

Browse files
committed
Make s390x non-clobber-only vector register support unstable
1 parent 2c8f6de commit 9b0b4c8

File tree

18 files changed

+775
-146
lines changed

18 files changed

+775
-146
lines changed

compiler/rustc_ast_lowering/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}`
152152
153153
ast_lowering_register_class_only_clobber =
154154
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
155+
ast_lowering_register_class_only_clobber_stable =
156+
this register class can only be used as a clobber in stable
155157
156158
ast_lowering_register_conflict =
157159
register `{$reg1_name}` conflicts with register `{$reg2_name}`

compiler/rustc_ast_lowering/src/asm.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
6161
.emit();
6262
}
6363
}
64+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
6465
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
6566
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
6667
&& !self.tcx.sess.opts.actually_rustdoc
@@ -333,11 +334,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
333334
// means that we disallow passing a value in/out of the asm and
334335
// require that the operand name an explicit register, not a
335336
// register class.
336-
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
337-
self.dcx().emit_err(RegisterClassOnlyClobber {
338-
op_span: op_sp,
339-
reg_class_name: reg_class.name(),
340-
});
337+
if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg)
338+
&& !op.is_clobber()
339+
{
340+
if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true)
341+
{
342+
// always clobber-only
343+
self.dcx().emit_err(RegisterClassOnlyClobber {
344+
op_span: op_sp,
345+
reg_class_name: reg_class.name(),
346+
});
347+
} else {
348+
// clobber-only in stable
349+
feature_err(
350+
&self.tcx.sess,
351+
sym::asm_experimental_reg,
352+
sp,
353+
fluent::ast_lowering_register_class_only_clobber_stable,
354+
)
355+
.emit();
356+
}
341357
continue;
342358
}
343359

compiler/rustc_codegen_cranelift/src/inline_asm.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
153153
let mut asm_gen = InlineAssemblyGenerator {
154154
tcx: fx.tcx,
155155
arch: fx.tcx.sess.asm_arch.unwrap(),
156+
allow_experimental_reg: fx.tcx.features().asm_experimental_reg(),
156157
enclosing_def_id: fx.instance.def_id(),
157158
template,
158159
operands,
@@ -296,6 +297,7 @@ pub(crate) fn codegen_naked_asm<'tcx>(
296297
let asm_gen = InlineAssemblyGenerator {
297298
tcx,
298299
arch: tcx.sess.asm_arch.unwrap(),
300+
allow_experimental_reg: tcx.features().asm_experimental_reg(),
299301
enclosing_def_id: instance.def_id(),
300302
template,
301303
operands: &operands,
@@ -315,6 +317,7 @@ pub(crate) fn codegen_naked_asm<'tcx>(
315317
struct InlineAssemblyGenerator<'a, 'tcx> {
316318
tcx: TyCtxt<'tcx>,
317319
arch: InlineAsmArch,
320+
allow_experimental_reg: bool,
318321
enclosing_def_id: DefId,
319322
template: &'a [InlineAsmTemplatePiece],
320323
operands: &'a [CInlineAsmOperand<'tcx>],
@@ -462,8 +465,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
462465
let mut slots_output = vec![None; self.operands.len()];
463466

464467
let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
465-
let reg_size =
466-
reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
468+
let reg_size = reg_class
469+
.supported_types(self.arch, self.allow_experimental_reg)
470+
.iter()
471+
.map(|(ty, _)| ty.size())
472+
.max()
473+
.unwrap();
467474
let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
468475
let offset = slot_size.align_to(align);
469476
*slot_size = offset + reg_size;

compiler/rustc_codegen_gcc/src/asm.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
125125
let asm_arch = self.tcx.sess.asm_arch.unwrap();
126126
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
127127
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
128+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
128129

129130
// GCC index of an output operand equals its position in the array
130131
let mut outputs = vec![];
@@ -185,18 +186,19 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
185186
(Register(reg_name), None) => {
186187
// `clobber_abi` can add lots of clobbers that are not supported by the target,
187188
// such as AVX-512 registers, so we just ignore unsupported registers
188-
let is_target_supported =
189-
reg.reg_class().supported_types(asm_arch).iter().any(
190-
|&(_, feature)| {
191-
if let Some(feature) = feature {
192-
self.tcx
193-
.asm_target_features(instance.def_id())
194-
.contains(&feature)
195-
} else {
196-
true // Register class is unconditionally supported
197-
}
198-
},
199-
);
189+
let is_target_supported = reg
190+
.reg_class()
191+
.supported_types(asm_arch, allow_experimental_reg)
192+
.iter()
193+
.any(|&(_, feature)| {
194+
if let Some(feature) = feature {
195+
self.tcx
196+
.asm_target_features(instance.def_id())
197+
.contains(&feature)
198+
} else {
199+
true // Register class is unconditionally supported
200+
}
201+
});
200202

201203
if is_target_supported && !clobbers.contains(&reg_name) {
202204
clobbers.push(reg_name);

compiler/rustc_codegen_llvm/src/asm.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
3434
catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
3535
) {
3636
let asm_arch = self.tcx.sess.asm_arch.unwrap();
37+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
3738

3839
// Collect the types of output operands
3940
let mut constraints = vec![];
@@ -45,7 +46,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
4546
match *op {
4647
InlineAsmOperandRef::Out { reg, late, place } => {
4748
let is_target_supported = |reg_class: InlineAsmRegClass| {
48-
for &(_, feature) in reg_class.supported_types(asm_arch) {
49+
for &(_, feature) in
50+
reg_class.supported_types(asm_arch, allow_experimental_reg)
51+
{
4952
if let Some(feature) = feature {
5053
if self
5154
.tcx
@@ -85,7 +88,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
8588
}
8689
continue;
8790
} else if !is_target_supported(reg.reg_class())
88-
|| reg.reg_class().is_clobber_only(asm_arch)
91+
|| reg.reg_class().is_clobber_only(asm_arch, allow_experimental_reg)
8992
{
9093
// We turn discarded outputs into clobber constraints
9194
// if the target feature needed by the register class is

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ declare_features! (
376376
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
377377
/// Enables experimental inline assembly support for additional architectures.
378378
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
379+
/// Enables experimental register support in inline assembly.
380+
(unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)),
379381
/// Allows using `label` operands in inline assembly.
380382
(unstable, asm_goto, "1.78.0", Some(119364)),
381383
/// Allows the `may_unwind` option in inline assembly.

compiler/rustc_hir_analysis/src/check/intrinsicck.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
218218
// Check the type against the list of types supported by the selected
219219
// register class.
220220
let asm_arch = self.tcx.sess.asm_arch.unwrap();
221+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
221222
let reg_class = reg.reg_class();
222-
let supported_tys = reg_class.supported_types(asm_arch);
223+
let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg);
223224
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
224225
let msg = format!("type `{ty}` cannot be used with this register class");
225226
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
@@ -313,6 +314,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
313314
self.tcx.dcx().delayed_bug("target architecture does not support asm");
314315
return;
315316
};
317+
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
316318
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
317319
// Validate register classes against currently enabled target
318320
// features. We check that at least one type is available for
@@ -352,7 +354,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
352354
if let InlineAsmRegClass::Err = reg_class {
353355
continue;
354356
}
355-
for &(_, feature) in reg_class.supported_types(asm_arch) {
357+
for &(_, feature) in reg_class.supported_types(asm_arch, allow_experimental_reg)
358+
{
356359
match feature {
357360
Some(feature) => {
358361
if target_features.contains(&feature) {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ symbols! {
416416
asm,
417417
asm_const,
418418
asm_experimental_arch,
419+
asm_experimental_reg,
419420
asm_goto,
420421
asm_sym,
421422
asm_unwind,

compiler/rustc_target/src/asm/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ impl InlineAsmRegClass {
607607
pub fn supported_types(
608608
self,
609609
arch: InlineAsmArch,
610+
allow_experimental_reg: bool,
610611
) -> &'static [(InlineAsmType, Option<Symbol>)] {
611612
match self {
612613
Self::X86(r) => r.supported_types(arch),
@@ -618,7 +619,7 @@ impl InlineAsmRegClass {
618619
Self::Hexagon(r) => r.supported_types(arch),
619620
Self::LoongArch(r) => r.supported_types(arch),
620621
Self::Mips(r) => r.supported_types(arch),
621-
Self::S390x(r) => r.supported_types(arch),
622+
Self::S390x(r) => r.supported_types(arch, allow_experimental_reg),
622623
Self::Sparc(r) => r.supported_types(arch),
623624
Self::SpirV(r) => r.supported_types(arch),
624625
Self::Wasm(r) => r.supported_types(arch),
@@ -696,8 +697,8 @@ impl InlineAsmRegClass {
696697

697698
/// Returns whether registers in this class can only be used as clobbers
698699
/// and not as inputs/outputs.
699-
pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
700-
self.supported_types(arch).is_empty()
700+
pub fn is_clobber_only(self, arch: InlineAsmArch, allow_experimental_reg: bool) -> bool {
701+
self.supported_types(arch, allow_experimental_reg).is_empty()
701702
}
702703
}
703704

compiler/rustc_target/src/asm/s390x.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,22 @@ impl S390xInlineAsmRegClass {
3838
pub fn supported_types(
3939
self,
4040
_arch: InlineAsmArch,
41+
allow_experimental_reg: bool,
4142
) -> &'static [(InlineAsmType, Option<Symbol>)] {
4243
match self {
4344
Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
4445
Self::freg => types! { _: F32, F64; },
45-
Self::vreg => types! {
46-
vector: I32, F32, I64, F64, I128, F128,
47-
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
48-
},
46+
Self::vreg => {
47+
if allow_experimental_reg {
48+
// non-clobber-only vector register support is unstable.
49+
types! {
50+
vector: I32, F32, I64, F64, I128, F128,
51+
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
52+
}
53+
} else {
54+
&[]
55+
}
56+
}
4957
Self::areg => &[],
5058
}
5159
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# `asm_experimental_arch`
2+
3+
The tracking issue for this feature is: [#133416]
4+
5+
[#133416]: https://github.com/rust-lang/rust/issues/133416
6+
7+
------------------------
8+
9+
This tracks support for additional registers in architectures where inline assembly is already stable.
10+
11+
## Register classes
12+
13+
| Architecture | Register class | Registers | LLVM constraint code |
14+
| ------------ | -------------- | --------- | -------------------- |
15+
| s390x | `vreg` | `v[0-31]` | `v` |
16+
17+
> **Notes**:
18+
> - s390x `vreg` is clobber-only in stable.
19+
20+
## Register class supported types
21+
22+
| Architecture | Register class | Target feature | Allowed types |
23+
| ------------ | -------------- | -------------- | ------------- |
24+
| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
25+
26+
## Register aliases
27+
28+
| Architecture | Base register | Aliases |
29+
| ------------ | ------------- | ------- |
30+
31+
## Unsupported registers
32+
33+
| Architecture | Unsupported register | Reason |
34+
| ------------ | -------------------- | ------ |
35+
36+
## Template modifiers
37+
38+
| Architecture | Register class | Modifier | Example output | LLVM modifier |
39+
| ------------ | -------------- | -------- | -------------- | ------------- |
40+
| s390x | `vreg` | None | `%v0` | None |

tests/assembly/asm/s390x-types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//@ compile-flags: -Zmerge-functions=disabled
88

99
#![feature(no_core, lang_items, rustc_attrs, repr_simd, f128)]
10+
#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
1011
#![crate_type = "rlib"]
1112
#![no_core]
1213
#![allow(asm_sub_register, non_camel_case_types)]

tests/ui/asm/s390x/bad-reg.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
//@ add-core-stubs
22
//@ needs-asm-support
3-
//@ revisions: s390x s390x_vector
3+
//@ revisions: s390x s390x_vector s390x_vector_stable
44
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
55
//@[s390x] needs-llvm-components: systemz
66
//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
77
//@[s390x_vector] needs-llvm-components: systemz
8+
//@[s390x_vector_stable] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
9+
//@[s390x_vector_stable] needs-llvm-components: systemz
810

911
#![crate_type = "rlib"]
1012
#![feature(no_core, rustc_attrs, repr_simd)]
13+
#![cfg_attr(not(s390x_vector_stable), feature(asm_experimental_reg))]
1114
#![no_core]
1215
#![allow(non_camel_case_types)]
1316

@@ -68,29 +71,48 @@ fn f() {
6871

6972
// vreg
7073
asm!("", out("v0") _); // always ok
71-
asm!("", in("v0") v); // requires vector
74+
asm!("", in("v0") v); // requires vector & asm_experimental_reg
7275
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
73-
asm!("", out("v0") v); // requires vector
76+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
77+
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class
78+
asm!("", out("v0") v); // requires vector & asm_experimental_reg
7479
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
75-
asm!("", in("v0") x); // requires vector
80+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
81+
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class
82+
asm!("", in("v0") x); // requires vector & asm_experimental_reg
7683
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
77-
asm!("", out("v0") x); // requires vector
84+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
85+
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class
86+
asm!("", out("v0") x); // requires vector & asm_experimental_reg
7887
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
88+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
89+
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class
7990
asm!("", in("v0") b);
8091
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
8192
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
93+
//[s390x_vector_stable]~^^^ ERROR this register class can only be used as a clobber in stable [E0658]
94+
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
8295
asm!("", out("v0") b);
8396
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
8497
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
85-
asm!("/* {} */", in(vreg) v); // requires vector
98+
//[s390x_vector_stable]~^^^ ERROR this register class can only be used as a clobber in stable [E0658]
99+
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
100+
asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
86101
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
87-
asm!("/* {} */", in(vreg) x); // requires vector
102+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
103+
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class
104+
asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
88105
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
106+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
107+
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class
89108
asm!("/* {} */", in(vreg) b);
90109
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
91110
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
92-
asm!("/* {} */", out(vreg) _); // requires vector
111+
//[s390x_vector_stable]~^^^ ERROR this register class can only be used as a clobber in stable [E0658]
112+
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
113+
asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
93114
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
115+
//[s390x_vector_stable]~^^ ERROR this register class can only be used as a clobber in stable [E0658]
94116

95117
// Clobber-only registers
96118
// areg

0 commit comments

Comments
 (0)