]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | // Copyright 2017 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 | use abi::{self, Abi, Align, FieldPlacement, Size}; | |
12 | use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; | |
13 | use spec::HasTargetSpec; | |
14 | ||
15 | mod aarch64; | |
b7449926 | 16 | mod amdgpu; |
83c7162d XL |
17 | mod arm; |
18 | mod asmjs; | |
19 | mod hexagon; | |
20 | mod mips; | |
21 | mod mips64; | |
22 | mod msp430; | |
23 | mod nvptx; | |
24 | mod nvptx64; | |
25 | mod powerpc; | |
26 | mod powerpc64; | |
b7449926 | 27 | mod riscv; |
83c7162d XL |
28 | mod s390x; |
29 | mod sparc; | |
30 | mod sparc64; | |
31 | mod x86; | |
32 | mod x86_64; | |
33 | mod x86_win64; | |
34 | mod wasm32; | |
35 | ||
36 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | |
37 | pub enum PassMode { | |
38 | /// Ignore the argument (useful for empty struct). | |
39 | Ignore, | |
40 | /// Pass the argument directly. | |
41 | Direct(ArgAttributes), | |
42 | /// Pass a pair's elements directly in two arguments. | |
43 | Pair(ArgAttributes, ArgAttributes), | |
44 | /// Pass the argument after casting it, to either | |
45 | /// a single uniform or a pair of registers. | |
46 | Cast(CastTarget), | |
47 | /// Pass the argument indirectly via a hidden pointer. | |
b7449926 XL |
48 | /// The second value, if any, is for the extra data (vtable or length) |
49 | /// which indicates that it refers to an unsized rvalue. | |
50 | Indirect(ArgAttributes, Option<ArgAttributes>), | |
83c7162d XL |
51 | } |
52 | ||
53 | // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest | |
54 | // of this module | |
55 | pub use self::attr_impl::ArgAttribute; | |
56 | ||
57 | #[allow(non_upper_case_globals)] | |
58 | #[allow(unused)] | |
59 | mod attr_impl { | |
60 | // The subset of llvm::Attribute needed for arguments, packed into a bitfield. | |
61 | bitflags! { | |
62 | #[derive(Default)] | |
63 | pub struct ArgAttribute: u16 { | |
64 | const ByVal = 1 << 0; | |
65 | const NoAlias = 1 << 1; | |
66 | const NoCapture = 1 << 2; | |
67 | const NonNull = 1 << 3; | |
68 | const ReadOnly = 1 << 4; | |
69 | const SExt = 1 << 5; | |
70 | const StructRet = 1 << 6; | |
71 | const ZExt = 1 << 7; | |
72 | const InReg = 1 << 8; | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | /// A compact representation of LLVM attributes (at least those relevant for this module) | |
78 | /// that can be manipulated without interacting with LLVM's Attribute machinery. | |
79 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
80 | pub struct ArgAttributes { | |
81 | pub regular: ArgAttribute, | |
82 | pub pointee_size: Size, | |
83 | pub pointee_align: Option<Align> | |
84 | } | |
85 | ||
86 | impl ArgAttributes { | |
87 | pub fn new() -> Self { | |
88 | ArgAttributes { | |
89 | regular: ArgAttribute::default(), | |
94b46f34 | 90 | pointee_size: Size::ZERO, |
83c7162d XL |
91 | pointee_align: None, |
92 | } | |
93 | } | |
94 | ||
95 | pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { | |
b7449926 | 96 | self.regular |= attr; |
83c7162d XL |
97 | self |
98 | } | |
99 | ||
100 | pub fn contains(&self, attr: ArgAttribute) -> bool { | |
101 | self.regular.contains(attr) | |
102 | } | |
103 | } | |
104 | ||
105 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
106 | pub enum RegKind { | |
107 | Integer, | |
108 | Float, | |
109 | Vector | |
110 | } | |
111 | ||
112 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
113 | pub struct Reg { | |
114 | pub kind: RegKind, | |
115 | pub size: Size, | |
116 | } | |
117 | ||
118 | macro_rules! reg_ctor { | |
119 | ($name:ident, $kind:ident, $bits:expr) => { | |
120 | pub fn $name() -> Reg { | |
121 | Reg { | |
122 | kind: RegKind::$kind, | |
123 | size: Size::from_bits($bits) | |
124 | } | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | impl Reg { | |
130 | reg_ctor!(i8, Integer, 8); | |
131 | reg_ctor!(i16, Integer, 16); | |
132 | reg_ctor!(i32, Integer, 32); | |
133 | reg_ctor!(i64, Integer, 64); | |
134 | ||
135 | reg_ctor!(f32, Float, 32); | |
136 | reg_ctor!(f64, Float, 64); | |
137 | } | |
138 | ||
139 | impl Reg { | |
140 | pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { | |
141 | let dl = cx.data_layout(); | |
142 | match self.kind { | |
143 | RegKind::Integer => { | |
144 | match self.size.bits() { | |
145 | 1 => dl.i1_align, | |
8faf50e0 XL |
146 | 2..=8 => dl.i8_align, |
147 | 9..=16 => dl.i16_align, | |
148 | 17..=32 => dl.i32_align, | |
149 | 33..=64 => dl.i64_align, | |
150 | 65..=128 => dl.i128_align, | |
83c7162d XL |
151 | _ => panic!("unsupported integer: {:?}", self) |
152 | } | |
153 | } | |
154 | RegKind::Float => { | |
155 | match self.size.bits() { | |
156 | 32 => dl.f32_align, | |
157 | 64 => dl.f64_align, | |
158 | _ => panic!("unsupported float: {:?}", self) | |
159 | } | |
160 | } | |
161 | RegKind::Vector => dl.vector_align(self.size) | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
166 | /// An argument passed entirely registers with the | |
167 | /// same kind (e.g. HFA / HVA on PPC64 and AArch64). | |
168 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | |
169 | pub struct Uniform { | |
170 | pub unit: Reg, | |
171 | ||
172 | /// The total size of the argument, which can be: | |
173 | /// * equal to `unit.size` (one scalar/vector) | |
174 | /// * a multiple of `unit.size` (an array of scalar/vectors) | |
175 | /// * if `unit.kind` is `Integer`, the last element | |
176 | /// can be shorter, i.e. `{ i64, i64, i32 }` for | |
177 | /// 64-bit integers with a total size of 20 bytes | |
178 | pub total: Size, | |
179 | } | |
180 | ||
181 | impl From<Reg> for Uniform { | |
182 | fn from(unit: Reg) -> Uniform { | |
183 | Uniform { | |
184 | unit, | |
185 | total: unit.size | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | impl Uniform { | |
191 | pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { | |
192 | self.unit.align(cx) | |
193 | } | |
194 | } | |
195 | ||
196 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | |
197 | pub struct CastTarget { | |
198 | pub prefix: [Option<RegKind>; 8], | |
199 | pub prefix_chunk: Size, | |
200 | pub rest: Uniform, | |
201 | } | |
202 | ||
203 | impl From<Reg> for CastTarget { | |
204 | fn from(unit: Reg) -> CastTarget { | |
205 | CastTarget::from(Uniform::from(unit)) | |
206 | } | |
207 | } | |
208 | ||
209 | impl From<Uniform> for CastTarget { | |
210 | fn from(uniform: Uniform) -> CastTarget { | |
211 | CastTarget { | |
212 | prefix: [None; 8], | |
94b46f34 | 213 | prefix_chunk: Size::ZERO, |
83c7162d XL |
214 | rest: uniform |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | impl CastTarget { | |
220 | pub fn pair(a: Reg, b: Reg) -> CastTarget { | |
221 | CastTarget { | |
222 | prefix: [Some(a.kind), None, None, None, None, None, None, None], | |
223 | prefix_chunk: a.size, | |
224 | rest: Uniform::from(b) | |
225 | } | |
226 | } | |
227 | ||
228 | pub fn size<C: HasDataLayout>(&self, cx: C) -> Size { | |
229 | (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64) | |
230 | .abi_align(self.rest.align(cx)) + self.rest.total | |
231 | } | |
232 | ||
233 | pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { | |
234 | self.prefix.iter() | |
b7449926 | 235 | .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx))) |
83c7162d XL |
236 | .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)), |
237 | |acc, align| acc.max(align)) | |
238 | } | |
239 | } | |
240 | ||
241 | impl<'a, Ty> TyLayout<'a, Ty> { | |
242 | fn is_aggregate(&self) -> bool { | |
243 | match self.abi { | |
244 | Abi::Uninhabited | | |
245 | Abi::Scalar(_) | | |
246 | Abi::Vector { .. } => false, | |
247 | Abi::ScalarPair(..) | | |
248 | Abi::Aggregate { .. } => true | |
249 | } | |
250 | } | |
251 | ||
252 | fn homogeneous_aggregate<C>(&self, cx: C) -> Option<Reg> | |
253 | where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self> + Copy | |
254 | { | |
255 | match self.abi { | |
256 | Abi::Uninhabited => None, | |
257 | ||
258 | // The primitive for this algorithm. | |
259 | Abi::Scalar(ref scalar) => { | |
260 | let kind = match scalar.value { | |
261 | abi::Int(..) | | |
262 | abi::Pointer => RegKind::Integer, | |
94b46f34 | 263 | abi::Float(_) => RegKind::Float, |
83c7162d XL |
264 | }; |
265 | Some(Reg { | |
266 | kind, | |
267 | size: self.size | |
268 | }) | |
269 | } | |
270 | ||
271 | Abi::Vector { .. } => { | |
272 | Some(Reg { | |
273 | kind: RegKind::Vector, | |
274 | size: self.size | |
275 | }) | |
276 | } | |
277 | ||
278 | Abi::ScalarPair(..) | | |
279 | Abi::Aggregate { .. } => { | |
94b46f34 | 280 | let mut total = Size::ZERO; |
83c7162d XL |
281 | let mut result = None; |
282 | ||
283 | let is_union = match self.fields { | |
284 | FieldPlacement::Array { count, .. } => { | |
285 | if count > 0 { | |
286 | return self.field(cx, 0).homogeneous_aggregate(cx); | |
287 | } else { | |
288 | return None; | |
289 | } | |
290 | } | |
291 | FieldPlacement::Union(_) => true, | |
292 | FieldPlacement::Arbitrary { .. } => false | |
293 | }; | |
294 | ||
295 | for i in 0..self.fields.count() { | |
296 | if !is_union && total != self.fields.offset(i) { | |
297 | return None; | |
298 | } | |
299 | ||
300 | let field = self.field(cx, i); | |
301 | match (result, field.homogeneous_aggregate(cx)) { | |
302 | // The field itself must be a homogeneous aggregate. | |
303 | (_, None) => return None, | |
304 | // If this is the first field, record the unit. | |
305 | (None, Some(unit)) => { | |
306 | result = Some(unit); | |
307 | } | |
308 | // For all following fields, the unit must be the same. | |
309 | (Some(prev_unit), Some(unit)) => { | |
310 | if prev_unit != unit { | |
311 | return None; | |
312 | } | |
313 | } | |
314 | } | |
315 | ||
316 | // Keep track of the offset (without padding). | |
317 | let size = field.size; | |
318 | if is_union { | |
319 | total = total.max(size); | |
320 | } else { | |
321 | total += size; | |
322 | } | |
323 | } | |
324 | ||
325 | // There needs to be no padding. | |
326 | if total != self.size { | |
327 | None | |
328 | } else { | |
329 | result | |
330 | } | |
331 | } | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | /// Information about how to pass an argument to, | |
337 | /// or return a value from, a function, under some ABI. | |
338 | #[derive(Debug)] | |
339 | pub struct ArgType<'a, Ty> { | |
340 | pub layout: TyLayout<'a, Ty>, | |
341 | ||
342 | /// Dummy argument, which is emitted before the real argument. | |
343 | pub pad: Option<Reg>, | |
344 | ||
345 | pub mode: PassMode, | |
346 | } | |
347 | ||
348 | impl<'a, Ty> ArgType<'a, Ty> { | |
349 | pub fn new(layout: TyLayout<'a, Ty>) -> Self { | |
350 | ArgType { | |
351 | layout, | |
352 | pad: None, | |
353 | mode: PassMode::Direct(ArgAttributes::new()), | |
354 | } | |
355 | } | |
356 | ||
357 | pub fn make_indirect(&mut self) { | |
358 | assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); | |
359 | ||
360 | // Start with fresh attributes for the pointer. | |
361 | let mut attrs = ArgAttributes::new(); | |
362 | ||
363 | // For non-immediate arguments the callee gets its own copy of | |
364 | // the value on the stack, so there are no aliases. It's also | |
365 | // program-invisible so can't possibly capture | |
366 | attrs.set(ArgAttribute::NoAlias) | |
367 | .set(ArgAttribute::NoCapture) | |
368 | .set(ArgAttribute::NonNull); | |
369 | attrs.pointee_size = self.layout.size; | |
370 | // FIXME(eddyb) We should be doing this, but at least on | |
371 | // i686-pc-windows-msvc, it results in wrong stack offsets. | |
372 | // attrs.pointee_align = Some(self.layout.align); | |
373 | ||
b7449926 XL |
374 | let extra_attrs = if self.layout.is_unsized() { |
375 | Some(ArgAttributes::new()) | |
376 | } else { | |
377 | None | |
378 | }; | |
379 | ||
380 | self.mode = PassMode::Indirect(attrs, extra_attrs); | |
83c7162d XL |
381 | } |
382 | ||
383 | pub fn make_indirect_byval(&mut self) { | |
384 | self.make_indirect(); | |
385 | match self.mode { | |
b7449926 | 386 | PassMode::Indirect(ref mut attrs, _) => { |
83c7162d XL |
387 | attrs.set(ArgAttribute::ByVal); |
388 | } | |
389 | _ => unreachable!() | |
390 | } | |
391 | } | |
392 | ||
393 | pub fn extend_integer_width_to(&mut self, bits: u64) { | |
394 | // Only integers have signedness | |
395 | if let Abi::Scalar(ref scalar) = self.layout.abi { | |
396 | if let abi::Int(i, signed) = scalar.value { | |
397 | if i.size().bits() < bits { | |
398 | if let PassMode::Direct(ref mut attrs) = self.mode { | |
399 | attrs.set(if signed { | |
400 | ArgAttribute::SExt | |
401 | } else { | |
402 | ArgAttribute::ZExt | |
403 | }); | |
404 | } | |
405 | } | |
406 | } | |
407 | } | |
408 | } | |
409 | ||
410 | pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { | |
411 | assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); | |
412 | self.mode = PassMode::Cast(target.into()); | |
413 | } | |
414 | ||
415 | pub fn pad_with(&mut self, reg: Reg) { | |
416 | self.pad = Some(reg); | |
417 | } | |
418 | ||
419 | pub fn is_indirect(&self) -> bool { | |
420 | match self.mode { | |
b7449926 XL |
421 | PassMode::Indirect(..) => true, |
422 | _ => false | |
423 | } | |
424 | } | |
425 | ||
426 | pub fn is_sized_indirect(&self) -> bool { | |
427 | match self.mode { | |
428 | PassMode::Indirect(_, None) => true, | |
429 | _ => false | |
430 | } | |
431 | } | |
432 | ||
433 | pub fn is_unsized_indirect(&self) -> bool { | |
434 | match self.mode { | |
435 | PassMode::Indirect(_, Some(_)) => true, | |
83c7162d XL |
436 | _ => false |
437 | } | |
438 | } | |
439 | ||
440 | pub fn is_ignore(&self) -> bool { | |
441 | self.mode == PassMode::Ignore | |
442 | } | |
443 | } | |
444 | ||
445 | #[derive(Copy, Clone, PartialEq, Debug)] | |
446 | pub enum Conv { | |
447 | C, | |
448 | ||
449 | ArmAapcs, | |
450 | ||
451 | Msp430Intr, | |
452 | ||
453 | PtxKernel, | |
454 | ||
455 | X86Fastcall, | |
456 | X86Intr, | |
457 | X86Stdcall, | |
458 | X86ThisCall, | |
459 | X86VectorCall, | |
460 | ||
461 | X86_64SysV, | |
462 | X86_64Win64, | |
8faf50e0 XL |
463 | |
464 | AmdGpuKernel, | |
83c7162d XL |
465 | } |
466 | ||
467 | /// Metadata describing how the arguments to a native function | |
468 | /// should be passed in order to respect the native ABI. | |
469 | /// | |
470 | /// I will do my best to describe this structure, but these | |
471 | /// comments are reverse-engineered and may be inaccurate. -NDM | |
472 | #[derive(Debug)] | |
473 | pub struct FnType<'a, Ty> { | |
474 | /// The LLVM types of each argument. | |
475 | pub args: Vec<ArgType<'a, Ty>>, | |
476 | ||
477 | /// LLVM return type. | |
478 | pub ret: ArgType<'a, Ty>, | |
479 | ||
480 | pub variadic: bool, | |
481 | ||
482 | pub conv: Conv, | |
483 | } | |
484 | ||
485 | impl<'a, Ty> FnType<'a, Ty> { | |
486 | pub fn adjust_for_cabi<C>(&mut self, cx: C, abi: ::spec::abi::Abi) -> Result<(), String> | |
487 | where Ty: TyLayoutMethods<'a, C> + Copy, | |
488 | C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec | |
489 | { | |
490 | match &cx.target_spec().arch[..] { | |
491 | "x86" => { | |
492 | let flavor = if abi == ::spec::abi::Abi::Fastcall { | |
493 | x86::Flavor::Fastcall | |
494 | } else { | |
495 | x86::Flavor::General | |
496 | }; | |
497 | x86::compute_abi_info(cx, self, flavor); | |
498 | }, | |
499 | "x86_64" => if abi == ::spec::abi::Abi::SysV64 { | |
500 | x86_64::compute_abi_info(cx, self); | |
501 | } else if abi == ::spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows { | |
502 | x86_win64::compute_abi_info(self); | |
503 | } else { | |
504 | x86_64::compute_abi_info(cx, self); | |
505 | }, | |
506 | "aarch64" => aarch64::compute_abi_info(cx, self), | |
b7449926 | 507 | "amdgpu" => amdgpu::compute_abi_info(cx, self), |
83c7162d XL |
508 | "arm" => arm::compute_abi_info(cx, self), |
509 | "mips" => mips::compute_abi_info(cx, self), | |
510 | "mips64" => mips64::compute_abi_info(cx, self), | |
511 | "powerpc" => powerpc::compute_abi_info(cx, self), | |
512 | "powerpc64" => powerpc64::compute_abi_info(cx, self), | |
513 | "s390x" => s390x::compute_abi_info(cx, self), | |
514 | "asmjs" => asmjs::compute_abi_info(cx, self), | |
515 | "wasm32" => { | |
516 | if cx.target_spec().llvm_target.contains("emscripten") { | |
517 | asmjs::compute_abi_info(cx, self) | |
518 | } else { | |
519 | wasm32::compute_abi_info(self) | |
520 | } | |
521 | } | |
522 | "msp430" => msp430::compute_abi_info(self), | |
523 | "sparc" => sparc::compute_abi_info(cx, self), | |
524 | "sparc64" => sparc64::compute_abi_info(cx, self), | |
525 | "nvptx" => nvptx::compute_abi_info(self), | |
526 | "nvptx64" => nvptx64::compute_abi_info(self), | |
527 | "hexagon" => hexagon::compute_abi_info(self), | |
b7449926 XL |
528 | "riscv32" => riscv::compute_abi_info(self, 32), |
529 | "riscv64" => riscv::compute_abi_info(self, 64), | |
83c7162d XL |
530 | a => return Err(format!("unrecognized arch \"{}\" in target specification", a)) |
531 | } | |
532 | ||
b7449926 | 533 | if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { |
83c7162d XL |
534 | attrs.set(ArgAttribute::StructRet); |
535 | } | |
536 | ||
537 | Ok(()) | |
538 | } | |
539 | } |