1 use crate::abi::{self, Abi, Align, FieldPlacement, Size};
2 use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
3 use crate::spec::{self, HasTargetSpec};
24 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 dereferenceable size of the pointee.
73 pub pointee_size: Size,
74 pub pointee_align: Option<Align>
78 pub fn new() -> Self {
80 regular: ArgAttribute::default(),
81 pointee_size: Size::ZERO,
86 pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
91 pub fn contains(&self, attr: ArgAttribute) -> bool {
92 self.regular.contains(attr)
96 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
103 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
109 macro_rules! reg_ctor {
110 ($name:ident, $kind:ident, $bits:expr) => {
111 pub fn $name() -> Reg {
113 kind: RegKind::$kind,
114 size: Size::from_bits($bits)
121 reg_ctor!(i8, Integer, 8);
122 reg_ctor!(i16, Integer, 16);
123 reg_ctor!(i32, Integer, 32);
124 reg_ctor!(i64, Integer, 64);
126 reg_ctor!(f32, Float, 32);
127 reg_ctor!(f64, Float, 64);
131 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
132 let dl = cx.data_layout();
134 RegKind::Integer => {
135 match self.size.bits() {
136 1 => dl.i1_align.abi,
137 2..=8 => dl.i8_align.abi,
138 9..=16 => dl.i16_align.abi,
139 17..=32 => dl.i32_align.abi,
140 33..=64 => dl.i64_align.abi,
141 65..=128 => dl.i128_align.abi,
142 _ => panic!("unsupported integer: {:?}", self)
146 match self.size.bits() {
147 32 => dl.f32_align.abi,
148 64 => dl.f64_align.abi,
149 _ => panic!("unsupported float: {:?}", self)
152 RegKind::Vector => dl.vector_align(self.size).abi,
157 /// An argument passed entirely registers with the
158 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
159 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
163 /// The total size of the argument, which can be:
164 /// * equal to `unit.size` (one scalar/vector),
165 /// * a multiple of `unit.size` (an array of scalar/vectors),
166 /// * if `unit.kind` is `Integer`, the last element
167 /// can be shorter, i.e., `{ i64, i64, i32 }` for
168 /// 64-bit integers with a total size of 20 bytes.
172 impl From<Reg> for Uniform {
173 fn from(unit: Reg) -> Uniform {
182 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
187 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
188 pub struct CastTarget {
189 pub prefix: [Option<RegKind>; 8],
190 pub prefix_chunk: Size,
194 impl From<Reg> for CastTarget {
195 fn from(unit: Reg) -> CastTarget {
196 CastTarget::from(Uniform::from(unit))
200 impl From<Uniform> for CastTarget {
201 fn from(uniform: Uniform) -> CastTarget {
204 prefix_chunk: Size::ZERO,
211 pub fn pair(a: Reg, b: Reg) -> CastTarget {
213 prefix: [Some(a.kind), None, None, None, None, None, None, None],
214 prefix_chunk: a.size,
215 rest: Uniform::from(b)
219 pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
220 (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
221 .align_to(self.rest.align(cx)) + self.rest.total
224 pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
226 .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
227 .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)),
228 |acc, align| acc.max(align))
232 /// Returns value from the `homogeneous_aggregate` test function.
233 #[derive(Copy, Clone, Debug)]
234 pub enum HomogeneousAggregate {
235 /// Yes, all the "leaf fields" of this struct are passed in the
236 /// same way (specified in the `Reg` value).
239 /// There are distinct leaf fields passed in different ways,
240 /// or this is uninhabited.
243 /// There are no leaf fields at all.
247 impl HomogeneousAggregate {
248 /// If this is a homogeneous aggregate, returns the homogeneous
249 /// unit, else `None`.
250 pub fn unit(self) -> Option<Reg> {
251 if let HomogeneousAggregate::Homogeneous(r) = self {
259 impl<'a, Ty> TyLayout<'a, Ty> {
260 fn is_aggregate(&self) -> bool {
264 Abi::Vector { .. } => false,
265 Abi::ScalarPair(..) |
266 Abi::Aggregate { .. } => true
270 /// Returns `true` if this layout is an aggregate containing fields of only
271 /// a single type (e.g., `(u32, u32)`). Such aggregates are often
272 /// special-cased in ABIs.
274 /// Note: We generally ignore fields of zero-sized type when computing
275 /// this value (see #56877).
277 /// This is public so that it can be used in unit tests, but
278 /// should generally only be relevant to the ABI details of
279 /// specific targets.
280 pub fn homogeneous_aggregate<C>(&self, cx: &C) -> HomogeneousAggregate
281 where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self>
284 Abi::Uninhabited => HomogeneousAggregate::Heterogeneous,
286 // The primitive for this algorithm.
287 Abi::Scalar(ref scalar) => {
288 let kind = match scalar.value {
290 abi::Pointer => RegKind::Integer,
291 abi::F32 | abi::F64 => RegKind::Float,
293 HomogeneousAggregate::Homogeneous(Reg {
299 Abi::Vector { .. } => {
300 assert!(!self.is_zst());
301 HomogeneousAggregate::Homogeneous(Reg {
302 kind: RegKind::Vector,
307 Abi::ScalarPair(..) |
308 Abi::Aggregate { .. } => {
309 let mut total = Size::ZERO;
310 let mut result = None;
312 let is_union = match self.fields {
313 FieldPlacement::Array { count, .. } => {
315 return self.field(cx, 0).homogeneous_aggregate(cx);
317 return HomogeneousAggregate::NoData;
320 FieldPlacement::Union(_) => true,
321 FieldPlacement::Arbitrary { .. } => false
324 for i in 0..self.fields.count() {
325 if !is_union && total != self.fields.offset(i) {
326 return HomogeneousAggregate::Heterogeneous;
329 let field = self.field(cx, i);
331 match (result, field.homogeneous_aggregate(cx)) {
332 (_, HomogeneousAggregate::NoData) => {
333 // Ignore fields that have no data
335 (_, HomogeneousAggregate::Heterogeneous) => {
336 // The field itself must be a homogeneous aggregate.
337 return HomogeneousAggregate::Heterogeneous;
339 // If this is the first field, record the unit.
340 (None, HomogeneousAggregate::Homogeneous(unit)) => {
343 // For all following fields, the unit must be the same.
344 (Some(prev_unit), HomogeneousAggregate::Homogeneous(unit)) => {
345 if prev_unit != unit {
346 return HomogeneousAggregate::Heterogeneous;
351 // Keep track of the offset (without padding).
352 let size = field.size;
354 total = total.max(size);
360 // There needs to be no padding.
361 if total != self.size {
362 HomogeneousAggregate::Heterogeneous
366 assert_ne!(total, Size::ZERO);
367 HomogeneousAggregate::Homogeneous(reg)
370 assert_eq!(total, Size::ZERO);
371 HomogeneousAggregate::NoData
380 /// Information about how to pass an argument to,
381 /// or return a value from, a function, under some ABI.
383 pub struct ArgAbi<'a, Ty> {
384 pub layout: TyLayout<'a, Ty>,
386 /// Dummy argument, which is emitted before the real argument.
387 pub pad: Option<Reg>,
392 impl<'a, Ty> ArgAbi<'a, Ty> {
393 pub fn new(layout: TyLayout<'a, Ty>) -> Self {
397 mode: PassMode::Direct(ArgAttributes::new()),
401 pub fn make_indirect(&mut self) {
402 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
404 // Start with fresh attributes for the pointer.
405 let mut attrs = ArgAttributes::new();
407 // For non-immediate arguments the callee gets its own copy of
408 // the value on the stack, so there are no aliases. It's also
409 // program-invisible so can't possibly capture
410 attrs.set(ArgAttribute::NoAlias)
411 .set(ArgAttribute::NoCapture)
412 .set(ArgAttribute::NonNull);
413 attrs.pointee_size = self.layout.size;
414 // FIXME(eddyb) We should be doing this, but at least on
415 // i686-pc-windows-msvc, it results in wrong stack offsets.
416 // attrs.pointee_align = Some(self.layout.align.abi);
418 let extra_attrs = if self.layout.is_unsized() {
419 Some(ArgAttributes::new())
424 self.mode = PassMode::Indirect(attrs, extra_attrs);
427 pub fn make_indirect_byval(&mut self) {
428 self.make_indirect();
430 PassMode::Indirect(ref mut attrs, _) => {
431 attrs.set(ArgAttribute::ByVal);
437 pub fn extend_integer_width_to(&mut self, bits: u64) {
438 // Only integers have signedness
439 if let Abi::Scalar(ref scalar) = self.layout.abi {
440 if let abi::Int(i, signed) = scalar.value {
441 if i.size().bits() < bits {
442 if let PassMode::Direct(ref mut attrs) = self.mode {
443 attrs.set(if signed {
454 pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
455 assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
456 self.mode = PassMode::Cast(target.into());
459 pub fn pad_with(&mut self, reg: Reg) {
460 self.pad = Some(reg);
463 pub fn is_indirect(&self) -> bool {
465 PassMode::Indirect(..) => true,
470 pub fn is_sized_indirect(&self) -> bool {
472 PassMode::Indirect(_, None) => true,
477 pub fn is_unsized_indirect(&self) -> bool {
479 PassMode::Indirect(_, Some(_)) => true,
484 pub fn is_ignore(&self) -> bool {
486 PassMode::Ignore => true,
492 #[derive(Copy, Clone, PartialEq, Debug)]
514 /// Metadata describing how the arguments to a native function
515 /// should be passed in order to respect the native ABI.
517 /// I will do my best to describe this structure, but these
518 /// comments are reverse-engineered and may be inaccurate. -NDM
520 pub struct FnAbi<'a, Ty> {
521 /// The LLVM types of each argument.
522 pub args: Vec<ArgAbi<'a, Ty>>,
524 /// LLVM return type.
525 pub ret: ArgAbi<'a, Ty>,
527 pub c_variadic: bool,
532 impl<'a, Ty> FnAbi<'a, Ty> {
533 pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
534 where Ty: TyLayoutMethods<'a, C> + Copy,
535 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
537 match &cx.target_spec().arch[..] {
539 let flavor = if abi == spec::abi::Abi::Fastcall {
540 x86::Flavor::Fastcall
544 x86::compute_abi_info(cx, self, flavor);
546 "x86_64" => if abi == spec::abi::Abi::SysV64 {
547 x86_64::compute_abi_info(cx, self);
548 } else if abi == spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
549 x86_win64::compute_abi_info(self);
551 x86_64::compute_abi_info(cx, self);
553 "aarch64" => aarch64::compute_abi_info(cx, self),
554 "amdgpu" => amdgpu::compute_abi_info(cx, self),
555 "arm" => arm::compute_abi_info(cx, self),
556 "mips" => mips::compute_abi_info(cx, self),
557 "mips64" => mips64::compute_abi_info(cx, self),
558 "powerpc" => powerpc::compute_abi_info(self),
559 "powerpc64" => powerpc64::compute_abi_info(cx, self),
560 "s390x" => s390x::compute_abi_info(cx, self),
561 "msp430" => msp430::compute_abi_info(self),
562 "sparc" => sparc::compute_abi_info(cx, self),
563 "sparc64" => sparc64::compute_abi_info(cx, self),
564 "nvptx" => nvptx::compute_abi_info(self),
565 "nvptx64" => nvptx64::compute_abi_info(self),
566 "hexagon" => hexagon::compute_abi_info(self),
567 "riscv32" => riscv::compute_abi_info(self, 32),
568 "riscv64" => riscv::compute_abi_info(self, 64),
569 "wasm32" if cx.target_spec().target_os != "emscripten"
570 => wasm32_bindgen_compat::compute_abi_info(self),
571 "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
572 a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
575 if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
576 attrs.set(ArgAttribute::StructRet);