]> git.lizzy.rs Git - rust.git/blob - src/librustc_target/abi/call/powerpc64.rs
Rollup merge of #58306 - GuillaumeGomez:crate-browser-history, r=QuietMisdreavus
[rust.git] / src / librustc_target / abi / call / powerpc64.rs
1 // FIXME:
2 // Alignment of 128 bit types is not currently handled, this will
3 // need to be fixed when PowerPC vector support is added.
4
5 use crate::abi::call::{FnType, ArgType, Reg, RegKind, Uniform};
6 use crate::abi::{Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
7 use crate::spec::HasTargetSpec;
8
9 #[derive(Debug, Clone, Copy, PartialEq)]
10 enum ABI {
11     ELFv1, // original ABI used for powerpc64 (big-endian)
12     ELFv2, // newer ABI used for powerpc64le and musl (both endians)
13 }
14 use ABI::*;
15
16 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>, abi: ABI)
17                                        -> Option<Uniform>
18     where Ty: TyLayoutMethods<'a, C> + Copy,
19           C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
20 {
21     arg.layout.homogeneous_aggregate(cx).unit().and_then(|unit| {
22         // ELFv1 only passes one-member aggregates transparently.
23         // ELFv2 passes up to eight uniquely addressable members.
24         if (abi == ELFv1 && arg.layout.size > unit.size)
25                 || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
26             return None;
27         }
28
29         let valid_unit = match unit.kind {
30             RegKind::Integer => false,
31             RegKind::Float => true,
32             RegKind::Vector => arg.layout.size.bits() == 128
33         };
34
35         if valid_unit {
36             Some(Uniform {
37                 unit,
38                 total: arg.layout.size
39             })
40         } else {
41             None
42         }
43     })
44 }
45
46 fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>, abi: ABI)
47     where Ty: TyLayoutMethods<'a, C> + Copy,
48           C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
49 {
50     if !ret.layout.is_aggregate() {
51         ret.extend_integer_width_to(64);
52         return;
53     }
54
55     // The ELFv1 ABI doesn't return aggregates in registers
56     if abi == ELFv1 {
57         ret.make_indirect();
58         return;
59     }
60
61     if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
62         ret.cast_to(uniform);
63         return;
64     }
65
66     let size = ret.layout.size;
67     let bits = size.bits();
68     if bits <= 128 {
69         let unit = if cx.data_layout().endian == Endian::Big {
70             Reg { kind: RegKind::Integer, size }
71         } else if bits <= 8 {
72             Reg::i8()
73         } else if bits <= 16 {
74             Reg::i16()
75         } else if bits <= 32 {
76             Reg::i32()
77         } else {
78             Reg::i64()
79         };
80
81         ret.cast_to(Uniform {
82             unit,
83             total: size
84         });
85         return;
86     }
87
88     ret.make_indirect();
89 }
90
91 fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>, abi: ABI)
92     where Ty: TyLayoutMethods<'a, C> + Copy,
93           C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
94 {
95     if !arg.layout.is_aggregate() {
96         arg.extend_integer_width_to(64);
97         return;
98     }
99
100     if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
101         arg.cast_to(uniform);
102         return;
103     }
104
105     let size = arg.layout.size;
106     let (unit, total) = if size.bits() <= 64 {
107         // Aggregates smaller than a doubleword should appear in
108         // the least-significant bits of the parameter doubleword.
109         (Reg { kind: RegKind::Integer, size }, size)
110     } else {
111         // Aggregates larger than a doubleword should be padded
112         // at the tail to fill out a whole number of doublewords.
113         let reg_i64 = Reg::i64();
114         (reg_i64, size.align_to(reg_i64.align(cx)))
115     };
116
117     arg.cast_to(Uniform {
118         unit,
119         total
120     });
121 }
122
123 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>)
124     where Ty: TyLayoutMethods<'a, C> + Copy,
125           C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
126 {
127     let abi = if cx.target_spec().target_env == "musl" {
128         ELFv2
129     } else {
130         match cx.data_layout().endian {
131             Endian::Big => ELFv1,
132             Endian::Little => ELFv2
133         }
134     };
135
136     if !fty.ret.is_ignore() {
137         classify_ret_ty(cx, &mut fty.ret, abi);
138     }
139
140     for arg in &mut fty.args {
141         if arg.is_ignore() { continue; }
142         classify_arg_ty(cx, arg, abi);
143     }
144 }