]> git.proxmox.com Git - rustc.git/blame_incremental - src/librustc_trans/cabi_x86_64.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc_trans / cabi_x86_64.rs
... / ...
CommitLineData
1// Copyright 2012-2013 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// 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
14#![allow(non_upper_case_globals)]
15use self::RegClass::*;
16
17use llvm::{Integer, Pointer, Float, Double};
18use llvm::{Struct, Array, Attribute, Vector};
19use abi::{self, ArgType, FnType};
20use context::CrateContext;
21use type_::Type;
22
23#[derive(Clone, Copy, PartialEq)]
24enum RegClass {
25 NoClass,
26 Int,
27 SSEFs,
28 SSEFv,
29 SSEDs,
30 SSEDv,
31 SSEInt(/* bitwidth */ u64),
32 /// Data that can appear in the upper half of an SSE register.
33 SSEUp,
34 X87,
35 X87Up,
36 ComplexX87,
37 Memory
38}
39
40trait TypeMethods {
41 fn is_reg_ty(&self) -> bool;
42}
43
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 }
51}
52
53impl RegClass {
54 fn is_sse(&self) -> bool {
55 match *self {
56 SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
57 _ => false
58 }
59 }
60}
61
62trait ClassList {
63 fn is_pass_byval(&self) -> bool;
64 fn is_ret_bysret(&self) -> bool;
65}
66
67impl ClassList for [RegClass] {
68 fn is_pass_byval(&self) -> bool {
69 if self.is_empty() { return false; }
70
71 let class = self[0];
72 class == Memory
73 || class == X87
74 || class == ComplexX87
75 }
76
77 fn is_ret_bysret(&self) -> bool {
78 if self.is_empty() { return false; }
79
80 self[0] == Memory
81 }
82}
83
84fn classify_ty(ty: Type) -> Vec<RegClass> {
85 fn align(off: usize, ty: Type) -> usize {
86 let a = ty_align(ty);
87 return (off + a - 1) / a * a;
88 }
89
90 fn ty_align(ty: Type) -> usize {
91 abi::ty_align(ty, 8)
92 }
93
94 fn ty_size(ty: Type) -> usize {
95 abi::ty_size(ty, 8)
96 }
97
98 fn all_mem(cls: &mut [RegClass]) {
99 for elt in cls {
100 *elt = Memory;
101 }
102 }
103
104 fn unify(cls: &mut [RegClass],
105 i: usize,
106 newv: RegClass) {
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
132 (..) => newv
133 };
134 cls[i] = to_write;
135 }
136
137 fn classify_struct(tys: &[Type],
138 cls: &mut [RegClass],
139 i: usize,
140 off: usize,
141 packed: bool) {
142 let mut field_off = off;
143 for ty in tys {
144 if !packed {
145 field_off = align(field_off, *ty);
146 }
147 classify(*ty, cls, i, field_off);
148 field_off += ty_size(*ty);
149 }
150 }
151
152 fn classify(ty: Type,
153 cls: &mut [RegClass], ix: usize,
154 off: usize) {
155 let t_align = ty_align(ty);
156 let t_size = ty_size(ty);
157
158 let misalign = off % t_align;
159 if misalign != 0 {
160 let mut i = off / 8;
161 let e = (off + t_size + 7) / 8;
162 while i < e {
163 unify(cls, ix + i, Memory);
164 i += 1;
165 }
166 return;
167 }
168
169 match ty.kind() {
170 Integer |
171 Pointer => {
172 unify(cls, ix + off / 8, Int);
173 }
174 Float => {
175 if off % 8 == 4 {
176 unify(cls, ix + off / 8, SSEFv);
177 } else {
178 unify(cls, ix + off / 8, SSEFs);
179 }
180 }
181 Double => {
182 unify(cls, ix + off / 8, SSEDs);
183 }
184 Struct => {
185 classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
186 }
187 Array => {
188 let len = ty.array_length();
189 let elt = ty.element_type();
190 let eltsz = ty_size(elt);
191 let mut i = 0;
192 while i < len {
193 classify(elt, cls, ix, off + i * eltsz);
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,
205 _ => bug!("classify: unhandled vector element type")
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;
216 }
217 }
218 _ => bug!("classify: unhandled type")
219 }
220 }
221
222 fn fixup(ty: Type, cls: &mut [RegClass]) {
223 let mut i = 0;
224 let ty_kind = ty.kind();
225 let e = cls.len();
226 if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
227 if cls[i].is_sse() {
228 i += 1;
229 while i < e {
230 if cls[i] != SSEUp {
231 all_mem(cls);
232 return;
233 }
234 i += 1;
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;
256 while i != e && cls[i] == SSEUp { i += 1; }
257 } else if cls[i] == X87 {
258 i += 1;
259 while i != e && cls[i] == X87Up { i += 1; }
260 } else {
261 i += 1;
262 }
263 }
264 }
265 }
266
267 let words = (ty_size(ty) + 7) / 8;
268 let mut cls = vec![NoClass; words];
269 if words > 4 {
270 all_mem(&mut cls);
271 return cls;
272 }
273 classify(ty, &mut cls, 0, 0);
274 fixup(ty, &mut cls);
275 return cls;
276}
277
278fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
279 fn llvec_len(cls: &[RegClass]) -> usize {
280 let mut len = 1;
281 for c in cls {
282 if *c != SSEUp {
283 break;
284 }
285 len += 1;
286 }
287 return len;
288 }
289
290 let mut tys = Vec::new();
291 let mut i = 0;
292 let e = cls.len();
293 while i < e {
294 match cls[i] {
295 Int => {
296 tys.push(Type::i64(ccx));
297 }
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 }
307 _ => bug!(),
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);
311 tys.push(vec_ty);
312 i += vec_len;
313 continue;
314 }
315 SSEFs => {
316 tys.push(Type::f32(ccx));
317 }
318 SSEDs => {
319 tys.push(Type::f64(ccx));
320 }
321 _ => bug!("llregtype: unhandled class")
322 }
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)
330 }
331}
332
333pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
334 fn x86_64_ty<F>(ccx: &CrateContext,
335 arg: &mut ArgType,
336 is_mem_cls: F,
337 ind_attr: Option<Attribute>)
338 where F: FnOnce(&[RegClass]) -> bool
339 {
340 if !arg.ty.is_reg_ty() {
341 let cls = classify_ty(arg.ty);
342 if is_mem_cls(&cls) {
343 arg.make_indirect(ccx);
344 if let Some(attr) = ind_attr {
345 arg.attrs.set(attr);
346 }
347 } else {
348 arg.cast = Some(llreg_ty(ccx, &cls));
349 }
350 } else {
351 arg.extend_integer_width_to(32);
352 }
353 }
354
355 let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
356 let mut sse_regs = 8; // XMM0-7
357
358 if !fty.ret.is_ignore() {
359 x86_64_ty(ccx, &mut fty.ret, |cls| {
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 }
367 }, None);
368 }
369
370 for arg in &mut fty.args {
371 if arg.is_ignore() { continue; }
372 x86_64_ty(ccx, arg, |cls| {
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
387 }, Some(Attribute::ByVal));
388
389 // An integer, pointer, double or float parameter
390 // thus the above closure passed to `x86_64_ty` won't
391 // get called.
392 match arg.ty.kind() {
393 Integer | Pointer => int_regs -= 1,
394 Double | Float => sse_regs -= 1,
395 _ => {}
396 }
397 }
398}