Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 07ca922

Browse files
committedOct 12, 2024·
Support s390x z13 vector ABI
1 parent f496659 commit 07ca922

File tree

10 files changed

+281
-27
lines changed

10 files changed

+281
-27
lines changed
 

‎compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
3030
use rustc_span::Span;
3131
use rustc_span::def_id::DefId;
3232
use rustc_target::abi::call::FnAbi;
33-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
33+
use rustc_target::spec::{HasS390xVector, HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
3434

3535
use crate::common::{SignType, TypeReflection, type_is_pointer};
3636
use crate::context::CodegenCx;
@@ -2347,6 +2347,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
23472347
}
23482348
}
23492349

2350+
impl<'tcx> HasS390xVector for Builder<'_, '_, 'tcx> {
2351+
fn has_s390x_vector(&self) -> bool {
2352+
self.cx.has_s390x_vector()
2353+
}
2354+
}
2355+
23502356
pub trait ToGccComp {
23512357
fn to_gcc_comparison(&self) -> ComparisonOp;
23522358
}

‎compiler/rustc_codegen_gcc/src/context.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use rustc_session::Session;
1919
use rustc_span::source_map::respan;
2020
use rustc_span::{DUMMY_SP, Span};
2121
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
22-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
22+
use rustc_target::spec::{
23+
HasS390xVector, HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi,
24+
};
2325

2426
use crate::callee::get_fn;
2527
use crate::common::SignType;
@@ -538,6 +540,13 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
538540
}
539541
}
540542

543+
impl<'gcc, 'tcx> HasS390xVector for CodegenCx<'gcc, 'tcx> {
544+
fn has_s390x_vector(&self) -> bool {
545+
// `unstable_target_features` is used here because "vector" is gated behind s390x_target_feature.
546+
self.tcx.sess.unstable_target_features.contains(&sym::vector)
547+
}
548+
}
549+
541550
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
542551
#[inline]
543552
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {

‎compiler/rustc_middle/src/ty/layout.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
2121
use rustc_target::abi::call::FnAbi;
2222
use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call};
2323
use rustc_target::spec::abi::Abi as SpecAbi;
24-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi};
24+
use rustc_target::spec::{
25+
HasS390xVector, HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi,
26+
};
2527
use tracing::debug;
2628
use {rustc_abi as abi, rustc_hir as hir};
2729

@@ -544,6 +546,13 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
544546
}
545547
}
546548

549+
impl<'tcx> HasS390xVector for TyCtxt<'tcx> {
550+
fn has_s390x_vector(&self) -> bool {
551+
// `unstable_target_features` is used here because "vector" is gated behind s390x_target_feature.
552+
self.sess.unstable_target_features.contains(&sym::vector)
553+
}
554+
}
555+
547556
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
548557
#[inline]
549558
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -595,6 +604,12 @@ impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
595604
}
596605
}
597606

