]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/cabi_x86_64.rs
New upstream version 1.23.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
cc61c64b 14use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind};
54a0048b 15use context::CrateContext;
223e47cc 16
cc61c64b 17use rustc::ty::layout::{self, Layout, TyLayout, Size};
970d7e83 18
cc61c64b
XL
19#[derive(Clone, Copy, PartialEq, Debug)]
20enum Class {
21 None,
22 Int,
23 Sse,
24 SseUp
970d7e83
LB
25}
26
cc61c64b
XL
27#[derive(Clone, Copy, Debug)]
28struct Memory;
970d7e83 29
abe05a73
XL
30// Currently supported vector size (AVX-512).
31const LARGEST_VECTOR_SIZE: usize = 512;
cc61c64b 32const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
223e47cc 33
cc61c64b
XL
34fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
35 -> Result<[Class; MAX_EIGHTBYTES], Memory> {
36 fn unify(cls: &mut [Class],
37 off: u64,
38 c: Class) {
39 let i = (off / 8) as usize;
40 let to_write = match (cls[i], c) {
41 (Class::None, _) => c,
42 (_, Class::None) => return,
223e47cc 43
cc61c64b
XL
44 (Class::Int, _) |
45 (_, Class::Int) => Class::Int,
223e47cc 46
cc61c64b
XL
47 (Class::Sse, _) |
48 (_, Class::Sse) => Class::Sse,
223e47cc 49
cc61c64b 50 (Class::SseUp, Class::SseUp) => Class::SseUp
85aaf69f
SL
51 };
52 cls[i] = to_write;
223e47cc
LB
53 }
54
cc61c64b
XL
55 fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
56 layout: TyLayout<'tcx>,
57 cls: &mut [Class],
58 off: u64)
59 -> Result<(), Memory> {
60 if off % layout.align(ccx).abi() != 0 {
61 if layout.size(ccx).bytes() > 0 {
62 return Err(Memory);
1a4d82fc 63 }
cc61c64b 64 return Ok(());
223e47cc 65 }
223e47cc 66
cc61c64b
XL
67 match *layout {
68 Layout::Scalar { value, .. } |
69 Layout::RawNullablePointer { value, .. } => {
70 let reg = match value {
71 layout::Int(_) |
72 layout::Pointer => Class::Int,
73 layout::F32 |
74 layout::F64 => Class::Sse
75 };
76 unify(cls, off, reg);
223e47cc
LB
77 }
78
cc61c64b
XL
79 Layout::CEnum { .. } => {
80 unify(cls, off, Class::Int);
970d7e83 81 }
cc61c64b
XL
82
83 Layout::Vector { element, count } => {
84 unify(cls, off, Class::Sse);
85
86 // everything after the first one is the upper
87 // half of a register.
88 let eltsz = element.size(ccx).bytes();
89 for i in 1..count {
90 unify(cls, off + i * eltsz, Class::SseUp);
223e47cc 91 }
970d7e83 92 }
cc61c64b
XL
93
94 Layout::Array { count, .. } => {
95 if count > 0 {
96 let elt = layout.field(ccx, 0);
97 let eltsz = elt.size(ccx).bytes();
98 for i in 0..count {
99 classify(ccx, elt, cls, off + i * eltsz)?;
100 }
85aaf69f
SL
101 }
102 }
85aaf69f 103
cc61c64b
XL
104 Layout::Univariant { ref variant, .. } => {
105 for i in 0..layout.field_count() {
106 let field_off = off + variant.offsets[i].bytes();
107 classify(ccx, layout.field(ccx, i), cls, field_off)?;
108 }
109 }
85aaf69f 110
cc61c64b
XL
111 Layout::UntaggedUnion { .. } => {
112 for i in 0..layout.field_count() {
113 classify(ccx, layout.field(ccx, i), cls, off)?;
223e47cc 114 }
223e47cc 115 }
cc61c64b
XL
116
117 Layout::FatPointer { .. } |
118 Layout::General { .. } |
119 Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
223e47cc 120 }
cc61c64b
XL
121
122 Ok(())
223e47cc
LB
123 }
124
cc61c64b
XL
125 let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize;
126 if n > MAX_EIGHTBYTES {
127 return Err(Memory);
128 }
129
130 let mut cls = [Class::None; MAX_EIGHTBYTES];
131 classify(ccx, arg.layout, &mut cls, 0)?;
132 if n > 2 {
133 if cls[0] != Class::Sse {
134 return Err(Memory);
135 }
136 if cls[1..n].iter().any(|&c| c != Class::SseUp) {
137 return Err(Memory);
138 }
139 } else {
85aaf69f 140 let mut i = 0;
cc61c64b
XL
141 while i < n {
142 if cls[i] == Class::SseUp {
143 cls[i] = Class::Sse;
144 } else if cls[i] == Class::Sse {
85aaf69f 145 i += 1;
cc61c64b 146 while i != n && cls[i] == Class::SseUp { i += 1; }
970d7e83 147 } else {
cc61c64b 148 i += 1;
223e47cc
LB
149 }
150 }
151 }
152
cc61c64b 153 Ok(cls)
223e47cc
LB
154}
155
cc61c64b
XL
156fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
157 if *i >= cls.len() {
158 return None;
223e47cc
LB
159 }
160
cc61c64b
XL
161 match cls[*i] {
162 Class::None => None,
163 Class::Int => {
164 *i += 1;
165 Some(match size {
166 1 => Reg::i8(),
167 2 => Reg::i16(),
168 3 |
169 4 => Reg::i32(),
170 _ => Reg::i64()
171 })
223e47cc 172 }
cc61c64b
XL
173 Class::Sse => {
174 let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
175 *i += vec_len;
176 Some(if vec_len == 1 {
177 match size {
178 4 => Reg::f32(),
179 _ => Reg::f64()
54a0048b 180 }
223e47cc 181 } else {
cc61c64b
XL
182 Reg {
183 kind: RegKind::Vector,
184 size: Size::from_bytes(vec_len as u64 * 8)
185 }
186 })
1a4d82fc 187 }
cc61c64b 188 c => bug!("reg_component: unhandled class {:?}", c)
223e47cc 189 }
cc61c64b
XL
190}
191
192fn cast_target(cls: &[Class], size: u64) -> CastTarget {
193 let mut i = 0;
194 let lo = reg_component(cls, &mut i, size).unwrap();
195 let offset = i as u64 * 8;
196 let target = if size <= offset {
197 CastTarget::from(lo)
198 } else {
199 let hi = reg_component(cls, &mut i, size - offset).unwrap();
200 CastTarget::Pair(lo, hi)
201 };
202 assert_eq!(reg_component(cls, &mut i, 0), None);
203 target
204}
223e47cc 205
cc61c64b 206pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
b039eaaf
SL
207 let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
208 let mut sse_regs = 8; // XMM0-7
1a4d82fc 209
cc61c64b
XL
210 let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| {
211 let cls = classify_arg(ccx, arg);
212
213 let mut needed_int = 0;
214 let mut needed_sse = 0;
215 let in_mem = match cls {
216 Err(Memory) => true,
217 Ok(ref cls) if is_arg => {
218 for &c in cls {
219 match c {
220 Class::Int => needed_int += 1,
221 Class::Sse => needed_sse += 1,
222 _ => {}
223 }
224 }
225 arg.layout.is_aggregate() &&
226 (int_regs < needed_int || sse_regs < needed_sse)
227 }
228 Ok(_) => false
229 };
230
231 if in_mem {
232 arg.make_indirect(ccx);
233 if is_arg {
234 arg.attrs.set(ArgAttribute::ByVal);
235 } else {
236 // `sret` parameter thus one less integer register available
b039eaaf 237 int_regs -= 1;
cc61c64b
XL
238 }
239 } else {
240 // split into sized chunks passed individually
241 int_regs -= needed_int;
242 sse_regs -= needed_sse;
243
244 if arg.layout.is_aggregate() {
245 let size = arg.layout.size(ccx).bytes();
246 arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size))
b039eaaf 247 } else {
cc61c64b 248 arg.extend_integer_width_to(32);
b039eaaf 249 }
cc61c64b
XL
250 }
251 };
252
253 if !fty.ret.is_ignore() {
254 x86_64_ty(&mut fty.ret, false);
54a0048b 255 }
1a4d82fc 256
54a0048b
SL
257 for arg in &mut fty.args {
258 if arg.is_ignore() { continue; }
cc61c64b 259 x86_64_ty(arg, true);
b039eaaf 260 }
223e47cc 261}