@@ -437,34 +437,57 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
437
437
let field_ty = last_field. mt . ty ;
438
438
let ( unsized_size, unsized_align) = size_and_align_of_dst ( bcx, field_ty, info) ;
439
439
440
+ let dbloc = DebugLoc :: None ;
441
+
440
442
// #27023 FIXME: We should be adding any necessary padding
441
443
// to `sized_size` (to accommodate the `unsized_align`
442
444
// required of the unsized field that follows) before
443
445
// summing it with `sized_size`.
444
446
445
447
// Return the sum of sizes and max of aligns.
446
- let mut size = Add ( bcx, sized_size, unsized_size, DebugLoc :: None ) ;
448
+ let mut size = Add ( bcx, sized_size, unsized_size, dbloc ) ;
447
449
448
450
// Issue #27023: If there is a drop flag, *now* we add 1
449
451
// to the size. (We can do this without adding any
450
452
// padding because drop flags do not have any alignment
451
453
// constraints.)
452
454
if sizing_type. needs_drop_flag ( ) {
453
- size = Add ( bcx, size, C_uint ( bcx. ccx ( ) , 1_u64 ) , DebugLoc :: None ) ;
455
+ size = Add ( bcx, size, C_uint ( bcx. ccx ( ) , 1_u64 ) , dbloc ) ;
454
456
}
455
457
458
+ // Choose max of two known alignments (combined value must
459
+ // be aligned according to more restrictive of the two).
456
460
let align = Select ( bcx,
457
461
ICmp ( bcx,
458
- llvm:: IntULT ,
462
+ llvm:: IntUGT ,
459
463
sized_align,
460
464
unsized_align,
461
- DebugLoc :: None ) ,
465
+ dbloc ) ,
462
466
sized_align,
463
467
unsized_align) ;
464
468
465
- // #27023 FIXME: We should be adding any necessary padding
466
- // to `size` (to make it a multiple of `align`) before
467
- // returning it.
469
+ // Issue #27023: must add any necessary padding to `size`
470
+ // (to make it a multiple of `align`) before returning it.
471
+ //
472
+ // Namely, the returned size should be, in C notation:
473
+ //
474
+ // `size + ((size & (align-1)) ? align : 0)`
475
+ //
476
+ // Currently I am emulating the above via:
477
+ //
478
+ // `size + ((size & (align-1)) * align-(size & (align-1)))`
479
+ //
480
+ // because I am not sure which is cheaper between a branch
481
+ // or a multiply.
482
+
483
+ let mask = Sub ( bcx, align, C_uint ( bcx. ccx ( ) , 1_u64 ) , dbloc) ;
484
+ let lowbits = And ( bcx, size, mask, DebugLoc :: None ) ;
485
+ let nonzero = ICmp ( bcx, llvm:: IntNE , lowbits, C_uint ( bcx. ccx ( ) , 0_u64 ) , dbloc) ;
486
+ let add_size = Mul ( bcx,
487
+ ZExt ( bcx, nonzero, Type :: i64 ( bcx. ccx ( ) ) ) ,
488
+ Sub ( bcx, align, lowbits, dbloc) ,
489
+ dbloc) ;
490
+ let size = Add ( bcx, size, add_size, dbloc) ;
468
491
469
492
( size, align)
470
493
}
0 commit comments