]>
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 | ||
cc61c64b | 14 | use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind}; |
54a0048b | 15 | use context::CrateContext; |
223e47cc | 16 | |
cc61c64b | 17 | use rustc::ty::layout::{self, Layout, TyLayout, Size}; |
970d7e83 | 18 | |
cc61c64b XL |
19 | #[derive(Clone, Copy, PartialEq, Debug)] |
20 | enum Class { | |
21 | None, | |
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 | |
cc61c64b XL |
34 | fn 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 |
156 | fn 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 | ||
192 | fn 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 | 206 | pub 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 | } |