1 use crate::abi::{self, Abi, Align, FieldPlacement, Size};
2 use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
3 use crate::spec::{self, HasTargetSpec};
21 mod wasm32_bindgen_compat;
26 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
28 /// Ignore the argument.
30 /// Pass the argument directly.
31 Direct(ArgAttributes),
32 /// Pass a pair's elements directly in two arguments.
33 Pair(ArgAttributes, ArgAttributes),
34 /// Pass the argument after casting it, to either
35 /// a single uniform or a pair of registers.
37 /// Pass the argument indirectly via a hidden pointer.
38 /// The second value, if any, is for the extra data (vtable or length)
39 /// which indicates that it refers to an unsized rvalue.
40 Indirect(ArgAttributes, Option<ArgAttributes>),
43 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
45 pub use attr_impl::ArgAttribute;
47 #[allow(non_upper_case_globals)]
50 // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
53 pub struct ArgAttribute: u16 {
55 const NoAlias = 1 << 1;
56 const NoCapture = 1 << 2;
57 const NonNull = 1 << 3;
58 const ReadOnly = 1 << 4;
60 const StructRet = 1 << 6;
67 /// A compact representation of LLVM attributes (at least those relevant for this module)
68 /// that can be manipulated without interacting with LLVM's Attribute machinery.
69 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
70 pub struct ArgAttributes {
71 pub regular: ArgAttribute,
72 /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
73 /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
74 pub pointee_size: Size,
75 pub pointee_align: Option<Align>,
79 pub fn new() -> Self {
81 regular: ArgAttribute::default(),
82 pointee_size: Size::ZERO,
87 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
92 pub fn contains(&self, attr: ArgAttribute) -> bool {
93 self.regular.contains(attr)
97 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
104 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
110 macro_rules! reg_ctor {
111 ($name:ident, $kind:ident, $bits:expr) => {
112 pub fn $name() -> Reg {
113 Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
119 reg_ctor!(i8, Integer, 8);
120 reg_ctor!(i16, Integer, 16);
121 reg_ctor!(i32, Integer, 32);
122 reg_ctor!(i64, Integer, 64);
124 reg_ctor!(f32, Float, 32);
125 reg_ctor!(f64, Float, 64);
129 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
130 let dl = cx.data_layout();
132 RegKind::Integer => match self.size.bits() {
133 1 => dl.i1_align.abi,
134 2..=8 => dl.i8_align.abi,
135 9..=16 => dl.i16_align.abi,
136 17..=32 => dl.i32_align.abi,
137 33..=64 => dl.i64_align.abi,
138 65..=128 => dl.i128_align.abi,
139 _ => panic!("unsupported integer: {:?}", self),
141 RegKind::Float => match self.size.bits() {
142 32 => dl.f32_align.abi,
143 64 => dl.f64_align.abi,
144 _ => panic!("unsupported float: {:?}", self),
146 RegKind::Vector => dl.vector_align(self.size).abi,
151 /// An argument passed entirely registers with the
152 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
153 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
157 /// The total size of the argument, which can be:
158 /// * equal to `unit.size` (one scalar/vector),
159 /// * a multiple of `unit.size` (an array of scalar/vectors),
160 /// * if `unit.kind` is `Integer`, the last element
161 /// can be shorter, i.e., `{ i64, i64, i32 }` for
162 /// 64-bit integers with a total size of 20 bytes.
166 impl From<Reg> for Uniform {
167 fn from(unit: Reg) -> Uniform {
168 Uniform { unit, total: unit.size }
173 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
178 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
179 pub struct CastTarget {
180 pub prefix: [Option<RegKind>; 8],
181 pub prefix_chunk: Size,
185 impl From<Reg> for CastTarget {
186 fn from(unit: Reg) -> CastTarget {
187 CastTarget::from(Uniform::from(unit))
191 impl From<Uniform> for CastTarget {
192 fn from(uniform: Uniform) -> CastTarget {
193 CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform }
198 pub fn pair(a: Reg, b: Reg) -> CastTarget {
200 prefix: [Some(a.kind), None, None, None, None, None, None, None],
201 prefix_chunk: a.size,
202 rest: Uniform::from(b),
206 pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
207 (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
208 .align_to(self.rest.align(cx))
212 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
215 .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
216 .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
222 /// Returns value from the `homogeneous_aggregate` test function.
223 #[derive(Copy, Clone, Debug)]
224 pub enum HomogeneousAggregate {
225 /// Yes, all the "leaf fields" of this struct are passed in the
226 /// same way (specified in the `Reg` value).
229 /// There are distinct leaf fields passed in different ways,
230 /// or this is uninhabited.
233 /// There are no leaf fields at all.
237 impl HomogeneousAggregate {
238 /// If this is a homogeneous aggregate, returns the homogeneous
239 /// unit, else `None`.
240 pub fn unit(self) -> Option<Reg> {
241 if let HomogeneousAggregate::Homogeneous(r) = self { Some(r) } else { None }
245 impl<'a, Ty> TyLayout<'a, Ty> {
246 fn is_aggregate(&self) -> bool {
248 Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
249 Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
253 /// Returns `true` if this layout is an aggregate containing fields of only
254 /// a single type (e.g., `(u32, u32)`). Such aggregates are often
255 /// special-cased in ABIs.
257 /// Note: We generally ignore fields of zero-sized type when computing
258 /// this value (see #56877).
260 /// This is public so that it can be used in unit tests, but
261 /// should generally only be relevant to the ABI details of
262 /// specific targets.
263 pub fn homogeneous_aggregate<C>(&self, cx: &C) -> HomogeneousAggregate
265 Ty: TyLayoutMethods<'a, C> + Copy,
266 C: LayoutOf<Ty = Ty, TyLayout = Self>,
269 Abi::Uninhabited => HomogeneousAggregate::Heterogeneous,
271 // The primitive for this algorithm.
272 Abi::Scalar(ref scalar) => {
273 let kind = match scalar.value {
274 abi::Int(..) | abi::Pointer => RegKind::Integer,
275 abi::F32 | abi::F64 => RegKind::Float,
277 HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })
280 Abi::Vector { .. } => {
281 assert!(!self.is_zst());
282 HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, size: self.size })
285 Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
286 let mut total = Size::ZERO;
287 let mut result = None;
289 let is_union = match self.fields {
290 FieldPlacement::Array { count, .. } => {
292 return self.field(cx, 0).homogeneous_aggregate(cx);
294 return HomogeneousAggregate::NoData;
297 FieldPlacement::Union(_) => true,
298 FieldPlacement::Arbitrary { .. } => false,
301 for i in 0..self.fields.count() {
302 if !is_union && total != self.fields.offset(i) {
303 return HomogeneousAggregate::Heterogeneous;
306 let field = self.field(cx, i);
308 match (result, field.homogeneous_aggregate(cx)) {
309 (_, HomogeneousAggregate::NoData) => {
310 // Ignore fields that have no data
312 (_, HomogeneousAggregate::Heterogeneous) => {
313 // The field itself must be a homogeneous aggregate.
314 return HomogeneousAggregate::Heterogeneous;
316 // If this is the first field, record the unit.
317 (None, HomogeneousAggregate::Homogeneous(unit)) => {
320 // For all following fields, the unit must be the same.
321 (Some(prev_unit), HomogeneousAggregate::Homogeneous(unit)) => {
322 if prev_unit != unit {
323 return HomogeneousAggregate::Heterogeneous;
328 // Keep track of the offset (without padding).
329 let size = field.size;
331 total = total.max(size);
337 // There needs to be no padding.
338 if total != self.size {
339 HomogeneousAggregate::Heterogeneous
343 assert_ne!(total, Size::ZERO);
344 HomogeneousAggregate::Homogeneous(reg)
347 assert_eq!(total, Size::ZERO);
348 HomogeneousAggregate::NoData
357 /// Information about how to pass an argument to,
358 /// or return a value from, a function, under some ABI.
360 pub struct ArgAbi<'a, Ty> {
361 pub layout: TyLayout<'a, Ty>,
363 /// Dummy argument, which is emitted before the real argument.
364 pub pad: Option<Reg>,
369 impl<'a, Ty> ArgAbi<'a, Ty> {
370 pub fn new(layout: TyLayout<'a, Ty>) -> Self {
371 ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) }
374 pub fn make_indirect(&mut self) {
375 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
377 // Start with fresh attributes for the pointer.
378 let mut attrs = ArgAttributes::new();
380 // For non-immediate arguments the callee gets its own copy of
381 // the value on the stack, so there are no aliases. It's also
382 // program-invisible so can't possibly capture
383 attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
384 attrs.pointee_size = self.layout.size;
385 // FIXME(eddyb) We should be doing this, but at least on
386 // i686-pc-windows-msvc, it results in wrong stack offsets.
387 // attrs.pointee_align = Some(self.layout.align.abi);
389 let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
391 self.mode = PassMode::Indirect(attrs, extra_attrs);
394 pub fn make_indirect_byval(&mut self) {
395 self.make_indirect();
397 PassMode::Indirect(ref mut attrs, _) => {
398 attrs.set(ArgAttribute::ByVal);
404 pub fn extend_integer_width_to(&mut self, bits: u64) {
405 // Only integers have signedness
406 if let Abi::Scalar(ref scalar) = self.layout.abi {
407 if let abi::Int(i, signed) = scalar.value {
408 if i.size().bits() < bits {
409 if let PassMode::Direct(ref mut attrs) = self.mode {
410 attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt });
417 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
418 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
419 self.mode = PassMode::Cast(target.into());
422 pub fn pad_with(&mut self, reg: Reg) {
423 self.pad = Some(reg);
426 pub fn is_indirect(&self) -> bool {
428 PassMode::Indirect(..) => true,
433 pub fn is_sized_indirect(&self) -> bool {
435 PassMode::Indirect(_, None) => true,
440 pub fn is_unsized_indirect(&self) -> bool {
442 PassMode::Indirect(_, Some(_)) => true,
447 pub fn is_ignore(&self) -> bool {
449 PassMode::Ignore => true,
455 #[derive(Copy, Clone, PartialEq, Debug)]
457 // General language calling conventions, for which every target
458 // should have its own backend (e.g. LLVM) support.
462 // Target-specific calling conventions.
481 /// Metadata describing how the arguments to a native function
482 /// should be passed in order to respect the native ABI.
484 /// I will do my best to describe this structure, but these
485 /// comments are reverse-engineered and may be inaccurate. -NDM
487 pub struct FnAbi<'a, Ty> {
488 /// The LLVM types of each argument.
489 pub args: Vec<ArgAbi<'a, Ty>>,
491 /// LLVM return type.
492 pub ret: ArgAbi<'a, Ty>,
494 pub c_variadic: bool,
499 impl<'a, Ty> FnAbi<'a, Ty> {
500 pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
502 Ty: TyLayoutMethods<'a, C> + Copy,
503 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
505 match &cx.target_spec().arch[..] {
507 let flavor = if abi == spec::abi::Abi::Fastcall {
508 x86::Flavor::Fastcall
512 x86::compute_abi_info(cx, self, flavor);
515 if abi == spec::abi::Abi::SysV64 {
516 x86_64::compute_abi_info(cx, self);
517 } else if abi == spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
518 x86_win64::compute_abi_info(self);
520 x86_64::compute_abi_info(cx, self);
523 "aarch64" => aarch64::compute_abi_info(cx, self),
524 "amdgpu" => amdgpu::compute_abi_info(cx, self),
525 "arm" => arm::compute_abi_info(cx, self),
526 "mips" => mips::compute_abi_info(cx, self),
527 "mips64" => mips64::compute_abi_info(cx, self),
528 "powerpc" => powerpc::compute_abi_info(self),
529 "powerpc64" => powerpc64::compute_abi_info(cx, self),
530 "s390x" => s390x::compute_abi_info(cx, self),
531 "msp430" => msp430::compute_abi_info(self),
532 "sparc" => sparc::compute_abi_info(cx, self),
533 "sparc64" => sparc64::compute_abi_info(cx, self),
534 "nvptx" => nvptx::compute_abi_info(self),
535 "nvptx64" => nvptx64::compute_abi_info(self),
536 "hexagon" => hexagon::compute_abi_info(self),
537 "riscv32" => riscv::compute_abi_info(self, 32),
538 "riscv64" => riscv::compute_abi_info(self, 64),
539 "wasm32" if cx.target_spec().target_os != "emscripten" => {
540 wasm32_bindgen_compat::compute_abi_info(self)
542 "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
543 a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
546 if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
547 attrs.set(ArgAttribute::StructRet);