]> git.proxmox.com Git - rustc.git/blame - src/librustc_target/abi/call/mod.rs
New upstream version 1.31.0+dfsg1
[rustc.git] / src / librustc_target / abi / call / mod.rs
CommitLineData
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
11use abi::{self, Abi, Align, FieldPlacement, Size};
12use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
13use spec::HasTargetSpec;
14
15mod aarch64;
b7449926 16mod amdgpu;
83c7162d
XL
17mod arm;
18mod asmjs;
19mod hexagon;
20mod mips;
21mod mips64;
22mod msp430;
23mod nvptx;
24mod nvptx64;
25mod powerpc;
26mod powerpc64;
b7449926 27mod riscv;
83c7162d
XL
28mod s390x;
29mod sparc;
30mod sparc64;
31mod x86;
32mod x86_64;
33mod x86_win64;
34mod wasm32;
35
36#[derive(Clone, Copy, PartialEq, Eq, Debug)]
37pub 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
55pub use self::attr_impl::ArgAttribute;
56
57#[allow(non_upper_case_globals)]
58#[allow(unused)]
59mod 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)]
80pub struct ArgAttributes {
81 pub regular: ArgAttribute,
82 pub pointee_size: Size,
83 pub pointee_align: Option<Align>
84}
85
86impl 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)]
106pub enum RegKind {
107 Integer,
108 Float,
109 Vector
110}
111
112#[derive(Copy, Clone, PartialEq, Eq, Debug)]
113pub struct Reg {
114 pub kind: RegKind,
115 pub size: Size,
116}
117
118macro_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
129impl 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
139impl 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)]
169pub 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
181impl From<Reg> for Uniform {
182 fn from(unit: Reg) -> Uniform {
183 Uniform {
184 unit,
185 total: unit.size
186 }
187 }
188}
189
190impl 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)]
197pub struct CastTarget {
198 pub prefix: [Option<RegKind>; 8],
199 pub prefix_chunk: Size,
200 pub rest: Uniform,
201}
202
203impl From<Reg> for CastTarget {
204 fn from(unit: Reg) -> CastTarget {
205 CastTarget::from(Uniform::from(unit))
206 }
207}
208
209impl 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
219impl 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
241impl<'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)]
339pub 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
348impl<'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)]
446pub 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)]
473pub 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
485impl<'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}