diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-09-26 14:41:06 +0300 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-11-19 02:14:33 +0200 |
| commit | f62e43da2891a65a484a917d84642544ed093ba2 (patch) | |
| tree | 5b0338f9070e2cbe50dd8bde7b25d74e1b412e4f /src | |
| parent | 5df25c4aed68a4f761645f63e6ce34ec8c30a75e (diff) | |
rustc: track validity ranges for layout::Abi::Scalar values.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/ty/layout.rs | 301 | ||||
| -rw-r--r-- | src/librustc_lint/types.rs | 4 | ||||
| -rw-r--r-- | src/librustc_trans/abi.rs | 19 | ||||
| -rw-r--r-- | src/librustc_trans/base.rs | 9 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_s390x.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86_64.rs | 4 | ||||
| -rw-r--r-- | src/librustc_trans/debuginfo/metadata.rs | 8 | ||||
| -rw-r--r-- | src/librustc_trans/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_trans/mir/block.rs | 13 | ||||
| -rw-r--r-- | src/librustc_trans/mir/constant.rs | 16 | ||||
| -rw-r--r-- | src/librustc_trans/mir/lvalue.rs | 71 | ||||
| -rw-r--r-- | src/librustc_trans/mir/rvalue.rs | 36 | ||||
| -rw-r--r-- | src/librustc_trans/type_.rs | 1 | ||||
| -rw-r--r-- | src/librustc_trans/type_of.rs | 14 |
15 files changed, 294 insertions, 219 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 9d8736338f1..899245b22aa 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -416,7 +416,6 @@ impl Align { /// Integers, also used for enum discriminants. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Integer { - I1, I8, I16, I32, @@ -427,7 +426,6 @@ pub enum Integer { impl<'a, 'tcx> Integer { pub fn size(&self) -> Size { match *self { - I1 => Size::from_bits(1), I8 => Size::from_bytes(1), I16 => Size::from_bytes(2), I32 => Size::from_bytes(4), @@ -440,7 +438,6 @@ impl<'a, 'tcx> Integer { let dl = cx.data_layout(); match *self { - I1 => dl.i1_align, I8 => dl.i8_align, I16 => dl.i16_align, I32 => dl.i32_align, @@ -451,13 +448,11 @@ impl<'a, 'tcx> Integer { 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, (I16, false) => tcx.types.u16, (I32, false) => tcx.types.u32, (I64, false) => tcx.types.u64, (I128, false) => tcx.types.u128, - (I1, true) => tcx.types.i8, (I8, true) => tcx.types.i8, (I16, true) => tcx.types.i16, (I32, true) => tcx.types.i32, @@ -469,7 +464,6 @@ impl<'a, 'tcx> Integer { /// Find the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i128) -> Integer { match x { - -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1, -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, @@ -481,7 +475,6 @@ impl<'a, 'tcx> Integer { /// Find the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u128) -> Integer { match x { - 0...0x0000_0000_0000_0001 => I1, 0...0x0000_0000_0000_00ff => I8, 0...0x0000_0000_0000_ffff => I16, 0...0x0000_0000_ffff_ffff => I32, @@ -621,6 +614,29 @@ impl<'a, 'tcx> Primitive { } } +/// Information about one scalar component of a Rust type. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Scalar { + pub value: Primitive, + + /// Inclusive wrap-around range of valid values, that is, if + /// min > max, it represents min..=u128::MAX followed by 0..=max. + // FIXME(eddyb) always use the shortest range, e.g. by finding + // the largest space between two consecutive valid values and + // taking everything else as the (shortest) valid range. + pub valid_range: RangeInclusive<u128>, +} + +impl Scalar { + pub fn is_bool(&self) -> bool { + if let Int(I8, _) = self.value { + self.valid_range == (0..=1) + } else { + false + } + } +} + /// The first half of a fat pointer. /// - For a trait object, this is the address of the box. /// - For a slice, this is the base address. @@ -737,9 +753,9 @@ impl FieldPlacement { /// Describes how values of the type are passed by target ABIs, /// in terms of categories of C types there are ABI rules for. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Abi { - Scalar(Primitive), + Scalar(Scalar), Vector, Aggregate { /// If true, the size is exact, otherwise it's only a lower bound. @@ -777,13 +793,7 @@ pub enum Variants { /// all space reserved for the discriminant, and their first field starts /// at a non-0 offset, after where the discriminant would go. Tagged { - discr: Primitive, - /// Inclusive wrap-around range of discriminant values, that is, - /// if min > max, it represents min..=u128::MAX followed by 0..=max. - // FIXME(eddyb) always use the shortest range, e.g. by finding - // the largest space between two consecutive discriminants and - // taking everything else as the (shortest) discriminant range. - discr_range: RangeInclusive<u128>, + discr: Scalar, variants: Vec<CachedLayout>, }, @@ -797,7 +807,7 @@ pub enum Variants { /// `Some` is the identity function (with a non-null reference). NicheFilling { dataful_variant: usize, - niche: Primitive, + niche: Scalar, niche_value: u128, variants: Vec<CachedLayout>, } @@ -832,6 +842,21 @@ pub struct CachedLayout { pub size: Size } +impl CachedLayout { + fn scalar<C: HasDataLayout>(cx: C, scalar: Scalar) -> Self { + let size = scalar.value.size(cx); + let align = scalar.value.align(cx); + CachedLayout { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(0), + abi: Abi::Scalar(scalar), + size, + align, + primitive_align: align + } + } +} + fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx CachedLayout, LayoutError<'tcx>> @@ -867,16 +892,14 @@ impl<'a, 'tcx> CachedLayout { let cx = (tcx, param_env); let dl = cx.data_layout(); let scalar = |value: Primitive| { - let align = value.align(dl); - tcx.intern_layout(CachedLayout { - variants: Variants::Single { index: 0 }, - fields: FieldPlacement::Union(0), - abi: Abi::Scalar(value), - size: value.size(dl), - align, - primitive_align: align - }) + let bits = value.size(dl).bits(); + assert!(bits <= 128); + tcx.intern_layout(CachedLayout::scalar(cx, Scalar { + value, + valid_range: 0..=(!0 >> (128 - bits)) + })) }; + #[derive(Copy, Clone, Debug)] enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. @@ -1030,7 +1053,12 @@ impl<'a, 'tcx> CachedLayout { let ptr_layout = |pointee: Ty<'tcx>| { let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); if pointee.is_sized(tcx, param_env, DUMMY_SP) { - return Ok(scalar(Pointer)); + let non_zero = !ty.is_unsafe_ptr(); + let bits = Pointer.size(dl).bits(); + return Ok(tcx.intern_layout(CachedLayout::scalar(cx, Scalar { + value: Pointer, + valid_range: (non_zero as u128)..=(!0 >> (128 - bits)) + }))); } let unsized_part = tcx.struct_tail(pointee); @@ -1066,8 +1094,18 @@ impl<'a, 'tcx> CachedLayout { Ok(match ty.sty { // Basic scalars. - ty::TyBool => scalar(Int(I1, false)), - ty::TyChar => scalar(Int(I32, false)), + ty::TyBool => { + tcx.intern_layout(CachedLayout::scalar(cx, Scalar { + value: Int(I8, false), + valid_range: 0..=1 + })) + } + ty::TyChar => { + tcx.intern_layout(CachedLayout::scalar(cx, Scalar { + value: Int(I32, false), + valid_range: 0..=0x10FFFF + })) + } ty::TyInt(ity) => { scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)) } @@ -1076,7 +1114,13 @@ impl<'a, 'tcx> CachedLayout { } ty::TyFloat(FloatTy::F32) => scalar(F32), ty::TyFloat(FloatTy::F64) => scalar(F64), - ty::TyFnPtr(_) => scalar(Pointer), + ty::TyFnPtr(_) => { + let bits = Pointer.size(dl).bits(); + tcx.intern_layout(CachedLayout::scalar(cx, Scalar { + value: Pointer, + valid_range: 1..=(!0 >> (128 - bits)) + })) + } // The never type. ty::TyNever => { @@ -1330,22 +1374,26 @@ impl<'a, 'tcx> CachedLayout { } let offset = st[i].fields.offset(field_index) + offset; let CachedLayout { - mut abi, size, mut align, mut primitive_align, .. } = st[i]; - let mut niche_align = niche.align(dl); - if offset.bytes() == 0 && niche.size(dl) == size { - abi = Abi::Scalar(niche); - } else if let Abi::Aggregate { ref mut packed, .. } = abi { + let mut niche_align = niche.value.align(dl); + let abi = if offset.bytes() == 0 && niche.value.size(dl) == size { + Abi::Scalar(niche.clone()) + } else { + let mut packed = st[i].abi.is_packed(); if offset.abi_align(niche_align) != offset { - *packed = true; + packed = true; niche_align = dl.i8_align; } - } + Abi::Aggregate { + sized: true, + packed + } + }; align = align.max(niche_align); primitive_align = primitive_align.max(niche_align); @@ -1468,25 +1516,28 @@ impl<'a, 'tcx> CachedLayout { } } - let discr = Int(ity, signed); + let discr = Scalar { + value: Int(ity, signed), + valid_range: (min as u128)..=(max as u128) + }; + let abi = if discr.value.size(dl) == size { + Abi::Scalar(discr.clone()) + } else { + Abi::Aggregate { + sized: true, + packed: false + } + }; tcx.intern_layout(CachedLayout { variants: Variants::Tagged { discr, - discr_range: (min as u128)..=(max as u128), variants }, // FIXME(eddyb): using `FieldPlacement::Arbitrary` here results // in lost optimizations, specifically around allocations, see // `test/codegen/{alloc-optimisation,vec-optimizes-away}.rs`. fields: FieldPlacement::Union(1), - abi: if discr.size(dl) == size { - Abi::Scalar(discr) - } else { - Abi::Aggregate { - sized: true, - packed: false - } - }, + abi, align, primitive_align, size @@ -1650,7 +1701,7 @@ impl<'a, 'tcx> CachedLayout { }) .collect(); record(adt_kind.into(), match layout.variants { - Variants::Tagged { discr, .. } => Some(discr.size(tcx)), + Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)), _ => None }, variant_infos); } @@ -1852,16 +1903,23 @@ impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) { } pub trait MaybeResult<T> { + fn from_ok(x: T) -> Self; fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self; } impl<T> MaybeResult<T> for T { + fn from_ok(x: T) -> Self { + x + } fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self { f(self) } } impl<T, E> MaybeResult<T> for Result<T, E> { + fn from_ok(x: T) -> Self { + Ok(x) + } fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self { self.map(f) } @@ -1961,7 +2019,13 @@ impl<'a, 'tcx> TyLayout<'tcx> { // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldPlacement` is checked by users. if i == 0 { - return cx.layout_of(Pointer.to_ty(tcx)).map_same(|mut ptr_layout| { + let nil = tcx.mk_nil(); + let ptr_ty = if self.ty.is_unsafe_ptr() { + tcx.mk_mut_ptr(nil) + } else { + tcx.mk_mut_ref(tcx.types.re_static, nil) + }; + return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| { ptr_layout.ty = self.ty; ptr_layout }); @@ -2042,9 +2106,14 @@ impl<'a, 'tcx> TyLayout<'tcx> { } // Discriminant field for enums (where applicable). - Variants::Tagged { discr, .. } | - Variants::NicheFilling { niche: discr, .. } => { - return cx.layout_of([discr.to_ty(tcx)][i]); + Variants::Tagged { ref discr, .. } | + Variants::NicheFilling { niche: ref discr, .. } => { + assert_eq!(i, 0); + let layout = CachedLayout::scalar(tcx, discr.clone()); + return MaybeResult::from_ok(TyLayout { + cached: tcx.intern_layout(layout), + ty: discr.value.to_ty(tcx) + }); } } } @@ -2081,79 +2150,74 @@ impl<'a, 'tcx> TyLayout<'tcx> { /// Find the offset of a niche leaf field, starting from /// the given type and recursing through aggregates. - /// The tuple is `(offset, primitive, niche_value)`. - // FIXME(eddyb) track value ranges and traverse already optimized enums. + /// The tuple is `(offset, scalar, niche_value)`. + // FIXME(eddyb) traverse already optimized enums. fn find_niche<C>(&self, cx: C) - -> Result<Option<(Size, Primitive, u128)>, LayoutError<'tcx>> + -> Result<Option<(Size, Scalar, u128)>, LayoutError<'tcx>> where C: LayoutOf<Ty<'tcx>, TyLayout = Result<Self, LayoutError<'tcx>>> + HasTyCtxt<'tcx> { - let tcx = cx.tcx(); - match (&self.variants, self.abi, &self.ty.sty) { - // FIXME(eddyb) check this via value ranges on scalars. - (_, Abi::Scalar(Int(I1, _)), _) => { - Ok(Some((Size::from_bytes(0), Int(I8, false), 2))) - } - (_, Abi::Scalar(Int(I32, _)), &ty::TyChar) => { - Ok(Some((Size::from_bytes(0), Int(I32, false), 0x10FFFF+1))) - } - (_, Abi::Scalar(Pointer), &ty::TyRef(..)) | - (_, Abi::Scalar(Pointer), &ty::TyFnPtr(..)) => { - Ok(Some((Size::from_bytes(0), Pointer, 0))) - } - (_, Abi::Scalar(Pointer), &ty::TyAdt(def, _)) if def.is_box() => { - Ok(Some((Size::from_bytes(0), Pointer, 0))) - } - - // FIXME(eddyb) check this via value ranges on scalars. - (&Variants::Tagged { discr, ref discr_range, .. }, _, _) => { - // FIXME(eddyb) support negative/wrap-around discriminant ranges. - if discr_range.start < discr_range.end { - if discr_range.start > 0 { - Ok(Some((self.fields.offset(0), discr, 0))) - } else { - let bits = discr.size(tcx).bits(); - assert!(bits <= 128); - let max_value = !0u128 >> (128 - bits); - if discr_range.end < max_value { - Ok(Some((self.fields.offset(0), discr, discr_range.end + 1))) - } else { - Ok(None) - } - } + if let Abi::Scalar(Scalar { value, ref valid_range }) = self.abi { + // FIXME(eddyb) support negative/wrap-around discriminant ranges. + return if valid_range.start < valid_range.end { + let bits = value.size(cx).bits(); + assert!(bits <= 128); + let max_value = !0u128 >> (128 - bits); + if valid_range.start > 0 { + let niche = valid_range.start - 1; + Ok(Some((self.fields.offset(0), Scalar { + value, + valid_range: niche..=valid_range.end + }, niche))) + } else if valid_range.end < max_value { + let niche = valid_range.end + 1; + Ok(Some((self.fields.offset(0), Scalar { + value, + valid_range: valid_range.start..=niche + }, niche))) } else { Ok(None) } - } + } else { + Ok(None) + }; + } - // Is this the NonZero lang item wrapping a pointer or integer type? - (_, _, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => { + // Is this the NonZero lang item wrapping a pointer or integer type? + if let ty::TyAdt(def, _) = self.ty.sty { + if Some(def.did) == cx.tcx().lang_items().non_zero() { let field = self.field(cx, 0)?; let offset = self.fields.offset(0); - if let Abi::Scalar(value) = field.abi { - Ok(Some((offset, value, 0))) - } else { - Ok(None) + if let Abi::Scalar(Scalar { value, ref valid_range }) = field.abi { + return Ok(Some((offset, Scalar { + value, + valid_range: 0..=valid_range.end + }, 0))); } } + } - // Perhaps one of the fields is non-zero, let's recurse and find out. - _ => { - if let FieldPlacement::Array { count, .. } = self.fields { - if count > 0 { - return self.field(cx, 0)?.find_niche(cx); - } - } - for i in 0..self.fields.count() { - let r = self.field(cx, i)?.find_niche(cx)?; - if let Some((offset, primitive, niche_value)) = r { - let offset = self.fields.offset(i) + offset; - return Ok(Some((offset, primitive, niche_value))); - } - } - Ok(None) + // Perhaps one of the fields is non-zero, let's recurse and find out. + if let FieldPlacement::Union(_) = self.fields { + // Only Rust enums have safe-to-inspect fields + // (a discriminant), other unions are unsafe. + if let Variants::Single { .. } = self.variants { + return Ok(None); + } + } + if let FieldPlacement::Array { count, .. } = self.fields { + if count > 0 { + return self.field(cx, 0)?.find_niche(cx); } } + for i in 0..self.fields.count() { + let r = self.field(cx, i)?.find_niche(cx)?; + if let Some((offset, scalar, niche_value)) = r { + let offset = self.fields.offset(i) + offset; + return Ok(Some((offset, scalar, niche_value))); + } + } + Ok(None) } } @@ -2169,13 +2233,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants { index.hash_stable(hcx, hasher); } Tagged { - discr, - discr_range: RangeInclusive { start, end }, + ref discr, ref variants, } => { discr.hash_stable(hcx, hasher); - start.hash_stable(hcx, hasher); - end.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); } NicheFilling { @@ -2236,6 +2297,17 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi { } } +impl<'gcx> HashStable<StableHashingContext<'gcx>> for Scalar { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; + value.hash_stable(hcx, hasher); + start.hash_stable(hcx, hasher); + end.hash_stable(hcx, hasher); + } +} + impl_stable_hash_for!(struct ::ty::layout::CachedLayout { variants, fields, @@ -2246,7 +2318,6 @@ impl_stable_hash_for!(struct ::ty::layout::CachedLayout { }); impl_stable_hash_for!(enum ::ty::layout::Integer { - I1, I8, I16, I32, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 46debcce958..1356574f646 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -753,8 +753,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { bug!("failed to get layout for `{}`: {}", t, e) }); - if let layout::Variants::Tagged { ref variants, discr, .. } = layout.variants { - let discr_size = discr.size(cx.tcx).bytes(); + if let layout::Variants::Tagged { ref variants, ref discr, .. } = layout.variants { + let discr_size = discr.value.size(cx.tcx).bytes(); debug!("enum `{}` is {} bytes large with layout:\n{:#?}", t, layout.size.bytes(), layout); diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 688fa8fe02d..c87f856b005 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -287,8 +287,8 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> { match self.abi { // The primitive for this algorithm. - layout::Abi::Scalar(value) => { - let kind = match value { + layout::Abi::Scalar(ref scalar) => { + let kind = match scalar.value { layout::Int(..) | layout::Pointer => RegKind::Integer, layout::F32 | @@ -471,8 +471,8 @@ impl<'a, 'tcx> ArgType<'tcx> { pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - match self.layout.abi { - layout::Abi::Scalar(layout::Int(i, signed)) => { + if let layout::Abi::Scalar(ref scalar) = self.layout.abi { + if let layout::Int(i, signed) = scalar.value { if i.size().bits() < bits { self.attrs.set(if signed { ArgAttribute::SExt @@ -481,8 +481,6 @@ impl<'a, 'tcx> ArgType<'tcx> { }); } } - - _ => {} } } @@ -695,9 +693,12 @@ impl<'a, 'tcx> FnType<'tcx> { let arg_of = |ty: Ty<'tcx>, is_return: bool| { let mut arg = ArgType::new(ccx.layout_of(ty)); - if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = arg.layout.abi { - arg.attrs.set(ArgAttribute::ZExt); - } else if arg.layout.is_zst() { + if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { + if scalar.is_bool() { + arg.attrs.set(ArgAttribute::ZExt); + } + } + if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. // The same is true for s390x-unknown-linux-gnu. diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3c6626cfa7f..ff70184b262 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -375,11 +375,12 @@ pub fn from_immediate(bcx: &Builder, val: ValueRef) -> ValueRef { } pub fn to_immediate(bcx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { - if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = layout.abi { - bcx.trunc(val, Type::i1(bcx.ccx)) - } else { - val + if let layout::Abi::Scalar(ref scalar) = layout.abi { + if scalar.is_bool() { + return bcx.trunc(val, Type::i1(bcx.ccx)); + } } + val } pub fn call_memcpy(b: &Builder, diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs index 9c24b637efd..9fb460043ae 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_trans/cabi_s390x.rs @@ -27,8 +27,12 @@ fn classify_ret_ty(ret: &mut ArgType) { fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, layout: TyLayout<'tcx>) -> bool { match layout.abi { - layout::Abi::Scalar(layout::F32) | - layout::Abi::Scalar(layout::F64) => true, + layout::Abi::Scalar(ref scalar) => { + match scalar.value { + layout::F32 | layout::F64 => true, + _ => false + } + } layout::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(ccx, layout.field(ccx, 0)) diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index 401e75387c4..dc9f681af52 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -22,8 +22,12 @@ pub enum Flavor { fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, layout: TyLayout<'tcx>) -> bool { match layout.abi { - layout::Abi::Scalar(layout::F32) | - layout::Abi::Scalar(layout::F64) => true, + layout::Abi::Scalar(ref scalar) => { + match scalar.value { + layout::F32 | layout::F64 => true, + _ => false + } + } layout::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(ccx, layout.field(ccx, 0)) diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index b799a7690bd..bc445c7d2a7 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -65,8 +65,8 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>) } match layout.abi { - layout::Abi::Scalar(value) => { - let reg = match value { + layout::Abi::Scalar(ref scalar) => { + let reg = match scalar.value { layout::Int(..) | layout::Pointer => Class::Int, layout::F32 | diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2768c7fb577..e0822b96eeb 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1429,11 +1429,13 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } | layout::Variants::NicheFilling { .. } => None, - layout::Variants::Tagged { discr, .. } => Some(discriminant_type_metadata(discr)), + layout::Variants::Tagged { ref discr, .. } => { + Some(discriminant_type_metadata(discr.value)) + } }; - match (layout.abi, discriminant_type_metadata) { - (layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr), + match (&layout.abi, discriminant_type_metadata) { + (&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr), _ => {} } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 83fc1017316..f6c4153c183 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -26,6 +26,7 @@ #![feature(i128_type)] #![feature(i128)] #![feature(inclusive_range)] +#![feature(inclusive_range_syntax)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index cd152a391b8..139c4c656db 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -671,10 +671,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (align | Alignment::Packed(arg.layout.align)) .non_abi()); } else { + // We can't use `LvalueRef::load` here because the argument + // may have a type we don't treat as immediate, but the ABI + // used for this call is passing it by-value. In that case, + // the load would just produce `OperandValue::Ref` instead + // of the `OperandValue::Immediate` we need for the call. llval = bcx.load(llval, align.non_abi()); - } - if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = arg.layout.abi { - bcx.range_metadata(llval, 0..2); + if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { + if scalar.is_bool() { + bcx.range_metadata(llval, 0..2); + } + } // We store bools as i8 so we need to truncate to i1. llval = base::to_immediate(bcx, llval, arg.layout); } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index d782ffe1f9d..7e1569c8f8f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -455,9 +455,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { Value(base)); } let layout = self.ccx.layout_of(projected_ty); - if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = layout.abi { + if let layout::Abi::Scalar(ref scalar) = layout.abi { let i1_type = Type::i1(self.ccx); - if val_ty(val) != i1_type { + if scalar.is_bool() && val_ty(val) != i1_type { unsafe { val = llvm::LLVMConstTrunc(val, i1_type.to_ref()); } @@ -685,10 +685,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { assert!(cast_layout.is_llvm_immediate()); let ll_t_out = cast_layout.immediate_llvm_type(self.ccx); let llval = operand.llval; - let signed = match self.ccx.layout_of(operand.ty).abi { - layout::Abi::Scalar(layout::Int(_, signed)) => signed, - _ => false - }; + + let mut signed = false; + let l = self.ccx.layout_of(operand.ty); + if let layout::Abi::Scalar(ref scalar) = l.abi { + if let layout::Int(_, true) = scalar.value { + signed = true; + } + } unsafe { match (r_t_in, r_t_out) { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 1f8209c7066..f9a179ee0ee 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -148,16 +148,29 @@ impl<'a, 'tcx> LvalueRef<'tcx> { const_llval } else { let load = bcx.load(self.llval, self.alignment.non_abi()); - if self.layout.ty.is_bool() { - bcx.range_metadata(load, 0..2); - } else if self.layout.ty.is_char() { - // a char is a Unicode codepoint, and so takes values from 0 - // to 0x10FFFF inclusive only. - bcx.range_metadata(load, 0..0x10FFFF+1); - } else if self.layout.ty.is_region_ptr() || - self.layout.ty.is_box() || - self.layout.ty.is_fn() { - bcx.nonnull_metadata(load); + if let layout::Abi::Scalar(ref scalar) = self.layout.abi { + let (min, max) = (scalar.valid_range.start, scalar.valid_range.end); + let max_next = max.wrapping_add(1); + let bits = scalar.value.size(bcx.ccx).bits(); + assert!(bits <= 128); + let mask = !0u128 >> (128 - bits); + // For a (max) value of -1, max will be `-1 as usize`, which overflows. + // However, that is fine here (it would still represent the full range), + // i.e., if the range is everything. The lo==hi case would be + // rejected by the LLVM verifier (it would mean either an + // empty set, which is impossible, or the entire range of the + // type, which is pointless). + match scalar.value { + layout::Int(..) if max_next & mask != min & mask => { + // llvm::ConstantRange can deal with ranges that wrap around, + // so an overflow on (max + 1) is fine. + bcx.range_metadata(load, min..max_next); + } + layout::Pointer if 0 < min && min < max => { + bcx.nonnull_metadata(load); + } + _ => {} + } } load }; @@ -274,48 +287,18 @@ impl<'a, 'tcx> LvalueRef<'tcx> { let cast_to = bcx.ccx.layout_of(cast_to).immediate_llvm_type(bcx.ccx); match self.layout.variants { layout::Variants::Single { index } => { - assert_eq!(index, 0); - return C_uint(cast_to, 0); + return C_uint(cast_to, index as u64); } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, } let discr = self.project_field(bcx, 0); - let discr_scalar = match discr.layout.abi { - layout::Abi::Scalar(discr) => discr, - _ => bug!("discriminant not scalar: {:#?}", discr.layout) - }; - let (min, max) = match self.layout.variants { - layout::Variants::Tagged { ref discr_range, .. } => { - (discr_range.start, discr_range.end) - } - _ => (0, !0), - }; - let max_next = max.wrapping_add(1); - let bits = discr_scalar.size(bcx.ccx).bits(); - assert!(bits <= 128); - let mask = !0u128 >> (128 - bits); - let lldiscr = bcx.load(discr.llval, discr.alignment.non_abi()); - match discr_scalar { - // For a (max) discr of -1, max will be `-1 as usize`, which overflows. - // However, that is fine here (it would still represent the full range), - layout::Int(..) if max_next & mask != min & mask => { - // llvm::ConstantRange can deal with ranges that wrap around, - // so an overflow on (max + 1) is fine. - bcx.range_metadata(lldiscr, min..max_next); - } - _ => { - // i.e., if the range is everything. The lo==hi case would be - // rejected by the LLVM verifier (it would mean either an - // empty set, which is impossible, or the entire range of the - // type, which is pointless). - } - }; + let lldiscr = discr.load(bcx).immediate(); match self.layout.variants { layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { .. } => { - let signed = match discr_scalar { + layout::Variants::Tagged { ref discr, .. } => { + let signed = match discr.value { layout::Int(_, signed) => signed, _ => false }; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index f584c6a653e..e52dcd07562 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -119,6 +119,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } // Use llvm.memset.p0i8.* to initialize byte arrays + let v = base::from_immediate(&bcx, v); if common::val_ty(v) == Type::i8(bcx.ccx) { base::call_memset(&bcx, start, v, size, align, false); return bcx; @@ -278,28 +279,25 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ll_t_out = cast.immediate_llvm_type(bcx.ccx); let llval = operand.immediate(); - match operand.layout.variants { - layout::Variants::Tagged { - ref discr_range, .. - } if discr_range.end > discr_range.start => { - // We want `table[e as usize]` to not - // have bound checks, and this is the most - // convenient place to put the `assume`. - - base::call_assume(&bcx, bcx.icmp( - llvm::IntULE, - llval, - C_uint_big(ll_t_in, discr_range.end) - )); + let mut signed = false; + if let layout::Abi::Scalar(ref scalar) = operand.layout.abi { + if let layout::Int(_, s) = scalar.value { + signed = s; + + if scalar.valid_range.end > scalar.valid_range.start { + // We want `table[e as usize]` to not + // have bound checks, and this is the most + // convenient place to put the `assume`. + + base::call_assume(&bcx, bcx.icmp( + llvm::IntULE, + llval, + C_uint_big(ll_t_in, scalar.valid_range.end) + )); + } } - _ => {} } - let signed = match operand.layout.abi { - layout::Abi::Scalar(layout::Int(_, signed)) => signed, - _ => false - }; - let newval = match (r_t_in, r_t_out) { (CastTy::Int(_), CastTy::Int(_)) => { bcx.intcast(llval, ll_t_out, signed) diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 53aaed15783..2774359c994 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -268,7 +268,6 @@ impl Type { pub fn from_integer(cx: &CrateContext, i: layout::Integer) -> Type { use rustc::ty::layout::Integer::*; match i { - I1 => Type::i1(cx), I8 => Type::i8(cx), I16 => Type::i16(cx), I32 => Type::i32(cx), diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6fec1a675cd..eab5cb159de 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -176,14 +176,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { - if let layout::Abi::Scalar(value) = self.abi { + if let layout::Abi::Scalar(ref scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs // can be either fat or thin (data pointers of fat pointers). if let Some(&llty) = ccx.scalar_lltypes().borrow().get(&self.ty) { return llty; } - let llty = match value { - layout::Int(layout::I1, _) => Type::i8(ccx), + let llty = match scalar.value { layout::Int(i, _) => Type::from_integer(ccx, i), layout::F32 => Type::f32(ccx), layout::F64 => Type::f64(ccx), @@ -249,11 +248,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { - if let layout::Abi::Scalar(layout::Int(layout::I1, _)) = self.abi { - Type::i1(ccx) - } else { - self.llvm_type(ccx) + if let layout::Abi::Scalar(ref scalar) = self.abi { + if scalar.is_bool() { + return Type::i1(ccx); + } } + self.llvm_type(ccx) } fn over_align(&self) -> Option<Align> { |
