]>
Commit | Line | Data |
---|---|---|
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 | ||
83c7162d XL |
14 | use abi::call::{ArgType, CastTarget, FnType, Reg, RegKind}; |
15 | use abi::{self, Abi, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; | |
970d7e83 | 16 | |
2c00a5a8 XL |
17 | /// Classification of "eightbyte" components. |
18 | // NB: the order of the variants is from general to specific, | |
19 | // such that `unify(a, b)` is the "smaller" of `a` and `b`. | |
20 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] | |
cc61c64b | 21 | enum Class { |
cc61c64b XL |
22 | Int, |
23 | Sse, | |
24 | SseUp | |
970d7e83 LB |
25 | } |
26 | ||
cc61c64b XL |
27 | #[derive(Clone, Copy, Debug)] |
28 | struct Memory; | |
970d7e83 | 29 | |
abe05a73 XL |
30 | // Currently supported vector size (AVX-512). |
31 | const LARGEST_VECTOR_SIZE: usize = 512; | |
cc61c64b | 32 | const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64; |
223e47cc | 33 | |
83c7162d XL |
34 | fn classify_arg<'a, Ty, C>(cx: C, arg: &ArgType<'a, Ty>) |
35 | -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> | |
36 | where Ty: TyLayoutMethods<'a, C> + Copy, | |
37 | C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout | |
38 | { | |
39 | fn classify<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>, | |
40 | cls: &mut [Option<Class>], off: Size) -> Result<(), Memory> | |
41 | where Ty: TyLayoutMethods<'a, C> + Copy, | |
42 | C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout | |
43 | { | |
ff7c6d11 XL |
44 | if !off.is_abi_aligned(layout.align) { |
45 | if !layout.is_zst() { | |
cc61c64b | 46 | return Err(Memory); |
1a4d82fc | 47 | } |
cc61c64b | 48 | return Ok(()); |
223e47cc | 49 | } |
223e47cc | 50 | |
2c00a5a8 | 51 | let mut c = match layout.abi { |
83c7162d | 52 | Abi::Uninhabited => return Ok(()), |
ff7c6d11 | 53 | |
83c7162d | 54 | Abi::Scalar(ref scalar) => { |
2c00a5a8 | 55 | match scalar.value { |
83c7162d XL |
56 | abi::Int(..) | |
57 | abi::Pointer => Class::Int, | |
94b46f34 | 58 | abi::Float(_) => Class::Sse |
223e47cc | 59 | } |
970d7e83 | 60 | } |
cc61c64b | 61 | |
83c7162d | 62 | Abi::Vector { .. } => Class::Sse, |
2c00a5a8 | 63 | |
83c7162d XL |
64 | Abi::ScalarPair(..) | |
65 | Abi::Aggregate { .. } => { | |
ff7c6d11 | 66 | match layout.variants { |
83c7162d | 67 | abi::Variants::Single { .. } => { |
ff7c6d11 XL |
68 | for i in 0..layout.fields.count() { |
69 | let field_off = off + layout.fields.offset(i); | |
2c00a5a8 | 70 | classify(cx, layout.field(cx, i), cls, field_off)?; |
ff7c6d11 | 71 | } |
2c00a5a8 | 72 | return Ok(()); |
cc61c64b | 73 | } |
83c7162d XL |
74 | abi::Variants::Tagged { .. } | |
75 | abi::Variants::NicheFilling { .. } => return Err(Memory), | |
85aaf69f SL |
76 | } |
77 | } | |
85aaf69f | 78 | |
2c00a5a8 XL |
79 | }; |
80 | ||
81 | // Fill in `cls` for scalars (Int/Sse) and vectors (Sse). | |
82 | let first = (off.bytes() / 8) as usize; | |
83 | let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize; | |
84 | for cls in &mut cls[first..=last] { | |
85 | *cls = Some(cls.map_or(c, |old| old.min(c))); | |
86 | ||
87 | // Everything after the first Sse "eightbyte" | |
88 | // component is the upper half of a register. | |
89 | if c == Class::Sse { | |
90 | c = Class::SseUp; | |
91 | } | |
223e47cc | 92 | } |
cc61c64b XL |
93 | |
94 | Ok(()) | |
223e47cc LB |
95 | } |
96 | ||
ff7c6d11 | 97 | let n = ((arg.layout.size.bytes() + 7) / 8) as usize; |
cc61c64b XL |
98 | if n > MAX_EIGHTBYTES { |
99 | return Err(Memory); | |
100 | } | |
101 | ||
2c00a5a8 | 102 | let mut cls = [None; MAX_EIGHTBYTES]; |
94b46f34 | 103 | classify(cx, arg.layout, &mut cls, Size::ZERO)?; |
cc61c64b | 104 | if n > 2 { |
2c00a5a8 | 105 | if cls[0] != Some(Class::Sse) { |
cc61c64b XL |
106 | return Err(Memory); |
107 | } | |
2c00a5a8 | 108 | if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) { |
cc61c64b XL |
109 | return Err(Memory); |
110 | } | |
111 | } else { | |
85aaf69f | 112 | let mut i = 0; |
cc61c64b | 113 | while i < n { |
2c00a5a8 XL |
114 | if cls[i] == Some(Class::SseUp) { |
115 | cls[i] = Some(Class::Sse); | |
116 | } else if cls[i] == Some(Class::Sse) { | |
85aaf69f | 117 | i += 1; |
2c00a5a8 | 118 | while i != n && cls[i] == Some(Class::SseUp) { i += 1; } |
970d7e83 | 119 | } else { |
cc61c64b | 120 | i += 1; |
223e47cc LB |
121 | } |
122 | } | |
123 | } | |
124 | ||
cc61c64b | 125 | Ok(cls) |
223e47cc LB |
126 | } |
127 | ||
2c00a5a8 | 128 | fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> { |
cc61c64b XL |
129 | if *i >= cls.len() { |
130 | return None; | |
223e47cc LB |
131 | } |
132 | ||
cc61c64b | 133 | match cls[*i] { |
2c00a5a8 XL |
134 | None => None, |
135 | Some(Class::Int) => { | |
cc61c64b | 136 | *i += 1; |
2c00a5a8 XL |
137 | Some(if size.bytes() < 8 { |
138 | Reg { | |
139 | kind: RegKind::Integer, | |
140 | size | |
141 | } | |
142 | } else { | |
143 | Reg::i64() | |
cc61c64b | 144 | }) |
223e47cc | 145 | } |
2c00a5a8 XL |
146 | Some(Class::Sse) => { |
147 | let vec_len = 1 + cls[*i+1..].iter() | |
148 | .take_while(|&&c| c == Some(Class::SseUp)) | |
149 | .count(); | |
cc61c64b XL |
150 | *i += vec_len; |
151 | Some(if vec_len == 1 { | |
ff7c6d11 | 152 | match size.bytes() { |
cc61c64b XL |
153 | 4 => Reg::f32(), |
154 | _ => Reg::f64() | |
54a0048b | 155 | } |
223e47cc | 156 | } else { |
cc61c64b XL |
157 | Reg { |
158 | kind: RegKind::Vector, | |
ff7c6d11 | 159 | size: Size::from_bytes(8) * (vec_len as u64) |
cc61c64b XL |
160 | } |
161 | }) | |
1a4d82fc | 162 | } |
83c7162d | 163 | Some(c) => unreachable!("reg_component: unhandled class {:?}", c) |
223e47cc | 164 | } |
cc61c64b XL |
165 | } |
166 | ||
2c00a5a8 | 167 | fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget { |
cc61c64b XL |
168 | let mut i = 0; |
169 | let lo = reg_component(cls, &mut i, size).unwrap(); | |
ff7c6d11 | 170 | let offset = Size::from_bytes(8) * (i as u64); |
2c00a5a8 XL |
171 | let mut target = CastTarget::from(lo); |
172 | if size > offset { | |
173 | if let Some(hi) = reg_component(cls, &mut i, size - offset) { | |
0531ce1d | 174 | target = CastTarget::pair(lo, hi); |
2c00a5a8 XL |
175 | } |
176 | } | |
94b46f34 | 177 | assert_eq!(reg_component(cls, &mut i, Size::ZERO), None); |
cc61c64b XL |
178 | target |
179 | } | |
223e47cc | 180 | |
83c7162d XL |
181 | pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) |
182 | where Ty: TyLayoutMethods<'a, C> + Copy, | |
183 | C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout | |
184 | { | |
b039eaaf SL |
185 | let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 |
186 | let mut sse_regs = 8; // XMM0-7 | |
1a4d82fc | 187 | |
83c7162d | 188 | let mut x86_64_ty = |arg: &mut ArgType<'a, Ty>, is_arg: bool| { |
2c00a5a8 | 189 | let mut cls_or_mem = classify_arg(cx, arg); |
cc61c64b XL |
190 | |
191 | let mut needed_int = 0; | |
192 | let mut needed_sse = 0; | |
2c00a5a8 XL |
193 | if is_arg { |
194 | if let Ok(cls) = cls_or_mem { | |
195 | for &c in &cls { | |
cc61c64b | 196 | match c { |
2c00a5a8 XL |
197 | Some(Class::Int) => needed_int += 1, |
198 | Some(Class::Sse) => needed_sse += 1, | |
cc61c64b XL |
199 | _ => {} |
200 | } | |
201 | } | |
2c00a5a8 XL |
202 | if arg.layout.is_aggregate() { |
203 | if int_regs < needed_int || sse_regs < needed_sse { | |
204 | cls_or_mem = Err(Memory); | |
205 | } | |
206 | } | |
cc61c64b | 207 | } |
2c00a5a8 | 208 | } |
cc61c64b | 209 | |
2c00a5a8 XL |
210 | match cls_or_mem { |
211 | Err(Memory) => { | |
212 | if is_arg { | |
213 | arg.make_indirect_byval(); | |
214 | } else { | |
215 | // `sret` parameter thus one less integer register available | |
216 | arg.make_indirect(); | |
217 | int_regs -= 1; | |
218 | } | |
cc61c64b | 219 | } |
2c00a5a8 XL |
220 | Ok(ref cls) => { |
221 | // split into sized chunks passed individually | |
222 | int_regs -= needed_int; | |
223 | sse_regs -= needed_sse; | |
224 | ||
225 | if arg.layout.is_aggregate() { | |
226 | let size = arg.layout.size; | |
227 | arg.cast_to(cast_target(cls, size)) | |
228 | } else { | |
229 | arg.extend_integer_width_to(32); | |
230 | } | |
b039eaaf | 231 | } |
cc61c64b XL |
232 | } |
233 | }; | |
234 | ||
235 | if !fty.ret.is_ignore() { | |
236 | x86_64_ty(&mut fty.ret, false); | |
54a0048b | 237 | } |
1a4d82fc | 238 | |
54a0048b SL |
239 | for arg in &mut fty.args { |
240 | if arg.is_ignore() { continue; } | |
cc61c64b | 241 | x86_64_ty(arg, true); |
b039eaaf | 242 | } |
223e47cc | 243 | } |