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.
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.
11 use abi::{self, Abi, Align, FieldPlacement, Size};
12 use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
13 use spec::HasTargetSpec;
35 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
37 /// Ignore the argument (useful for empty struct).
39 /// Pass the argument directly.
40 Direct(ArgAttributes),
41 /// Pass a pair's elements directly in two arguments.
42 Pair(ArgAttributes, ArgAttributes),
43 /// Pass the argument after casting it, to either
44 /// a single uniform or a pair of registers.
46 /// Pass the argument indirectly via a hidden pointer.
47 /// The second value, if any, is for the extra data (vtable or length)
48 /// which indicates that it refers to an unsized rvalue.
49 Indirect(ArgAttributes, Option<ArgAttributes>),
52 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
54 pub use self::attr_impl::ArgAttribute;
56 #[allow(non_upper_case_globals)]
59 // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
62 pub struct ArgAttribute: u16 {
64 const NoAlias = 1 << 1;
65 const NoCapture = 1 << 2;
66 const NonNull = 1 << 3;
67 const ReadOnly = 1 << 4;
69 const StructRet = 1 << 6;
76 /// A compact representation of LLVM attributes (at least those relevant for this module)
77 /// that can be manipulated without interacting with LLVM's Attribute machinery.
78 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
79 pub struct ArgAttributes {
80 pub regular: ArgAttribute,
81 pub pointee_size: Size,
82 pub pointee_align: Option<Align>
86 pub fn new() -> Self {
88 regular: ArgAttribute::default(),
89 pointee_size: Size::ZERO,
94 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
99 pub fn contains(&self, attr: ArgAttribute) -> bool {
100 self.regular.contains(attr)
104 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
111 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
117 macro_rules! reg_ctor {
118 ($name:ident, $kind:ident, $bits:expr) => {
119 pub fn $name() -> Reg {
121 kind: RegKind::$kind,
122 size: Size::from_bits($bits)
129 reg_ctor!(i8, Integer, 8);
130 reg_ctor!(i16, Integer, 16);
131 reg_ctor!(i32, Integer, 32);
132 reg_ctor!(i64, Integer, 64);
134 reg_ctor!(f32, Float, 32);
135 reg_ctor!(f64, Float, 64);
139 pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
140 let dl = cx.data_layout();
142 RegKind::Integer => {
143 match self.size.bits() {
145 2..=8 => dl.i8_align,
146 9..=16 => dl.i16_align,
147 17..=32 => dl.i32_align,
148 33..=64 => dl.i64_align,
149 65..=128 => dl.i128_align,
150 _ => panic!("unsupported integer: {:?}", self)
154 match self.size.bits() {
157 _ => panic!("unsupported float: {:?}", self)
160 RegKind::Vector => dl.vector_align(self.size)
165 /// An argument passed entirely registers with the
166 /// same kind (e.g. HFA / HVA on PPC64 and AArch64).
167 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
171 /// The total size of the argument, which can be:
172 /// * equal to `unit.size` (one scalar/vector)
173 /// * a multiple of `unit.size` (an array of scalar/vectors)
174 /// * if `unit.kind` is `Integer`, the last element
175 /// can be shorter, i.e. `{ i64, i64, i32 }` for
176 /// 64-bit integers with a total size of 20 bytes
180 impl From<Reg> for Uniform {
181 fn from(unit: Reg) -> Uniform {
190 pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
195 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
196 pub struct CastTarget {
197 pub prefix: [Option<RegKind>; 8],
198 pub prefix_chunk: Size,
202 impl From<Reg> for CastTarget {
203 fn from(unit: Reg) -> CastTarget {
204 CastTarget::from(Uniform::from(unit))
208 impl From<Uniform> for CastTarget {
209 fn from(uniform: Uniform) -> CastTarget {
212 prefix_chunk: Size::ZERO,
219 pub fn pair(a: Reg, b: Reg) -> CastTarget {
221 prefix: [Some(a.kind), None, None, None, None, None, None, None],
222 prefix_chunk: a.size,
223 rest: Uniform::from(b)
227 pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
228 (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
229 .abi_align(self.rest.align(cx)) + self.rest.total
232 pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
234 .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
235 .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
236 |acc, align| acc.max(align))
240 impl<'a, Ty> TyLayout<'a, Ty> {
241 fn is_aggregate(&self) -> bool {
245 Abi::Vector { .. } => false,
246 Abi::ScalarPair(..) |
247 Abi::Aggregate { .. } => true
251 fn homogeneous_aggregate<C>(&self, cx: C) -> Option<Reg>
252 where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self> + Copy
255 Abi::Uninhabited => None,
257 // The primitive for this algorithm.
258 Abi::Scalar(ref scalar) => {
259 let kind = match scalar.value {
261 abi::Pointer => RegKind::Integer,
262 abi::Float(_) => RegKind::Float,
270 Abi::Vector { .. } => {
272 kind: RegKind::Vector,
277 Abi::ScalarPair(..) |
278 Abi::Aggregate { .. } => {
279 let mut total = Size::ZERO;
280 let mut result = None;
282 let is_union = match self.fields {
283 FieldPlacement::Array { count, .. } => {
285 return self.field(cx, 0).homogeneous_aggregate(cx);
290 FieldPlacement::Union(_) => true,
291 FieldPlacement::Arbitrary { .. } => false
294 for i in 0..self.fields.count() {
295 if !is_union && total != self.fields.offset(i) {
299 let field = self.field(cx, i);
300 match (result, field.homogeneous_aggregate(cx)) {
301 // The field itself must be a homogeneous aggregate.
302 (_, None) => return None,
303 // If this is the first field, record the unit.
304 (None, Some(unit)) => {
307 // For all following fields, the unit must be the same.
308 (Some(prev_unit), Some(unit)) => {
309 if prev_unit != unit {
315 // Keep track of the offset (without padding).
316 let size = field.size;
318 total = total.max(size);
324 // There needs to be no padding.
325 if total != self.size {
335 /// Information about how to pass an argument to,
336 /// or return a value from, a function, under some ABI.
338 pub struct ArgType<'a, Ty> {
339 pub layout: TyLayout<'a, Ty>,
341 /// Dummy argument, which is emitted before the real argument.
342 pub pad: Option<Reg>,
347 impl<'a, Ty> ArgType<'a, Ty> {
348 pub fn new(layout: TyLayout<'a, Ty>) -> Self {
352 mode: PassMode::Direct(ArgAttributes::new()),
356 pub fn make_indirect(&mut self) {
357 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
359 // Start with fresh attributes for the pointer.
360 let mut attrs = ArgAttributes::new();
362 // For non-immediate arguments the callee gets its own copy of
363 // the value on the stack, so there are no aliases. It's also
364 // program-invisible so can't possibly capture
365 attrs.set(ArgAttribute::NoAlias)
366 .set(ArgAttribute::NoCapture)
367 .set(ArgAttribute::NonNull);
368 attrs.pointee_size = self.layout.size;
369 // FIXME(eddyb) We should be doing this, but at least on
370 // i686-pc-windows-msvc, it results in wrong stack offsets.
371 // attrs.pointee_align = Some(self.layout.align);
373 let extra_attrs = if self.layout.is_unsized() {
374 Some(ArgAttributes::new())
379 self.mode = PassMode::Indirect(attrs, extra_attrs);
382 pub fn make_indirect_byval(&mut self) {
383 self.make_indirect();
385 PassMode::Indirect(ref mut attrs, _) => {
386 attrs.set(ArgAttribute::ByVal);
392 pub fn extend_integer_width_to(&mut self, bits: u64) {
393 // Only integers have signedness
394 if let Abi::Scalar(ref scalar) = self.layout.abi {
395 if let abi::Int(i, signed) = scalar.value {
396 if i.size().bits() < bits {
397 if let PassMode::Direct(ref mut attrs) = self.mode {
398 attrs.set(if signed {
409 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
410 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
411 self.mode = PassMode::Cast(target.into());
414 pub fn pad_with(&mut self, reg: Reg) {
415 self.pad = Some(reg);
418 pub fn is_indirect(&self) -> bool {
420 PassMode::Indirect(..) => true,
425 pub fn is_sized_indirect(&self) -> bool {
427 PassMode::Indirect(_, None) => true,
432 pub fn is_unsized_indirect(&self) -> bool {
434 PassMode::Indirect(_, Some(_)) => true,
439 pub fn is_ignore(&self) -> bool {
440 self.mode == PassMode::Ignore
444 #[derive(Copy, Clone, PartialEq, Debug)]
466 /// Metadata describing how the arguments to a native function
467 /// should be passed in order to respect the native ABI.
469 /// I will do my best to describe this structure, but these
470 /// comments are reverse-engineered and may be inaccurate. -NDM
472 pub struct FnType<'a, Ty> {
473 /// The LLVM types of each argument.
474 pub args: Vec<ArgType<'a, Ty>>,
476 /// LLVM return type.
477 pub ret: ArgType<'a, Ty>,
484 impl<'a, Ty> FnType<'a, Ty> {
485 pub fn adjust_for_cabi<C>(&mut self, cx: C, abi: ::spec::abi::Abi) -> Result<(), String>
486 where Ty: TyLayoutMethods<'a, C> + Copy,
487 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
489 match &cx.target_spec().arch[..] {
491 let flavor = if abi == ::spec::abi::Abi::Fastcall {
492 x86::Flavor::Fastcall
496 x86::compute_abi_info(cx, self, flavor);
498 "x86_64" => if abi == ::spec::abi::Abi::SysV64 {
499 x86_64::compute_abi_info(cx, self);
500 } else if abi == ::spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
501 x86_win64::compute_abi_info(self);
503 x86_64::compute_abi_info(cx, self);
505 "aarch64" => aarch64::compute_abi_info(cx, self),
506 "arm" => arm::compute_abi_info(cx, self),
507 "mips" => mips::compute_abi_info(cx, self),
508 "mips64" => mips64::compute_abi_info(cx, self),
509 "powerpc" => powerpc::compute_abi_info(cx, self),
510 "powerpc64" => powerpc64::compute_abi_info(cx, self),
511 "s390x" => s390x::compute_abi_info(cx, self),
512 "asmjs" => asmjs::compute_abi_info(cx, self),
514 if cx.target_spec().llvm_target.contains("emscripten") {
515 asmjs::compute_abi_info(cx, self)
517 wasm32::compute_abi_info(self)
520 "msp430" => msp430::compute_abi_info(self),
521 "sparc" => sparc::compute_abi_info(cx, self),
522 "sparc64" => sparc64::compute_abi_info(cx, self),
523 "nvptx" => nvptx::compute_abi_info(self),
524 "nvptx64" => nvptx64::compute_abi_info(self),
525 "hexagon" => hexagon::compute_abi_info(self),
526 "riscv32" => riscv::compute_abi_info(self, 32),
527 "riscv64" => riscv::compute_abi_info(self, 64),
528 a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
531 if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
532 attrs.set(ArgAttribute::StructRet);