1use std::fmt::Write;
2
3use rustc_abi::Primitive::{Float, Int, Pointer};
4use rustc_abi::{Align, BackendRepr, FieldsShape, Scalar, Size, Variants};
5use rustc_codegen_ssa::traits::*;
6use rustc_middle::bug;
7use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
8use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
9use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
10use tracing::debug;
11
12use crate::common::*;
13use crate::type_::Type;
14
15fn uncached_llvm_type<'a, 'tcx>(
16 cx: &CodegenCx<'a, 'tcx>,
17 layout: TyAndLayout<'tcx>,
18 defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>,
19) -> &'a Type {
20 match layout.backend_repr {
21 BackendRepr::Scalar(_) => bug!("handled elsewhere"),
22 BackendRepr::Vector { element, count } => {
23 let element = layout.scalar_llvm_type_at(cx, element);
24 return cx.type_vector(element, count);
25 }
26 BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {}
27 }
28
29 let name = match layout.ty.kind() {
30 ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
34 if !cx.sess().fewer_names() =>
36 {
37 let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string()));
38 if let (&ty::Adt(def, _), &Variants::Single { index }) =
39 (layout.ty.kind(), &layout.variants)
40 {
41 if def.is_enum() {
42 write!(&mut name, "::{}", def.variant(index).name).unwrap();
43 }
44 }
45 if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
46 (layout.ty.kind(), &layout.variants)
47 {
48 write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
49 }
50 Some(name)
51 }
52 _ => None,
53 };
54
55 match layout.fields {
56 FieldsShape::Primitive | FieldsShape::Union(_) => {
57 let fill = cx.type_padding_filler(layout.size, layout.align.abi);
58 let packed = false;
59 match name {
60 None => cx.type_struct(&[fill], packed),
61 Some(ref name) => {
62 let llty = cx.type_named_struct(name);
63 cx.set_struct_body(llty, &[fill], packed);
64 llty
65 }
66 }
67 }
68 FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).llvm_type(cx), count),
69 FieldsShape::Arbitrary { .. } => match name {
70 None => {
71 let (llfields, packed) = struct_llfields(cx, layout);
72 cx.type_struct(&llfields, packed)
73 }
74 Some(ref name) => {
75 let llty = cx.type_named_struct(name);
76 *defer = Some((llty, layout));
77 llty
78 }
79 },
80 }
81}
82
83fn struct_llfields<'a, 'tcx>(
84 cx: &CodegenCx<'a, 'tcx>,
85 layout: TyAndLayout<'tcx>,
86) -> (Vec<&'a Type>, bool) {
87 debug!("struct_llfields: {:#?}", layout);
88 let field_count = layout.fields.count();
89
90 let mut packed = false;
91 let mut offset = Size::ZERO;
92 let mut prev_effective_align = layout.align.abi;
93 let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
94 for i in layout.fields.index_by_increasing_offset() {
95 let target_offset = layout.fields.offset(i as usize);
96 let field = layout.field(cx, i);
97 let effective_field_align =
98 layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset);
99 packed |= effective_field_align < field.align.abi;
100
101 debug!(
102 "struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \
103 effective_field_align: {}",
104 i,
105 field,
106 offset,
107 target_offset,
108 effective_field_align.bytes()
109 );
110 assert!(target_offset >= offset);
111 let padding = target_offset - offset;
112 if padding != Size::ZERO {
113 let padding_align = prev_effective_align.min(effective_field_align);
114 assert_eq!(offset.align_to(padding_align) + padding, target_offset);
115 result.push(cx.type_padding_filler(padding, padding_align));
116 debug!(" padding before: {:?}", padding);
117 }
118 result.push(field.llvm_type(cx));
119 offset = target_offset + field.size;
120 prev_effective_align = effective_field_align;
121 }
122 if layout.is_sized() && field_count > 0 {
123 if offset > layout.size {
124 bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
125 }
126 let padding = layout.size - offset;
127 if padding != Size::ZERO {
128 let padding_align = prev_effective_align;
129 assert_eq!(offset.align_to(padding_align) + padding, layout.size);
130 debug!(
131 "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
132 padding, offset, layout.size
133 );
134 result.push(cx.type_padding_filler(padding, padding_align));
135 }
136 } else {
137 debug!("struct_llfields: offset: {:?} stride: {:?}", offset, layout.size);
138 }
139 (result, packed)
140}
141
142impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
143 pub(crate) fn align_of(&self, ty: Ty<'tcx>) -> Align {
144 self.layout_of(ty).align.abi
145 }
146
147 pub(crate) fn size_of(&self, ty: Ty<'tcx>) -> Size {
148 self.layout_of(ty).size
149 }
150
151 pub(crate) fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) {
152 let layout = self.layout_of(ty);
153 (layout.size, layout.align.abi)
154 }
155}
156
157pub(crate) trait LayoutLlvmExt<'tcx> {
158 fn is_llvm_immediate(&self) -> bool;
159 fn is_llvm_scalar_pair(&self) -> bool;
160 fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
161 fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
162 fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type;
163 fn scalar_pair_element_llvm_type<'a>(
164 &self,
165 cx: &CodegenCx<'a, 'tcx>,
166 index: usize,
167 immediate: bool,
168 ) -> &'a Type;
169}
170
171impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
172 fn is_llvm_immediate(&self) -> bool {
173 match self.backend_repr {
174 BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true,
175 BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
176 }
177 }
178
179 fn is_llvm_scalar_pair(&self) -> bool {
180 match self.backend_repr {
181 BackendRepr::ScalarPair(..) => true,
182 BackendRepr::Scalar(_) | BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => {
183 false
184 }
185 }
186 }
187
188 fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
200 if let BackendRepr::Scalar(scalar) = self.backend_repr {
204 if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
207 return llty;
208 }
209 let llty = self.scalar_llvm_type_at(cx, scalar);
210 cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
211 return llty;
212 }
213
214 let variant_index = match self.variants {
216 Variants::Single { index } => Some(index),
217 _ => None,
218 };
219 if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
220 return llty;
221 }
222
223 debug!("llvm_type({:#?})", self);
224
225 assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
226
227 let normal_ty = cx.tcx.erase_regions(self.ty);
230
231 let mut defer = None;
232 let llty = if self.ty != normal_ty {
233 let mut layout = cx.layout_of(normal_ty);
234 if let Some(v) = variant_index {
235 layout = layout.for_variant(cx, v);
236 }
237 layout.llvm_type(cx)
238 } else {
239 uncached_llvm_type(cx, *self, &mut defer)
240 };
241 debug!("--> mapped {:#?} to llty={:?}", self, llty);
242
243 cx.type_lowering.borrow_mut().insert((self.ty, variant_index), llty);
244
245 if let Some((llty, layout)) = defer {
246 let (llfields, packed) = struct_llfields(cx, layout);
247 cx.set_struct_body(llty, &llfields, packed);
248 }
249 llty
250 }
251
252 fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
253 match self.backend_repr {
254 BackendRepr::Scalar(scalar) => {
255 if scalar.is_bool() {
256 return cx.type_i1();
257 }
258 }
259 BackendRepr::ScalarPair(..) => {
260 return cx.type_struct(
263 &[
264 self.scalar_pair_element_llvm_type(cx, 0, true),
265 self.scalar_pair_element_llvm_type(cx, 1, true),
266 ],
267 false,
268 );
269 }
270 _ => {}
271 };
272 self.llvm_type(cx)
273 }
274
275 fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type {
276 match scalar.primitive() {
277 Int(i, _) => cx.type_from_integer(i),
278 Float(f) => cx.type_from_float(f),
279 Pointer(address_space) => cx.type_ptr_ext(address_space),
280 }
281 }
282
283 fn scalar_pair_element_llvm_type<'a>(
284 &self,
285 cx: &CodegenCx<'a, 'tcx>,
286 index: usize,
287 immediate: bool,
288 ) -> &'a Type {
289 let BackendRepr::ScalarPair(a, b) = self.backend_repr else {
293 bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self);
294 };
295 let scalar = [a, b][index];
296
297 if immediate && scalar.is_bool() {
304 return cx.type_i1();
305 }
306
307 self.scalar_llvm_type_at(cx, scalar)
308 }
309}