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