607+
impl<'tcx> HasS390xVector for LayoutCx<'tcx> {
608+
fn has_s390x_vector(&self) -> bool {
609+
self.calc.cx.has_s390x_vector()
610+
}
611+
}
612+
598613
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
599614
fn tcx(&self) -> TyCtxt<'tcx> {
600615
self.calc.cx

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,7 @@ symbols! {
21262126
vec_pop,
21272127
vec_with_capacity,
21282128
vecdeque_iter,
2129+
vector,
21292130
version,
21302131
vfp2,
21312132
vis,

‎compiler/rustc_target/src/abi/call/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_macros::HashStable_Generic;
55
use rustc_span::Symbol;
66

77
use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
8-
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
8+
use crate::spec::{self, HasS390xVector, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
99

1010
mod aarch64;
1111
mod amdgpu;
@@ -876,7 +876,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
876876
) -> Result<(), AdjustForForeignAbiError>
877877
where
878878
Ty: TyAbiInterface<'a, C> + Copy,
879-
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt,
879+
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasS390xVector,
880880
{
881881
if abi == spec::abi::Abi::X86Interrupt {
882882
if let Some(arg) = self.args.first_mut() {
Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,46 @@
1-
// FIXME: The assumes we're using the non-vector ABI, i.e., compiling
2-
// for a pre-z13 machine or using -mno-vx.
1+
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind};
2+
use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
3+
use crate::spec::{HasS390xVector, HasTargetSpec};
34

4-
use crate::abi::call::{ArgAbi, FnAbi, Reg};
5-
use crate::abi::{HasDataLayout, TyAbiInterface};
6-
use crate::spec::HasTargetSpec;
5+
#[derive(Debug, Clone, Copy, PartialEq)]
6+
enum ABI {
7+
NoVector, // no-vector ABI, i.e., compiling for a pre-z13 machine or using -C target-feature=-vector
8+
Vector, // vector ABI, i.e., compiling for a z13 or later machine or using -C target-feature=+vector
9+
}
10+
use ABI::*;
711

8-
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
9-
if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
12+
fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>, expected_size: Size) -> bool
13+
where
14+
Ty: TyAbiInterface<'a, C> + Copy,
15+
{
16+
match layout.abi {
17+
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false,
18+
Abi::Vector { .. } => layout.size == expected_size,
19+
Abi::Aggregate { .. } => {
20+
for i in 0..layout.fields.count() {
21+
if contains_vector(cx, layout.field(cx, i), expected_size) {
22+
return true;
23+
}
24+
}
25+
false
26+
}
27+
}
28+
}
29+
30+
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>, abi: ABI) {
31+
let size = ret.layout.size;
32+
if abi == Vector && size.bits() <= 128 && matches!(ret.layout.abi, Abi::Vector { .. }) {
33+
ret.cast_to(Reg { kind: RegKind::Vector, size }); // FIXME: this cast is unneeded?
34+
return;
35+
}
36+
if !ret.layout.is_aggregate() && size.bits() <= 64 {
1037
ret.extend_integer_width_to(64);
11-
} else {
12-
ret.make_indirect();
38+
return;
1339
}
40+
ret.make_indirect();
1441
}
1542

16-
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
43+
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
1744
where
1845
Ty: TyAbiInterface<'a, C> + Copy,
1946
C: HasDataLayout + HasTargetSpec,
@@ -32,19 +59,25 @@ where
3259
}
3360
return;
3461
}
35-
if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
62+
63+
let size = arg.layout.size;
64+
if abi == Vector && size.bits() <= 128 && contains_vector(cx, arg.layout, size) {
65+
arg.cast_to(Reg { kind: RegKind::Vector, size });
66+
return;
67+
}
68+
if !arg.layout.is_aggregate() && size.bits() <= 64 {
3669
arg.extend_integer_width_to(64);
3770
return;
3871
}
3972

