]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/cabi_powerpc64.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / librustc_trans / cabi_powerpc64.rs
1 // Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // FIXME:
12 // Alignment of 128 bit types is not currently handled, this will
13 // need to be fixed when PowerPC vector support is added.
14
15 use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform};
16 use context::CrateContext;
17 use rustc::ty::layout;
18
19 #[derive(Debug, Clone, Copy, PartialEq)]
20 enum ABI {
21 ELFv1, // original ABI used for powerpc64 (big-endian)
22 ELFv2, // newer ABI used for powerpc64le
23 }
24 use self::ABI::*;
25
26 fn is_homogeneous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
27 arg: &mut ArgType<'tcx>,
28 abi: ABI)
29 -> Option<Uniform> {
30 arg.layout.homogeneous_aggregate(ccx).and_then(|unit| {
31 let size = arg.layout.size(ccx);
32
33 // ELFv1 only passes one-member aggregates transparently.
34 // ELFv2 passes up to eight uniquely addressable members.
35 if (abi == ELFv1 && size > unit.size)
36 || size > unit.size.checked_mul(8, ccx).unwrap() {
37 return None;
38 }
39
40 let valid_unit = match unit.kind {
41 RegKind::Integer => false,
42 RegKind::Float => true,
43 RegKind::Vector => size.bits() == 128
44 };
45
46 if valid_unit {
47 Some(Uniform {
48 unit,
49 total: size
50 })
51 } else {
52 None
53 }
54 })
55 }
56
57 fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>, abi: ABI) {
58 if !ret.layout.is_aggregate() {
59 ret.extend_integer_width_to(64);
60 return;
61 }
62
63 // The ELFv1 ABI doesn't return aggregates in registers
64 if abi == ELFv1 {
65 ret.make_indirect(ccx);
66 return;
67 }
68
69 if let Some(uniform) = is_homogeneous_aggregate(ccx, ret, abi) {
70 ret.cast_to(ccx, uniform);
71 return;
72 }
73
74 let size = ret.layout.size(ccx);
75 let bits = size.bits();
76 if bits <= 128 {
77 let unit = if bits <= 8 {
78 Reg::i8()
79 } else if bits <= 16 {
80 Reg::i16()
81 } else if bits <= 32 {
82 Reg::i32()
83 } else {
84 Reg::i64()
85 };
86
87 ret.cast_to(ccx, Uniform {
88 unit,
89 total: size
90 });
91 return;
92 }
93
94 ret.make_indirect(ccx);
95 }
96
97 fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>, abi: ABI) {
98 if !arg.layout.is_aggregate() {
99 arg.extend_integer_width_to(64);
100 return;
101 }
102
103 if let Some(uniform) = is_homogeneous_aggregate(ccx, arg, abi) {
104 arg.cast_to(ccx, uniform);
105 return;
106 }
107
108 let size = arg.layout.size(ccx);
109 let (unit, total) = match abi {
110 ELFv1 => {
111 // In ELFv1, aggregates smaller than a doubleword should appear in
112 // the least-significant bits of the parameter doubleword. The rest
113 // should be padded at their tail to fill out multiple doublewords.
114 if size.bits() <= 64 {
115 (Reg { kind: RegKind::Integer, size }, size)
116 } else {
117 let align = layout::Align::from_bits(64, 64).unwrap();
118 (Reg::i64(), size.abi_align(align))
119 }
120 },
121 ELFv2 => {
122 // In ELFv2, we can just cast directly.
123 (Reg::i64(), size)
124 },
125 };
126
127 arg.cast_to(ccx, Uniform {
128 unit,
129 total
130 });
131 }
132
133 pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
134 let abi = match ccx.sess().target.target.target_endian.as_str() {
135 "big" => ELFv1,
136 "little" => ELFv2,
137 _ => unimplemented!(),
138 };
139
140 if !fty.ret.is_ignore() {
141 classify_ret_ty(ccx, &mut fty.ret, abi);
142 }
143
144 for arg in &mut fty.args {
145 if arg.is_ignore() { continue; }
146 classify_arg_ty(ccx, arg, abi);
147 }
148 }