@@ -252,7 +252,9 @@ pub(crate) fn size_and_align_of<'tcx>(
252
252
assert ! ( !layout. ty. is_simd( ) ) ;
253
253
254
254
let i = layout. fields . count ( ) - 1 ;
255
- let sized_size = layout. fields . offset ( i) . bytes ( ) ;
255
+ let unsized_offset_unadjusted = layout. fields . offset ( i) . bytes ( ) ;
256
+ let unsized_offset_unadjusted =
257
+ fx. bcx . ins ( ) . iconst ( fx. pointer_type , unsized_offset_unadjusted as i64 ) ;
256
258
let sized_align = layout. align . abi . bytes ( ) ;
257
259
let sized_align = fx. bcx . ins ( ) . iconst ( fx. pointer_type , sized_align as i64 ) ;
258
260
@@ -261,27 +263,41 @@ pub(crate) fn size_and_align_of<'tcx>(
261
263
let field_layout = layout. field ( fx, i) ;
262
264
let ( unsized_size, mut unsized_align) = size_and_align_of ( fx, field_layout, info) ;
263
265
264
- // FIXME (#26403, #27023): We should be adding padding
265
- // to `sized_size` (to accommodate the `unsized_align`
266
- // required of the unsized field that follows) before
267
- // summing it with `sized_size`. (Note that since #26403
268
- // is unfixed, we do not yet add the necessary padding
269
- // here. But this is where the add would go.)
270
-
271
- // Return the sum of sizes and max of aligns.
272
- let size = fx. bcx . ins ( ) . iadd_imm ( unsized_size, sized_size as i64 ) ;
273
-
274
- // Packed types ignore the alignment of their fields.
275
- if let ty:: Adt ( def, _) = layout. ty . kind ( ) {
276
- if def. repr ( ) . packed ( ) {
277
- unsized_align = sized_align;
266
+ // # First compute the dynamic alignment
267
+
268
+ // For packed types, we need to cap the alignment.
269
+ if let ty:: Adt ( def, _) = ty. kind ( ) {
270
+ if let Some ( packed) = def. repr ( ) . pack {
271
+ if packed. bytes ( ) == 1 {
272
+ // We know this will be capped to 1.
273
+ unsized_align = fx. bcx . ins ( ) . iconst ( fx. pointer_type , 1 ) ;
274
+ } else {
275
+ // We have to dynamically compute `min(unsized_align, packed)`.
276
+ let packed = fx. bcx . ins ( ) . iconst ( fx. pointer_type , packed. bytes ( ) as i64 ) ;
277
+ let cmp =
278
+ fx. bcx . ins ( ) . icmp ( IntCC :: UnsignedGreaterThan , unsized_align, packed) ;
279
+ unsized_align = fx. bcx . ins ( ) . select ( cmp, unsized_align, packed) ;
280
+ }
278
281
}
279
282
}
280
283
281
284
// Choose max of two known alignments (combined value must
282
285
// be aligned according to more restrictive of the two).
283
286
let cmp = fx. bcx . ins ( ) . icmp ( IntCC :: UnsignedGreaterThan , sized_align, unsized_align) ;
284
- let align = fx. bcx . ins ( ) . select ( cmp, sized_align, unsized_align) ;
287
+ let full_align = fx. bcx . ins ( ) . select ( cmp, sized_align, unsized_align) ;
288
+
289
+ // # Then compute the dynamic size
290
+
291
+ // The full formula for the size would be:
292
+ // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
293
+ // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
294
+ // However, `unsized_size` is a multiple of `unsized_align`.
295
+ // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
296
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align);
297
+ // Furthermore, `align >= unsized_align`, and therefore we only need to do:
298
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align);
299
+
300
+ let full_size = fx. bcx . ins ( ) . iadd ( unsized_offset_unadjusted, unsized_size) ;
285
301
286
302
// Issue #27023: must add any necessary padding to `size`
287
303
// (to make it a multiple of `align`) before returning it.
@@ -293,12 +309,12 @@ pub(crate) fn size_and_align_of<'tcx>(
293
309
// emulated via the semi-standard fast bit trick:
294
310
//
295
311
// `(size + (align-1)) & -align`
296
- let addend = fx. bcx . ins ( ) . iadd_imm ( align , -1 ) ;
297
- let add = fx. bcx . ins ( ) . iadd ( size , addend) ;
298
- let neg = fx. bcx . ins ( ) . ineg ( align ) ;
299
- let size = fx. bcx . ins ( ) . band ( add, neg) ;
312
+ let addend = fx. bcx . ins ( ) . iadd_imm ( full_align , -1 ) ;
313
+ let add = fx. bcx . ins ( ) . iadd ( full_size , addend) ;
314
+ let neg = fx. bcx . ins ( ) . ineg ( full_align ) ;
315
+ let full_size = fx. bcx . ins ( ) . band ( add, neg) ;
300
316
301
- ( size , align )
317
+ ( full_size , full_align )
302
318
}
303
319
_ => bug ! ( "size_and_align_of_dst: {ty} not supported" ) ,
304
320
}
0 commit comments