4073
if arg.layout.is_single_fp_element(cx) {
41-
match arg.layout.size.bytes() {
74+
match size.bytes() {
4275
4 => arg.cast_to(Reg::f32()),
4376
8 => arg.cast_to(Reg::f64()),
4477
_ => arg.make_indirect(),
4578
}
4679
} else {
47-
match arg.layout.size.bytes() {
80+
match size.bytes() {
4881
1 => arg.cast_to(Reg::i8()),
4982
2 => arg.cast_to(Reg::i16()),
5083
4 => arg.cast_to(Reg::i32()),
@@ -57,13 +90,15 @@ where
5790
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
5891
where
5992
Ty: TyAbiInterface<'a, C> + Copy,
60-
C: HasDataLayout + HasTargetSpec,
93+
C: HasDataLayout + HasTargetSpec + HasS390xVector,
6194
{
95+
let abi = if cx.has_s390x_vector() { Vector } else { NoVector };
96+
6297
if !fn_abi.ret.is_ignore() {
63-
classify_ret(&mut fn_abi.ret);
98+
classify_ret(&mut fn_abi.ret, abi);
6499
}
65100

66101
for arg in fn_abi.args.iter_mut() {
67-
classify_arg(cx, arg);
102+
classify_arg(cx, arg, abi);
68103
}
69104
}

‎compiler/rustc_target/src/spec/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,10 @@ pub trait HasWasmCAbiOpt {
20962096
fn wasm_c_abi_opt(&self) -> WasmCAbi;
20972097
}
20982098

2099+
pub trait HasS390xVector {
2100+
fn has_s390x_vector(&self) -> bool;
2101+
}
2102+
20992103
type StaticCow<T> = Cow<'static, T>;
21002104

21012105
/// Optional aspects of a target specification.

‎compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
66
base.endian = Endian::Big;
77
// z10 is the oldest CPU supported by LLVM
88
base.cpu = "z10".into();
9-
// FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
10-
// ABI. Pass the -vector feature string to LLVM to respect this assumption.
11-
base.features = "-vector".into();
129
base.max_atomic_width = Some(128);
1310
base.min_global_align = Some(16);
1411
base.stack_probes = StackProbeType::Inline;

‎compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
66
base.endian = Endian::Big;
77
// z10 is the oldest CPU supported by LLVM
88
base.cpu = "z10".into();
9-
// FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
10-
// ABI. Pass the -vector feature string to LLVM to respect this assumption.
11-
base.features = "-vector".into();
129
base.max_atomic_width = Some(128);
1310
base.min_global_align = Some(16);
1411
base.static_position_independent_executables = true;

‎tests/assembly/s390x-vector-abi.rs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
//@ revisions: z10 z10_vector z13 z13_no_vector
2+
// ignore-tidy-linelength
3+
//@ assembly-output: emit-asm
4+
//@ compile-flags: -O -Z merge-functions=disabled
5+
//@[z10] compile-flags: --target s390x-unknown-linux-gnu
6+
//@[z10] needs-llvm-components: systemz
7+
//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
8+
//@[z10_vector] needs-llvm-components: systemz
9+
//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13
10+
//@[z13] needs-llvm-components: systemz
11+
//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector
12+
//@[z13_no_vector] needs-llvm-components: systemz
13+
14+
#![feature(no_core, lang_items, repr_simd)]
15+
#![no_core]
16+
#![crate_type = "lib"]
17+
#![allow(non_camel_case_types)]
18+
19+
#[lang = "sized"]
20+
pub trait Sized {}
21+
#[lang = "copy"]
22+
pub trait Copy {}
23+
#[lang = "freeze"]
24+
pub trait Freeze {}
25+
26+
impl<T: Copy, const N: usize> Copy for [T; N] {}
27+
28+
#[repr(simd)]
29+
pub struct i8x8([i8; 8]);
30+
#[repr(simd)]
31+
pub struct i8x16([i8; 16]);
32+
#[repr(simd)]
33+
pub struct i8x32([i8; 32]);
34+
pub struct Wrapper<T>(T);
35+
36+
impl Copy for i8 {}
37+
impl Copy for i64 {}
38+
impl Copy for i8x8 {}
39+
impl Copy for i8x16 {}
40+
impl Copy for i8x32 {}
41+
impl<T: Copy> Copy for Wrapper<T> {}
42+
43+
// CHECK-LABEL: vector_ret_small:
44+
// z10: lg %r0, 0(%r3)
45+
// z10-NEXT: stg %r0, 0(%r2)
46+
// z10-NEXT: br %r14
47+
// z13_no_vector: lg %r0, 0(%r3)
48+
// z13_no_vector-NEXT: stg %r0, 0(%r2)
49+
// z13_no_vector-NEXT: br %r14
50+
// z10_vector: vlrepg %v24, 0(%r2)
51+
// z10_vector-NEXT: br %r14
52+
// z13: vlrepg %v24, 0(%r2)
53+
// z13-NEXT: br %r14
54+
#[no_mangle]
55+
extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
56+
*x
57+
}
58+
// CHECK-LABEL: vector_ret:
59+
// z10: mvc 8(8,%r2), 8(%r3)
60+
// z10-NEXT: mvc 0(8,%r2), 0(%r3)
61+
// z10-NEXT: br %r14
62+
// z13: vl %v24, 0(%r2), 3
63+
// z13-NEXT: br %r14
64+
#[no_mangle]
65+
extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
66+
*x
67+
}
68+
// CHECK-LABEL: vector_ret_large:
69+
// z10: mvc 24(8,%r2), 24(%r3)
70+
// z10-NEXT: mvc 16(8,%r2), 16(%r3)
71+
// z10-NEXT: mvc 8(8,%r2), 8(%r3)
72+
// z10-NEXT: mvc 0(8,%r2), 0(%r3)
73+
// z10-NEXT: br %r14
74+
// z13: vl %v0, 0(%r3), 4
75+
// z13-NEXT: vl %v1, 16(%r3), 4
76+
// z13-NEXT: vst %v1, 16(%r2), 4
77+
// z13-NEXT: vst %v0, 0(%r2), 4
78+
// z13-NEXT: br %r14
79+
#[no_mangle]
80+
extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 {
81+
*x
82+
}
83+
84+
// FIXME: single-element vector aggregates are treated like vectors only as arguments, not as return types
85+
// CHECK-LABEL: vector_wrapper_ret_small:
86+
// z10: lg %r0, 0(%r3)
87+
// z10-NEXT: stg %r0, 0(%r2)
88+
// z10-NEXT: br %r14
89+
// z13: vlrepg %v24, 0(%r2)
90+
// z13-NEXT: br %r14
91+
#[no_mangle]
92+
extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> {
93+
*x
94+
}
95+
// FIXME: single-element vector aggregates are treated like vectors only as arguments, not as return types
96+
// CHECK-LABEL: vector_wrapper_ret:
97+
// z10: mvc 8(8,%r2), 8(%r3)
98+
// z10-NEXT: mvc 0(8,%r2), 0(%r3)
99+
// z10-NEXT: br %r14
100+
// z13: vl %v24, 0(%r2), 3
101+
// z13-NEXT: br %r14
102+
#[no_mangle]
103+
extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> {
104+
*x
105+
}
106+
// CHECK-LABEL: vector_wrapper_ret_large:
107+
// z10: mvc 24(8,%r2), 24(%r3)
108+
// z10-NEXT: mvc 16(8,%r2), 16(%r3)
109+
// z10-NEXT: mvc 8(8,%r2), 8(%r3)
110+
// z10-NEXT: mvc 0(8,%r2), 0(%r3)
111+
// z10-NEXT: br %r14
112+
// z13: vl %v0, 0(%r3), 4
113+
// z13-NEXT: vl %v1, 16(%r3), 4
114+
// z13-NEXT: vst %v1, 16(%r2), 4
115+
// z13-NEXT: vst %v0, 0(%r2), 4
116+
// z13-NEXT: br %r14
117+
#[no_mangle]
118+
extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> {
119+
*x
120+
}
121+
122+
// FIXME: should check output for z10, but it is very long...
123+
// vector_arg_small:
124+
// .cfi_startproc
125+
// stmg %r6, %r15, 48(%r15)
126+
// .cfi_offset %r6, -112
127+
// .cfi_offset %r15, -40
128+
// risbg %r5, %r4, 32, 55, 8
129+
// sll %r2, 24
130+
// lb %r0, 175(%r15)
131+
// rosbg %r2, %r3, 40, 47, 16
132+
// rosbg %r2, %r5, 48, 63, 0
133+
// llc %r1, 167(%r15)
134+
// sll %r0, 8
135+
// ic %r0, 183(%r15)
136+
// sllg %r2, %r2, 32
137+
// sll %r6, 24
138+
// rosbg %r6, %r1, 32, 47, 16
139+
// rosbg %r6, %r0, 48, 63, 0
140+
// lr %r2, %r6
141+
// lmg %r6, %r15, 48(%r15)
142+
// br %r14
143+
// CHECK-LABEL: vector_arg_small:
144+
// z13: vlgvg %r2, %v24, 0
145+
// z13-NEXT: br %r14
146+
#[no_mangle]
147+
extern "C" fn vector_arg_small(x: i8x8) -> i64 {
148+
unsafe { *(&x as *const i8x8 as *const i64) }
149+
}
150+
// CHECK-LABEL: vector_arg:
151+
// z10: lg %r2, 0(%r2)
152+
// z10-NEXT: br %r14
153+
// z13: vlgvg %r2, %v24, 0
154+
// z13-NEXT: br %r14
155+
#[no_mangle]
156+
extern "C" fn vector_arg(x: i8x16) -> i64 {
157+
unsafe { *(&x as *const i8x16 as *const i64) }
158+
}
159+
// CHECK-LABEL: vector_arg_large:
160+
// CHECK: lg %r2, 0(%r2)
161+
// CHECK-NEXT: br %r14
162+
#[no_mangle]
163+
extern "C" fn vector_arg_large(x: i8x32) -> i64 {
164+
unsafe { *(&x as *const i8x32 as *const i64) }
165+
}
166+
167+
// FIXME: should check output for z10, but it is very long...
168+
// CHECK-LABEL: vector_wrapper_arg_small:
169+
// z13: vlgvg %r2, %v24, 0
170+
// z13-NEXT: br %r14
171+
#[no_mangle]
172+
extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
173+
unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
174+
}
175+
// CHECK-LABEL: vector_wrapper_arg:
176+
// z10: lg %r2, 0(%r2)
177+
// z10-NEXT: br %r14
178+
// z13: vlgvg %r2, %v24, 0
179+
// z13-NEXT: br %r14
180+
#[no_mangle]
181+
extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
182+
unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
183+
}
184+
// CHECK-LABEL: vector_wrapper_arg_large:
185+
// CHECK: lg %r2, 0(%r2)
186+
// CHECK-NEXT: br %r14
187+
#[no_mangle]
188+
extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
189+
unsafe { *(&x as *const Wrapper<i8x32> as *const i64) }
190+
}

0 commit comments

Comments
 (0)
Please sign in to comment.