rustc_trans: avoid working with sizes/offsets and alignments as integers.
This commit is contained in:
parent
9deea47c96
commit
f44b099187
38 changed files with 862 additions and 985 deletions
|
|
@ -24,7 +24,7 @@ use std::fmt;
|
|||
use std::i64;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ops::{Deref, Add, Sub, Mul, AddAssign};
|
||||
|
||||
use ich::StableHashingContext;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
|
|
@ -203,6 +203,18 @@ impl TargetDataLayout {
|
|||
bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vector_align(&self, vec_size: Size) -> Align {
|
||||
for &(size, align) in &self.vector_align {
|
||||
if size == vec_size {
|
||||
return align;
|
||||
}
|
||||
}
|
||||
// Default to natural alignment, which is what LLVM does.
|
||||
// That is, use the size, rounded up to a power of 2.
|
||||
let align = vec_size.bytes().next_power_of_two();
|
||||
Align::from_bytes(align, align).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasDataLayout: Copy {
|
||||
|
|
@ -236,7 +248,8 @@ pub struct Size {
|
|||
|
||||
impl Size {
|
||||
pub fn from_bits(bits: u64) -> Size {
|
||||
Size::from_bytes((bits + 7) / 8)
|
||||
// Avoid potential overflow from `bits + 7`.
|
||||
Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: u64) -> Size {
|
||||
|
|
@ -261,6 +274,11 @@ impl Size {
|
|||
Size::from_bytes((self.bytes() + mask) & !mask)
|
||||
}
|
||||
|
||||
pub fn is_abi_aligned(self, align: Align) -> bool {
|
||||
let mask = align.abi() - 1;
|
||||
self.bytes() & mask == 0
|
||||
}
|
||||
|
||||
pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
|
||||
let dl = cx.data_layout();
|
||||
|
||||
|
|
@ -278,8 +296,6 @@ impl Size {
|
|||
pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
|
||||
let dl = cx.data_layout();
|
||||
|
||||
// Each Size is less than dl.obj_size_bound(), so the sum is
|
||||
// also less than 1 << 62 (and therefore can't overflow).
|
||||
match self.bytes().checked_mul(count) {
|
||||
Some(bytes) if bytes < dl.obj_size_bound() => {
|
||||
Some(Size::from_bytes(bytes))
|
||||
|
|
@ -289,6 +305,46 @@ impl Size {
|
|||
}
|
||||
}
|
||||
|
||||
// Panicking addition, subtraction and multiplication for convenience.
|
||||
// Avoid during layout computation, return `LayoutError` instead.
|
||||
|
||||
impl Add for Size {
|
||||
type Output = Size;
|
||||
fn add(self, other: Size) -> Size {
|
||||
// Each Size is less than 1 << 61, so the sum is
|
||||
// less than 1 << 62 (and therefore can't overflow).
|
||||
Size::from_bytes(self.bytes() + other.bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Size {
|
||||
type Output = Size;
|
||||
fn sub(self, other: Size) -> Size {
|
||||
// Each Size is less than 1 << 61, so an underflow
|
||||
// would result in a value larger than 1 << 61,
|
||||
// which Size::from_bytes will catch for us.
|
||||
Size::from_bytes(self.bytes() - other.bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<u64> for Size {
|
||||
type Output = Size;
|
||||
fn mul(self, count: u64) -> Size {
|
||||
match self.bytes().checked_mul(count) {
|
||||
Some(bytes) => Size::from_bytes(bytes),
|
||||
None => {
|
||||
bug!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Size {
|
||||
fn add_assign(&mut self, other: Size) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
/// Alignment of a type in bytes, both ABI-mandated and preferred.
|
||||
/// Each field is a power of two, giving the alignment a maximum
|
||||
/// value of 2^(2^8 - 1), which is limited by LLVM to a i32, with
|
||||
|
|
@ -301,7 +357,8 @@ pub struct Align {
|
|||
|
||||
impl Align {
|
||||
pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {
|
||||
Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)
|
||||
Align::from_bytes(Size::from_bits(abi).bytes(),
|
||||
Size::from_bits(pref).bytes())
|
||||
}
|
||||
|
||||
pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
|
||||
|
|
@ -340,6 +397,14 @@ impl Align {
|
|||
1 << self.pref
|
||||
}
|
||||
|
||||
pub fn abi_bits(self) -> u64 {
|
||||
self.abi() * 8
|
||||
}
|
||||
|
||||
pub fn pref_bits(self) -> u64 {
|
||||
self.pref() * 8
|
||||
}
|
||||
|
||||
pub fn min(self, other: Align) -> Align {
|
||||
Align {
|
||||
abi: cmp::min(self.abi, other.abi),
|
||||
|
|
@ -366,7 +431,7 @@ pub enum Integer {
|
|||
I128,
|
||||
}
|
||||
|
||||
impl Integer {
|
||||
impl<'a, 'tcx> Integer {
|
||||
pub fn size(&self) -> Size {
|
||||
match *self {
|
||||
I1 => Size::from_bits(1),
|
||||
|
|
@ -391,8 +456,7 @@ impl Integer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_ty<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>,
|
||||
signed: bool) -> Ty<'tcx> {
|
||||
pub fn to_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx> {
|
||||
match (*self, signed) {
|
||||
(I1, false) => tcx.types.u8,
|
||||
(I8, false) => tcx.types.u8,
|
||||
|
|
@ -467,12 +531,12 @@ impl Integer {
|
|||
/// signed discriminant range and #[repr] attribute.
|
||||
/// N.B.: u64 values above i64::MAX will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
repr: &ReprOptions,
|
||||
min: i64,
|
||||
max: i64)
|
||||
-> (Integer, bool) {
|
||||
fn repr_discr(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
repr: &ReprOptions,
|
||||
min: i64,
|
||||
max: i64)
|
||||
-> (Integer, bool) {
|
||||
// Theoretically, negative values could be larger in unsigned representation
|
||||
// than the unsigned representation of the signed minimum. However, if there
|
||||
// are any negative values, the only valid unsigned representation is u64
|
||||
|
|
@ -898,16 +962,6 @@ impl<'a, 'tcx> Struct {
|
|||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn over_align(&self) -> Option<u32> {
|
||||
let align = self.align.abi();
|
||||
let primitive_align = self.primitive_align.abi();
|
||||
if align > primitive_align {
|
||||
Some(align as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An untagged union.
|
||||
|
|
@ -981,16 +1035,6 @@ impl<'a, 'tcx> Union {
|
|||
pub fn stride(&self) -> Size {
|
||||
self.min_size.abi_align(self.align)
|
||||
}
|
||||
|
||||
pub fn over_align(&self) -> Option<u32> {
|
||||
let align = self.align.abi();
|
||||
let primitive_align = self.primitive_align.abi();
|
||||
if align > primitive_align {
|
||||
Some(align as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The first half of a fat pointer.
|
||||
|
|
@ -1607,9 +1651,8 @@ impl<'a, 'tcx> Layout {
|
|||
|
||||
FatPointer { metadata, .. } => {
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
Pointer.size(dl).abi_align(metadata.align(dl))
|
||||
.checked_add(metadata.size(dl), dl).unwrap()
|
||||
.abi_align(self.align(dl))
|
||||
(Pointer.size(dl).abi_align(metadata.align(dl)) +
|
||||
metadata.size(dl)).abi_align(self.align(dl))
|
||||
}
|
||||
|
||||
CEnum { discr, .. } => Int(discr).size(dl),
|
||||
|
|
@ -1638,15 +1681,7 @@ impl<'a, 'tcx> Layout {
|
|||
None => bug!("Layout::align({:?}): {} * {} overflowed",
|
||||
self, elem_size.bytes(), count)
|
||||
};
|
||||
for &(size, align) in &dl.vector_align {
|
||||
if size == vec_size {
|
||||
return align;
|
||||
}
|
||||
}
|
||||
// Default to natural alignment, which is what LLVM does.
|
||||
// That is, use the size, rounded up to a power of 2.
|
||||
let align = vec_size.bytes().next_power_of_two();
|
||||
Align::from_bytes(align, align).unwrap()
|
||||
dl.vector_align(vec_size)
|
||||
}
|
||||
|
||||
FatPointer { metadata, .. } => {
|
||||
|
|
@ -1666,7 +1701,7 @@ impl<'a, 'tcx> Layout {
|
|||
}
|
||||
|
||||
/// Returns alignment before repr alignment is applied
|
||||
pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align {
|
||||
pub fn primitive_align<C: HasDataLayout>(&self, cx: C) -> Align {
|
||||
match *self {
|
||||
Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align,
|
||||
Univariant { ref variant, .. } |
|
||||
|
|
@ -1674,18 +1709,7 @@ impl<'a, 'tcx> Layout {
|
|||
variant.primitive_align
|
||||
},
|
||||
|
||||
_ => self.align(dl)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns repr alignment if it is greater than the primitive alignment.
|
||||
pub fn over_align(&self, dl: &TargetDataLayout) -> Option<u32> {
|
||||
let align = self.align(dl);
|
||||
let primitive_align = self.primitive_align(dl);
|
||||
if align.abi() > primitive_align.abi() {
|
||||
Some(align.abi() as u32)
|
||||
} else {
|
||||
None
|
||||
_ => self.align(cx.data_layout())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1205,15 +1205,13 @@ extern "C" {
|
|||
pub fn LLVMRustBuildAtomicLoad(B: BuilderRef,
|
||||
PointerVal: ValueRef,
|
||||
Name: *const c_char,
|
||||
Order: AtomicOrdering,
|
||||
Alignment: c_uint)
|
||||
Order: AtomicOrdering)
|
||||
-> ValueRef;
|
||||
|
||||
pub fn LLVMRustBuildAtomicStore(B: BuilderRef,
|
||||
Val: ValueRef,
|
||||
Ptr: ValueRef,
|
||||
Order: AtomicOrdering,
|
||||
Alignment: c_uint)
|
||||
Order: AtomicOrdering)
|
||||
-> ValueRef;
|
||||
|
||||
pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef,
|
||||
|
|
@ -1247,23 +1245,6 @@ extern "C" {
|
|||
|
||||
/// Creates target data from a target layout string.
|
||||
pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef;
|
||||
/// Number of bytes clobbered when doing a Store to *T.
|
||||
pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong;
|
||||
|
||||
/// Distance between successive elements in an array of T. Includes ABI padding.
|
||||
pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong;
|
||||
|
||||
/// Returns the preferred alignment of a type.
|
||||
pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint;
|
||||
/// Returns the minimum alignment of a type.
|
||||
pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint;
|
||||
|
||||
/// Computes the byte offset of the indexed struct element for a
|
||||
/// target.
|
||||
pub fn LLVMOffsetOfElement(TD: TargetDataRef,
|
||||
StructTy: TypeRef,
|
||||
Element: c_uint)
|
||||
-> c_ulonglong;
|
||||
|
||||
/// Disposes target data.
|
||||
pub fn LLVMDisposeTargetData(TD: TargetDataRef);
|
||||
|
|
|
|||
|
|
@ -30,17 +30,16 @@ use cabi_sparc64;
|
|||
use cabi_nvptx;
|
||||
use cabi_nvptx64;
|
||||
use cabi_hexagon;
|
||||
use machine::llalign_of_min;
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
|
||||
use rustc::ty::layout::{self, Align, Layout, Size, TyLayout};
|
||||
use rustc::ty::layout::{HasDataLayout, LayoutTyper};
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
use libc::c_uint;
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
|
||||
pub use syntax::abi::Abi;
|
||||
|
|
@ -108,8 +107,8 @@ impl ArgAttributes {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self {
|
||||
self.dereferenceable_bytes = bytes;
|
||||
pub fn set_dereferenceable(&mut self, size: Size) -> &mut Self {
|
||||
self.dereferenceable_bytes = size.bytes();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +173,32 @@ impl Reg {
|
|||
}
|
||||
|
||||
impl Reg {
|
||||
fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
pub fn align(&self, ccx: &CrateContext) -> Align {
|
||||
let dl = ccx.data_layout();
|
||||
match self.kind {
|
||||
RegKind::Integer => {
|
||||
match self.size.bits() {
|
||||
1 => dl.i1_align,
|
||||
2...8 => dl.i8_align,
|
||||
9...16 => dl.i16_align,
|
||||
17...32 => dl.i32_align,
|
||||
33...64 => dl.i64_align,
|
||||
65...128 => dl.i128_align,
|
||||
_ => bug!("unsupported integer: {:?}", self)
|
||||
}
|
||||
}
|
||||
RegKind::Float => {
|
||||
match self.size.bits() {
|
||||
32 => dl.f32_align,
|
||||
64 => dl.f64_align,
|
||||
_ => bug!("unsupported float: {:?}", self)
|
||||
}
|
||||
}
|
||||
RegKind::Vector => dl.vector_align(self.size)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
match self.kind {
|
||||
RegKind::Integer => Type::ix(ccx, self.size.bits()),
|
||||
RegKind::Float => {
|
||||
|
|
@ -193,7 +217,7 @@ impl Reg {
|
|||
|
||||
/// An argument passed entirely registers with the
|
||||
/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Uniform {
|
||||
pub unit: Reg,
|
||||
|
||||
|
|
@ -216,7 +240,11 @@ impl From<Reg> for Uniform {
|
|||
}
|
||||
|
||||
impl Uniform {
|
||||
fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
pub fn align(&self, ccx: &CrateContext) -> Align {
|
||||
self.unit.align(ccx)
|
||||
}
|
||||
|
||||
pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
let llunit = self.unit.llvm_type(ccx);
|
||||
|
||||
if self.total <= self.unit.size {
|
||||
|
|
@ -328,11 +356,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
|
|||
}
|
||||
|
||||
// Keep track of the offset (without padding).
|
||||
let size = field.size(ccx);
|
||||
match unaligned_offset.checked_add(size, ccx) {
|
||||
Some(offset) => unaligned_offset = offset,
|
||||
None => return None
|
||||
}
|
||||
unaligned_offset += field.size(ccx);
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
|
|
@ -387,6 +411,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CastTarget {
|
||||
Uniform(Uniform),
|
||||
Pair(Reg, Reg)
|
||||
|
|
@ -405,7 +430,28 @@ impl From<Uniform> for CastTarget {
|
|||
}
|
||||
|
||||
impl CastTarget {
|
||||
fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
pub fn size(&self, ccx: &CrateContext) -> Size {
|
||||
match *self {
|
||||
CastTarget::Uniform(u) => u.total,
|
||||
CastTarget::Pair(a, b) => {
|
||||
(a.size.abi_align(a.align(ccx)) + b.size)
|
||||
.abi_align(self.align(ccx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align(&self, ccx: &CrateContext) -> Align {
|
||||
match *self {
|
||||
CastTarget::Uniform(u) => u.align(ccx),
|
||||
CastTarget::Pair(a, b) => {
|
||||
ccx.data_layout().aggregate_align
|
||||
.max(a.align(ccx))
|
||||
.max(b.align(ccx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
|
||||
match *self {
|
||||
CastTarget::Uniform(u) => u.llvm_type(ccx),
|
||||
CastTarget::Pair(a, b) => {
|
||||
|
|
@ -426,11 +472,11 @@ impl CastTarget {
|
|||
pub struct ArgType<'tcx> {
|
||||
kind: ArgKind,
|
||||
pub layout: TyLayout<'tcx>,
|
||||
/// Coerced LLVM Type
|
||||
pub cast: Option<Type>,
|
||||
/// Dummy argument, which is emitted before the real argument
|
||||
pub pad: Option<Type>,
|
||||
/// LLVM attributes of argument
|
||||
/// Cast target, either a single uniform or a pair of registers.
|
||||
pub cast: Option<CastTarget>,
|
||||
/// Dummy argument, which is emitted before the real argument.
|
||||
pub pad: Option<Reg>,
|
||||
/// Attributes of argument.
|
||||
pub attrs: ArgAttributes
|
||||
}
|
||||
|
||||
|
|
@ -451,14 +497,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
// Wipe old attributes, likely not valid through indirection.
|
||||
self.attrs = ArgAttributes::default();
|
||||
|
||||
let llarg_sz = self.layout.size(ccx).bytes();
|
||||
|
||||
// For non-immediate arguments the callee gets its own copy of
|
||||
// the value on the stack, so there are no aliases. It's also
|
||||
// program-invisible so can't possibly capture
|
||||
self.attrs.set(ArgAttribute::NoAlias)
|
||||
.set(ArgAttribute::NoCapture)
|
||||
.set_dereferenceable(llarg_sz);
|
||||
.set_dereferenceable(self.layout.size(ccx));
|
||||
|
||||
self.kind = ArgKind::Indirect;
|
||||
}
|
||||
|
|
@ -500,12 +544,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cast_to<T: Into<CastTarget>>(&mut self, ccx: &CrateContext, target: T) {
|
||||
self.cast = Some(target.into().llvm_type(ccx));
|
||||
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
|
||||
self.cast = Some(target.into());
|
||||
}
|
||||
|
||||
pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) {
|
||||
self.pad = Some(reg.llvm_type(ccx));
|
||||
pub fn pad_with(&mut self, reg: Reg) {
|
||||
self.pad = Some(reg);
|
||||
}
|
||||
|
||||
pub fn is_indirect(&self) -> bool {
|
||||
|
|
@ -533,16 +577,14 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
let ccx = bcx.ccx;
|
||||
if self.is_indirect() {
|
||||
let llsz = C_usize(ccx, self.layout.size(ccx).bytes());
|
||||
let llalign = self.layout.align(ccx).abi();
|
||||
base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
|
||||
base::call_memcpy(bcx, dst, val, llsz, self.layout.align(ccx));
|
||||
} else if let Some(ty) = self.cast {
|
||||
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
|
||||
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
||||
let can_store_through_cast_ptr = false;
|
||||
if can_store_through_cast_ptr {
|
||||
let cast_dst = bcx.pointercast(dst, ty.ptr_to());
|
||||
let llalign = self.layout.align(ccx).abi();
|
||||
bcx.store(val, cast_dst, Some(llalign as u32));
|
||||
let cast_dst = bcx.pointercast(dst, ty.llvm_type(ccx).ptr_to());
|
||||
bcx.store(val, cast_dst, Some(self.layout.align(ccx)));
|
||||
} else {
|
||||
// The actual return type is a struct, but the ABI
|
||||
// adaptation code has cast it into some scalar type. The
|
||||
|
|
@ -559,8 +601,9 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
// bitcasting to the struct type yields invalid cast errors.
|
||||
|
||||
// We instead thus allocate some scratch space...
|
||||
let llscratch = bcx.alloca(ty, "abi_cast", None);
|
||||
base::Lifetime::Start.call(bcx, llscratch);
|
||||
let llscratch = bcx.alloca(ty.llvm_type(ccx), "abi_cast", None);
|
||||
let scratch_size = ty.size(ccx);
|
||||
bcx.lifetime_start(llscratch, scratch_size);
|
||||
|
||||
// ...where we first store the value...
|
||||
bcx.store(val, llscratch, None);
|
||||
|
|
@ -570,10 +613,9 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
bcx.pointercast(dst, Type::i8p(ccx)),
|
||||
bcx.pointercast(llscratch, Type::i8p(ccx)),
|
||||
C_usize(ccx, self.layout.size(ccx).bytes()),
|
||||
cmp::min(self.layout.align(ccx).abi() as u32,
|
||||
llalign_of_min(ccx, ty)));
|
||||
self.layout.align(ccx).min(ty.align(ccx)));
|
||||
|
||||
base::Lifetime::End.call(bcx, llscratch);
|
||||
bcx.lifetime_end(llscratch, scratch_size);
|
||||
}
|
||||
} else {
|
||||
if self.layout.ty == ccx.tcx().types.bool {
|
||||
|
|
@ -840,7 +882,7 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
// Replace newtypes with their inner-most type.
|
||||
if unit.size == size {
|
||||
// Needs a cast as we've unpacked a newtype.
|
||||
arg.cast_to(ccx, unit);
|
||||
arg.cast_to(unit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -850,7 +892,7 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
// FIXME(eddyb) This should be using Uniform instead of a pair,
|
||||
// but the resulting [2 x float/double] breaks emscripten.
|
||||
// See https://github.com/kripken/emscripten-fastcomp/issues/178.
|
||||
arg.cast_to(ccx, CastTarget::Pair(unit, unit));
|
||||
arg.cast_to(CastTarget::Pair(unit, unit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -862,7 +904,7 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
// We want to pass small aggregates as immediates, but using
|
||||
// a LLVM aggregate type for this leads to bad optimizations,
|
||||
// so we pick an appropriately sized integer type instead.
|
||||
arg.cast_to(ccx, Reg {
|
||||
arg.cast_to(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size
|
||||
});
|
||||
|
|
@ -931,10 +973,10 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
} else if self.ret.is_indirect() {
|
||||
llargument_tys.push(self.ret.memory_ty(ccx).ptr_to());
|
||||
Type::void(ccx)
|
||||
} else if let Some(cast) = self.ret.cast {
|
||||
cast.llvm_type(ccx)
|
||||
} else {
|
||||
self.ret.cast.unwrap_or_else(|| {
|
||||
type_of::immediate_type_of(ccx, self.ret.layout.ty)
|
||||
})
|
||||
type_of::immediate_type_of(ccx, self.ret.layout.ty)
|
||||
};
|
||||
|
||||
for arg in &self.args {
|
||||
|
|
@ -943,15 +985,15 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
}
|
||||
// add padding
|
||||
if let Some(ty) = arg.pad {
|
||||
llargument_tys.push(ty);
|
||||
llargument_tys.push(ty.llvm_type(ccx));
|
||||
}
|
||||
|
||||
let llarg_ty = if arg.is_indirect() {
|
||||
arg.memory_ty(ccx).ptr_to()
|
||||
} else if let Some(cast) = arg.cast {
|
||||
cast.llvm_type(ccx)
|
||||
} else {
|
||||
arg.cast.unwrap_or_else(|| {
|
||||
type_of::immediate_type_of(ccx, arg.layout.ty)
|
||||
})
|
||||
type_of::immediate_type_of(ccx, arg.layout.ty)
|
||||
};
|
||||
|
||||
llargument_tys.push(llarg_ty);
|
||||
|
|
@ -998,7 +1040,3 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align_up_to(off: u64, a: u64) -> u64 {
|
||||
(off + a - 1) / a * a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,10 +42,9 @@
|
|||
//! taken to it, implementing them for Rust seems difficult.
|
||||
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use rustc::ty::layout::{self, Align, HasDataLayout, LayoutTyper, Size};
|
||||
|
||||
use context::CrateContext;
|
||||
use machine;
|
||||
use monomorphize;
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
|
|
@ -134,9 +133,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
layout::UntaggedUnion { ref variants, .. }=> {
|
||||
// Use alignment-sized ints to fill all the union storage.
|
||||
let size = variants.stride().bytes();
|
||||
let align = variants.align.abi();
|
||||
let fill = union_fill(cx, size, align);
|
||||
let fill = union_fill(cx, variants.stride(), variants.align);
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &[fill], variants.packed)
|
||||
|
|
@ -159,22 +156,18 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
// So we start with the discriminant, pad it up to the alignment with
|
||||
// more of its own type, then use alignment-sized ints to get the rest
|
||||
// of the size.
|
||||
let size = size.bytes();
|
||||
let align = align.abi();
|
||||
let primitive_align = primitive_align.abi();
|
||||
assert!(align <= ::std::u32::MAX as u64);
|
||||
let discr_ty = Type::from_integer(cx, discr);
|
||||
let discr_size = discr.size().bytes();
|
||||
let padded_discr_size = roundup(discr_size, align as u32);
|
||||
let variant_part_size = size-padded_discr_size;
|
||||
let variant_fill = union_fill(cx, variant_part_size, primitive_align);
|
||||
let padded_discr_size = discr.size().abi_align(align);
|
||||
let variant_part_size = size - padded_discr_size;
|
||||
|
||||
assert_eq!(machine::llalign_of_min(cx, variant_fill), primitive_align as u32);
|
||||
assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
|
||||
let fields: Vec<Type> =
|
||||
[discr_ty,
|
||||
Type::array(&discr_ty, (padded_discr_size - discr_size)/discr_size),
|
||||
variant_fill].iter().cloned().collect();
|
||||
// Ensure discr_ty can fill pad evenly
|
||||
assert_eq!(padded_discr_size.bytes() % discr_size, 0);
|
||||
let fields = [
|
||||
discr_ty,
|
||||
Type::array(&discr_ty, padded_discr_size.bytes() / discr_size - 1),
|
||||
union_fill(cx, variant_part_size, primitive_align)
|
||||
];
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &fields, false)
|
||||
|
|
@ -190,17 +183,19 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
|
||||
assert_eq!(size%align, 0);
|
||||
assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
|
||||
let align_units = size/align;
|
||||
let layout_align = layout::Align::from_bytes(align, align).unwrap();
|
||||
if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) {
|
||||
Type::array(&Type::from_integer(cx, ity), align_units)
|
||||
fn union_fill(cx: &CrateContext, size: Size, align: Align) -> Type {
|
||||
let abi_align = align.abi();
|
||||
let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) {
|
||||
Type::from_integer(cx, ity)
|
||||
} else {
|
||||
Type::array(&Type::vector(&Type::i32(cx), align/4),
|
||||
align_units)
|
||||
}
|
||||
let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align));
|
||||
assert_eq!(vec_align.abi(), abi_align);
|
||||
Type::vector(&Type::i32(cx), abi_align / 4)
|
||||
};
|
||||
|
||||
let size = size.bytes();
|
||||
assert_eq!(size % abi_align, 0);
|
||||
Type::array(&elem_ty, size / abi_align)
|
||||
}
|
||||
|
||||
// Lookup `Struct::memory_index` and double it to account for padding
|
||||
|
|
@ -231,7 +226,7 @@ pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
};
|
||||
debug!("struct_llfields: variant: {:?}", variant);
|
||||
let mut first_field = true;
|
||||
let mut min_offset = 0;
|
||||
let mut offset = Size::from_bytes(0);
|
||||
let mut result: Vec<Type> = Vec::with_capacity(field_count * 2);
|
||||
let field_iter = variant.field_index_by_increasing_offset().map(|i| {
|
||||
(i, match t.sty {
|
||||
|
|
@ -249,48 +244,47 @@ pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
cx.tcx().normalize_associated_type(&ty)
|
||||
},
|
||||
_ => bug!()
|
||||
}, variant.offsets[i as usize].bytes())
|
||||
}, variant.offsets[i as usize])
|
||||
});
|
||||
for (index, ty, target_offset) in field_iter {
|
||||
assert!(target_offset >= min_offset);
|
||||
let padding_bytes = target_offset - min_offset;
|
||||
debug!("struct_llfields: {} ty: {} offset: {:?} target_offset: {:?}",
|
||||
index, ty, offset, target_offset);
|
||||
assert!(target_offset >= offset);
|
||||
let padding = target_offset - offset;
|
||||
if first_field {
|
||||
debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}",
|
||||
index, ty, min_offset, target_offset);
|
||||
assert_eq!(padding_bytes, 0);
|
||||
assert_eq!(padding.bytes(), 0);
|
||||
first_field = false;
|
||||
} else {
|
||||
result.push(Type::array(&Type::i8(cx), padding_bytes));
|
||||
debug!("struct_llfields: {} ty: {} pad_bytes: {} min_offset: {} target_offset: {}",
|
||||
index, ty, padding_bytes, min_offset, target_offset);
|
||||
result.push(Type::array(&Type::i8(cx), padding.bytes()));
|
||||
debug!(" padding before: {:?}", padding);
|
||||
}
|
||||
let llty = type_of::in_memory_type_of(cx, ty);
|
||||
result.push(llty);
|
||||
let layout = cx.layout_of(ty);
|
||||
if variant.packed {
|
||||
assert_eq!(padding_bytes, 0);
|
||||
assert_eq!(padding.bytes(), 0);
|
||||
} else {
|
||||
let field_align = layout.align(cx);
|
||||
assert!(field_align.abi() <= variant.align.abi(),
|
||||
"non-packed type has field with larger align ({}): {:#?}",
|
||||
field_align.abi(), variant);
|
||||
}
|
||||
let target_size = layout.size(&cx.tcx().data_layout).bytes();
|
||||
min_offset = target_offset + target_size;
|
||||
let target_size = layout.size(&cx.tcx().data_layout);
|
||||
offset = target_offset + target_size;
|
||||
}
|
||||
if variant.sized && field_count > 0 {
|
||||
if variant.stride().bytes() < min_offset {
|
||||
bug!("variant: {:?} stride: {} min_offset: {}", variant, variant.stride().bytes(),
|
||||
min_offset);
|
||||
if offset > variant.stride() {
|
||||
bug!("variant: {:?} stride: {:?} offset: {:?}",
|
||||
variant, variant.stride(), offset);
|
||||
}
|
||||
let padding_bytes = variant.stride().bytes() - min_offset;
|
||||
debug!("struct_llfields: pad_bytes: {} min_offset: {} min_size: {} stride: {}\n",
|
||||
padding_bytes, min_offset, variant.min_size.bytes(), variant.stride().bytes());
|
||||
result.push(Type::array(&Type::i8(cx), padding_bytes));
|
||||
let padding = variant.stride() - offset;
|
||||
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} min_size: {:?} stride: {:?}",
|
||||
padding, offset, variant.min_size, variant.stride());
|
||||
result.push(Type::array(&Type::i8(cx), padding.bytes()));
|
||||
assert!(result.len() == (field_count * 2));
|
||||
} else {
|
||||
debug!("struct_llfields: min_offset: {} min_size: {} stride: {}\n",
|
||||
min_offset, variant.min_size.bytes(), variant.stride().bytes());
|
||||
debug!("struct_llfields: offset: {:?} min_size: {:?} stride: {:?}",
|
||||
offset, variant.min_size, variant.stride());
|
||||
}
|
||||
|
||||
result
|
||||
|
|
@ -310,7 +304,3 @@ pub fn assert_discr_in_range<D: PartialOrd>(min: D, max: D, discr: D) {
|
|||
assert!(min <= discr || discr <= max)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME this utility routine should be somewhere more general
|
||||
#[inline]
|
||||
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ use rustc::middle::lang_items::StartFnLangItem;
|
|||
use rustc::middle::trans::{Linkage, Visibility, Stats};
|
||||
use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::Align;
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::dep_graph::{DepNode, DepKind, DepConstructor};
|
||||
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
|
||||
|
|
@ -55,7 +56,7 @@ use builder::Builder;
|
|||
use callee;
|
||||
use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
|
||||
use collector::{self, TransItemCollectionMode};
|
||||
use common::{C_struct_in_context, C_u64, C_undef, C_array};
|
||||
use common::{C_struct_in_context, C_undef, C_array};
|
||||
use common::CrateContext;
|
||||
use common::{type_is_zero_size, val_ty};
|
||||
use common;
|
||||
|
|
@ -63,7 +64,6 @@ use consts;
|
|||
use context::{self, LocalCrateContext, SharedCrateContext};
|
||||
use debuginfo;
|
||||
use declare;
|
||||
use machine;
|
||||
use meth;
|
||||
use mir;
|
||||
use monomorphize::{self, Instance};
|
||||
|
|
@ -489,42 +489,11 @@ pub fn to_immediate(bcx: &Builder, val: ValueRef, ty: Ty) -> ValueRef {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Lifetime { Start, End }
|
||||
|
||||
impl Lifetime {
|
||||
// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
|
||||
// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
|
||||
// and the intrinsic for `lt` and passes them to `emit`, which is in
|
||||
// charge of generating code to call the passed intrinsic on whatever
|
||||
// block of generated code is targeted for the intrinsic.
|
||||
//
|
||||
// If LLVM lifetime intrinsic support is disabled (i.e. optimizations
|
||||
// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
|
||||
pub fn call(self, b: &Builder, ptr: ValueRef) {
|
||||
if b.ccx.sess().opts.optimize == config::OptLevel::No {
|
||||
return;
|
||||
}
|
||||
|
||||
let size = machine::llsize_of_alloc(b.ccx, val_ty(ptr).element_type());
|
||||
if size == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let lifetime_intrinsic = b.ccx.get_intrinsic(match self {
|
||||
Lifetime::Start => "llvm.lifetime.start",
|
||||
Lifetime::End => "llvm.lifetime.end"
|
||||
});
|
||||
|
||||
let ptr = b.pointercast(ptr, Type::i8p(b.ccx));
|
||||
b.call(lifetime_intrinsic, &[C_u64(b.ccx, size), ptr], None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
||||
dst: ValueRef,
|
||||
src: ValueRef,
|
||||
n_bytes: ValueRef,
|
||||
align: u32) {
|
||||
pub fn call_memcpy(b: &Builder,
|
||||
dst: ValueRef,
|
||||
src: ValueRef,
|
||||
n_bytes: ValueRef,
|
||||
align: Align) {
|
||||
let ccx = b.ccx;
|
||||
let ptr_width = &ccx.sess().target.target.target_pointer_width;
|
||||
let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
|
||||
|
|
@ -532,7 +501,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
|||
let src_ptr = b.pointercast(src, Type::i8p(ccx));
|
||||
let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
|
||||
let size = b.intcast(n_bytes, ccx.isize_ty(), false);
|
||||
let align = C_i32(ccx, align as i32);
|
||||
let align = C_i32(ccx, align.abi() as i32);
|
||||
let volatile = C_bool(ccx, false);
|
||||
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
||||
}
|
||||
|
|
@ -542,11 +511,11 @@ pub fn memcpy_ty<'a, 'tcx>(
|
|||
dst: ValueRef,
|
||||
src: ValueRef,
|
||||
t: Ty<'tcx>,
|
||||
align: Option<u32>,
|
||||
align: Option<Align>,
|
||||
) {
|
||||
let ccx = bcx.ccx;
|
||||
|
||||
let size = ccx.size_of(t);
|
||||
let size = ccx.size_of(t).bytes();
|
||||
if size == 0 {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
|
|||
use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef};
|
||||
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
|
||||
use common::*;
|
||||
use machine::llalign_of_pref;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
use libc::{c_uint, c_char};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::layout::{Align, Size};
|
||||
use rustc::session::{config, Session};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CString;
|
||||
|
|
@ -487,7 +487,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
|
||||
pub fn alloca(&self, ty: Type, name: &str, align: Option<Align>) -> ValueRef {
|
||||
let builder = Builder::with_ccx(self.ccx);
|
||||
builder.position_at_start(unsafe {
|
||||
llvm::LLVMGetFirstBasicBlock(self.llfn())
|
||||
|
|
@ -495,7 +495,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
builder.dynamic_alloca(ty, name, align)
|
||||
}
|
||||
|
||||
pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option<u32>) -> ValueRef {
|
||||
pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option<Align>) -> ValueRef {
|
||||
self.count_insn("alloca");
|
||||
unsafe {
|
||||
let alloca = if name.is_empty() {
|
||||
|
|
@ -506,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
name.as_ptr())
|
||||
};
|
||||
if let Some(align) = align {
|
||||
llvm::LLVMSetAlignment(alloca, align as c_uint);
|
||||
llvm::LLVMSetAlignment(alloca, align.abi() as c_uint);
|
||||
}
|
||||
alloca
|
||||
}
|
||||
|
|
@ -519,12 +519,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
|
||||
pub fn load(&self, ptr: ValueRef, align: Option<Align>) -> ValueRef {
|
||||
self.count_insn("load");
|
||||
unsafe {
|
||||
let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
|
||||
if let Some(align) = align {
|
||||
llvm::LLVMSetAlignment(load, align as c_uint);
|
||||
llvm::LLVMSetAlignment(load, align.abi() as c_uint);
|
||||
}
|
||||
load
|
||||
}
|
||||
|
|
@ -539,20 +539,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
|
||||
pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering, align: Align) -> ValueRef {
|
||||
self.count_insn("load.atomic");
|
||||
unsafe {
|
||||
let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
|
||||
let align = llalign_of_pref(self.ccx, ty.element_type());
|
||||
llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order,
|
||||
align as c_uint)
|
||||
let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order);
|
||||
llvm::LLVMSetAlignment(load, align.abi() as c_uint);
|
||||
load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
|
||||
hi: u64, signed: llvm::Bool,
|
||||
align: Option<u32>) -> ValueRef {
|
||||
align: Option<Align>) -> ValueRef {
|
||||
let value = self.load(ptr, align);
|
||||
|
||||
unsafe {
|
||||
|
|
@ -571,7 +570,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
value
|
||||
}
|
||||
|
||||
pub fn load_nonnull(&self, ptr: ValueRef, align: Option<u32>) -> ValueRef {
|
||||
pub fn load_nonnull(&self, ptr: ValueRef, align: Option<Align>) -> ValueRef {
|
||||
let value = self.load(ptr, align);
|
||||
unsafe {
|
||||
llvm::LLVMSetMetadata(value, llvm::MD_nonnull as c_uint,
|
||||
|
|
@ -581,7 +580,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
value
|
||||
}
|
||||
|
||||
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Option<u32>) -> ValueRef {
|
||||
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Option<Align>) -> ValueRef {
|
||||
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
|
||||
assert!(!self.llbuilder.is_null());
|
||||
self.count_insn("store");
|
||||
|
|
@ -589,7 +588,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
unsafe {
|
||||
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
||||
if let Some(align) = align {
|
||||
llvm::LLVMSetAlignment(store, align as c_uint);
|
||||
llvm::LLVMSetAlignment(store, align.abi() as c_uint);
|
||||
}
|
||||
store
|
||||
}
|
||||
|
|
@ -607,14 +606,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
|
||||
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
|
||||
order: AtomicOrdering, align: Align) {
|
||||
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
|
||||
self.count_insn("store.atomic");
|
||||
let ptr = self.check_store(val, ptr);
|
||||
unsafe {
|
||||
let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
|
||||
let align = llalign_of_pref(self.ccx, ty.element_type());
|
||||
llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint);
|
||||
let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order);
|
||||
llvm::LLVMSetAlignment(store, align.abi() as c_uint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1233,4 +1232,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
return Cow::Owned(casted_args);
|
||||
}
|
||||
|
||||
pub fn lifetime_start(&self, ptr: ValueRef, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
|
||||
}
|
||||
|
||||
pub fn lifetime_end(&self, ptr: ValueRef, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
|
||||
}
|
||||
|
||||
/// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
|
||||
/// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
|
||||
/// and the intrinsic for `lt` and passes them to `emit`, which is in
|
||||
/// charge of generating code to call the passed intrinsic on whatever
|
||||
/// block of generated code is targetted for the intrinsic.
|
||||
///
|
||||
/// If LLVM lifetime intrinsic support is disabled (i.e. optimizations
|
||||
/// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
|
||||
fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: ValueRef, size: Size) {
|
||||
if self.ccx.sess().opts.optimize == config::OptLevel::No {
|
||||
return;
|
||||
}
|
||||
|
||||
let size = size.bytes();
|
||||
if size == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let lifetime_intrinsic = self.ccx.get_intrinsic(intrinsic);
|
||||
|
||||
let ptr = self.pointercast(ptr, Type::i8p(self.ccx));
|
||||
self.call(lifetime_intrinsic, &[C_u64(self.ccx, size), ptr], None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
return;
|
||||
}
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, ret) {
|
||||
ret.cast_to(ccx, uniform);
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = ret.layout.size(ccx);
|
||||
|
|
@ -60,7 +60,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
Reg::i64()
|
||||
};
|
||||
|
||||
ret.cast_to(ccx, Uniform {
|
||||
ret.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
@ -75,7 +75,7 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
return;
|
||||
}
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, arg) {
|
||||
arg.cast_to(ccx, uniform);
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = arg.layout.size(ccx);
|
||||
|
|
@ -91,7 +91,7 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
Reg::i64()
|
||||
};
|
||||
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
|
||||
if vfp {
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, ret) {
|
||||
ret.cast_to(ccx, uniform);
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
} else {
|
||||
Reg::i32()
|
||||
};
|
||||
ret.cast_to(ccx, Uniform {
|
||||
ret.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
@ -79,14 +79,14 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
|
||||
if vfp {
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, arg) {
|
||||
arg.cast_to(ccx, uniform);
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let align = arg.layout.align(ccx).abi();
|
||||
let total = arg.layout.size(ccx);
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
|
||||
total
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
if let Some(unit) = ret.layout.homogeneous_aggregate(ccx) {
|
||||
let size = ret.layout.size(ccx);
|
||||
if unit.size == size {
|
||||
ret.cast_to(ccx, Uniform {
|
||||
ret.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,45 +8,48 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp;
|
||||
use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use context::CrateContext;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
|
||||
use rustc::ty::layout::Size;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ret: &mut ArgType<'tcx>,
|
||||
offset: &mut Size) {
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
} else {
|
||||
ret.make_indirect(ccx);
|
||||
*offset += ccx.tcx().data_layout.pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut Size) {
|
||||
let dl = &ccx.tcx().data_layout;
|
||||
let size = arg.layout.size(ccx);
|
||||
let mut align = arg.layout.align(ccx).abi();
|
||||
align = cmp::min(cmp::max(align, 4), 8);
|
||||
let align = arg.layout.align(ccx).max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: Reg::i32(),
|
||||
total: size
|
||||
});
|
||||
if ((align - 1) & *offset) > 0 {
|
||||
arg.pad_with(ccx, Reg::i32());
|
||||
if !offset.is_abi_aligned(align) {
|
||||
arg.pad_with(Reg::i32());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
*offset = align_up_to(*offset, align);
|
||||
*offset += align_up_to(size.bytes(), align);
|
||||
*offset = offset.abi_align(align) + size.abi_align(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
|
||||
let mut offset = Size::from_bytes(0);
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(ccx, &mut fty.ret);
|
||||
classify_ret_ty(ccx, &mut fty.ret, &mut offset);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() { continue; }
|
||||
classify_arg_ty(ccx, arg, &mut offset);
|
||||
|
|
|
|||
|
|
@ -8,45 +8,48 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp;
|
||||
use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use context::CrateContext;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
|
||||
use rustc::ty::layout::Size;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ret: &mut ArgType<'tcx>,
|
||||
offset: &mut Size) {
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(64);
|
||||
} else {
|
||||
ret.make_indirect(ccx);
|
||||
*offset += ccx.tcx().data_layout.pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut Size) {
|
||||
let dl = &ccx.tcx().data_layout;
|
||||
let size = arg.layout.size(ccx);
|
||||
let mut align = arg.layout.align(ccx).abi();
|
||||
align = cmp::min(cmp::max(align, 4), 8);
|
||||
let align = arg.layout.align(ccx).max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: Reg::i64(),
|
||||
total: size
|
||||
});
|
||||
if ((align - 1) & *offset) > 0 {
|
||||
arg.pad_with(ccx, Reg::i64());
|
||||
if !offset.is_abi_aligned(align) {
|
||||
arg.pad_with(Reg::i64());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(64);
|
||||
}
|
||||
|
||||
*offset = align_up_to(*offset, align);
|
||||
*offset += align_up_to(size.bytes(), align);
|
||||
*offset = offset.abi_align(align) + size.abi_align(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
|
||||
let mut offset = Size::from_bytes(0);
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(ccx, &mut fty.ret);
|
||||
classify_ret_ty(ccx, &mut fty.ret, &mut offset);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 8 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() { continue; }
|
||||
classify_arg_ty(ccx, arg, &mut offset);
|
||||
|
|
|
|||
|
|
@ -8,46 +8,48 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform};
|
||||
use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use context::CrateContext;
|
||||
|
||||
use std::cmp;
|
||||
use rustc::ty::layout::Size;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ret: &mut ArgType<'tcx>,
|
||||
offset: &mut Size) {
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
} else {
|
||||
ret.make_indirect(ccx);
|
||||
*offset += ccx.tcx().data_layout.pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut Size) {
|
||||
let dl = &ccx.tcx().data_layout;
|
||||
let size = arg.layout.size(ccx);
|
||||
let mut align = arg.layout.align(ccx).abi();
|
||||
align = cmp::min(cmp::max(align, 4), 8);
|
||||
let align = arg.layout.align(ccx).max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: Reg::i32(),
|
||||
total: size
|
||||
});
|
||||
if ((align - 1) & *offset) > 0 {
|
||||
arg.pad_with(ccx, Reg::i32());
|
||||
if !offset.is_abi_aligned(align) {
|
||||
arg.pad_with(Reg::i32());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
*offset = align_up_to(*offset, align);
|
||||
*offset += align_up_to(size.bytes(), align);
|
||||
*offset = offset.abi_align(align) + size.abi_align(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
|
||||
let mut offset = Size::from_bytes(0);
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(ccx, &mut fty.ret);
|
||||
classify_ret_ty(ccx, &mut fty.ret, &mut offset);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() { continue; }
|
||||
classify_arg_ty(ccx, arg, &mut offset);
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, ret, abi) {
|
||||
ret.cast_to(ccx, uniform);
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
Reg::i64()
|
||||
};
|
||||
|
||||
ret.cast_to(ccx, Uniform {
|
||||
ret.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
@ -101,7 +101,7 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, arg, abi) {
|
||||
arg.cast_to(ccx, uniform);
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
},
|
||||
};
|
||||
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit,
|
||||
total
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,16 +49,16 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
|
||||
if is_single_fp_element(ccx, arg.layout) {
|
||||
match size.bytes() {
|
||||
4 => arg.cast_to(ccx, Reg::f32()),
|
||||
8 => arg.cast_to(ccx, Reg::f64()),
|
||||
4 => arg.cast_to(Reg::f32()),
|
||||
8 => arg.cast_to(Reg::f64()),
|
||||
_ => arg.make_indirect(ccx)
|
||||
}
|
||||
} else {
|
||||
match size.bytes() {
|
||||
1 => arg.cast_to(ccx, Reg::i8()),
|
||||
2 => arg.cast_to(ccx, Reg::i16()),
|
||||
4 => arg.cast_to(ccx, Reg::i32()),
|
||||
8 => arg.cast_to(ccx, Reg::i64()),
|
||||
1 => arg.cast_to(Reg::i8()),
|
||||
2 => arg.cast_to(Reg::i16()),
|
||||
4 => arg.cast_to(Reg::i32()),
|
||||
8 => arg.cast_to(Reg::i64()),
|
||||
_ => arg.make_indirect(ccx)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,45 +8,48 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp;
|
||||
use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
|
||||
use context::CrateContext;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
|
||||
use rustc::ty::layout::Size;
|
||||
|
||||
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ret: &mut ArgType<'tcx>,
|
||||
offset: &mut Size) {
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
} else {
|
||||
ret.make_indirect(ccx);
|
||||
*offset += ccx.tcx().data_layout.pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) {
|
||||
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut Size) {
|
||||
let dl = &ccx.tcx().data_layout;
|
||||
let size = arg.layout.size(ccx);
|
||||
let mut align = arg.layout.align(ccx).abi();
|
||||
align = cmp::min(cmp::max(align, 4), 8);
|
||||
let align = arg.layout.align(ccx).max(dl.i32_align).min(dl.i64_align);
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: Reg::i32(),
|
||||
total: size
|
||||
});
|
||||
if ((align - 1) & *offset) > 0 {
|
||||
arg.pad_with(ccx, Reg::i32());
|
||||
if !offset.is_abi_aligned(align) {
|
||||
arg.pad_with(Reg::i32());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(32)
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
*offset = align_up_to(*offset, align);
|
||||
*offset += align_up_to(size.bytes(), align);
|
||||
*offset = offset.abi_align(align) + size.abi_align(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
|
||||
let mut offset = Size::from_bytes(0);
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(ccx, &mut fty.ret);
|
||||
classify_ret_ty(ccx, &mut fty.ret, &mut offset);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() { continue; }
|
||||
classify_arg_ty(ccx, arg, &mut offset);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, ret) {
|
||||
ret.cast_to(ccx, uniform);
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = ret.layout.size(ccx);
|
||||
|
|
@ -63,7 +63,7 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc
|
|||
Reg::i64()
|
||||
};
|
||||
|
||||
ret.cast_to(ccx, Uniform {
|
||||
ret.cast_to(Uniform {
|
||||
unit,
|
||||
total: size
|
||||
});
|
||||
|
|
@ -81,12 +81,12 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc
|
|||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(ccx, arg) {
|
||||
arg.cast_to(ccx, uniform);
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
let total = arg.layout.size(ccx);
|
||||
arg.cast_to(ccx, Uniform {
|
||||
arg.cast_to(Uniform {
|
||||
unit: Reg::i64(),
|
||||
total
|
||||
});
|
||||
|
|
|
|||
|
|
@ -56,16 +56,16 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// float aggregates directly in a floating-point register.
|
||||
if !t.options.is_like_msvc && is_single_fp_element(ccx, fty.ret.layout) {
|
||||
match size.bytes() {
|
||||
4 => fty.ret.cast_to(ccx, Reg::f32()),
|
||||
8 => fty.ret.cast_to(ccx, Reg::f64()),
|
||||
4 => fty.ret.cast_to(Reg::f32()),
|
||||
8 => fty.ret.cast_to(Reg::f64()),
|
||||
_ => fty.ret.make_indirect(ccx)
|
||||
}
|
||||
} else {
|
||||
match size.bytes() {
|
||||
1 => fty.ret.cast_to(ccx, Reg::i8()),
|
||||
2 => fty.ret.cast_to(ccx, Reg::i16()),
|
||||
4 => fty.ret.cast_to(ccx, Reg::i32()),
|
||||
8 => fty.ret.cast_to(ccx, Reg::i64()),
|
||||
1 => fty.ret.cast_to(Reg::i8()),
|
||||
2 => fty.ret.cast_to(Reg::i16()),
|
||||
4 => fty.ret.cast_to(Reg::i32()),
|
||||
8 => fty.ret.cast_to(Reg::i64()),
|
||||
_ => fty.ret.make_indirect(ccx)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
|
|||
fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
||||
-> Result<[Class; MAX_EIGHTBYTES], Memory> {
|
||||
fn unify(cls: &mut [Class],
|
||||
off: u64,
|
||||
off: Size,
|
||||
c: Class) {
|
||||
let i = (off / 8) as usize;
|
||||
let i = (off.bytes() / 8) as usize;
|
||||
let to_write = match (cls[i], c) {
|
||||
(Class::None, _) => c,
|
||||
(_, Class::None) => return,
|
||||
|
|
@ -55,9 +55,9 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
layout: TyLayout<'tcx>,
|
||||
cls: &mut [Class],
|
||||
off: u64)
|
||||
off: Size)
|
||||
-> Result<(), Memory> {
|
||||
if off % layout.align(ccx).abi() != 0 {
|
||||
if !off.is_abi_aligned(layout.align(ccx)) {
|
||||
if layout.size(ccx).bytes() > 0 {
|
||||
return Err(Memory);
|
||||
}
|
||||
|
|
@ -85,25 +85,25 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
|
||||
// everything after the first one is the upper
|
||||
// half of a register.
|
||||
let eltsz = element.size(ccx).bytes();
|
||||
let eltsz = element.size(ccx);
|
||||
for i in 1..count {
|
||||
unify(cls, off + i * eltsz, Class::SseUp);
|
||||
unify(cls, off + eltsz * i, Class::SseUp);
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Array { count, .. } => {
|
||||
if count > 0 {
|
||||
let elt = layout.field(ccx, 0);
|
||||
let eltsz = elt.size(ccx).bytes();
|
||||
let eltsz = elt.size(ccx);
|
||||
for i in 0..count {
|
||||
classify(ccx, elt, cls, off + i * eltsz)?;
|
||||
classify(ccx, elt, cls, off + eltsz * i)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Univariant { ref variant, .. } => {
|
||||
for i in 0..layout.field_count() {
|
||||
let field_off = off + variant.offsets[i].bytes();
|
||||
let field_off = off + variant.offsets[i];
|
||||
classify(ccx, layout.field(ccx, i), cls, field_off)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
}
|
||||
|
||||
let mut cls = [Class::None; MAX_EIGHTBYTES];
|
||||
classify(ccx, arg.layout, &mut cls, 0)?;
|
||||
classify(ccx, arg.layout, &mut cls, Size::from_bytes(0))?;
|
||||
if n > 2 {
|
||||
if cls[0] != Class::Sse {
|
||||
return Err(Memory);
|
||||
|
|
@ -153,7 +153,7 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
Ok(cls)
|
||||
}
|
||||
|
||||
fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
|
||||
fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option<Reg> {
|
||||
if *i >= cls.len() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
|
|||
Class::None => None,
|
||||
Class::Int => {
|
||||
*i += 1;
|
||||
Some(match size {
|
||||
Some(match size.bytes() {
|
||||
1 => Reg::i8(),
|
||||
2 => Reg::i16(),
|
||||
3 |
|
||||
|
|
@ -174,14 +174,14 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
|
|||
let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count();
|
||||
*i += vec_len;
|
||||
Some(if vec_len == 1 {
|
||||
match size {
|
||||
match size.bytes() {
|
||||
4 => Reg::f32(),
|
||||
_ => Reg::f64()
|
||||
}
|
||||
} else {
|
||||
Reg {
|
||||
kind: RegKind::Vector,
|
||||
size: Size::from_bytes(vec_len as u64 * 8)
|
||||
size: Size::from_bytes(8) * (vec_len as u64)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -189,17 +189,17 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option<Reg> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cast_target(cls: &[Class], size: u64) -> CastTarget {
|
||||
fn cast_target(cls: &[Class], size: Size) -> CastTarget {
|
||||
let mut i = 0;
|
||||
let lo = reg_component(cls, &mut i, size).unwrap();
|
||||
let offset = i as u64 * 8;
|
||||
let offset = Size::from_bytes(8) * (i as u64);
|
||||
let target = if size <= offset {
|
||||
CastTarget::from(lo)
|
||||
} else {
|
||||
let hi = reg_component(cls, &mut i, size - offset).unwrap();
|
||||
CastTarget::Pair(lo, hi)
|
||||
};
|
||||
assert_eq!(reg_component(cls, &mut i, 0), None);
|
||||
assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);
|
||||
target
|
||||
}
|
||||
|
||||
|
|
@ -242,8 +242,8 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType
|
|||
sse_regs -= needed_sse;
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
let size = arg.layout.size(ccx).bytes();
|
||||
arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size))
|
||||
let size = arg.layout.size(ccx);
|
||||
arg.cast_to(cast_target(cls.as_ref().unwrap(), size))
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType
|
|||
let size = a.layout.size(ccx);
|
||||
if a.layout.is_aggregate() {
|
||||
match size.bits() {
|
||||
8 => a.cast_to(ccx, Reg::i8()),
|
||||
16 => a.cast_to(ccx, Reg::i16()),
|
||||
32 => a.cast_to(ccx, Reg::i32()),
|
||||
64 => a.cast_to(ccx, Reg::i64()),
|
||||
8 => a.cast_to(Reg::i8()),
|
||||
16 => a.cast_to(Reg::i16()),
|
||||
32 => a.cast_to(Reg::i32()),
|
||||
64 => a.cast_to(Reg::i64()),
|
||||
_ => a.make_indirect(ccx)
|
||||
};
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@ use base;
|
|||
use builder::Builder;
|
||||
use consts;
|
||||
use declare;
|
||||
use machine;
|
||||
use monomorphize;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{Layout, LayoutTyper};
|
||||
use rustc::ty::layout::{HasDataLayout, Layout, LayoutTyper};
|
||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::hir;
|
||||
|
||||
|
|
@ -252,10 +251,6 @@ pub fn C_big_integral(t: Type, u: u128) -> ValueRef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn C_nil(ccx: &CrateContext) -> ValueRef {
|
||||
C_struct(ccx, &[], false)
|
||||
}
|
||||
|
||||
pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef {
|
||||
C_uint(Type::i1(ccx), val as u64)
|
||||
}
|
||||
|
|
@ -273,8 +268,7 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
|
|||
}
|
||||
|
||||
pub fn C_usize(ccx: &CrateContext, i: u64) -> ValueRef {
|
||||
let bit_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
|
||||
|
||||
let bit_size = ccx.data_layout().pointer_size.bits();
|
||||
if bit_size < 64 {
|
||||
// make sure it doesn't overflow
|
||||
assert!(i < (1<<bit_size));
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use llvm::{ValueRef, True};
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::middle::const_val::ConstEvalErr;
|
||||
use {debuginfo, machine};
|
||||
use debuginfo;
|
||||
use base;
|
||||
use trans_item::{TransItem, TransItemExt};
|
||||
use common::{self, CrateContext, val_ty};
|
||||
|
|
@ -23,10 +23,10 @@ use monomorphize::Instance;
|
|||
use type_::Type;
|
||||
use type_of;
|
||||
use rustc::ty;
|
||||
use rustc::ty::layout::Align;
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
use std::cmp;
|
||||
use std::ffi::{CStr, CString};
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
|
@ -45,26 +45,26 @@ pub fn bitcast(val: ValueRef, ty: Type) -> ValueRef {
|
|||
|
||||
fn set_global_alignment(ccx: &CrateContext,
|
||||
gv: ValueRef,
|
||||
mut align: machine::llalign) {
|
||||
mut align: Align) {
|
||||
// The target may require greater alignment for globals than the type does.
|
||||
// Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
|
||||
// which can force it to be smaller. Rust doesn't support this yet.
|
||||
if let Some(min) = ccx.sess().target.target.options.min_global_align {
|
||||
match ty::layout::Align::from_bits(min, min) {
|
||||
Ok(min) => align = cmp::max(align, min.abi() as machine::llalign),
|
||||
Ok(min) => align = align.max(min),
|
||||
Err(err) => {
|
||||
ccx.sess().err(&format!("invalid minimum global alignment: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
llvm::LLVMSetAlignment(gv, align);
|
||||
llvm::LLVMSetAlignment(gv, align.abi() as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr_of_mut(ccx: &CrateContext,
|
||||
cv: ValueRef,
|
||||
align: machine::llalign,
|
||||
align: Align,
|
||||
kind: &str)
|
||||
-> ValueRef {
|
||||
unsafe {
|
||||
|
|
@ -82,15 +82,16 @@ pub fn addr_of_mut(ccx: &CrateContext,
|
|||
|
||||
pub fn addr_of(ccx: &CrateContext,
|
||||
cv: ValueRef,
|
||||
align: machine::llalign,
|
||||
align: Align,
|
||||
kind: &str)
|
||||
-> ValueRef {
|
||||
if let Some(&gv) = ccx.const_globals().borrow().get(&cv) {
|
||||
unsafe {
|
||||
// Upgrade the alignment in cases where the same constant is used with different
|
||||
// alignment requirements
|
||||
if align > llvm::LLVMGetAlignment(gv) {
|
||||
llvm::LLVMSetAlignment(gv, align);
|
||||
let llalign = align.abi() as u32;
|
||||
if llalign > llvm::LLVMGetAlignment(gv) {
|
||||
llvm::LLVMSetAlignment(gv, llalign);
|
||||
}
|
||||
}
|
||||
return gv;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
// except according to those terms.
|
||||
|
||||
use self::RecursiveTypeDescription::*;
|
||||
use self::MemberOffset::*;
|
||||
use self::MemberDescriptionFactory::*;
|
||||
use self::EnumDiscriminantInfo::*;
|
||||
|
||||
use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align_of,
|
||||
use super::utils::{debug_context, DIB, span_start,
|
||||
get_namespace_for_item, create_DIArray, is_node_local_to_unit};
|
||||
use super::namespace::mangled_name_of_item;
|
||||
use super::type_names::compute_debuginfo_type_name;
|
||||
|
|
@ -30,13 +29,11 @@ use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
|||
use rustc::ty::fold::TypeVisitor;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::util::TypeIdHasher;
|
||||
use rustc::hir;
|
||||
use rustc::ich::Fingerprint;
|
||||
use {type_of, machine, monomorphize};
|
||||
use monomorphize;
|
||||
use common::{self, CrateContext};
|
||||
use type_::Type;
|
||||
use rustc::ty::{self, AdtKind, Ty};
|
||||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use rustc::ty::layout::{self, Align, LayoutTyper, Size};
|
||||
use rustc::session::{Session, config};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc::util::common::path2cstr;
|
||||
|
|
@ -184,7 +181,6 @@ enum RecursiveTypeDescription<'tcx> {
|
|||
unfinished_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
metadata_stub: DICompositeType,
|
||||
llvm_type: Type,
|
||||
member_description_factory: MemberDescriptionFactory<'tcx>,
|
||||
},
|
||||
FinalMetadata(DICompositeType)
|
||||
|
|
@ -195,7 +191,6 @@ fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>(
|
|||
unfinished_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
metadata_stub: DICompositeType,
|
||||
llvm_type: Type,
|
||||
member_description_factory: MemberDescriptionFactory<'tcx>)
|
||||
-> RecursiveTypeDescription<'tcx> {
|
||||
|
||||
|
|
@ -208,7 +203,6 @@ fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>(
|
|||
unfinished_type,
|
||||
unique_type_id,
|
||||
metadata_stub,
|
||||
llvm_type,
|
||||
member_description_factory,
|
||||
}
|
||||
}
|
||||
|
|
@ -224,9 +218,7 @@ impl<'tcx> RecursiveTypeDescription<'tcx> {
|
|||
unfinished_type,
|
||||
unique_type_id,
|
||||
metadata_stub,
|
||||
llvm_type,
|
||||
ref member_description_factory,
|
||||
..
|
||||
} => {
|
||||
// Make sure that we have a forward declaration of the type in
|
||||
// the TypeMap so that recursive references are possible. This
|
||||
|
|
@ -251,7 +243,6 @@ impl<'tcx> RecursiveTypeDescription<'tcx> {
|
|||
// ... and attach them to the stub to complete it.
|
||||
set_members_of_composite_type(cx,
|
||||
metadata_stub,
|
||||
llvm_type,
|
||||
&member_descriptions[..]);
|
||||
return MetadataCreationResult::new(metadata_stub, true);
|
||||
}
|
||||
|
|
@ -274,20 +265,21 @@ macro_rules! return_if_metadata_created_in_meantime {
|
|||
|
||||
fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
array_or_slice_type: Ty<'tcx>,
|
||||
element_type: Ty<'tcx>,
|
||||
len: Option<u64>,
|
||||
span: Span)
|
||||
-> MetadataCreationResult {
|
||||
let element_type_metadata = type_metadata(cx, element_type, span);
|
||||
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let element_llvm_type = type_of::type_of(cx, element_type);
|
||||
let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
|
||||
let (size, align) = cx.size_and_align_of(array_or_slice_type);
|
||||
|
||||
let (array_size_in_bytes, upper_bound) = match len {
|
||||
Some(len) => (element_type_size * len, len as c_longlong),
|
||||
None => (0, -1)
|
||||
let upper_bound = match array_or_slice_type.sty {
|
||||
ty::TyArray(_, len) => {
|
||||
len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong
|
||||
}
|
||||
_ => -1
|
||||
};
|
||||
|
||||
let subrange = unsafe {
|
||||
|
|
@ -298,8 +290,8 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let metadata = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateArrayType(
|
||||
DIB(cx),
|
||||
bytes_to_bits(array_size_in_bytes),
|
||||
bytes_to_bits(element_type_align),
|
||||
size.bits(),
|
||||
align.abi_bits() as u32,
|
||||
element_type_metadata,
|
||||
subscripts)
|
||||
};
|
||||
|
|
@ -308,66 +300,52 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
vec_type: Ty<'tcx>,
|
||||
slice_ptr_type: Ty<'tcx>,
|
||||
element_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> MetadataCreationResult {
|
||||
let data_ptr_type = cx.tcx().mk_ptr(ty::TypeAndMut {
|
||||
ty: element_type,
|
||||
mutbl: hir::MutImmutable
|
||||
});
|
||||
let data_ptr_type = cx.tcx().mk_imm_ptr(element_type);
|
||||
|
||||
let element_type_metadata = type_metadata(cx, data_ptr_type, span);
|
||||
let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
|
||||
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let slice_llvm_type = type_of::type_of(cx, vec_type);
|
||||
let slice_type_name = compute_debuginfo_type_name(cx, vec_type, true);
|
||||
let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true);
|
||||
|
||||
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
|
||||
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx().types.usize);
|
||||
|
||||
let member_llvm_types = slice_llvm_type.field_types();
|
||||
assert!(slice_layout_is_correct(cx,
|
||||
&member_llvm_types[..],
|
||||
element_type));
|
||||
let member_descriptions = [
|
||||
MemberDescription {
|
||||
name: "data_ptr".to_string(),
|
||||
llvm_type: member_llvm_types[0],
|
||||
type_metadata: element_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
type_metadata: data_ptr_metadata,
|
||||
offset: Size::from_bytes(0),
|
||||
size: pointer_size,
|
||||
align: pointer_align,
|
||||
flags: DIFlags::FlagZero,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "length".to_string(),
|
||||
llvm_type: member_llvm_types[1],
|
||||
type_metadata: type_metadata(cx, cx.tcx().types.usize, span),
|
||||
offset: ComputedMemberOffset,
|
||||
offset: pointer_size,
|
||||
size: usize_size,
|
||||
align: usize_align,
|
||||
flags: DIFlags::FlagZero,
|
||||
},
|
||||
];
|
||||
|
||||
assert!(member_descriptions.len() == member_llvm_types.len());
|
||||
|
||||
let file_metadata = unknown_file_metadata(cx);
|
||||
|
||||
let metadata = composite_type_metadata(cx,
|
||||
slice_llvm_type,
|
||||
slice_ptr_type,
|
||||
&slice_type_name[..],
|
||||
unique_type_id,
|
||||
&member_descriptions,
|
||||
NO_SCOPE_METADATA,
|
||||
file_metadata,
|
||||
span);
|
||||
return MetadataCreationResult::new(metadata, false);
|
||||
|
||||
fn slice_layout_is_correct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
member_llvm_types: &[Type],
|
||||
element_type: Ty<'tcx>)
|
||||
-> bool {
|
||||
member_llvm_types.len() == 2 &&
|
||||
member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() &&
|
||||
member_llvm_types[1] == cx.isize_ty()
|
||||
}
|
||||
MetadataCreationResult::new(metadata, false)
|
||||
}
|
||||
|
||||
fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
|
@ -436,38 +414,38 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let trait_type_name =
|
||||
compute_debuginfo_type_name(cx, trait_object_type, false);
|
||||
|
||||
let trait_llvm_type = type_of::type_of(cx, trait_object_type);
|
||||
let file_metadata = unknown_file_metadata(cx);
|
||||
|
||||
|
||||
let ptr_type = cx.tcx().mk_ptr(ty::TypeAndMut {
|
||||
ty: cx.tcx().types.u8,
|
||||
mutbl: hir::MutImmutable
|
||||
});
|
||||
let ptr_type_metadata = type_metadata(cx, ptr_type, syntax_pos::DUMMY_SP);
|
||||
let llvm_type = type_of::type_of(cx, ptr_type);
|
||||
let layout = cx.layout_of(cx.tcx().mk_mut_ptr(trait_type));
|
||||
|
||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
|
||||
let data_ptr_field = layout.field(cx, 0);
|
||||
let vtable_field = layout.field(cx, 1);
|
||||
let member_descriptions = [
|
||||
MemberDescription {
|
||||
name: "pointer".to_string(),
|
||||
llvm_type: llvm_type,
|
||||
type_metadata: ptr_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
type_metadata: type_metadata(cx,
|
||||
cx.tcx().mk_mut_ptr(cx.tcx().types.u8),
|
||||
syntax_pos::DUMMY_SP),
|
||||
offset: layout.field_offset(cx, 0),
|
||||
size: data_ptr_field.size(cx),
|
||||
align: data_ptr_field.align(cx),
|
||||
flags: DIFlags::FlagArtificial,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "vtable".to_string(),
|
||||
llvm_type: llvm_type,
|
||||
type_metadata: ptr_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
type_metadata: type_metadata(cx, vtable_field.ty, syntax_pos::DUMMY_SP),
|
||||
offset: layout.field_offset(cx, 1),
|
||||
size: vtable_field.size(cx),
|
||||
align: vtable_field.align(cx),
|
||||
flags: DIFlags::FlagArtificial,
|
||||
},
|
||||
];
|
||||
|
||||
composite_type_metadata(cx,
|
||||
trait_llvm_type,
|
||||
trait_object_type,
|
||||
&trait_type_name[..],
|
||||
unique_type_id,
|
||||
&member_descriptions,
|
||||
|
|
@ -556,15 +534,12 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
ty::TyTuple(ref elements, _) if elements.is_empty() => {
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::TyArray(typ, len) => {
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, Some(len), usage_site_span)
|
||||
}
|
||||
ty::TyArray(typ, _) |
|
||||
ty::TySlice(typ) => {
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span)
|
||||
fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
|
||||
}
|
||||
ty::TyStr => {
|
||||
fixed_vec_metadata(cx, unique_type_id, cx.tcx().types.i8, None, usage_site_span)
|
||||
fixed_vec_metadata(cx, unique_type_id, t, cx.tcx().types.i8, usage_site_span)
|
||||
}
|
||||
ty::TyDynamic(..) => {
|
||||
MetadataCreationResult::new(
|
||||
|
|
@ -770,15 +745,14 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
_ => bug!("debuginfo::basic_type_metadata - t is invalid type")
|
||||
};
|
||||
|
||||
let llvm_type = type_of::type_of(cx, t);
|
||||
let (size, align) = size_and_align_of(cx, llvm_type);
|
||||
let (size, align) = cx.size_and_align_of(t);
|
||||
let name = CString::new(name).unwrap();
|
||||
let ty_metadata = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_ptr(),
|
||||
bytes_to_bits(size),
|
||||
bytes_to_bits(align),
|
||||
size.bits(),
|
||||
align.abi_bits() as u32,
|
||||
encoding)
|
||||
};
|
||||
|
||||
|
|
@ -790,29 +764,25 @@ fn foreign_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
unique_type_id: UniqueTypeId) -> DIType {
|
||||
debug!("foreign_type_metadata: {:?}", t);
|
||||
|
||||
let llvm_type = type_of::type_of(cx, t);
|
||||
|
||||
let name = compute_debuginfo_type_name(cx, t, false);
|
||||
create_struct_stub(cx, llvm_type, &name, unique_type_id, NO_SCOPE_METADATA)
|
||||
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
|
||||
}
|
||||
|
||||
fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
pointer_type: Ty<'tcx>,
|
||||
pointee_type_metadata: DIType)
|
||||
-> DIType {
|
||||
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
|
||||
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
|
||||
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
|
||||
let name = compute_debuginfo_type_name(cx, pointer_type, false);
|
||||
let name = CString::new(name).unwrap();
|
||||
let ptr_metadata = unsafe {
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||
DIB(cx),
|
||||
pointee_type_metadata,
|
||||
bytes_to_bits(pointer_size),
|
||||
bytes_to_bits(pointer_align),
|
||||
pointer_size.bits(),
|
||||
pointer_align.abi_bits() as u32,
|
||||
name.as_ptr())
|
||||
};
|
||||
return ptr_metadata;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_unit_metadata(scc: &SharedCrateContext,
|
||||
|
|
@ -907,21 +877,15 @@ impl MetadataCreationResult {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MemberOffset {
|
||||
FixedMemberOffset { bytes: usize },
|
||||
// For ComputedMemberOffset, the offset is read from the llvm type definition.
|
||||
ComputedMemberOffset
|
||||
}
|
||||
|
||||
// Description of a type member, which can either be a regular field (as in
|
||||
// structs or tuples) or an enum variant.
|
||||
#[derive(Debug)]
|
||||
struct MemberDescription {
|
||||
name: String,
|
||||
llvm_type: Type,
|
||||
type_metadata: DIType,
|
||||
offset: MemberOffset,
|
||||
offset: Size,
|
||||
size: Size,
|
||||
align: Align,
|
||||
flags: DIFlags,
|
||||
}
|
||||
|
||||
|
|
@ -998,13 +962,13 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
|
|||
};
|
||||
let fty = monomorphize::field_ty(cx.tcx(), self.substs, f);
|
||||
|
||||
let offset = FixedMemberOffset { bytes: offsets[i].bytes() as usize};
|
||||
|
||||
let (size, align) = cx.size_and_align_of(fty);
|
||||
MemberDescription {
|
||||
name,
|
||||
llvm_type: type_of::in_memory_type_of(cx, fty),
|
||||
type_metadata: type_metadata(cx, fty, self.span),
|
||||
offset,
|
||||
offset: offsets[i],
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero,
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -1018,7 +982,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
span: Span)
|
||||
-> RecursiveTypeDescription<'tcx> {
|
||||
let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
|
||||
let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type);
|
||||
|
||||
let (struct_def_id, variant, substs) = match struct_type.sty {
|
||||
ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs),
|
||||
|
|
@ -1028,7 +991,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let containing_scope = get_namespace_for_item(cx, struct_def_id);
|
||||
|
||||
let struct_metadata_stub = create_struct_stub(cx,
|
||||
struct_llvm_type,
|
||||
struct_type,
|
||||
&struct_name,
|
||||
unique_type_id,
|
||||
containing_scope);
|
||||
|
|
@ -1038,7 +1001,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
struct_type,
|
||||
unique_type_id,
|
||||
struct_metadata_stub,
|
||||
struct_llvm_type,
|
||||
StructMDF(StructMemberDescriptionFactory {
|
||||
ty: struct_type,
|
||||
variant,
|
||||
|
|
@ -1069,15 +1031,14 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
|
|||
bug!("{} is not a tuple", self.ty);
|
||||
};
|
||||
|
||||
self.component_types
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &component_type)| {
|
||||
self.component_types.iter().enumerate().map(|(i, &component_type)| {
|
||||
let (size, align) = cx.size_and_align_of(component_type);
|
||||
MemberDescription {
|
||||
name: format!("__{}", i),
|
||||
llvm_type: type_of::type_of(cx, component_type),
|
||||
type_metadata: type_metadata(cx, component_type, self.span),
|
||||
offset: FixedMemberOffset { bytes: offsets[i].bytes() as usize },
|
||||
offset: offsets[i],
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero,
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -1091,18 +1052,16 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
span: Span)
|
||||
-> RecursiveTypeDescription<'tcx> {
|
||||
let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
|
||||
let tuple_llvm_type = type_of::type_of(cx, tuple_type);
|
||||
|
||||
create_and_register_recursive_type_forward_declaration(
|
||||
cx,
|
||||
tuple_type,
|
||||
unique_type_id,
|
||||
create_struct_stub(cx,
|
||||
tuple_llvm_type,
|
||||
tuple_type,
|
||||
&tuple_name[..],
|
||||
unique_type_id,
|
||||
NO_SCOPE_METADATA),
|
||||
tuple_llvm_type,
|
||||
TupleMDF(TupleMemberDescriptionFactory {
|
||||
ty: tuple_type,
|
||||
component_types: component_types.to_vec(),
|
||||
|
|
@ -1126,11 +1085,13 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
|
|||
-> Vec<MemberDescription> {
|
||||
self.variant.fields.iter().map(|field| {
|
||||
let fty = monomorphize::field_ty(cx.tcx(), self.substs, field);
|
||||
let (size, align) = cx.size_and_align_of(fty);
|
||||
MemberDescription {
|
||||
name: field.name.to_string(),
|
||||
llvm_type: type_of::type_of(cx, fty),
|
||||
type_metadata: type_metadata(cx, fty, self.span),
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero,
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -1143,7 +1104,6 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
span: Span)
|
||||
-> RecursiveTypeDescription<'tcx> {
|
||||
let union_name = compute_debuginfo_type_name(cx, union_type, false);
|
||||
let union_llvm_type = type_of::in_memory_type_of(cx, union_type);
|
||||
|
||||
let (union_def_id, variant, substs) = match union_type.sty {
|
||||
ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs),
|
||||
|
|
@ -1153,7 +1113,7 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let containing_scope = get_namespace_for_item(cx, union_def_id);
|
||||
|
||||
let union_metadata_stub = create_union_stub(cx,
|
||||
union_llvm_type,
|
||||
union_type,
|
||||
&union_name,
|
||||
unique_type_id,
|
||||
containing_scope);
|
||||
|
|
@ -1163,7 +1123,6 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
union_type,
|
||||
unique_type_id,
|
||||
union_metadata_stub,
|
||||
union_llvm_type,
|
||||
UnionMDF(UnionMemberDescriptionFactory {
|
||||
variant,
|
||||
substs,
|
||||
|
|
@ -1206,9 +1165,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, struct_def)| {
|
||||
let (variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
member_desc_factory) =
|
||||
let (variant_type_metadata, member_desc_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
|
|
@ -1222,13 +1179,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
&member_descriptions);
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
llvm_type: variant_llvm_type,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size: struct_def.stride(),
|
||||
align: struct_def.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -1239,9 +1196,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
if adt.variants.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
let (variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
member_description_factory) =
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
variant,
|
||||
|
|
@ -1255,14 +1210,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
&member_descriptions[..]);
|
||||
vec![
|
||||
MemberDescription {
|
||||
name: "".to_string(),
|
||||
llvm_type: variant_llvm_type,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size: variant.stride(),
|
||||
align: variant.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
|
|
@ -1278,15 +1233,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
let non_null_variant_name = non_null_variant.name.as_str();
|
||||
|
||||
// The llvm type and metadata of the pointer
|
||||
let nnty = monomorphize::field_ty(cx.tcx(), &substs, &non_null_variant.fields[0] );
|
||||
let non_null_llvm_type = type_of::type_of(cx, nnty);
|
||||
let nnty = monomorphize::field_ty(cx.tcx(), &substs, &non_null_variant.fields[0]);
|
||||
let (size, align) = cx.size_and_align_of(nnty);
|
||||
let non_null_type_metadata = type_metadata(cx, nnty, self.span);
|
||||
|
||||
// The type of the artificial struct wrapping the pointer
|
||||
let artificial_struct_llvm_type = Type::struct_(cx,
|
||||
&[non_null_llvm_type],
|
||||
false);
|
||||
|
||||
// For the metadata of the wrapper struct, we need to create a
|
||||
// MemberDescription of the struct's single field.
|
||||
let sole_struct_member_description = MemberDescription {
|
||||
|
|
@ -1297,9 +1247,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
}
|
||||
CtorKind::Const => bug!()
|
||||
},
|
||||
llvm_type: non_null_llvm_type,
|
||||
type_metadata: non_null_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero
|
||||
};
|
||||
|
||||
|
|
@ -1313,7 +1264,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
// Now we can create the metadata of the artificial struct
|
||||
let artificial_struct_metadata =
|
||||
composite_type_metadata(cx,
|
||||
artificial_struct_llvm_type,
|
||||
nnty,
|
||||
&non_null_variant_name,
|
||||
unique_type_id,
|
||||
&[sole_struct_member_description],
|
||||
|
|
@ -1334,9 +1285,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
vec![
|
||||
MemberDescription {
|
||||
name: union_member_name,
|
||||
llvm_type: artificial_struct_llvm_type,
|
||||
type_metadata: artificial_struct_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
|
|
@ -1345,7 +1297,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
nndiscr,
|
||||
ref discrfield_source, ..} => {
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
|
||||
let (variant_type_metadata, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
|
|
@ -1359,7 +1311,6 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
&variant_member_descriptions[..]);
|
||||
|
||||
// Encode the information about the null variant in the union
|
||||
|
|
@ -1378,9 +1329,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
|||
vec![
|
||||
MemberDescription {
|
||||
name: union_member_name,
|
||||
llvm_type: variant_llvm_type,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
offset: Size::from_bytes(0),
|
||||
size: struct_def.stride(),
|
||||
align: struct_def.align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
]
|
||||
|
|
@ -1404,14 +1356,16 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
|
|||
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
|
||||
-> Vec<MemberDescription> {
|
||||
self.args.iter().enumerate().map(|(i, &(ref name, ty))| {
|
||||
let (size, align) = cx.size_and_align_of(ty);
|
||||
MemberDescription {
|
||||
name: name.to_string(),
|
||||
llvm_type: type_of::type_of(cx, ty),
|
||||
type_metadata: match self.discriminant_type_metadata {
|
||||
Some(metadata) if i == 0 => metadata,
|
||||
_ => type_metadata(cx, ty, self.span)
|
||||
},
|
||||
offset: FixedMemberOffset { bytes: self.offsets[i].bytes() as usize },
|
||||
offset: self.offsets[i],
|
||||
size,
|
||||
align,
|
||||
flags: DIFlags::FlagZero
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -1436,7 +1390,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
discriminant_info: EnumDiscriminantInfo,
|
||||
containing_scope: DIScope,
|
||||
span: Span)
|
||||
-> (DICompositeType, Type, MemberDescriptionFactory<'tcx>) {
|
||||
-> (DICompositeType, MemberDescriptionFactory<'tcx>) {
|
||||
let substs = match enum_type.sty {
|
||||
ty::TyAdt(def, s) if def.adt_kind() == AdtKind::Enum => s,
|
||||
ref t @ _ => bug!("{:#?} is not an enum", t)
|
||||
|
|
@ -1456,17 +1410,9 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}).collect::<Vec<_>>();
|
||||
|
||||
if let Some((discr, signed)) = maybe_discr_and_signed {
|
||||
field_tys.insert(0, discr.to_ty(&cx.tcx(), signed));
|
||||
field_tys.insert(0, discr.to_ty(cx.tcx(), signed));
|
||||
}
|
||||
|
||||
|
||||
let variant_llvm_type =
|
||||
Type::struct_(cx, &field_tys
|
||||
.iter()
|
||||
.map(|t| type_of::type_of(cx, t))
|
||||
.collect::<Vec<_>>()
|
||||
,
|
||||
struct_def.packed);
|
||||
// Could do some consistency checks here: size, align, field count, discr type
|
||||
|
||||
let variant_name = variant.name.as_str();
|
||||
|
|
@ -1478,7 +1424,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
&variant_name);
|
||||
|
||||
let metadata_stub = create_struct_stub(cx,
|
||||
variant_llvm_type,
|
||||
enum_type,
|
||||
&variant_name,
|
||||
unique_type_id,
|
||||
containing_scope);
|
||||
|
|
@ -1526,7 +1472,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
span,
|
||||
});
|
||||
|
||||
(metadata_stub, variant_llvm_type, member_description_factory)
|
||||
(metadata_stub, member_description_factory)
|
||||
}
|
||||
|
||||
fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
|
@ -1570,12 +1516,11 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
match cached_discriminant_type_metadata {
|
||||
Some(discriminant_type_metadata) => discriminant_type_metadata,
|
||||
None => {
|
||||
let discriminant_llvm_type = Type::from_integer(cx, inttype);
|
||||
let (discriminant_size, discriminant_align) =
|
||||
size_and_align_of(cx, discriminant_llvm_type);
|
||||
(inttype.size(), inttype.align(cx));
|
||||
let discriminant_base_type_metadata =
|
||||
type_metadata(cx,
|
||||
inttype.to_ty(&cx.tcx(), signed),
|
||||
inttype.to_ty(cx.tcx(), signed),
|
||||
syntax_pos::DUMMY_SP);
|
||||
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
|
||||
|
||||
|
|
@ -1587,8 +1532,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
name.as_ptr(),
|
||||
file_metadata,
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(discriminant_size),
|
||||
bytes_to_bits(discriminant_align),
|
||||
discriminant_size.bits(),
|
||||
discriminant_align.abi_bits() as u32,
|
||||
create_DIArray(DIB(cx), &enumerators_metadata),
|
||||
discriminant_base_type_metadata)
|
||||
};
|
||||
|
|
@ -1615,8 +1560,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
ref l @ _ => bug!("Not an enum layout: {:#?}", l)
|
||||
};
|
||||
|
||||
let enum_llvm_type = type_of::type_of(cx, enum_type);
|
||||
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
|
||||
let (enum_type_size, enum_type_align) = cx.size_and_align_of(enum_type);
|
||||
|
||||
let enum_name = CString::new(enum_name).unwrap();
|
||||
let unique_type_id_str = CString::new(
|
||||
|
|
@ -1629,8 +1573,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
enum_name.as_ptr(),
|
||||
file_metadata,
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(enum_type_size),
|
||||
bytes_to_bits(enum_type_align),
|
||||
enum_type_size.bits(),
|
||||
enum_type_align.abi_bits() as u32,
|
||||
DIFlags::FlagZero,
|
||||
ptr::null_mut(),
|
||||
0, // RuntimeLang
|
||||
|
|
@ -1642,7 +1586,6 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
enum_type,
|
||||
unique_type_id,
|
||||
enum_metadata,
|
||||
enum_llvm_type,
|
||||
EnumMDF(EnumMemberDescriptionFactory {
|
||||
enum_type,
|
||||
type_rep: type_rep.layout,
|
||||
|
|
@ -1664,28 +1607,27 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
/// results in a LLVM struct.
|
||||
///
|
||||
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
|
||||
fn composite_type_metadata(cx: &CrateContext,
|
||||
composite_llvm_type: Type,
|
||||
composite_type_name: &str,
|
||||
composite_type_unique_id: UniqueTypeId,
|
||||
member_descriptions: &[MemberDescription],
|
||||
containing_scope: DIScope,
|
||||
fn composite_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
composite_type: Ty<'tcx>,
|
||||
composite_type_name: &str,
|
||||
composite_type_unique_id: UniqueTypeId,
|
||||
member_descriptions: &[MemberDescription],
|
||||
containing_scope: DIScope,
|
||||
|
||||
// Ignore source location information as long as it
|
||||
// can't be reconstructed for non-local crates.
|
||||
_file_metadata: DIFile,
|
||||
_definition_span: Span)
|
||||
-> DICompositeType {
|
||||
// Ignore source location information as long as it
|
||||
// can't be reconstructed for non-local crates.
|
||||
_file_metadata: DIFile,
|
||||
_definition_span: Span)
|
||||
-> DICompositeType {
|
||||
// Create the (empty) struct metadata node ...
|
||||
let composite_type_metadata = create_struct_stub(cx,
|
||||
composite_llvm_type,
|
||||
composite_type,
|
||||
composite_type_name,
|
||||
composite_type_unique_id,
|
||||
containing_scope);
|
||||
// ... and immediately create and add the member descriptions.
|
||||
set_members_of_composite_type(cx,
|
||||
composite_type_metadata,
|
||||
composite_llvm_type,
|
||||
member_descriptions);
|
||||
|
||||
return composite_type_metadata;
|
||||
|
|
@ -1693,7 +1635,6 @@ fn composite_type_metadata(cx: &CrateContext,
|
|||
|
||||
fn set_members_of_composite_type(cx: &CrateContext,
|
||||
composite_type_metadata: DICompositeType,
|
||||
composite_llvm_type: Type,
|
||||
member_descriptions: &[MemberDescription]) {
|
||||
// In some rare cases LLVM metadata uniquing would lead to an existing type
|
||||
// description being used instead of a new one created in
|
||||
|
|
@ -1714,14 +1655,7 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
|||
|
||||
let member_metadata: Vec<DIDescriptor> = member_descriptions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, member_description)| {
|
||||
let (member_size, member_align) = size_and_align_of(cx, member_description.llvm_type);
|
||||
let member_offset = match member_description.offset {
|
||||
FixedMemberOffset { bytes } => bytes as u64,
|
||||
ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
|
||||
};
|
||||
|
||||
.map(|member_description| {
|
||||
let member_name = member_description.name.as_bytes();
|
||||
let member_name = CString::new(member_name).unwrap();
|
||||
unsafe {
|
||||
|
|
@ -1731,9 +1665,9 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
|||
member_name.as_ptr(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(member_size),
|
||||
bytes_to_bits(member_align),
|
||||
bytes_to_bits(member_offset),
|
||||
member_description.size.bits(),
|
||||
member_description.align.abi_bits() as u32,
|
||||
member_description.offset.bits(),
|
||||
member_description.flags,
|
||||
member_description.type_metadata)
|
||||
}
|
||||
|
|
@ -1750,13 +1684,13 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
|||
// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do
|
||||
// any caching, does not add any fields to the struct. This can be done later
|
||||
// with set_members_of_composite_type().
|
||||
fn create_struct_stub(cx: &CrateContext,
|
||||
struct_llvm_type: Type,
|
||||
struct_type_name: &str,
|
||||
unique_type_id: UniqueTypeId,
|
||||
containing_scope: DIScope)
|
||||
-> DICompositeType {
|
||||
let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
|
||||
fn create_struct_stub<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
struct_type: Ty<'tcx>,
|
||||
struct_type_name: &str,
|
||||
unique_type_id: UniqueTypeId,
|
||||
containing_scope: DIScope)
|
||||
-> DICompositeType {
|
||||
let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
|
||||
|
||||
let name = CString::new(struct_type_name).unwrap();
|
||||
let unique_type_id = CString::new(
|
||||
|
|
@ -1774,8 +1708,8 @@ fn create_struct_stub(cx: &CrateContext,
|
|||
name.as_ptr(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(struct_size),
|
||||
bytes_to_bits(struct_align),
|
||||
struct_size.bits(),
|
||||
struct_align.abi_bits() as u32,
|
||||
DIFlags::FlagZero,
|
||||
ptr::null_mut(),
|
||||
empty_array,
|
||||
|
|
@ -1787,13 +1721,13 @@ fn create_struct_stub(cx: &CrateContext,
|
|||
return metadata_stub;
|
||||
}
|
||||
|
||||
fn create_union_stub(cx: &CrateContext,
|
||||
union_llvm_type: Type,
|
||||
union_type_name: &str,
|
||||
unique_type_id: UniqueTypeId,
|
||||
containing_scope: DIScope)
|
||||
-> DICompositeType {
|
||||
let (union_size, union_align) = size_and_align_of(cx, union_llvm_type);
|
||||
fn create_union_stub<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
union_type: Ty<'tcx>,
|
||||
union_type_name: &str,
|
||||
unique_type_id: UniqueTypeId,
|
||||
containing_scope: DIScope)
|
||||
-> DICompositeType {
|
||||
let (union_size, union_align) = cx.size_and_align_of(union_type);
|
||||
|
||||
let name = CString::new(union_type_name).unwrap();
|
||||
let unique_type_id = CString::new(
|
||||
|
|
@ -1811,8 +1745,8 @@ fn create_union_stub(cx: &CrateContext,
|
|||
name.as_ptr(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(union_size),
|
||||
bytes_to_bits(union_align),
|
||||
union_size.bits(),
|
||||
union_align.abi_bits() as u32,
|
||||
DIFlags::FlagZero,
|
||||
empty_array,
|
||||
0, // RuntimeLang
|
||||
|
|
@ -1867,7 +1801,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
|
|||
is_local_to_unit,
|
||||
global,
|
||||
ptr::null_mut(),
|
||||
global_align,
|
||||
global_align.abi() as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1899,8 +1833,6 @@ pub fn create_vtable_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP);
|
||||
let llvm_vtable_type = Type::vtable_ptr(cx).element_type();
|
||||
let (struct_size, struct_align) = size_and_align_of(cx, llvm_vtable_type);
|
||||
|
||||
unsafe {
|
||||
// LLVMRustDIBuilderCreateStructType() wants an empty array. A null
|
||||
|
|
@ -1919,8 +1851,8 @@ pub fn create_vtable_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
name.as_ptr(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
bytes_to_bits(struct_size),
|
||||
bytes_to_bits(struct_align),
|
||||
Size::from_bytes(0).bits(),
|
||||
cx.tcx().data_layout.pointer_align.abi_bits() as u32,
|
||||
DIFlags::FlagArtificial,
|
||||
ptr::null_mut(),
|
||||
empty_array,
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
cx.sess().opts.optimize != config::OptLevel::No,
|
||||
DIFlags::FlagZero,
|
||||
argument_index,
|
||||
align,
|
||||
align.abi() as u32,
|
||||
)
|
||||
};
|
||||
source_loc::set_debug_location(bcx,
|
||||
|
|
|
|||
|
|
@ -18,15 +18,11 @@ use rustc::ty::DefIdTree;
|
|||
|
||||
use llvm;
|
||||
use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
|
||||
use machine;
|
||||
use common::{CrateContext};
|
||||
use type_::Type;
|
||||
|
||||
use syntax_pos::{self, Span};
|
||||
use syntax::ast;
|
||||
|
||||
use std::ops;
|
||||
|
||||
pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
|
||||
{
|
||||
// The is_local_to_unit flag indicates whether a function is local to the
|
||||
|
|
@ -53,15 +49,6 @@ pub fn span_start(cx: &CrateContext, span: Span) -> syntax_pos::Loc {
|
|||
cx.sess().codemap().lookup_char_pos(span.lo())
|
||||
}
|
||||
|
||||
pub fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u32) {
|
||||
(machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits<T>(bytes: T) -> T
|
||||
where T: ops::Mul<Output=T> + From<u8> {
|
||||
bytes * 8u8.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn debug_context<'a, 'tcx>(cx: &'a CrateContext<'a, 'tcx>)
|
||||
-> &'a CrateDebugContext<'tcx> {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,11 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
|||
debug!("calculate size of DST: {}; with lost info: {:?}",
|
||||
t, Value(info));
|
||||
if bcx.ccx.shared().type_is_sized(t) {
|
||||
let size = bcx.ccx.size_of(t);
|
||||
let align = bcx.ccx.align_of(t);
|
||||
debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
|
||||
let (size, align) = bcx.ccx.size_and_align_of(t);
|
||||
debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}",
|
||||
t, Value(info), size, align);
|
||||
let size = C_usize(bcx.ccx, size);
|
||||
let align = C_usize(bcx.ccx, align as u64);
|
||||
let size = C_usize(bcx.ccx, size.bytes());
|
||||
let align = C_usize(bcx.ccx, align.abi());
|
||||
return (size, align);
|
||||
}
|
||||
assert!(!info.is_null());
|
||||
|
|
@ -122,8 +121,9 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
|||
let unit = t.sequence_element_type(bcx.tcx());
|
||||
// The info in this case is the length of the str, so the size is that
|
||||
// times the unit size.
|
||||
(bcx.mul(info, C_usize(bcx.ccx, bcx.ccx.size_of(unit))),
|
||||
C_usize(bcx.ccx, bcx.ccx.align_of(unit) as u64))
|
||||
let (size, align) = bcx.ccx.size_and_align_of(unit);
|
||||
(bcx.mul(info, C_usize(bcx.ccx, size.bytes())),
|
||||
C_usize(bcx.ccx, align.abi()))
|
||||
}
|
||||
_ => bug!("Unexpected unsized type, found {}", t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ use common::*;
|
|||
use declare;
|
||||
use glue;
|
||||
use type_of;
|
||||
use machine;
|
||||
use type_::Type;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::HasDataLayout;
|
||||
use rustc::hir;
|
||||
use syntax::ast;
|
||||
use syntax::symbol::Symbol;
|
||||
|
|
@ -125,7 +125,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
}
|
||||
"try" => {
|
||||
try_intrinsic(bcx, ccx, llargs[0], llargs[1], llargs[2], llresult);
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
"breakpoint" => {
|
||||
let llfn = ccx.get_intrinsic(&("llvm.debugtrap"));
|
||||
|
|
@ -133,42 +133,39 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
}
|
||||
"size_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
C_usize(ccx, ccx.size_of(tp_ty).bytes())
|
||||
}
|
||||
"size_of_val" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
if bcx.ccx.shared().type_is_sized(tp_ty) {
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
C_usize(ccx, ccx.size_of(tp_ty).bytes())
|
||||
} else if bcx.ccx.shared().type_has_metadata(tp_ty) {
|
||||
let (llsize, _) =
|
||||
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
|
||||
llsize
|
||||
} else {
|
||||
C_usize(ccx, 0u64)
|
||||
C_usize(ccx, 0)
|
||||
}
|
||||
}
|
||||
"min_align_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
C_usize(ccx, ccx.align_of(tp_ty) as u64)
|
||||
C_usize(ccx, ccx.align_of(tp_ty).abi())
|
||||
}
|
||||
"min_align_of_val" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
if bcx.ccx.shared().type_is_sized(tp_ty) {
|
||||
C_usize(ccx, ccx.align_of(tp_ty) as u64)
|
||||
C_usize(ccx, ccx.align_of(tp_ty).abi())
|
||||
} else if bcx.ccx.shared().type_has_metadata(tp_ty) {
|
||||
let (_, llalign) =
|
||||
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
|
||||
llalign
|
||||
} else {
|
||||
C_usize(ccx, 1u64)
|
||||
C_usize(ccx, 1)
|
||||
}
|
||||
}
|
||||
"pref_align_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_usize(ccx, machine::llalign_of_pref(ccx, lltp_ty) as u64)
|
||||
C_usize(ccx, ccx.align_of(tp_ty).pref())
|
||||
}
|
||||
"type_name" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
|
|
@ -187,11 +184,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
// large quantities of `mov [byte ptr foo],0` in the generated code.)
|
||||
memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_usize(ccx, 1));
|
||||
}
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
// Effectively no-ops
|
||||
"uninit" => {
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
"needs_drop" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
|
|
@ -232,11 +229,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let tp_ty = substs.type_at(0);
|
||||
let mut ptr = llargs[0];
|
||||
if let Some(ty) = fn_ty.ret.cast {
|
||||
ptr = bcx.pointercast(ptr, ty.ptr_to());
|
||||
ptr = bcx.pointercast(ptr, ty.llvm_type(ccx).ptr_to());
|
||||
}
|
||||
let load = bcx.volatile_load(ptr);
|
||||
unsafe {
|
||||
llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty));
|
||||
llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty).abi() as u32);
|
||||
}
|
||||
to_immediate(bcx, load, tp_ty)
|
||||
},
|
||||
|
|
@ -249,19 +246,18 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let val = if fn_ty.args[1].is_indirect() {
|
||||
bcx.load(llargs[1], None)
|
||||
} else {
|
||||
if !type_is_zero_size(ccx, tp_ty) {
|
||||
from_immediate(bcx, llargs[1])
|
||||
} else {
|
||||
C_nil(ccx)
|
||||
if type_is_zero_size(ccx, tp_ty) {
|
||||
return;
|
||||
}
|
||||
from_immediate(bcx, llargs[1])
|
||||
};
|
||||
let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
|
||||
let store = bcx.volatile_store(val, ptr);
|
||||
unsafe {
|
||||
llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty));
|
||||
llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty).abi() as u32);
|
||||
}
|
||||
}
|
||||
C_nil(ccx)
|
||||
return;
|
||||
},
|
||||
"prefetch_read_data" | "prefetch_write_data" |
|
||||
"prefetch_read_instruction" | "prefetch_write_instruction" => {
|
||||
|
|
@ -279,8 +275,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
|
||||
"overflowing_add" | "overflowing_sub" | "overflowing_mul" |
|
||||
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => {
|
||||
let sty = &arg_tys[0].sty;
|
||||
match int_type_width_signed(sty, ccx) {
|
||||
let ty = arg_tys[0];
|
||||
match int_type_width_signed(ty, ccx) {
|
||||
Some((width, signed)) =>
|
||||
match name {
|
||||
"ctlz" | "cttz" => {
|
||||
|
|
@ -317,7 +313,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
bcx.store(result, bcx.struct_gep(llresult, 0), None);
|
||||
bcx.store(overflow, bcx.struct_gep(llresult, 1), None);
|
||||
|
||||
C_nil(bcx.ccx)
|
||||
return;
|
||||
},
|
||||
"overflowing_add" => bcx.add(llargs[0], llargs[1]),
|
||||
"overflowing_sub" => bcx.sub(llargs[0], llargs[1]),
|
||||
|
|
@ -347,8 +343,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
span_invalid_monomorphization_error(
|
||||
tcx.sess, span,
|
||||
&format!("invalid monomorphization of `{}` intrinsic: \
|
||||
expected basic integer type, found `{}`", name, sty));
|
||||
C_nil(ccx)
|
||||
expected basic integer type, found `{}`", name, ty));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +366,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
tcx.sess, span,
|
||||
&format!("invalid monomorphization of `{}` intrinsic: \
|
||||
expected basic float type, found `{}`", name, sty));
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,11 +395,14 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
bcx.select(is_zero, zero, bcx.sub(offset, llargs[1]))
|
||||
}
|
||||
name if name.starts_with("simd_") => {
|
||||
generic_simd_intrinsic(bcx, name,
|
||||
callee_ty,
|
||||
&llargs,
|
||||
ret_ty, llret_ty,
|
||||
span)
|
||||
match generic_simd_intrinsic(bcx, name,
|
||||
callee_ty,
|
||||
&llargs,
|
||||
ret_ty, llret_ty,
|
||||
span) {
|
||||
Ok(llval) => llval,
|
||||
Err(()) => return
|
||||
}
|
||||
}
|
||||
// This requires that atomic intrinsics follow a specific naming pattern:
|
||||
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
|
||||
|
|
@ -437,16 +436,16 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
_ => ccx.sess().fatal("Atomic intrinsic not in correct format"),
|
||||
};
|
||||
|
||||
let invalid_monomorphization = |sty| {
|
||||
let invalid_monomorphization = |ty| {
|
||||
span_invalid_monomorphization_error(tcx.sess, span,
|
||||
&format!("invalid monomorphization of `{}` intrinsic: \
|
||||
expected basic integer type, found `{}`", name, sty));
|
||||
expected basic integer type, found `{}`", name, ty));
|
||||
};
|
||||
|
||||
match split[1] {
|
||||
"cxchg" | "cxchgweak" => {
|
||||
let sty = &substs.type_at(0).sty;
|
||||
if int_type_width_signed(sty, ccx).is_some() {
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, ccx).is_some() {
|
||||
let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False };
|
||||
let val = bcx.atomic_cmpxchg(llargs[0], llargs[1], llargs[2], order,
|
||||
failorder, weak);
|
||||
|
|
@ -454,40 +453,41 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let success = bcx.zext(bcx.extract_value(val, 1), Type::bool(bcx.ccx));
|
||||
bcx.store(result, bcx.struct_gep(llresult, 0), None);
|
||||
bcx.store(success, bcx.struct_gep(llresult, 1), None);
|
||||
return;
|
||||
} else {
|
||||
invalid_monomorphization(sty);
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
C_nil(ccx)
|
||||
}
|
||||
|
||||
"load" => {
|
||||
let sty = &substs.type_at(0).sty;
|
||||
if int_type_width_signed(sty, ccx).is_some() {
|
||||
bcx.atomic_load(llargs[0], order)
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, ccx).is_some() {
|
||||
let align = ccx.align_of(ty);
|
||||
bcx.atomic_load(llargs[0], order, align)
|
||||
} else {
|
||||
invalid_monomorphization(sty);
|
||||
C_nil(ccx)
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
}
|
||||
|
||||
"store" => {
|
||||
let sty = &substs.type_at(0).sty;
|
||||
if int_type_width_signed(sty, ccx).is_some() {
|
||||
bcx.atomic_store(llargs[1], llargs[0], order);
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, ccx).is_some() {
|
||||
let align = ccx.align_of(ty);
|
||||
bcx.atomic_store(llargs[1], llargs[0], order, align);
|
||||
return;
|
||||
} else {
|
||||
invalid_monomorphization(sty);
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
C_nil(ccx)
|
||||
}
|
||||
|
||||
"fence" => {
|
||||
bcx.atomic_fence(order, llvm::SynchronizationScope::CrossThread);
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
|
||||
"singlethreadfence" => {
|
||||
bcx.atomic_fence(order, llvm::SynchronizationScope::SingleThread);
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
|
||||
// These are all AtomicRMW ops
|
||||
|
|
@ -507,12 +507,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
_ => ccx.sess().fatal("unknown atomic operation")
|
||||
};
|
||||
|
||||
let sty = &substs.type_at(0).sty;
|
||||
if int_type_width_signed(sty, ccx).is_some() {
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, ccx).is_some() {
|
||||
bcx.atomic_rmw(atom_op, llargs[0], llargs[1], order)
|
||||
} else {
|
||||
invalid_monomorphization(sty);
|
||||
C_nil(ccx)
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -662,16 +661,16 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let (dest, align) = lval.trans_field_ptr(bcx, i);
|
||||
bcx.store(val, dest, align.to_align());
|
||||
}
|
||||
C_nil(ccx)
|
||||
return;
|
||||
}
|
||||
_ => val,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
|
||||
if !fn_ty.ret.is_ignore() {
|
||||
if let Some(ty) = fn_ty.ret.cast {
|
||||
let ptr = bcx.pointercast(llresult, ty.ptr_to());
|
||||
let ptr = bcx.pointercast(llresult, ty.llvm_type(ccx).ptr_to());
|
||||
bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
|
||||
} else {
|
||||
store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty);
|
||||
|
|
@ -682,16 +681,15 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
allow_overlap: bool,
|
||||
volatile: bool,
|
||||
tp_ty: Ty<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
dst: ValueRef,
|
||||
src: ValueRef,
|
||||
count: ValueRef)
|
||||
-> ValueRef {
|
||||
let ccx = bcx.ccx;
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
|
||||
let size = machine::llsize_of(ccx, lltp_ty);
|
||||
let int_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
|
||||
let (size, align) = ccx.size_and_align_of(ty);
|
||||
let size = C_usize(ccx, size.bytes());
|
||||
let align = C_i32(ccx, align.abi() as i32);
|
||||
|
||||
let operation = if allow_overlap {
|
||||
"memmove"
|
||||
|
|
@ -699,7 +697,8 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
"memcpy"
|
||||
};
|
||||
|
||||
let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, int_size);
|
||||
let name = format!("llvm.{}.p0i8.p0i8.i{}", operation,
|
||||
ccx.data_layout().pointer_size.bits());
|
||||
|
||||
let dst_ptr = bcx.pointercast(dst, Type::i8p(ccx));
|
||||
let src_ptr = bcx.pointercast(src, Type::i8p(ccx));
|
||||
|
|
@ -723,9 +722,9 @@ fn memset_intrinsic<'a, 'tcx>(
|
|||
count: ValueRef
|
||||
) -> ValueRef {
|
||||
let ccx = bcx.ccx;
|
||||
let align = C_i32(ccx, ccx.align_of(ty) as i32);
|
||||
let lltp_ty = type_of::type_of(ccx, ty);
|
||||
let size = machine::llsize_of(ccx, lltp_ty);
|
||||
let (size, align) = ccx.size_and_align_of(ty);
|
||||
let size = C_usize(ccx, size.bytes());
|
||||
let align = C_i32(ccx, align.abi() as i32);
|
||||
let dst = bcx.pointercast(dst, Type::i8p(ccx));
|
||||
call_memset(bcx, dst, val, bcx.mul(size, count), align, volatile)
|
||||
}
|
||||
|
|
@ -975,7 +974,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
ret_ty: Ty<'tcx>,
|
||||
llret_ty: Type,
|
||||
span: Span
|
||||
) -> ValueRef {
|
||||
) -> Result<ValueRef, ()> {
|
||||
// macros for error handling:
|
||||
macro_rules! emit_error {
|
||||
($msg: tt) => {
|
||||
|
|
@ -993,7 +992,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
($cond: expr, $($fmt: tt)*) => {
|
||||
if !$cond {
|
||||
emit_error!($($fmt)*);
|
||||
return C_nil(bcx.ccx)
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1039,12 +1038,12 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
ret_ty,
|
||||
ret_ty.simd_type(tcx));
|
||||
|
||||
return compare_simd_types(bcx,
|
||||
llargs[0],
|
||||
llargs[1],
|
||||
in_elem,
|
||||
llret_ty,
|
||||
cmp_op)
|
||||
return Ok(compare_simd_types(bcx,
|
||||
llargs[0],
|
||||
llargs[1],
|
||||
in_elem,
|
||||
llret_ty,
|
||||
cmp_op))
|
||||
}
|
||||
|
||||
if name.starts_with("simd_shuffle") {
|
||||
|
|
@ -1090,23 +1089,23 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
.collect();
|
||||
let indices = match indices {
|
||||
Some(i) => i,
|
||||
None => return C_null(llret_ty)
|
||||
None => return Ok(C_null(llret_ty))
|
||||
};
|
||||
|
||||
return bcx.shuffle_vector(llargs[0], llargs[1], C_vector(&indices))
|
||||
return Ok(bcx.shuffle_vector(llargs[0], llargs[1], C_vector(&indices)))
|
||||
}
|
||||
|
||||
if name == "simd_insert" {
|
||||
require!(in_elem == arg_tys[2],
|
||||
"expected inserted type `{}` (element of input `{}`), found `{}`",
|
||||
in_elem, in_ty, arg_tys[2]);
|
||||
return bcx.insert_element(llargs[0], llargs[2], llargs[1])
|
||||
return Ok(bcx.insert_element(llargs[0], llargs[2], llargs[1]))
|
||||
}
|
||||
if name == "simd_extract" {
|
||||
require!(ret_ty == in_elem,
|
||||
"expected return type `{}` (element of input `{}`), found `{}`",
|
||||
in_elem, in_ty, ret_ty);
|
||||
return bcx.extract_element(llargs[0], llargs[1])
|
||||
return Ok(bcx.extract_element(llargs[0], llargs[1]))
|
||||
}
|
||||
|
||||
if name == "simd_cast" {
|
||||
|
|
@ -1120,7 +1119,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
// casting cares about nominal type, not just structural type
|
||||
let out_elem = ret_ty.simd_type(tcx);
|
||||
|
||||
if in_elem == out_elem { return llargs[0]; }
|
||||
if in_elem == out_elem { return Ok(llargs[0]); }
|
||||
|
||||
enum Style { Float, Int(/* is signed? */ bool), Unsupported }
|
||||
|
||||
|
|
@ -1141,7 +1140,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
|
||||
match (in_style, out_style) {
|
||||
(Style::Int(in_is_signed), Style::Int(_)) => {
|
||||
return match in_width.cmp(&out_width) {
|
||||
return Ok(match in_width.cmp(&out_width) {
|
||||
Ordering::Greater => bcx.trunc(llargs[0], llret_ty),
|
||||
Ordering::Equal => llargs[0],
|
||||
Ordering::Less => if in_is_signed {
|
||||
|
|
@ -1149,28 +1148,28 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
} else {
|
||||
bcx.zext(llargs[0], llret_ty)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
(Style::Int(in_is_signed), Style::Float) => {
|
||||
return if in_is_signed {
|
||||
return Ok(if in_is_signed {
|
||||
bcx.sitofp(llargs[0], llret_ty)
|
||||
} else {
|
||||
bcx.uitofp(llargs[0], llret_ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
(Style::Float, Style::Int(out_is_signed)) => {
|
||||
return if out_is_signed {
|
||||
return Ok(if out_is_signed {
|
||||
bcx.fptosi(llargs[0], llret_ty)
|
||||
} else {
|
||||
bcx.fptoui(llargs[0], llret_ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
(Style::Float, Style::Float) => {
|
||||
return match in_width.cmp(&out_width) {
|
||||
return Ok(match in_width.cmp(&out_width) {
|
||||
Ordering::Greater => bcx.fptrunc(llargs[0], llret_ty),
|
||||
Ordering::Equal => llargs[0],
|
||||
Ordering::Less => bcx.fpext(llargs[0], llret_ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => {/* Unsupported. Fallthrough. */}
|
||||
}
|
||||
|
|
@ -1186,7 +1185,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
match in_elem.sty {
|
||||
$(
|
||||
$(ty::$p(_))|* => {
|
||||
return bcx.$call(llargs[0], llargs[1])
|
||||
return Ok(bcx.$call(llargs[0], llargs[1]))
|
||||
}
|
||||
)*
|
||||
_ => {},
|
||||
|
|
@ -1213,15 +1212,13 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
|||
span_bug!(span, "unknown SIMD intrinsic");
|
||||
}
|
||||
|
||||
// Returns the width of an int TypeVariant, and if it's signed or not
|
||||
// Returns the width of an int Ty, and if it's signed or not
|
||||
// Returns None if the type is not an integer
|
||||
// FIXME: there’s multiple of this functions, investigate using some of the already existing
|
||||
// stuffs.
|
||||
fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext)
|
||||
-> Option<(u64, bool)> {
|
||||
use rustc::ty::{TyInt, TyUint};
|
||||
match *sty {
|
||||
TyInt(t) => Some((match t {
|
||||
fn int_type_width_signed(ty: Ty, ccx: &CrateContext) -> Option<(u64, bool)> {
|
||||
match ty.sty {
|
||||
ty::TyInt(t) => Some((match t {
|
||||
ast::IntTy::Is => {
|
||||
match &ccx.tcx().sess.target.target.target_pointer_width[..] {
|
||||
"16" => 16,
|
||||
|
|
@ -1236,7 +1233,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext)
|
|||
ast::IntTy::I64 => 64,
|
||||
ast::IntTy::I128 => 128,
|
||||
}, true)),
|
||||
TyUint(t) => Some((match t {
|
||||
ty::TyUint(t) => Some((match t {
|
||||
ast::UintTy::Us => {
|
||||
match &ccx.tcx().sess.target.target.target_pointer_width[..] {
|
||||
"16" => 16,
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ mod declare;
|
|||
mod glue;
|
||||
mod intrinsic;
|
||||
mod llvm_util;
|
||||
mod machine;
|
||||
mod metadata;
|
||||
mod meth;
|
||||
mod mir;
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Information concerning the machine representation of various types.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use llvm::{self, ValueRef};
|
||||
use common::*;
|
||||
|
||||
use type_::Type;
|
||||
|
||||
pub type llbits = u64;
|
||||
pub type llsize = u64;
|
||||
pub type llalign = u32;
|
||||
|
||||
// ______________________________________________________________________
|
||||
// compute sizeof / alignof
|
||||
|
||||
// Returns the number of bytes between successive elements of type T in an
|
||||
// array of T. This is the "ABI" size. It includes any ABI-mandated padding.
|
||||
pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> llsize {
|
||||
unsafe {
|
||||
return llvm::LLVMABISizeOfType(cx.td(), ty.to_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the "real" size of the type in bits.
|
||||
pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> llbits {
|
||||
unsafe {
|
||||
llvm::LLVMSizeOfTypeInBits(cx.td(), ty.to_ref())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the size of the type as an LLVM constant integer value.
|
||||
pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
|
||||
// Once upon a time, this called LLVMSizeOf, which does a
|
||||
// getelementptr(1) on a null pointer and casts to an int, in
|
||||
// order to obtain the type size as a value without requiring the
|
||||
// target data layout. But we have the target data layout, so
|
||||
// there's no need for that contrivance. The instruction
|
||||
// selection DAG generator would flatten that GEP(1) node into a
|
||||
// constant of the type's alloc size, so let's save it some work.
|
||||
return C_usize(cx, llsize_of_alloc(cx, ty));
|
||||
}
|
||||
|
||||
// Returns the preferred alignment of the given type for the current target.
|
||||
// The preferred alignment may be larger than the alignment used when
|
||||
// packing the type into structs. This will be used for things like
|
||||
// allocations inside a stack frame, which LLVM has a free hand in.
|
||||
pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> llalign {
|
||||
unsafe {
|
||||
return llvm::LLVMPreferredAlignmentOfType(cx.td(), ty.to_ref());
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the minimum alignment of a type required by the platform.
|
||||
// This is the alignment that will be used for struct fields, arrays,
|
||||
// and similar ABI-mandated things.
|
||||
pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign {
|
||||
unsafe {
|
||||
return llvm::LLVMABIAlignmentOfType(cx.td(), ty.to_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 {
|
||||
unsafe {
|
||||
return llvm::LLVMOffsetOfElement(cx.td(),
|
||||
struct_ty.to_ref(),
|
||||
element as u32);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,11 +13,11 @@ use callee;
|
|||
use common::*;
|
||||
use builder::Builder;
|
||||
use consts;
|
||||
use machine;
|
||||
use monomorphize;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::HasDataLayout;
|
||||
use debuginfo;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -79,10 +79,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// Not in the cache. Build it.
|
||||
let nullptr = C_null(Type::nil(ccx).ptr_to());
|
||||
|
||||
let (size, align) = ccx.size_and_align_of(ty);
|
||||
let mut components: Vec<_> = [
|
||||
callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.tcx(), ty)),
|
||||
C_usize(ccx, ccx.size_of(ty)),
|
||||
C_usize(ccx, ccx.align_of(ty) as u64)
|
||||
C_usize(ccx, size.bytes()),
|
||||
C_usize(ccx, align.abi())
|
||||
].iter().cloned().collect();
|
||||
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
|
|
@ -97,7 +98,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
let vtable_const = C_struct(ccx, &components, false);
|
||||
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
|
||||
let align = ccx.data_layout().pointer_align;
|
||||
let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
|
||||
|
||||
debuginfo::create_vtable_metadata(ccx, ty, vtable);
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ use rustc::traits;
|
|||
use rustc::mir;
|
||||
use abi::{Abi, FnType, ArgType};
|
||||
use adt;
|
||||
use base::{self, Lifetime};
|
||||
use base;
|
||||
use callee;
|
||||
use builder::Builder;
|
||||
use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_undef};
|
||||
use consts;
|
||||
use machine::llalign_of_min;
|
||||
use meth;
|
||||
use monomorphize;
|
||||
use type_of;
|
||||
|
|
@ -31,8 +30,6 @@ use type_::Type;
|
|||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Pos;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use super::{MirContext, LocalRef};
|
||||
use super::constant::Const;
|
||||
use super::lvalue::{Alignment, LvalueRef};
|
||||
|
|
@ -120,7 +117,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
fn_ty: FnType<'tcx>,
|
||||
fn_ptr: ValueRef,
|
||||
llargs: &[ValueRef],
|
||||
destination: Option<(ReturnDest, Ty<'tcx>, mir::BasicBlock)>,
|
||||
destination: Option<(ReturnDest<'tcx>, Ty<'tcx>, mir::BasicBlock)>,
|
||||
cleanup: Option<mir::BasicBlock>
|
||||
| {
|
||||
if let Some(cleanup) = cleanup {
|
||||
|
|
@ -175,14 +172,23 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
if let Some(cleanup_pad) = cleanup_pad {
|
||||
bcx.cleanup_ret(cleanup_pad, None);
|
||||
} else {
|
||||
let ps = self.get_personality_slot(&bcx);
|
||||
let lp = bcx.load(ps, None);
|
||||
Lifetime::End.call(&bcx, ps);
|
||||
let slot = self.get_personality_slot(&bcx);
|
||||
|
||||
let (lp0ptr, align) = slot.trans_field_ptr(&bcx, 0);
|
||||
let lp0 = bcx.load(lp0ptr, align.to_align());
|
||||
|
||||
let (lp1ptr, align) = slot.trans_field_ptr(&bcx, 1);
|
||||
let lp1 = bcx.load(lp1ptr, align.to_align());
|
||||
|
||||
slot.storage_dead(&bcx);
|
||||
|
||||
if !bcx.sess().target.target.options.custom_unwind_resume {
|
||||
let mut lp = C_undef(self.landing_pad_type());
|
||||
lp = bcx.insert_value(lp, lp0, 0);
|
||||
lp = bcx.insert_value(lp, lp1, 1);
|
||||
bcx.resume(lp);
|
||||
} else {
|
||||
let exc_ptr = bcx.extract_value(lp, 0);
|
||||
bcx.call(bcx.ccx.eh_unwind_resume(), &[exc_ptr], cleanup_bundle);
|
||||
bcx.call(bcx.ccx.eh_unwind_resume(), &[lp0], cleanup_bundle);
|
||||
bcx.unreachable();
|
||||
}
|
||||
}
|
||||
|
|
@ -245,8 +251,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
let load = bcx.load(
|
||||
bcx.pointercast(llslot, cast_ty.ptr_to()),
|
||||
Some(ret.layout.align(bcx.ccx).abi() as u32));
|
||||
bcx.pointercast(llslot, cast_ty.llvm_type(bcx.ccx).ptr_to()),
|
||||
Some(ret.layout.align(bcx.ccx)));
|
||||
load
|
||||
} else {
|
||||
let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
|
||||
|
|
@ -336,6 +342,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let filename = C_str_slice(bcx.ccx, filename);
|
||||
let line = C_u32(bcx.ccx, loc.line as u32);
|
||||
let col = C_u32(bcx.ccx, loc.col.to_usize() as u32 + 1);
|
||||
let align = tcx.data_layout.aggregate_align
|
||||
.max(tcx.data_layout.i32_align)
|
||||
.max(tcx.data_layout.pointer_align);
|
||||
|
||||
// Put together the arguments to the panic entry point.
|
||||
let (lang_item, args, const_err) = match *msg {
|
||||
|
|
@ -351,7 +360,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}));
|
||||
|
||||
let file_line_col = C_struct(bcx.ccx, &[filename, line, col], false);
|
||||
let align = llalign_of_min(bcx.ccx, common::val_ty(file_line_col));
|
||||
let file_line_col = consts::addr_of(bcx.ccx,
|
||||
file_line_col,
|
||||
align,
|
||||
|
|
@ -366,7 +374,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let msg_file_line_col = C_struct(bcx.ccx,
|
||||
&[msg_str, filename, line, col],
|
||||
false);
|
||||
let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line_col));
|
||||
let msg_file_line_col = consts::addr_of(bcx.ccx,
|
||||
msg_file_line_col,
|
||||
align,
|
||||
|
|
@ -387,7 +394,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let msg_file_line_col = C_struct(bcx.ccx,
|
||||
&[msg_str, filename, line, col],
|
||||
false);
|
||||
let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line_col));
|
||||
let msg_file_line_col = consts::addr_of(bcx.ccx,
|
||||
msg_file_line_col,
|
||||
align,
|
||||
|
|
@ -552,7 +558,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
ReturnDest::Nothing => {
|
||||
(C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..])
|
||||
}
|
||||
ReturnDest::IndirectOperand(dst, _) |
|
||||
ReturnDest::IndirectOperand(dst, _) => (dst.llval, &llargs[..]),
|
||||
ReturnDest::Store(dst) => (dst, &llargs[..]),
|
||||
ReturnDest::DirectOperand(_) =>
|
||||
bug!("Cannot use direct operand with an intrinsic call")
|
||||
|
|
@ -566,7 +572,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||
// Make a fake operand for store_return
|
||||
let op = OperandRef {
|
||||
val: Ref(dst, Alignment::AbiAligned),
|
||||
val: Ref(dst.llval, Alignment::AbiAligned),
|
||||
ty: sig.output(),
|
||||
};
|
||||
self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
|
||||
|
|
@ -633,7 +639,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
// Fill padding with undef value, where applicable.
|
||||
if let Some(ty) = arg.pad {
|
||||
llargs.push(C_undef(ty));
|
||||
llargs.push(C_undef(ty.llvm_type(bcx.ccx)));
|
||||
}
|
||||
|
||||
if arg.is_ignore() {
|
||||
|
|
@ -651,13 +657,13 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
(op.pack_if_pair(bcx).immediate(), Alignment::AbiAligned, false)
|
||||
}
|
||||
}
|
||||
Ref(llval, Alignment::Packed) if arg.is_indirect() => {
|
||||
Ref(llval, align @ Alignment::Packed) if arg.is_indirect() => {
|
||||
// `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I
|
||||
// think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
|
||||
// have scary latent bugs around.
|
||||
|
||||
let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None);
|
||||
base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1));
|
||||
base::memcpy_ty(bcx, llscratch, llval, op.ty, align.to_align());
|
||||
(llscratch, Alignment::AbiAligned, true)
|
||||
}
|
||||
Ref(llval, align) => (llval, align, true)
|
||||
|
|
@ -670,8 +676,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None);
|
||||
llval = bcx.trunc(llval, Type::i1(bcx.ccx));
|
||||
} else if let Some(ty) = arg.cast {
|
||||
llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()),
|
||||
align.min_with(arg.layout.align(bcx.ccx).abi() as u32));
|
||||
llval = bcx.load(bcx.pointercast(llval, ty.llvm_type(bcx.ccx).ptr_to()),
|
||||
align.min_with(Some(arg.layout.align(bcx.ccx))));
|
||||
} else {
|
||||
llval = bcx.load(llval, align.to_align());
|
||||
}
|
||||
|
|
@ -759,14 +765,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
}
|
||||
|
||||
fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
|
||||
fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> LvalueRef<'tcx> {
|
||||
let ccx = bcx.ccx;
|
||||
if let Some(slot) = self.llpersonalityslot {
|
||||
if let Some(slot) = self.personality_slot {
|
||||
slot
|
||||
} else {
|
||||
let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
|
||||
let slot = bcx.alloca(llretty, "personalityslot", None);
|
||||
self.llpersonalityslot = Some(slot);
|
||||
let ty = ccx.tcx().intern_tup(&[
|
||||
ccx.tcx().mk_mut_ptr(ccx.tcx().types.u8),
|
||||
ccx.tcx().types.i32
|
||||
], false);
|
||||
let slot = LvalueRef::alloca(bcx, ty, "personalityslot");
|
||||
self.personality_slot = Some(slot);
|
||||
slot
|
||||
}
|
||||
}
|
||||
|
|
@ -794,16 +803,26 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
let ccx = bcx.ccx;
|
||||
let llpersonality = self.ccx.eh_personality();
|
||||
let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
|
||||
let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn);
|
||||
bcx.set_cleanup(llretval);
|
||||
let llretty = self.landing_pad_type();
|
||||
let lp = bcx.landing_pad(llretty, llpersonality, 1, self.llfn);
|
||||
bcx.set_cleanup(lp);
|
||||
|
||||
let slot = self.get_personality_slot(&bcx);
|
||||
Lifetime::Start.call(&bcx, slot);
|
||||
bcx.store(llretval, slot, None);
|
||||
slot.storage_live(&bcx);
|
||||
self.store_operand(&bcx, slot.llval, None, OperandRef {
|
||||
val: Pair(bcx.extract_value(lp, 0), bcx.extract_value(lp, 1)),
|
||||
ty: slot.ty.to_ty(ccx.tcx())
|
||||
});
|
||||
|
||||
bcx.br(target_bb);
|
||||
bcx.llbb()
|
||||
}
|
||||
|
||||
fn landing_pad_type(&self) -> Type {
|
||||
let ccx = self.ccx;
|
||||
Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false)
|
||||
}
|
||||
|
||||
fn unreachable_block(&mut self) -> BasicBlockRef {
|
||||
self.unreachable_block.unwrap_or_else(|| {
|
||||
let bl = self.new_block("unreachable");
|
||||
|
|
@ -825,7 +844,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
fn make_return_dest(&mut self, bcx: &Builder<'a, 'tcx>,
|
||||
dest: &mir::Lvalue<'tcx>, fn_ret_ty: &ArgType,
|
||||
llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest {
|
||||
llargs: &mut Vec<ValueRef>, is_intrinsic: bool)
|
||||
-> ReturnDest<'tcx> {
|
||||
// If the return is ignored, we can just return a do-nothing ReturnDest
|
||||
if fn_ret_ty.is_ignore() {
|
||||
return ReturnDest::Nothing;
|
||||
|
|
@ -841,14 +861,16 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
// Odd, but possible, case, we have an operand temporary,
|
||||
// but the calling convention has an indirect return.
|
||||
let tmp = LvalueRef::alloca(bcx, ret_ty, "tmp_ret");
|
||||
tmp.storage_live(bcx);
|
||||
llargs.push(tmp.llval);
|
||||
ReturnDest::IndirectOperand(tmp.llval, index)
|
||||
ReturnDest::IndirectOperand(tmp, index)
|
||||
} else if is_intrinsic {
|
||||
// Currently, intrinsics always need a location to store
|
||||
// the result. so we create a temporary alloca for the
|
||||
// result
|
||||
let tmp = LvalueRef::alloca(bcx, ret_ty, "tmp_ret");
|
||||
ReturnDest::IndirectOperand(tmp.llval, index)
|
||||
tmp.storage_live(bcx);
|
||||
ReturnDest::IndirectOperand(tmp, index)
|
||||
} else {
|
||||
ReturnDest::DirectOperand(index)
|
||||
};
|
||||
|
|
@ -891,8 +913,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let lvalue_ty = self.monomorphized_lvalue_ty(dst);
|
||||
assert!(!lvalue_ty.has_erasable_regions());
|
||||
let lvalue = LvalueRef::alloca(bcx, lvalue_ty, "transmute_temp");
|
||||
lvalue.storage_live(bcx);
|
||||
self.trans_transmute_into(bcx, src, &lvalue);
|
||||
let op = self.trans_load(bcx, lvalue.llval, lvalue.alignment, lvalue_ty);
|
||||
lvalue.storage_dead(bcx);
|
||||
self.locals[index] = LocalRef::Operand(Some(op));
|
||||
}
|
||||
LocalRef::Operand(Some(_)) => {
|
||||
|
|
@ -915,15 +939,15 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
|
||||
let in_type = val.ty;
|
||||
let out_type = dst.ty.to_ty(bcx.tcx());
|
||||
let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type));
|
||||
self.store_operand(bcx, cast_ptr, Some(llalign), val);
|
||||
let align = bcx.ccx.align_of(in_type).min(bcx.ccx.align_of(out_type));
|
||||
self.store_operand(bcx, cast_ptr, Some(align), val);
|
||||
}
|
||||
|
||||
|
||||
// Stores the return value of a function call into it's final location.
|
||||
fn store_return(&mut self,
|
||||
bcx: &Builder<'a, 'tcx>,
|
||||
dest: ReturnDest,
|
||||
dest: ReturnDest<'tcx>,
|
||||
ret_ty: &ArgType<'tcx>,
|
||||
op: OperandRef<'tcx>) {
|
||||
use self::ReturnDest::*;
|
||||
|
|
@ -932,15 +956,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
Nothing => (),
|
||||
Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
|
||||
IndirectOperand(tmp, index) => {
|
||||
let op = self.trans_load(bcx, tmp, Alignment::AbiAligned, op.ty);
|
||||
let op = self.trans_load(bcx, tmp.llval, Alignment::AbiAligned, op.ty);
|
||||
tmp.storage_dead(bcx);
|
||||
self.locals[index] = LocalRef::Operand(Some(op));
|
||||
}
|
||||
DirectOperand(index) => {
|
||||
// If there is a cast, we have to store and reload.
|
||||
let op = if ret_ty.cast.is_some() {
|
||||
let tmp = LvalueRef::alloca(bcx, op.ty, "tmp_ret");
|
||||
tmp.storage_live(bcx);
|
||||
ret_ty.store(bcx, op.immediate(), tmp.llval);
|
||||
self.trans_load(bcx, tmp.llval, tmp.alignment, op.ty)
|
||||
let op = self.trans_load(bcx, tmp.llval, tmp.alignment, op.ty);
|
||||
tmp.storage_dead(bcx);
|
||||
op
|
||||
} else {
|
||||
op.unpack_if_pair(bcx)
|
||||
};
|
||||
|
|
@ -950,13 +978,13 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
enum ReturnDest {
|
||||
enum ReturnDest<'tcx> {
|
||||
// Do nothing, the return value is indirect or ignored
|
||||
Nothing,
|
||||
// Store the return value to the pointer
|
||||
Store(ValueRef),
|
||||
// Stores an indirect return value to an operand local lvalue
|
||||
IndirectOperand(ValueRef, mir::Local),
|
||||
IndirectOperand(LvalueRef<'tcx>, mir::Local),
|
||||
// Stores a direct return value to an operand local lvalue
|
||||
DirectOperand(mir::Local)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ use rustc::traits;
|
|||
use rustc::mir;
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use rustc::ty::layout::{self, LayoutTyper, Size};
|
||||
use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::subst::{Kind, Substs, Subst};
|
||||
use rustc_apfloat::{ieee, Float, Status};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use {adt, base, machine};
|
||||
use {adt, base};
|
||||
use abi::{self, Abi};
|
||||
use callee;
|
||||
use builder::Builder;
|
||||
|
|
@ -100,9 +100,11 @@ impl<'tcx> Const<'tcx> {
|
|||
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
|
||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(v) => consts::addr_of(ccx, C_bytes(ccx, v.data), 1, "byte_str"),
|
||||
ConstVal::ByteStr(v) => {
|
||||
consts::addr_of(ccx, C_bytes(ccx, v.data), ccx.align_of(ty), "byte_str")
|
||||
}
|
||||
ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
|
||||
ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
|
||||
ConstVal::Function(..) => C_null(llty),
|
||||
ConstVal::Variant(_) |
|
||||
ConstVal::Aggregate(..) |
|
||||
ConstVal::Unevaluated(..) => {
|
||||
|
|
@ -368,12 +370,12 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
match &tcx.item_name(def_id)[..] {
|
||||
"size_of" => {
|
||||
let llval = C_usize(self.ccx,
|
||||
self.ccx.size_of(substs.type_at(0)));
|
||||
self.ccx.size_of(substs.type_at(0)).bytes());
|
||||
Ok(Const::new(llval, tcx.types.usize))
|
||||
}
|
||||
"min_align_of" => {
|
||||
let llval = C_usize(self.ccx,
|
||||
self.ccx.align_of(substs.type_at(0)) as u64);
|
||||
self.ccx.align_of(substs.type_at(0)).abi());
|
||||
Ok(Const::new(llval, tcx.types.usize))
|
||||
}
|
||||
_ => span_bug!(span, "{:?} in constant", terminator.kind)
|
||||
|
|
@ -590,7 +592,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
self.const_array(dest_ty, &fields)
|
||||
}
|
||||
|
||||
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
||||
mir::Rvalue::Aggregate(box mir::AggregateKind::Array(_), ref operands) => {
|
||||
// Make sure to evaluate all operands to
|
||||
// report as many errors as we possibly can.
|
||||
let mut fields = Vec::with_capacity(operands.len());
|
||||
|
|
@ -603,17 +605,23 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
}
|
||||
failure?;
|
||||
|
||||
match **kind {
|
||||
mir::AggregateKind::Array(_) => {
|
||||
self.const_array(dest_ty, &fields)
|
||||
}
|
||||
mir::AggregateKind::Adt(..) |
|
||||
mir::AggregateKind::Closure(..) |
|
||||
mir::AggregateKind::Generator(..) |
|
||||
mir::AggregateKind::Tuple => {
|
||||
Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty)
|
||||
self.const_array(dest_ty, &fields)
|
||||
}
|
||||
|
||||
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
||||
// Make sure to evaluate all operands to
|
||||
// report as many errors as we possibly can.
|
||||
let mut fields = Vec::with_capacity(operands.len());
|
||||
let mut failure = Ok(());
|
||||
for operand in operands {
|
||||
match self.const_operand(operand, span) {
|
||||
Ok(val) => fields.push(val),
|
||||
Err(err) => if failure.is_ok() { failure = Err(err); }
|
||||
}
|
||||
}
|
||||
failure?;
|
||||
|
||||
trans_const_adt(self.ccx, dest_ty, kind, &fields)
|
||||
}
|
||||
|
||||
mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
|
||||
|
|
@ -780,7 +788,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
let align = if self.ccx.shared().type_is_sized(ty) {
|
||||
self.ccx.align_of(ty)
|
||||
} else {
|
||||
self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
|
||||
self.ccx.tcx().data_layout.pointer_align
|
||||
};
|
||||
if bk == mir::BorrowKind::Mut {
|
||||
consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
|
||||
|
|
@ -860,7 +868,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
|
||||
mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
assert!(self.ccx.shared().type_is_sized(ty));
|
||||
let llval = C_usize(self.ccx, self.ccx.size_of(ty));
|
||||
let llval = C_usize(self.ccx, self.ccx.size_of(ty).bytes());
|
||||
Const::new(llval, tcx.types.usize)
|
||||
}
|
||||
|
||||
|
|
@ -1099,12 +1107,12 @@ pub fn trans_static_initializer<'a, 'tcx>(
|
|||
/// Currently the returned value has the same size as the type, but
|
||||
/// this could be changed in the future to avoid allocating unnecessary
|
||||
/// space after values of shorter-than-maximum cases.
|
||||
fn trans_const<'a, 'tcx>(
|
||||
fn trans_const_adt<'a, 'tcx>(
|
||||
ccx: &CrateContext<'a, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
kind: &mir::AggregateKind,
|
||||
vals: &[ValueRef]
|
||||
) -> ValueRef {
|
||||
vals: &[Const<'tcx>]
|
||||
) -> Const<'tcx> {
|
||||
let l = ccx.layout_of(t);
|
||||
let variant_index = match *kind {
|
||||
mir::AggregateKind::Adt(_, index, _, _) => index,
|
||||
|
|
@ -1121,112 +1129,97 @@ fn trans_const<'a, 'tcx>(
|
|||
};
|
||||
assert_eq!(vals.len(), 0);
|
||||
adt::assert_discr_in_range(min, max, discr);
|
||||
C_int(Type::from_integer(ccx, d), discr as i64)
|
||||
Const::new(C_int(Type::from_integer(ccx, d), discr as i64), t)
|
||||
}
|
||||
layout::General { discr: d, ref variants, .. } => {
|
||||
let variant = &variants[variant_index];
|
||||
let lldiscr = C_int(Type::from_integer(ccx, d), variant_index as i64);
|
||||
let mut vals_with_discr = vec![lldiscr];
|
||||
let mut vals_with_discr = vec![
|
||||
Const::new(lldiscr, d.to_ty(ccx.tcx(), false))
|
||||
];
|
||||
vals_with_discr.extend_from_slice(vals);
|
||||
let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
|
||||
let needed_padding = l.size(ccx).bytes() - variant.stride().bytes();
|
||||
if needed_padding > 0 {
|
||||
contents.push(padding(ccx, needed_padding));
|
||||
}
|
||||
C_struct(ccx, &contents[..], false)
|
||||
build_const_struct(ccx, l, &variant, &vals_with_discr)
|
||||
}
|
||||
layout::UntaggedUnion { ref variants, .. }=> {
|
||||
assert_eq!(variant_index, 0);
|
||||
let contents = build_const_union(ccx, variants, vals[0]);
|
||||
C_struct(ccx, &contents, variants.packed)
|
||||
let mut contents = vec![vals[0].llval];
|
||||
|
||||
let offset = ccx.size_of(vals[0].ty);
|
||||
let size = variants.stride();
|
||||
if offset != size {
|
||||
contents.push(padding(ccx, size - offset));
|
||||
}
|
||||
|
||||
Const::new(C_struct(ccx, &contents, variants.packed), t)
|
||||
}
|
||||
layout::Univariant { ref variant, .. } => {
|
||||
assert_eq!(variant_index, 0);
|
||||
let contents = build_const_struct(ccx, &variant, vals);
|
||||
C_struct(ccx, &contents[..], variant.packed)
|
||||
build_const_struct(ccx, l, &variant, vals)
|
||||
}
|
||||
layout::Vector { .. } => {
|
||||
C_vector(vals)
|
||||
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
|
||||
}
|
||||
layout::RawNullablePointer { nndiscr, .. } => {
|
||||
if variant_index as u64 == nndiscr {
|
||||
assert_eq!(vals.len(), 1);
|
||||
vals[0]
|
||||
Const::new(vals[0].llval, t)
|
||||
} else {
|
||||
C_null(type_of::type_of(ccx, t))
|
||||
Const::new(C_null(type_of::type_of(ccx, t)), t)
|
||||
}
|
||||
}
|
||||
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
|
||||
if variant_index as u64 == nndiscr {
|
||||
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
|
||||
build_const_struct(ccx, l, &nonnull, vals)
|
||||
} else {
|
||||
// Always use null even if it's not the `discrfield`th
|
||||
// field; see #8506.
|
||||
C_null(type_of::type_of(ccx, t))
|
||||
Const::new(C_null(type_of::type_of(ccx, t)), t)
|
||||
}
|
||||
}
|
||||
_ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
|
||||
_ => bug!("trans_const_adt: cannot handle type {} repreented as {:#?}", t, l)
|
||||
}
|
||||
}
|
||||
|
||||
/// Building structs is a little complicated, because we might need to
|
||||
/// insert padding if a field's value is less aligned than its type.
|
||||
///
|
||||
/// Continuing the example from `trans_const`, a value of type `(u32,
|
||||
/// Continuing the example from `trans_const_adt`, a value of type `(u32,
|
||||
/// E)` should have the `E` at offset 8, but if that field's
|
||||
/// initializer is 4-byte aligned then simply translating the tuple as
|
||||
/// a two-element struct will locate it at offset 4, and accesses to it
|
||||
/// will read the wrong memory.
|
||||
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
layout: layout::TyLayout<'tcx>,
|
||||
st: &layout::Struct,
|
||||
vals: &[ValueRef])
|
||||
-> Vec<ValueRef> {
|
||||
vals: &[Const<'tcx>])
|
||||
-> Const<'tcx> {
|
||||
assert_eq!(vals.len(), st.offsets.len());
|
||||
|
||||
if vals.len() == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// offset of current value
|
||||
let mut offset = 0;
|
||||
let mut offset = Size::from_bytes(0);
|
||||
let mut cfields = Vec::new();
|
||||
cfields.reserve(st.offsets.len()*2);
|
||||
|
||||
let parts = st.field_index_by_increasing_offset().map(|i| {
|
||||
(&vals[i], st.offsets[i].bytes())
|
||||
(vals[i], st.offsets[i])
|
||||
});
|
||||
for (&val, target_offset) in parts {
|
||||
for (val, target_offset) in parts {
|
||||
if offset < target_offset {
|
||||
cfields.push(padding(ccx, target_offset - offset));
|
||||
offset = target_offset;
|
||||
}
|
||||
assert!(!is_undef(val));
|
||||
cfields.push(val);
|
||||
offset += machine::llsize_of_alloc(ccx, val_ty(val));
|
||||
assert!(!is_undef(val.llval));
|
||||
cfields.push(val.llval);
|
||||
offset = target_offset + ccx.size_of(val.ty);
|
||||
}
|
||||
|
||||
if offset < st.stride().bytes() {
|
||||
cfields.push(padding(ccx, st.stride().bytes() - offset));
|
||||
}
|
||||
|
||||
cfields
|
||||
}
|
||||
|
||||
fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
un: &layout::Union,
|
||||
field_val: ValueRef)
|
||||
-> Vec<ValueRef> {
|
||||
let mut cfields = vec![field_val];
|
||||
|
||||
let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
|
||||
let size = un.stride().bytes();
|
||||
if offset != size {
|
||||
let size = layout.size(ccx);
|
||||
if offset < size {
|
||||
cfields.push(padding(ccx, size - offset));
|
||||
}
|
||||
|
||||
cfields
|
||||
Const::new(C_struct(ccx, &cfields, st.packed), layout.ty)
|
||||
}
|
||||
|
||||
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
|
||||
C_undef(Type::array(&Type::i8(ccx), size))
|
||||
fn padding(ccx: &CrateContext, size: Size) -> ValueRef {
|
||||
C_undef(Type::array(&Type::i8(ccx), size.bytes()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use llvm::{self, ValueRef};
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use rustc::ty::layout::{self, Align, LayoutTyper};
|
||||
use rustc::mir;
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
|
@ -19,7 +19,6 @@ use base;
|
|||
use builder::Builder;
|
||||
use common::{self, CrateContext, C_usize, C_u8, C_i32, C_int, C_null, val_ty};
|
||||
use consts;
|
||||
use machine;
|
||||
use type_of;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
|
|
@ -56,18 +55,15 @@ impl Alignment {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_align(self) -> Option<u32> {
|
||||
pub fn to_align(self) -> Option<Align> {
|
||||
match self {
|
||||
Alignment::Packed => Some(1),
|
||||
Alignment::Packed => Some(Align::from_bytes(1, 1).unwrap()),
|
||||
Alignment::AbiAligned => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min_with(self, align: u32) -> Option<u32> {
|
||||
match self {
|
||||
Alignment::Packed => Some(1),
|
||||
Alignment::AbiAligned => Some(align),
|
||||
}
|
||||
pub fn min_with(self, align: Option<Align>) -> Option<Align> {
|
||||
self.to_align().or(align)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +149,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
// The unit-like case might have a nonzero number of unit-like fields.
|
||||
// (e.d., Result of Either with (), as one side.)
|
||||
let ty = type_of::type_of(ccx, fty);
|
||||
assert_eq!(machine::llsize_of_alloc(ccx, ty), 0);
|
||||
assert_eq!(ccx.size_of(fty).bytes(), 0);
|
||||
return (bcx.pointercast(self.llval, ty.ptr_to()), Alignment::Packed);
|
||||
}
|
||||
layout::RawNullablePointer { .. } => {
|
||||
|
|
@ -174,7 +170,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
let ptr_val = if let layout::General { discr, .. } = *l {
|
||||
let variant_ty = Type::struct_(ccx,
|
||||
&adt::struct_llfields(ccx, l.ty, l.variant_index.unwrap(), st,
|
||||
Some(discr.to_ty(&bcx.tcx(), false))), st.packed);
|
||||
Some(discr.to_ty(bcx.tcx(), false))), st.packed);
|
||||
bcx.pointercast(self.llval, variant_ty.ptr_to())
|
||||
} else {
|
||||
self.llval
|
||||
|
|
@ -374,6 +370,14 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
|||
bcx.inbounds_gep(self.llval, &[zero, llindex])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn storage_live(&self, bcx: &Builder<'a, 'tcx>) {
|
||||
bcx.lifetime_start(self.llval, bcx.ccx.size_of(self.ty.to_ty(bcx.tcx())));
|
||||
}
|
||||
|
||||
pub fn storage_dead(&self, bcx: &Builder<'a, 'tcx>) {
|
||||
bcx.lifetime_end(self.llval, bcx.ccx.size_of(self.ty.to_ty(bcx.tcx())));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
|
|
@ -432,7 +436,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||
let index = self.trans_operand(bcx, index);
|
||||
let llindex = self.prepare_index(bcx, index.immediate());
|
||||
let llindex = index.immediate();
|
||||
((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
|
|
@ -487,22 +491,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Adjust the bitwidth of an index since LLVM is less forgiving
|
||||
/// than we are.
|
||||
///
|
||||
/// nmatsakis: is this still necessary? Not sure.
|
||||
fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef {
|
||||
let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
|
||||
let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.isize_ty());
|
||||
if index_size < int_size {
|
||||
bcx.zext(llindex, bcx.ccx.isize_ty())
|
||||
} else if index_size > int_size {
|
||||
bcx.trunc(llindex, bcx.ccx.isize_ty())
|
||||
} else {
|
||||
llindex
|
||||
}
|
||||
}
|
||||
|
||||
pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
|
||||
let tcx = self.ccx.tcx();
|
||||
let lvalue_ty = lvalue.ty(self.mir, tcx);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub struct MirContext<'a, 'tcx:'a> {
|
|||
/// don't really care about it very much. Anyway, this value
|
||||
/// contains an alloca into which the personality is stored and
|
||||
/// then later loaded when generating the DIVERGE_BLOCK.
|
||||
llpersonalityslot: Option<ValueRef>,
|
||||
personality_slot: Option<LvalueRef<'tcx>>,
|
||||
|
||||
/// A `Block` for each MIR `BasicBlock`
|
||||
blocks: IndexVec<mir::BasicBlock, BasicBlockRef>,
|
||||
|
|
@ -177,9 +177,8 @@ enum LocalRef<'tcx> {
|
|||
Operand(Option<OperandRef<'tcx>>),
|
||||
}
|
||||
|
||||
impl<'tcx> LocalRef<'tcx> {
|
||||
fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ty: Ty<'tcx>) -> LocalRef<'tcx> {
|
||||
impl<'a, 'tcx> LocalRef<'tcx> {
|
||||
fn new_operand(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> LocalRef<'tcx> {
|
||||
if common::type_is_zero_size(ccx, ty) {
|
||||
// Zero-size temporaries aren't always initialized, which
|
||||
// doesn't matter because they don't contain data, but
|
||||
|
|
@ -232,7 +231,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
|
|||
llfn,
|
||||
fn_ty,
|
||||
ccx,
|
||||
llpersonalityslot: None,
|
||||
personality_slot: None,
|
||||
blocks: block_bcxs,
|
||||
unreachable_block: None,
|
||||
cleanup_kinds,
|
||||
|
|
@ -470,7 +469,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let val = if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
|
||||
let meta = &mircx.fn_ty.args[idx];
|
||||
idx += 1;
|
||||
assert_eq!((meta.cast, meta.pad), (None, None));
|
||||
assert!(meta.cast.is_none() && meta.pad.is_none());
|
||||
let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
|
||||
llarg_idx += 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use llvm::ValueRef;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{Layout, LayoutTyper};
|
||||
use rustc::ty::layout::{Align, Layout, LayoutTyper};
|
||||
use rustc::mir;
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
|
@ -310,7 +310,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
pub fn store_operand(&mut self,
|
||||
bcx: &Builder<'a, 'tcx>,
|
||||
lldest: ValueRef,
|
||||
align: Option<u32>,
|
||||
align: Option<Align>,
|
||||
operand: OperandRef<'tcx>) {
|
||||
debug!("store_operand: operand={:?}, align={:?}", operand, align);
|
||||
// Avoid generating stores of zero-sized values, because the only way to have a zero-sized
|
||||
|
|
@ -319,10 +319,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
match operand.val {
|
||||
OperandValue::Ref(r, Alignment::Packed) =>
|
||||
base::memcpy_ty(bcx, lldest, r, operand.ty, Some(1)),
|
||||
OperandValue::Ref(r, Alignment::AbiAligned) =>
|
||||
base::memcpy_ty(bcx, lldest, r, operand.ty, align),
|
||||
OperandValue::Ref(r, source_align) =>
|
||||
base::memcpy_ty(bcx, lldest, r, operand.ty,
|
||||
source_align.min_with(align)),
|
||||
OperandValue::Immediate(s) => {
|
||||
bcx.store(base::from_immediate(bcx, s), lldest, align);
|
||||
}
|
||||
|
|
@ -331,7 +330,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
Layout::Univariant { ref variant, .. } => {
|
||||
(adt::struct_llfields_index(variant, 0),
|
||||
adt::struct_llfields_index(variant, 1),
|
||||
if variant.packed { Some(1) } else { None })
|
||||
if variant.packed { Some(variant.align) } else { None })
|
||||
}
|
||||
_ => (0, 1, align)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ use std::{u128, i128};
|
|||
use base;
|
||||
use builder::Builder;
|
||||
use callee;
|
||||
use common::{self, val_ty, C_bool, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_big_integral};
|
||||
use common::{self, val_ty};
|
||||
use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_big_integral};
|
||||
use consts;
|
||||
use adt;
|
||||
use machine;
|
||||
use monomorphize;
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
|
|
@ -104,33 +104,31 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let tr_elem = self.trans_operand(&bcx, elem);
|
||||
let size = count.as_u64();
|
||||
let size = C_usize(bcx.ccx, size);
|
||||
let count = count.as_u64();
|
||||
let count = C_usize(bcx.ccx, count);
|
||||
let base = base::get_dataptr(&bcx, dest.llval);
|
||||
let align = dest.alignment.to_align();
|
||||
|
||||
if let OperandValue::Immediate(v) = tr_elem.val {
|
||||
let align = align.unwrap_or_else(|| bcx.ccx.align_of(tr_elem.ty));
|
||||
let align = C_i32(bcx.ccx, align.abi() as i32);
|
||||
let size = C_usize(bcx.ccx, bcx.ccx.size_of(dest_ty).bytes());
|
||||
|
||||
// Use llvm.memset.p0i8.* to initialize all zero arrays
|
||||
if common::is_const_integral(v) && common::const_to_uint(v) == 0 {
|
||||
let align = align.unwrap_or_else(|| bcx.ccx.align_of(tr_elem.ty));
|
||||
let align = C_i32(bcx.ccx, align as i32);
|
||||
let ty = type_of::type_of(bcx.ccx, dest_ty);
|
||||
let size = machine::llsize_of(bcx.ccx, ty);
|
||||
let fill = C_uint(Type::i8(bcx.ccx), 0);
|
||||
let fill = C_u8(bcx.ccx, 0);
|
||||
base::call_memset(&bcx, base, fill, size, align, false);
|
||||
return bcx;
|
||||
}
|
||||
|
||||
// Use llvm.memset.p0i8.* to initialize byte arrays
|
||||
if common::val_ty(v) == Type::i8(bcx.ccx) {
|
||||
let align = align.unwrap_or_else(|| bcx.ccx.align_of(tr_elem.ty));
|
||||
let align = C_i32(bcx.ccx, align as i32);
|
||||
base::call_memset(&bcx, base, v, size, align, false);
|
||||
return bcx;
|
||||
}
|
||||
}
|
||||
|
||||
tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot, loop_bb| {
|
||||
tvec::slice_for_each(&bcx, base, tr_elem.ty, count, |bcx, llslot, loop_bb| {
|
||||
self.store_operand(bcx, llslot, align, tr_elem);
|
||||
bcx.br(loop_bb);
|
||||
})
|
||||
|
|
@ -459,7 +457,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
assert!(bcx.ccx.shared().type_is_sized(ty));
|
||||
let val = C_usize(bcx.ccx, bcx.ccx.size_of(ty));
|
||||
let val = C_usize(bcx.ccx, bcx.ccx.size_of(ty).bytes());
|
||||
let tcx = bcx.tcx();
|
||||
(bcx, OperandRef {
|
||||
val: OperandValue::Immediate(val),
|
||||
|
|
@ -469,12 +467,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => {
|
||||
let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
|
||||
let llty = type_of::type_of(bcx.ccx, content_ty);
|
||||
let llsize = machine::llsize_of(bcx.ccx, llty);
|
||||
let align = bcx.ccx.align_of(content_ty);
|
||||
let llalign = C_usize(bcx.ccx, align as u64);
|
||||
let llty_ptr = llty.ptr_to();
|
||||
let (size, align) = bcx.ccx.size_and_align_of(content_ty);
|
||||
let llsize = C_usize(bcx.ccx, size.bytes());
|
||||
let llalign = C_usize(bcx.ccx, align.abi());
|
||||
let box_ty = bcx.tcx().mk_box(content_ty);
|
||||
let llty_ptr = type_of::type_of(bcx.ccx, box_ty);
|
||||
|
||||
// Allocate space:
|
||||
let def_id = match bcx.tcx().lang_items().require(ExchangeMallocFnLangItem) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
use rustc::mir;
|
||||
|
||||
use base;
|
||||
use asm;
|
||||
use common;
|
||||
use builder::Builder;
|
||||
|
|
@ -63,10 +62,16 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
bcx
|
||||
}
|
||||
mir::StatementKind::StorageLive(local) => {
|
||||
self.trans_storage_liveness(bcx, local, base::Lifetime::Start)
|
||||
if let LocalRef::Lvalue(tr_lval) = self.locals[local] {
|
||||
tr_lval.storage_live(&bcx);
|
||||
}
|
||||
bcx
|
||||
}
|
||||
mir::StatementKind::StorageDead(local) => {
|
||||
self.trans_storage_liveness(bcx, local, base::Lifetime::End)
|
||||
if let LocalRef::Lvalue(tr_lval) = self.locals[local] {
|
||||
tr_lval.storage_dead(&bcx);
|
||||
}
|
||||
bcx
|
||||
}
|
||||
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||
let outputs = outputs.iter().map(|output| {
|
||||
|
|
@ -86,15 +91,4 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
mir::StatementKind::Nop => bcx,
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_storage_liveness(&self,
|
||||
bcx: Builder<'a, 'tcx>,
|
||||
index: mir::Local,
|
||||
intrinsic: base::Lifetime)
|
||||
-> Builder<'a, 'tcx> {
|
||||
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
|
||||
intrinsic.call(&bcx, tr_lval.llval);
|
||||
}
|
||||
bcx
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@
|
|||
use abi::FnType;
|
||||
use adt;
|
||||
use common::*;
|
||||
use machine;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::LayoutTyper;
|
||||
use rustc::ty::layout::{Align, LayoutTyper, Size};
|
||||
use trans_item::DefPathBasedNames;
|
||||
use type_::Type;
|
||||
|
||||
|
|
@ -212,19 +211,26 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> CrateContext<'a, 'tcx> {
|
||||
pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
|
||||
self.layout_of(ty).align(self).abi() as machine::llalign
|
||||
pub fn align_of(&self, ty: Ty<'tcx>) -> Align {
|
||||
self.layout_of(ty).align(self)
|
||||
}
|
||||
|
||||
pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
|
||||
self.layout_of(ty).size(self).bytes() as machine::llsize
|
||||
pub fn size_of(&self, ty: Ty<'tcx>) -> Size {
|
||||
self.layout_of(ty).size(self)
|
||||
}
|
||||
|
||||
pub fn over_align_of(&self, t: Ty<'tcx>)
|
||||
-> Option<machine::llalign> {
|
||||
pub fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) {
|
||||
let layout = self.layout_of(ty);
|
||||
(layout.size(self), layout.align(self))
|
||||
}
|
||||
|
||||
/// Returns alignment if it is different than the primitive alignment.
|
||||
pub fn over_align_of(&self, t: Ty<'tcx>) -> Option<Align> {
|
||||
let layout = self.layout_of(t);
|
||||
if let Some(align) = layout.over_align(&self.tcx().data_layout) {
|
||||
Some(align as machine::llalign)
|
||||
let align = layout.align(self);
|
||||
let primitive_align = layout.primitive_align(self);
|
||||
if align != primitive_align {
|
||||
Some(align)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,21 +257,18 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) {
|
|||
|
||||
extern "C" LLVMValueRef
|
||||
LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name,
|
||||
LLVMAtomicOrdering Order, unsigned Alignment) {
|
||||
LLVMAtomicOrdering Order) {
|
||||
LoadInst *LI = new LoadInst(unwrap(Source), 0);
|
||||
LI->setAtomic(fromRust(Order));
|
||||
LI->setAlignment(Alignment);
|
||||
return wrap(unwrap(B)->Insert(LI, Name));
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
|
||||
LLVMValueRef V,
|
||||
LLVMValueRef Target,
|
||||
LLVMAtomicOrdering Order,
|
||||
unsigned Alignment) {
|
||||
LLVMAtomicOrdering Order) {
|
||||
StoreInst *SI = new StoreInst(unwrap(V), unwrap(Target));
|
||||
SI->setAtomic(fromRust(Order));
|
||||
SI->setAlignment(Alignment);
|
||||
return wrap(unwrap(B)->Insert(SI));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue