]> git.lizzy.rs Git - rust.git/commitdiff
Fix more bugs in the alignment calculation refs to DSTs.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Mon, 27 Jul 2015 14:53:57 +0000 (16:53 +0200)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Tue, 28 Jul 2015 18:08:29 +0000 (20:08 +0200)
src/librustc_trans/trans/glue.rs

index 526c7277a665e6d6ab773c8d6fbbc704f62ddd35..67e2e4cba4c34732e8f2bb81d4b0d78051081752 100644 (file)
@@ -437,34 +437,57 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             let field_ty = last_field.mt.ty;
             let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
 
+            let dbloc = DebugLoc::None;
+
             // #27023 FIXME: We should be adding any necessary padding
             // to `sized_size` (to accommodate the `unsized_align`
             // required of the unsized field that follows) before
             // summing it with `sized_size`.
 
             // Return the sum of sizes and max of aligns.
-            let mut size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
+            let mut size = Add(bcx, sized_size, unsized_size, dbloc);
 
             // Issue #27023: If there is a drop flag, *now* we add 1
             // to the size.  (We can do this without adding any
             // padding because drop flags do not have any alignment
             // constraints.)
             if sizing_type.needs_drop_flag() {
-                size = Add(bcx, size, C_uint(bcx.ccx(), 1_u64), DebugLoc::None);
+                size = Add(bcx, size, C_uint(bcx.ccx(), 1_u64), dbloc);
             }
 
+            // Choose max of two known alignments (combined value must
+            // be aligned according to more restrictive of the two).
             let align = Select(bcx,
                                ICmp(bcx,
-                                    llvm::IntULT,
+                                    llvm::IntUGT,
                                     sized_align,
                                     unsized_align,
-                                    DebugLoc::None),
+                                    dbloc),
                                sized_align,
                                unsized_align);
 
-            // #27023 FIXME: We should be adding any necessary padding
-            // to `size` (to make it a multiple of `align`) before
-            // returning it.
+            // Issue #27023: must add any necessary padding to `size`
+            // (to make it a multiple of `align`) before returning it.
+            //
+            // Namely, the returned size should be, in C notation:
+            //
+            //   `size + ((size & (align-1)) ? align : 0)`
+            //
+            // Currently I am emulating the above via:
+            //
+            //   `size + ((size & (align-1)) * align-(size & (align-1)))`
+            //
+            // because I am not sure which is cheaper between a branch
+            // or a multiply.
+
+            let mask = Sub(bcx, align, C_uint(bcx.ccx(), 1_u64), dbloc);
+            let lowbits = And(bcx, size, mask, DebugLoc::None);
+            let nonzero = ICmp(bcx, llvm::IntNE, lowbits, C_uint(bcx.ccx(), 0_u64), dbloc);
+            let add_size = Mul(bcx,
+                               ZExt(bcx, nonzero, Type::i64(bcx.ccx())),
+                               Sub(bcx, align, lowbits, dbloc),
+                               dbloc);
+            let size = Add(bcx, size, add_size, dbloc);
 
             (size, align)
         }