]>
git.proxmox.com Git - rustc.git/blob - src/librustc_codegen_ssa/glue.rs
3 // Code relating to drop glue.
5 use crate::common
::IntPredicate
;
8 use rustc_middle
::ty
::{self, Ty}
;
10 pub fn size_and_align_of_dst
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
13 info
: Option
<Bx
::Value
>,
14 ) -> (Bx
::Value
, Bx
::Value
) {
15 let layout
= bx
.layout_of(t
);
16 debug
!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t
, info
, layout
);
17 if !layout
.is_unsized() {
18 let size
= bx
.const_usize(layout
.size
.bytes());
19 let align
= bx
.const_usize(layout
.align
.abi
.bytes());
24 // load size/align from vtable
25 let vtable
= info
.unwrap();
26 (meth
::SIZE
.get_usize(bx
, vtable
), meth
::ALIGN
.get_usize(bx
, vtable
))
28 ty
::Slice(_
) | ty
::Str
=> {
29 let unit
= layout
.field(bx
, 0);
30 // The info in this case is the length of the str, so the size is that
31 // times the unit size.
33 bx
.mul(info
.unwrap(), bx
.const_usize(unit
.size
.bytes())),
34 bx
.const_usize(unit
.align
.abi
.bytes()),
38 // First get the size of all statically known fields.
39 // Don't use size_of because it also rounds up to alignment, which we
40 // want to avoid, as the unsized field's alignment could be smaller.
41 assert
!(!t
.is_simd());
42 debug
!("DST {} layout: {:?}", t
, layout
);
44 let i
= layout
.fields
.count() - 1;
45 let sized_size
= layout
.fields
.offset(i
).bytes();
46 let sized_align
= layout
.align
.abi
.bytes();
47 debug
!("DST {} statically sized prefix size: {} align: {}", t
, sized_size
, sized_align
);
48 let sized_size
= bx
.const_usize(sized_size
);
49 let sized_align
= bx
.const_usize(sized_align
);
51 // Recurse to get the size of the dynamically sized field (must be
53 let field_ty
= layout
.field(bx
, i
).ty
;
54 let (unsized_size
, mut unsized_align
) = size_and_align_of_dst(bx
, field_ty
, info
);
56 // FIXME (#26403, #27023): We should be adding padding
57 // to `sized_size` (to accommodate the `unsized_align`
58 // required of the unsized field that follows) before
59 // summing it with `sized_size`. (Note that since #26403
60 // is unfixed, we do not yet add the necessary padding
61 // here. But this is where the add would go.)
63 // Return the sum of sizes and max of aligns.
64 let size
= bx
.add(sized_size
, unsized_size
);
66 // Packed types ignore the alignment of their fields.
67 if let ty
::Adt(def
, _
) = t
.kind
{
68 if def
.repr
.packed() {
69 unsized_align
= sized_align
;
73 // Choose max of two known alignments (combined value must
74 // be aligned according to more restrictive of the two).
76 bx
.const_to_opt_u128(sized_align
, false),
77 bx
.const_to_opt_u128(unsized_align
, false),
79 (Some(sized_align
), Some(unsized_align
)) => {
80 // If both alignments are constant, (the sized_align should always be), then
81 // pick the correct alignment statically.
82 bx
.const_usize(std
::cmp
::max(sized_align
, unsized_align
) as u64)
85 let cmp
= bx
.icmp(IntPredicate
::IntUGT
, sized_align
, unsized_align
);
86 bx
.select(cmp
, sized_align
, unsized_align
)
90 // Issue #27023: must add any necessary padding to `size`
91 // (to make it a multiple of `align`) before returning it.
93 // Namely, the returned size should be, in C notation:
95 // `size + ((size & (align-1)) ? align : 0)`
97 // emulated via the semi-standard fast bit trick:
99 // `(size + (align-1)) & -align`
100 let one
= bx
.const_usize(1);
101 let addend
= bx
.sub(align
, one
);
102 let add
= bx
.add(size
, addend
);
103 let neg
= bx
.neg(align
);
104 let size
= bx
.and(add
, neg
);