]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/cabi_aarch64.rs
Imported Upstream version 1.0.0~beta.3
[rustc.git] / src / librustc_trans / trans / cabi_aarch64.rs
CommitLineData
1a4d82fc 1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
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
1a4d82fc 11#![allow(non_upper_case_globals)]
223e47cc 12
85aaf69f 13use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
1a4d82fc
JJ
14use llvm::{StructRetAttribute, ZExtAttribute};
15use trans::cabi::{FnType, ArgType};
16use trans::context::CrateContext;
17use trans::type_::Type;
970d7e83 18
1a4d82fc 19use std::cmp;
223e47cc 20
c34b1796 21fn align_up_to(off: usize, a: usize) -> usize {
85aaf69f 22 return (off + a - 1) / a * a;
223e47cc
LB
23}
24
c34b1796 25fn align(off: usize, ty: Type) -> usize {
223e47cc
LB
26 let a = ty_align(ty);
27 return align_up_to(off, a);
28}
29
c34b1796 30fn ty_align(ty: Type) -> usize {
970d7e83 31 match ty.kind() {
c34b1796 32 Integer => ((ty.int_width() as usize) + 7) / 8,
1a4d82fc 33 Pointer => 8,
970d7e83
LB
34 Float => 4,
35 Double => 8,
36 Struct => {
37 if ty.is_packed() {
38 1
39 } else {
40 let str_tys = ty.field_types();
1a4d82fc 41 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
223e47cc 42 }
970d7e83
LB
43 }
44 Array => {
45 let elt = ty.element_type();
46 ty_align(elt)
47 }
85aaf69f
SL
48 Vector => {
49 let len = ty.vector_length();
50 let elt = ty.element_type();
51 ty_align(elt) * len
52 }
1a4d82fc 53 _ => panic!("ty_align: unhandled type")
223e47cc
LB
54 }
55}
56
c34b1796 57fn ty_size(ty: Type) -> usize {
970d7e83 58 match ty.kind() {
c34b1796 59 Integer => ((ty.int_width() as usize) + 7) / 8,
1a4d82fc 60 Pointer => 8,
970d7e83
LB
61 Float => 4,
62 Double => 8,
63 Struct => {
64 if ty.is_packed() {
65 let str_tys = ty.field_types();
66 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
67 } else {
68 let str_tys = ty.field_types();
69 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
223e47cc
LB
70 align(size, ty)
71 }
970d7e83
LB
72 }
73 Array => {
74 let len = ty.array_length();
75 let elt = ty.element_type();
76 let eltsz = ty_size(elt);
77 len * eltsz
78 }
85aaf69f
SL
79 Vector => {
80 let len = ty.vector_length();
81 let elt = ty.element_type();
82 let eltsz = ty_size(elt);
83 len * eltsz
84 }
1a4d82fc 85 _ => panic!("ty_size: unhandled type")
223e47cc
LB
86 }
87}
88
9346a6ac
AL
89fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
90 fn check_array(ty: Type) -> Option<(Type, u64)> {
91 let len = ty.array_length() as u64;
92 if len == 0 {
93 return None
94 }
95 let elt = ty.element_type();
96
97 // if our element is an HFA/HVA, so are we; multiply members by our len
98 is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
99 }
100
101 fn check_struct(ty: Type) -> Option<(Type, u64)> {
102 let str_tys = ty.field_types();
103 if str_tys.len() == 0 {
104 return None
105 }
106
107 let mut prev_base_ty = None;
108 let mut members = 0;
109 for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
110 match (prev_base_ty, opt_homog_agg) {
111 // field isn't itself an HFA, so we aren't either
112 (_, None) => return None,
113
114 // first field - store its type and number of members
115 (None, Some((field_ty, field_members))) => {
116 prev_base_ty = Some(field_ty);
117 members = field_members;
118 },
119
120 // 2nd or later field - give up if it's a different type; otherwise incr. members
121 (Some(prev_ty), Some((field_ty, field_members))) => {
122 if prev_ty != field_ty {
123 return None;
124 }
125 members += field_members;
126 }
127 }
128 }
129
130 // Because of previous checks, we know prev_base_ty is Some(...) because
131 // 1. str_tys has at least one element; and
132 // 2. prev_base_ty was filled in (or we would've returned early)
133 let (base_ty, members) = (prev_base_ty.unwrap(), members);
134
135 // Ensure there is no padding.
136 if ty_size(ty) == ty_size(base_ty) * (members as usize) {
137 Some((base_ty, members))
138 } else {
139 None
140 }
141 }
142
143 let homog_agg = match ty.kind() {
144 Float => Some((ty, 1)),
145 Double => Some((ty, 1)),
146 Array => check_array(ty),
147 Struct => check_struct(ty),
148 Vector => match ty_size(ty) {
149 4|8 => Some((ty, 1)),
150 _ => None
151 },
152 _ => None
153 };
154
155 // Ensure we have at most four uniquely addressable members
156 homog_agg.and_then(|(base_ty, members)| {
157 if members > 0 && members <= 4 {
158 Some((base_ty, members))
159 } else {
160 None
161 }
162 })
163}
164
1a4d82fc 165fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
223e47cc 166 if is_reg_ty(ty) {
1a4d82fc
JJ
167 let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
168 return ArgType::direct(ty, None, None, attr);
223e47cc 169 }
9346a6ac
AL
170 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
171 let llty = Type::array(&base_ty, members);
172 return ArgType::direct(ty, Some(llty), None, None);
173 }
223e47cc 174 let size = ty_size(ty);
1a4d82fc 175 if size <= 16 {
223e47cc 176 let llty = if size <= 1 {
1a4d82fc 177 Type::i8(ccx)
223e47cc 178 } else if size <= 2 {
1a4d82fc
JJ
179 Type::i16(ccx)
180 } else if size <= 4 {
181 Type::i32(ccx)
182 } else if size <= 8 {
183 Type::i64(ccx)
223e47cc 184 } else {
1a4d82fc 185 Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
223e47cc 186 };
1a4d82fc 187 return ArgType::direct(ty, Some(llty), None, None);
223e47cc 188 }
1a4d82fc 189 ArgType::indirect(ty, Some(StructRetAttribute))
223e47cc
LB
190}
191
1a4d82fc 192fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
223e47cc 193 if is_reg_ty(ty) {
1a4d82fc
JJ
194 let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
195 return ArgType::direct(ty, None, None, attr);
223e47cc 196 }
9346a6ac
AL
197 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
198 let llty = Type::array(&base_ty, members);
199 return ArgType::direct(ty, Some(llty), None, None);
200 }
223e47cc 201 let size = ty_size(ty);
1a4d82fc
JJ
202 if size <= 16 {
203 let llty = if size == 0 {
c34b1796 204 Type::array(&Type::i64(ccx), 0)
1a4d82fc
JJ
205 } else if size == 1 {
206 Type::i8(ccx)
207 } else if size == 2 {
208 Type::i16(ccx)
209 } else if size <= 4 {
210 Type::i32(ccx)
211 } else if size <= 8 {
212 Type::i64(ccx)
213 } else {
214 Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
215 };
216 return ArgType::direct(ty, Some(llty), None, None);
217 }
218 ArgType::indirect(ty, None)
223e47cc
LB
219}
220
970d7e83
LB
221fn is_reg_ty(ty: Type) -> bool {
222 match ty.kind() {
223 Integer
224 | Pointer
225 | Float
85aaf69f
SL
226 | Double
227 | Vector => true,
970d7e83 228 _ => false
223e47cc
LB
229 }
230}
231
1a4d82fc
JJ
232pub fn compute_abi_info(ccx: &CrateContext,
233 atys: &[Type],
234 rty: Type,
235 ret_def: bool) -> FnType {
236 let mut arg_tys = Vec::new();
85aaf69f 237 for &aty in atys {
1a4d82fc
JJ
238 let ty = classify_arg_ty(ccx, aty);
239 arg_tys.push(ty);
223e47cc 240 }
223e47cc 241
1a4d82fc
JJ
242 let ret_ty = if ret_def {
243 classify_ret_ty(ccx, rty)
244 } else {
245 ArgType::direct(Type::void(ccx), None, None, None)
246 };
247
248 return FnType {
249 arg_tys: arg_tys,
250 ret_ty: ret_ty,
251 };
223e47cc 252}