1use std::num::NonZero;
2
3use rustc_hashes::Hash64;
4use rustc_index::{Idx, IndexVec};
5
6use crate::{
7 AbiAlign, BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size,
8 Variants,
9};
10
11impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
13 pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
14 let dl = cx.data_layout();
15 LayoutData {
16 variants: Variants::Single { index: VariantIdx::new(0) },
17 fields: FieldsShape::Arbitrary {
18 offsets: IndexVec::new(),
19 in_memory_order: IndexVec::new(),
20 },
21 backend_repr: BackendRepr::Memory { sized },
22 largest_niche: None,
23 uninhabited: false,
24 align: AbiAlign::new(dl.i8_align),
25 size: Size::ZERO,
26 max_repr_align: None,
27 unadjusted_abi_align: dl.i8_align,
28 repr_c: false,
29 randomization_seed: Hash64::new(0),
30 }
31 }
32
33 pub fn never_type<C: HasDataLayout>(cx: &C) -> Self {
34 let dl = cx.data_layout();
35 LayoutData {
37 variants: Variants::Empty,
38 fields: FieldsShape::Primitive,
39 backend_repr: BackendRepr::Memory { sized: true },
40 largest_niche: None,
41 uninhabited: true,
42 align: AbiAlign::new(dl.i8_align),
43 size: Size::ZERO,
44 max_repr_align: None,
45 unadjusted_abi_align: dl.i8_align,
46 repr_c: false,
47 randomization_seed: Hash64::ZERO,
48 }
49 }
50
51 pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
52 let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
53 let size = scalar.size(cx);
54 let align = scalar.default_align(cx);
55
56 let range = scalar.valid_range(cx);
57
58 let randomization_seed = size
65 .bytes()
66 .wrapping_add(
67 match scalar.primitive() {
68 Primitive::Int(_, true) => 1,
69 Primitive::Int(_, false) => 2,
70 Primitive::Float(_) => 3,
71 Primitive::Pointer(_) => 4,
72 } << 32,
73 )
74 .wrapping_add((range.start as u64).rotate_right(16))
76 .wrapping_add((range.end as u64).rotate_right(16));
78
79 LayoutData {
80 variants: Variants::Single { index: VariantIdx::new(0) },
81 fields: FieldsShape::Primitive,
82 backend_repr: BackendRepr::Scalar(scalar),
83 largest_niche,
84 uninhabited: false,
85 size,
86 align,
87 max_repr_align: None,
88 unadjusted_abi_align: align.abi,
89 repr_c: false,
90 randomization_seed: Hash64::new(randomization_seed),
91 }
92 }
93
94 pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
95 let dl = cx.data_layout();
96 let b_align = b.default_align(dl).abi;
97 let align = a.default_align(dl).abi.max(b_align).max(dl.aggregate_align);
98 let b_offset = a.size(dl).align_to(b_align);
99 let size = (b_offset + b.size(dl)).align_to(align);
100
101 let largest_niche = Niche::from_scalar(dl, b_offset, b)
104 .into_iter()
105 .chain(Niche::from_scalar(dl, Size::ZERO, a))
106 .max_by_key(|niche| niche.available(dl));
107
108 let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
109
110 LayoutData {
111 variants: Variants::Single { index: VariantIdx::new(0) },
112 fields: FieldsShape::Arbitrary {
113 offsets: [Size::ZERO, b_offset].into(),
114 in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(),
115 },
116 backend_repr: BackendRepr::ScalarPair { a, b, b_offset },
117 largest_niche,
118 uninhabited: false,
119 align: AbiAlign::new(align),
120 size,
121 max_repr_align: None,
122 unadjusted_abi_align: align,
123 repr_c: false,
124 randomization_seed: Hash64::new(combined_seed),
125 }
126 }
127
128 pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
133 let dl = cx.data_layout();
134 LayoutData {
135 variants: Variants::Single { index },
136 fields: match NonZero::new(fields) {
137 Some(fields) => FieldsShape::Union(fields),
138 None => FieldsShape::Arbitrary {
139 offsets: IndexVec::new(),
140 in_memory_order: IndexVec::new(),
141 },
142 },
143 backend_repr: BackendRepr::Memory { sized: true },
144 largest_niche: None,
145 uninhabited: true,
146 align: AbiAlign::new(dl.i8_align),
147 size: Size::ZERO,
148 max_repr_align: None,
149 unadjusted_abi_align: dl.i8_align,
150 repr_c: false,
151 randomization_seed: Hash64::ZERO,
154 }
155 }
156
157 pub fn for_variant(parent: &Self, index: VariantIdx) -> Self {
159 let layout = match &parent.variants {
160 Variants::Multiple { variants, .. } => &variants[index],
161 _ => {
::core::panicking::panic_fmt(format_args!("Expected multi-variant layout in `Layout::for_variant`"));
}panic!("Expected multi-variant layout in `Layout::for_variant`"),
162 };
163
164 Self {
165 fields: FieldsShape::Arbitrary {
166 offsets: layout.field_offsets.clone(),
167 in_memory_order: layout.fields_in_memory_order.clone(),
168 },
169 variants: Variants::Single { index },
170 backend_repr: layout.backend_repr,
171 largest_niche: layout.largest_niche,
172 uninhabited: layout.uninhabited,
173 size: layout.size,
174 align: parent.align,
175 max_repr_align: parent.max_repr_align,
176 unadjusted_abi_align: parent.unadjusted_abi_align,
177 repr_c: parent.repr_c,
178 randomization_seed: Hash64::ZERO,
181 }
182 }
183}