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