From 009192b01bd88a7bb6c1948d1f47dd598af0bfd9 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 22 Jan 2023 23:03:58 -0500 Subject: abi: add `AddressSpace` field to `Primitive::Pointer` ...and remove it from `PointeeInfo`, which isn't meant for this. There are still various places (marked with FIXMEs) that assume all pointers have the same size and alignment. Fixing this requires parsing non-default address spaces in the data layout string, which will be done in a followup. --- compiler/rustc_middle/src/ty/layout.rs | 222 ++++++++++++++++----------------- 1 file changed, 110 insertions(+), 112 deletions(-) (limited to 'compiler/rustc_middle/src/ty/layout.rs') diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dfd016569c2..66b9d96e695 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -128,7 +128,8 @@ impl PrimitiveExt for Primitive { Int(i, signed) => i.to_ty(tcx, signed), F32 => tcx.types.f32, F64 => tcx.types.f64, - Pointer => tcx.mk_mut_ptr(tcx.mk_unit()), + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()), } } @@ -138,7 +139,11 @@ impl PrimitiveExt for Primitive { fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { Int(i, signed) => i.to_ty(tcx, signed), - Pointer => tcx.types.usize, + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Pointer(_) => { + let signed = false; + tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed) + } F32 | F64 => bug!("floats do not have an int type"), } } @@ -812,132 +817,125 @@ where let tcx = cx.tcx(); let param_env = cx.param_env(); - let addr_space_of_ty = |ty: Ty<'tcx>| { - if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } - }; - - let pointee_info = match *this.ty.kind() { - ty::RawPtr(mt) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - address_space: addr_space_of_ty(mt.ty), - }) - } - ty::FnPtr(fn_sig) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - address_space: cx.data_layout().instruction_address_space, - }) - } - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let address_space = addr_space_of_ty(ty); - let kind = if tcx.sess.opts.optimize == OptLevel::No { - // Use conservative pointer kind if not optimizing. This saves us the - // Freeze/Unpin queries, and can save time in the codegen backend (noalias - // attributes in LLVM have compile-time cost even in unoptimized builds). - PointerKind::SharedMutable - } else { - match mt { - hir::Mutability::Not => { - if ty.is_freeze(tcx, cx.param_env()) { - PointerKind::Frozen - } else { - PointerKind::SharedMutable + let pointee_info = + match *this.ty.kind() { + ty::RawPtr(mt) if offset.bytes() == 0 => { + tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + }) + } + ty::FnPtr(fn_sig) if offset.bytes() == 0 => { + tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| { + PointeeInfo { size: layout.size, align: layout.align.abi, safe: None } + }) + } + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let kind = if tcx.sess.opts.optimize == OptLevel::No { + // Use conservative pointer kind if not optimizing. This saves us the + // Freeze/Unpin queries, and can save time in the codegen backend (noalias + // attributes in LLVM have compile-time cost even in unoptimized builds). + PointerKind::SharedMutable + } else { + match mt { + hir::Mutability::Not => { + if ty.is_freeze(tcx, cx.param_env()) { + PointerKind::Frozen + } else { + PointerKind::SharedMutable + } } - } - hir::Mutability::Mut => { - // References to self-referential structures should not be considered - // noalias, as another pointer to the structure can be obtained, that - // is not based-on the original reference. We consider all !Unpin - // types to be potentially self-referential here. - if ty.is_unpin(tcx, cx.param_env()) { - PointerKind::UniqueBorrowed - } else { - PointerKind::UniqueBorrowedPinned + hir::Mutability::Mut => { + // References to self-referential structures should not be considered + // noalias, as another pointer to the structure can be obtained, that + // is not based-on the original reference. We consider all !Unpin + // types to be potentially self-referential here. + if ty.is_unpin(tcx, cx.param_env()) { + PointerKind::UniqueBorrowed + } else { + PointerKind::UniqueBorrowedPinned + } } } - } - }; + }; - tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: Some(kind), - address_space, - }) - } + tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: Some(kind), + }) + } - _ => { - let mut data_variant = match this.variants { - // Within the discriminant field, only the niche itself is - // always initialized, so we only check for a pointer at its - // offset. - // - // If the niche is a pointer, it's either valid (according - // to its type), or null (which the niche field's scalar - // validity range encodes). This allows using - // `dereferenceable_or_null` for e.g., `Option<&T>`, and - // this will continue to work as long as we don't start - // using more niches than just null (e.g., the first page of - // the address space, or unaligned pointers). - Variants::Multiple { - tag_encoding: TagEncoding::Niche { untagged_variant, .. }, - tag_field, - .. - } if this.fields.offset(tag_field) == offset => { - Some(this.for_variant(cx, untagged_variant)) - } - _ => Some(this), - }; + _ => { + let mut data_variant = match this.variants { + // Within the discriminant field, only the niche itself is + // always initialized, so we only check for a pointer at its + // offset. + // + // If the niche is a pointer, it's either valid (according + // to its type), or null (which the niche field's scalar + // validity range encodes). This allows using + // `dereferenceable_or_null` for e.g., `Option<&T>`, and + // this will continue to work as long as we don't start + // using more niches than just null (e.g., the first page of + // the address space, or unaligned pointers). + Variants::Multiple { + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, + tag_field, + .. + } if this.fields.offset(tag_field) == offset => { + Some(this.for_variant(cx, untagged_variant)) + } + _ => Some(this), + }; - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let FieldsShape::Union(_) = variant.fields { - data_variant = None; + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let FieldsShape::Union(_) = variant.fields { + data_variant = None; + } } - } - let mut result = None; - - if let Some(variant) = data_variant { - let ptr_end = offset + Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - result = field.to_result().ok().and_then(|field| { - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - let field_info = - field.pointee_info_at(cx, offset - field_start); - field_info - } else { - None + let mut result = None; + + if let Some(variant) = data_variant { + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + // (requires passing in the expected address space from the caller) + let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + result = field.to_result().ok().and_then(|field| { + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + let field_info = + field.pointee_info_at(cx, offset - field_start); + field_info + } else { + None + } + }); + if result.is_some() { + break; } - }); - if result.is_some() { - break; } } } - } - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind() { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); + // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + if let Some(ref mut pointee) = result { + if let ty::Adt(def, _) = this.ty.kind() { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } } } - } - result - } - }; + result + } + }; debug!( "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", -- cgit 1.4.1-3-g733a5