Skip to main content

rustc_target/callconv/
s390x.rs

1// Reference: ELF Application Binary Interface s390x Supplement
2// https://github.com/IBM/s390x-abi
3
4use rustc_abi::{BackendRepr, FieldsShape, HasDataLayout, Primitive, TyAbiInterface, TyAndLayout};
5
6use crate::callconv::{ArgAbi, FnAbi, Reg};
7use crate::spec::{Env, HasTargetSpec, Os};
8
9/// Is this a struct with a single float field?
10fn is_single_fp_element<'a, Ty, C>(mut layout: TyAndLayout<'a, Ty>, cx: &C) -> bool
11where
12    Ty: TyAbiInterface<'a, C> + Copy,
13    C: HasDataLayout,
14{
15    // Contrary to X86, trailing padding is allowed on s390x.
16
17    loop {
18        layout = layout.peel_transparent_wrappers(cx);
19
20        return match layout.backend_repr {
21            BackendRepr::Scalar(scalar) => match scalar.primitive() {
22                Primitive::Float(_) => true,
23                Primitive::Int(_, _) | Primitive::Pointer(_) => false,
24            },
25            BackendRepr::Memory { .. } => {
26                // A single-element array or union does not qualify.
27                if let FieldsShape::Arbitrary { .. } = layout.fields
28                    && layout.fields.count() == 1
29                    && layout.fields.offset(0).bytes() == 0
30                {
31                    layout = layout.field(cx, 0);
32                    continue;
33                } else {
34                    false
35                }
36            }
37            _ => false,
38        };
39    }
40}
41
42fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
43    let size = ret.layout.size;
44    if size.bits() <= 128 && #[allow(non_exhaustive_omitted_patterns)] match ret.layout.backend_repr {
    BackendRepr::SimdVector { .. } => true,
    _ => false,
}matches!(ret.layout.backend_repr, BackendRepr::SimdVector { .. }) {
45        return;
46    }
47    if !ret.layout.is_aggregate() && size.bits() <= 64 {
48        ret.extend_integer_width_to(64);
49    } else {
50        ret.make_indirect();
51    }
52}
53
54fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
55where
56    Ty: TyAbiInterface<'a, C> + Copy,
57    C: HasDataLayout + HasTargetSpec,
58{
59    if !arg.layout.is_sized() {
60        // Not touching this...
61        return;
62    }
63    if arg.is_ignore() {
64        // s390x-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
65        if cx.target_spec().os == Os::Linux
66            && #[allow(non_exhaustive_omitted_patterns)] match cx.target_spec().env {
    Env::Gnu | Env::Musl | Env::Uclibc => true,
    _ => false,
}matches!(cx.target_spec().env, Env::Gnu | Env::Musl | Env::Uclibc)
67            && arg.layout.is_zst()
68        {
69            arg.make_indirect_from_ignore();
70        }
71        return;
72    }
73    if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
74        arg.make_indirect();
75        return;
76    }
77
78    if arg.layout.is_complex_number(cx) {
79        arg.make_indirect();
80        return;
81    }
82
83    let size = arg.layout.size;
84    if size.bits() <= 128 {
85        if let BackendRepr::SimdVector { .. } = arg.layout.backend_repr {
86            // pass non-wrapped vector types using `PassMode::Direct`
87            return;
88        }
89
90        if arg.layout.is_single_vector_element(cx, size) {
91            // pass non-transparent wrappers around a vector as `PassMode::Cast`
92            arg.cast_to(Reg::opaque_vector(size));
93            return;
94        }
95    }
96    if !arg.layout.is_aggregate() && size.bits() <= 64 {
97        arg.extend_integer_width_to(64);
98        return;
99    }
100
101    if is_single_fp_element(arg.layout, cx) {
102        // Match GCC and Clang by explicitly passing padding, even though their behavior violates
103        // (our reading of) the specification, which says that:
104        //
105        // > Structures equivalent to a floating point type are passed in floating point registers.
106        // > A structure is equivalent to a floating point type if and only if it has exactly one
107        // > member, which is either of floating point type of itself a structure equivalent to a
108        // > floating point type.
109        //
110        // When the alignment is higher than 8, we pass the argument indirectly, which violates
111        // the specification but is consistent with GCC and Clang.
112        match size.bytes() {
113            2 => arg.cast_to(Reg::f16()),
114            4 => arg.cast_to(Reg::f32()),
115            8 => arg.cast_to(Reg::f64()),
116            _ => arg.make_indirect(),
117        }
118    } else {
119        match size.bytes() {
120            1 => arg.cast_to(Reg::i8()),
121            2 => arg.cast_to(Reg::i16()),
122            4 => arg.cast_to(Reg::i32()),
123            8 => arg.cast_to(Reg::i64()),
124            _ => arg.make_indirect(),
125        }
126    }
127}
128
129pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
130where
131    Ty: TyAbiInterface<'a, C> + Copy,
132    C: HasDataLayout + HasTargetSpec,
133{
134    if !fn_abi.ret.is_ignore() {
135        classify_ret(&mut fn_abi.ret);
136    }
137
138    for arg in fn_abi.args.iter_mut() {
139        classify_arg(cx, arg);
140    }
141}