diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 099d717e3c00c..7e55642814bba 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -12,7 +12,9 @@ //! Code that is useful in various codegen modules. -use llvm::{self, ValueRef, ContextRef, TypeKind, True, False, Bool, OperandBundleDef}; +use llvm; +use llvm::{ValueRef, ContextRef, TypeKind}; +use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def_id::DefId; use rustc::middle::lang_items::LangItem; use abi; @@ -27,8 +29,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; use rustc::hir; -use meth; - use libc::{c_uint, c_char}; use std::iter; @@ -448,101 +448,3 @@ pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, _ => bug!("unexpected type {:?} to ty_fn_sig", ty) } } - -pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) - -> (ValueRef, ValueRef) { - debug!("calculate size of DST: {}; with lost info: {:?}", - t, Value(info)); - if bx.cx.type_is_sized(t) { - let (size, align) = bx.cx.size_and_align_of(t); - debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}", - t, Value(info), size, align); - let size = C_usize(bx.cx, size.bytes()); - let align = C_usize(bx.cx, align.abi()); - return (size, align); - } - assert!(!info.is_null()); - match t.sty { - ty::TyDynamic(..) => { - // load size/align from vtable - (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info)) - } - ty::TySlice(_) | ty::TyStr => { - let unit = t.sequence_element_type(bx.tcx()); - // The info in this case is the length of the str, so the size is that - // times the unit size. - let (size, align) = bx.cx.size_and_align_of(unit); - (bx.mul(info, C_usize(bx.cx, size.bytes())), - C_usize(bx.cx, align.abi())) - } - _ => { - let cx = bx.cx; - // First get the size of all statically known fields. - // Don't use size_of because it also rounds up to alignment, which we - // want to avoid, as the unsized field's alignment could be smaller. - assert!(!t.is_simd()); - let layout = cx.layout_of(t); - debug!("DST {} layout: {:?}", t, layout); - - let i = layout.fields.count() - 1; - let sized_size = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi(); - debug!("DST {} statically sized prefix size: {} align: {}", - t, sized_size, sized_align); - let sized_size = C_usize(cx, sized_size); - let sized_align = C_usize(cx, sized_align); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). - let field_ty = layout.field(cx, i).ty; - let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); - - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) - - // Return the sum of sizes and max of aligns. - let size = bx.add(sized_size, unsized_size); - - // Packed types ignore the alignment of their fields. - if let ty::TyAdt(def, _) = t.sty { - if def.repr.packed() { - unsized_align = sized_align; - } - } - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let align = match (const_to_opt_u128(sized_align, false), - const_to_opt_u128(unsized_align, false)) { - (Some(sized_align), Some(unsized_align)) => { - // If both alignments are constant, (the sized_align should always be), then - // pick the correct alignment statically. - C_usize(cx, ::std::cmp::max(sized_align, unsized_align) as u64) - } - _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align), - sized_align, - unsized_align) - }; - - // 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)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - let addend = bx.sub(align, C_usize(bx.cx, 1)); - let size = bx.and(bx.add(size, addend), bx.neg(align)); - - (size, align) - } - } -} diff --git a/src/librustc_codegen_llvm/glue.rs b/src/librustc_codegen_llvm/glue.rs new file mode 100644 index 0000000000000..c7275d0940185 --- /dev/null +++ b/src/librustc_codegen_llvm/glue.rs @@ -0,0 +1,122 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! +// +// Code relating to drop glue. + +use std; + +use builder::Builder; +use common::*; +use llvm::{ValueRef}; +use llvm; +use meth; +use rustc::ty::layout::LayoutOf; +use rustc::ty::{self, Ty}; +use value::Value; + +pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) + -> (ValueRef, ValueRef) { + debug!("calculate size of DST: {}; with lost info: {:?}", + t, Value(info)); + if bx.cx.type_is_sized(t) { + let (size, align) = bx.cx.size_and_align_of(t); + debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}", + t, Value(info), size, align); + let size = C_usize(bx.cx, size.bytes()); + let align = C_usize(bx.cx, align.abi()); + return (size, align); + } + assert!(!info.is_null()); + match t.sty { + ty::TyDynamic(..) => { + // load size/align from vtable + (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info)) + } + ty::TySlice(_) | ty::TyStr => { + let unit = t.sequence_element_type(bx.tcx()); + // The info in this case is the length of the str, so the size is that + // times the unit size. + let (size, align) = bx.cx.size_and_align_of(unit); + (bx.mul(info, C_usize(bx.cx, size.bytes())), + C_usize(bx.cx, align.abi())) + } + _ => { + let cx = bx.cx; + // First get the size of all statically known fields. + // Don't use size_of because it also rounds up to alignment, which we + // want to avoid, as the unsized field's alignment could be smaller. + assert!(!t.is_simd()); + let layout = cx.layout_of(t); + debug!("DST {} layout: {:?}", t, layout); + + let i = layout.fields.count() - 1; + let sized_size = layout.fields.offset(i).bytes(); + let sized_align = layout.align.abi(); + debug!("DST {} statically sized prefix size: {} align: {}", + t, sized_size, sized_align); + let sized_size = C_usize(cx, sized_size); + let sized_align = C_usize(cx, sized_align); + + // Recurse to get the size of the dynamically sized field (must be + // the last field). + let field_ty = layout.field(cx, i).ty; + let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); + + // FIXME (#26403, #27023): We should be adding padding + // to `sized_size` (to accommodate the `unsized_align` + // required of the unsized field that follows) before + // summing it with `sized_size`. (Note that since #26403 + // is unfixed, we do not yet add the necessary padding + // here. But this is where the add would go.) + + // Return the sum of sizes and max of aligns. + let size = bx.add(sized_size, unsized_size); + + // Packed types ignore the alignment of their fields. + if let ty::TyAdt(def, _) = t.sty { + if def.repr.packed() { + unsized_align = sized_align; + } + } + + // Choose max of two known alignments (combined value must + // be aligned according to more restrictive of the two). + let align = match (const_to_opt_u128(sized_align, false), + const_to_opt_u128(unsized_align, false)) { + (Some(sized_align), Some(unsized_align)) => { + // If both alignments are constant, (the sized_align should always be), then + // pick the correct alignment statically. + C_usize(cx, std::cmp::max(sized_align, unsized_align) as u64) + } + _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align), + sized_align, + unsized_align) + }; + + // 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)` + // + // emulated via the semi-standard fast bit trick: + // + // `(size + (align-1)) & -align` + + let addend = bx.sub(align, C_usize(bx.cx, 1)); + let size = bx.and(bx.add(size, addend), bx.neg(align)); + + (size, align) + } + } +} diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index d7a068265a9e3..6bb5456f9034f 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -19,6 +19,7 @@ use mir::operand::{OperandRef, OperandValue}; use base::*; use common::*; use declare; +use glue; use type_::Type; use type_of::LayoutLlvmExt; use rustc::ty::{self, Ty}; @@ -145,7 +146,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { let (llsize, _) = - size_and_align_of_dst(bx, tp_ty, meta); + glue::size_and_align_of_dst(bx, tp_ty, meta); llsize } else { C_usize(cx, cx.size_of(tp_ty).bytes()) @@ -159,7 +160,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { let (_, llalign) = - size_and_align_of_dst(bx, tp_ty, meta); + glue::size_and_align_of_dst(bx, tp_ty, meta); llalign } else { C_usize(cx, cx.align_of(tp_ty).abi()) diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index fd2d1f5388765..eee4e5f8f7a09 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -109,6 +109,7 @@ mod consts; mod context; mod debuginfo; mod declare; +mod glue; mod intrinsic; mod llvm_util; mod metadata; diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 93c31286932e5..2a1e3980adbcf 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -16,13 +16,12 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; -use common::{ - CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big,size_and_align_of_dst -}; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; use consts; use type_of::LayoutLlvmExt; use type_::Type; use value::Value; +use glue; use std::ptr; @@ -223,7 +222,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let unaligned_offset = C_usize(cx, offset.bytes()); // Get the alignment of the field - let (_, unsized_align) = size_and_align_of_dst(bx, field.ty, meta); + let (_, unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta); // Bump the unaligned offset up to the appropriate alignment using the // following expression: