]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/cabi_x86_64.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc_trans / cabi_x86_64.rs
CommitLineData
970d7e83 1// Copyright 2012-2013 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
11// The classification code for the x86_64 ABI is taken from the clay language
12// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
13
1a4d82fc
JJ
14#![allow(non_upper_case_globals)]
15use self::RegClass::*;
223e47cc 16
1a4d82fc 17use llvm::{Integer, Pointer, Float, Double};
85aaf69f 18use llvm::{Struct, Array, Attribute, Vector};
c30ab7b3 19use abi::{self, ArgType, FnType};
54a0048b
SL
20use context::CrateContext;
21use type_::Type;
970d7e83 22
1a4d82fc 23#[derive(Clone, Copy, PartialEq)]
970d7e83
LB
24enum RegClass {
25 NoClass,
26 Int,
27 SSEFs,
28 SSEFv,
29 SSEDs,
30 SSEDv,
85aaf69f
SL
31 SSEInt(/* bitwidth */ u64),
32 /// Data that can appear in the upper half of an SSE register.
970d7e83
LB
33 SSEUp,
34 X87,
35 X87Up,
36 ComplexX87,
37 Memory
223e47cc
LB
38}
39
970d7e83
LB
40trait TypeMethods {
41 fn is_reg_ty(&self) -> bool;
223e47cc
LB
42}
43
970d7e83
LB
44impl TypeMethods for Type {
45 fn is_reg_ty(&self) -> bool {
46 match self.kind() {
47 Integer | Pointer | Float | Double => true,
48 _ => false
49 }
50 }
223e47cc
LB
51}
52
970d7e83
LB
53impl RegClass {
54 fn is_sse(&self) -> bool {
55 match *self {
85aaf69f 56 SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
970d7e83
LB
57 _ => false
58 }
59 }
60}
61
62trait ClassList {
63 fn is_pass_byval(&self) -> bool;
64 fn is_ret_bysret(&self) -> bool;
65}
66
1a4d82fc 67impl ClassList for [RegClass] {
970d7e83 68 fn is_pass_byval(&self) -> bool {
9346a6ac 69 if self.is_empty() { return false; }
970d7e83
LB
70
71 let class = self[0];
72 class == Memory
73 || class == X87
74 || class == ComplexX87
75 }
76
77 fn is_ret_bysret(&self) -> bool {
9346a6ac 78 if self.is_empty() { return false; }
970d7e83
LB
79
80 self[0] == Memory
81 }
82}
83
1a4d82fc 84fn classify_ty(ty: Type) -> Vec<RegClass> {
c34b1796 85 fn align(off: usize, ty: Type) -> usize {
223e47cc 86 let a = ty_align(ty);
85aaf69f 87 return (off + a - 1) / a * a;
223e47cc
LB
88 }
89
c34b1796 90 fn ty_align(ty: Type) -> usize {
c30ab7b3 91 abi::ty_align(ty, 8)
223e47cc
LB
92 }
93
c34b1796 94 fn ty_size(ty: Type) -> usize {
c30ab7b3 95 abi::ty_size(ty, 8)
223e47cc
LB
96 }
97
970d7e83 98 fn all_mem(cls: &mut [RegClass]) {
85aaf69f 99 for elt in cls {
1a4d82fc 100 *elt = Memory;
223e47cc
LB
101 }
102 }
103
970d7e83 104 fn unify(cls: &mut [RegClass],
c34b1796 105 i: usize,
970d7e83 106 newv: RegClass) {
85aaf69f
SL
107 if cls[i] == newv { return }
108
109 let to_write = match (cls[i], newv) {
110 (NoClass, _) => newv,
111 (_, NoClass) => return,
112
113 (Memory, _) |
114 (_, Memory) => Memory,
115
116 (Int, _) |
117 (_, Int) => Int,
118
119 (X87, _) |
120 (X87Up, _) |
121 (ComplexX87, _) |
122 (_, X87) |
123 (_, X87Up) |
124 (_, ComplexX87) => Memory,
125
126 (SSEFv, SSEUp) |
127 (SSEFs, SSEUp) |
128 (SSEDv, SSEUp) |
129 (SSEDs, SSEUp) |
130 (SSEInt(_), SSEUp) => return,
131
9e0c209e 132 (..) => newv
85aaf69f
SL
133 };
134 cls[i] = to_write;
223e47cc
LB
135 }
136
970d7e83 137 fn classify_struct(tys: &[Type],
1a4d82fc 138 cls: &mut [RegClass],
c34b1796
AL
139 i: usize,
140 off: usize,
1a4d82fc 141 packed: bool) {
223e47cc 142 let mut field_off = off;
85aaf69f 143 for ty in tys {
1a4d82fc
JJ
144 if !packed {
145 field_off = align(field_off, *ty);
146 }
223e47cc
LB
147 classify(*ty, cls, i, field_off);
148 field_off += ty_size(*ty);
149 }
150 }
151
970d7e83 152 fn classify(ty: Type,
c34b1796
AL
153 cls: &mut [RegClass], ix: usize,
154 off: usize) {
970d7e83
LB
155 let t_align = ty_align(ty);
156 let t_size = ty_size(ty);
157
158 let misalign = off % t_align;
85aaf69f
SL
159 if misalign != 0 {
160 let mut i = off / 8;
161 let e = (off + t_size + 7) / 8;
970d7e83
LB
162 while i < e {
163 unify(cls, ix + i, Memory);
85aaf69f 164 i += 1;
223e47cc 165 }
970d7e83
LB
166 return;
167 }
223e47cc 168
970d7e83
LB
169 match ty.kind() {
170 Integer |
171 Pointer => {
85aaf69f 172 unify(cls, ix + off / 8, Int);
970d7e83
LB
173 }
174 Float => {
85aaf69f
SL
175 if off % 8 == 4 {
176 unify(cls, ix + off / 8, SSEFv);
970d7e83 177 } else {
85aaf69f 178 unify(cls, ix + off / 8, SSEFs);
223e47cc 179 }
970d7e83
LB
180 }
181 Double => {
85aaf69f 182 unify(cls, ix + off / 8, SSEDs);
970d7e83
LB
183 }
184 Struct => {
85aaf69f 185 classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
970d7e83
LB
186 }
187 Array => {
188 let len = ty.array_length();
189 let elt = ty.element_type();
190 let eltsz = ty_size(elt);
85aaf69f 191 let mut i = 0;
970d7e83
LB
192 while i < len {
193 classify(elt, cls, ix, off + i * eltsz);
85aaf69f
SL
194 i += 1;
195 }
196 }
197 Vector => {
198 let len = ty.vector_length();
199 let elt = ty.element_type();
200 let eltsz = ty_size(elt);
201 let mut reg = match elt.kind() {
202 Integer => SSEInt(elt.int_width()),
203 Float => SSEFv,
204 Double => SSEDv,
54a0048b 205 _ => bug!("classify: unhandled vector element type")
85aaf69f
SL
206 };
207
208 let mut i = 0;
209 while i < len {
210 unify(cls, ix + (off + i * eltsz) / 8, reg);
211
212 // everything after the first one is the upper
213 // half of a register.
214 reg = SSEUp;
215 i += 1;
223e47cc 216 }
223e47cc 217 }
54a0048b 218 _ => bug!("classify: unhandled type")
223e47cc
LB
219 }
220 }
221
970d7e83 222 fn fixup(ty: Type, cls: &mut [RegClass]) {
85aaf69f 223 let mut i = 0;
970d7e83
LB
224 let ty_kind = ty.kind();
225 let e = cls.len();
85aaf69f 226 if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
970d7e83 227 if cls[i].is_sse() {
85aaf69f 228 i += 1;
223e47cc 229 while i < e {
970d7e83 230 if cls[i] != SSEUp {
223e47cc
LB
231 all_mem(cls);
232 return;
233 }
85aaf69f 234 i += 1;
970d7e83
LB
235 }
236 } else {
237 all_mem(cls);
238 return
239 }
240 } else {
241 while i < e {
242 if cls[i] == Memory {
243 all_mem(cls);
244 return;
245 }
246 if cls[i] == X87Up {
247 // for darwin
248 // cls[i] = SSEDs;
249 all_mem(cls);
250 return;
251 }
252 if cls[i] == SSEUp {
253 cls[i] = SSEDv;
254 } else if cls[i].is_sse() {
255 i += 1;
85aaf69f 256 while i != e && cls[i] == SSEUp { i += 1; }
970d7e83
LB
257 } else if cls[i] == X87 {
258 i += 1;
85aaf69f 259 while i != e && cls[i] == X87Up { i += 1; }
970d7e83
LB
260 } else {
261 i += 1;
223e47cc
LB
262 }
263 }
264 }
265 }
266
267 let words = (ty_size(ty) + 7) / 8;
c1a9b12d 268 let mut cls = vec![NoClass; words];
223e47cc 269 if words > 4 {
85aaf69f 270 all_mem(&mut cls);
223e47cc
LB
271 return cls;
272 }
85aaf69f
SL
273 classify(ty, &mut cls, 0, 0);
274 fixup(ty, &mut cls);
223e47cc
LB
275 return cls;
276}
277
1a4d82fc 278fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
c34b1796 279 fn llvec_len(cls: &[RegClass]) -> usize {
85aaf69f
SL
280 let mut len = 1;
281 for c in cls {
970d7e83 282 if *c != SSEUp {
223e47cc
LB
283 break;
284 }
85aaf69f 285 len += 1;
223e47cc
LB
286 }
287 return len;
288 }
289
1a4d82fc 290 let mut tys = Vec::new();
85aaf69f 291 let mut i = 0;
970d7e83
LB
292 let e = cls.len();
293 while i < e {
294 match cls[i] {
295 Int => {
1a4d82fc 296 tys.push(Type::i64(ccx));
970d7e83 297 }
85aaf69f
SL
298 SSEFv | SSEDv | SSEInt(_) => {
299 let (elts_per_word, elt_ty) = match cls[i] {
300 SSEFv => (2, Type::f32(ccx)),
301 SSEDv => (1, Type::f64(ccx)),
302 SSEInt(bits) => {
303 assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
304 "llreg_ty: unsupported SSEInt width {}", bits);
305 (64 / bits, Type::ix(ccx, bits))
306 }
54a0048b 307 _ => bug!(),
85aaf69f
SL
308 };
309 let vec_len = llvec_len(&cls[i + 1..]);
310 let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
970d7e83
LB
311 tys.push(vec_ty);
312 i += vec_len;
1a4d82fc 313 continue;
970d7e83
LB
314 }
315 SSEFs => {
1a4d82fc 316 tys.push(Type::f32(ccx));
970d7e83
LB
317 }
318 SSEDs => {
1a4d82fc 319 tys.push(Type::f64(ccx));
223e47cc 320 }
54a0048b 321 _ => bug!("llregtype: unhandled class")
223e47cc 322 }
85aaf69f
SL
323 i += 1;
324 }
325 if tys.len() == 1 && tys[0].kind() == Vector {
326 // if the type contains only a vector, pass it as that vector.
327 tys[0]
328 } else {
329 Type::struct_(ccx, &tys, false)
223e47cc
LB
330 }
331}
332
54a0048b 333pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
1a4d82fc 334 fn x86_64_ty<F>(ccx: &CrateContext,
54a0048b 335 arg: &mut ArgType,
1a4d82fc 336 is_mem_cls: F,
54a0048b
SL
337 ind_attr: Option<Attribute>)
338 where F: FnOnce(&[RegClass]) -> bool
1a4d82fc 339 {
54a0048b
SL
340 if !arg.ty.is_reg_ty() {
341 let cls = classify_ty(arg.ty);
85aaf69f 342 if is_mem_cls(&cls) {
54a0048b
SL
343 arg.make_indirect(ccx);
344 if let Some(attr) = ind_attr {
345 arg.attrs.set(attr);
346 }
223e47cc 347 } else {
54a0048b 348 arg.cast = Some(llreg_ty(ccx, &cls));
223e47cc 349 }
970d7e83 350 } else {
54a0048b 351 arg.extend_integer_width_to(32);
1a4d82fc 352 }
223e47cc
LB
353 }
354
b039eaaf
SL
355 let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
356 let mut sse_regs = 8; // XMM0-7
1a4d82fc 357
54a0048b
SL
358 if !fty.ret.is_ignore() {
359 x86_64_ty(ccx, &mut fty.ret, |cls| {
b039eaaf
SL
360 if cls.is_ret_bysret() {
361 // `sret` parameter thus one less register available
362 int_regs -= 1;
363 true
364 } else {
365 false
366 }
54a0048b
SL
367 }, None);
368 }
1a4d82fc 369
54a0048b
SL
370 for arg in &mut fty.args {
371 if arg.is_ignore() { continue; }
372 x86_64_ty(ccx, arg, |cls| {
b039eaaf
SL
373 let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
374 let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
375 let in_mem = cls.is_pass_byval() ||
376 int_regs < needed_int ||
377 sse_regs < needed_sse;
378 if in_mem {
379 // `byval` parameter thus one less integer register available
380 int_regs -= 1;
381 } else {
382 // split into sized chunks passed individually
383 int_regs -= needed_int;
384 sse_regs -= needed_sse;
385 }
386 in_mem
54a0048b 387 }, Some(Attribute::ByVal));
b039eaaf
SL
388
389 // An integer, pointer, double or float parameter
390 // thus the above closure passed to `x86_64_ty` won't
391 // get called.
54a0048b
SL
392 match arg.ty.kind() {
393 Integer | Pointer => int_regs -= 1,
394 Double | Float => sse_regs -= 1,
395 _ => {}
b039eaaf
SL
396 }
397 }
223e47cc 398}