@@ -47,6 +47,7 @@ use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
4747use std::str::FromStr;
4848
4949use bitflags::bitflags;
50+ use rustc_data_structures::fx::FxHashMap;
5051#[cfg(feature = "nightly")]
5152use rustc_data_structures::stable_hasher::StableOrd;
5253use rustc_hashes::Hash64;
@@ -221,6 +222,17 @@ impl ReprOptions {
221222/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222223pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
223224
225+ /// Informations relative to a specific address space.
226+ #[derive(Copy, Clone, Debug, PartialEq, Eq)]
227+ pub struct AddressSpaceInfo {
228+ /// The size of the bitwise representation of the pointer.
229+ pointer_size: Size,
230+ /// The alignment requirements for pointers in this address space.
231+ pointer_align: AbiAlign,
232+ /// The size of the index that used for address calculations on pointers in this address space.
233+ pointer_index: Size,
234+ }
235+
224236/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225237/// for a target, which contains everything needed to compute layouts.
226238#[derive(Debug, PartialEq, Eq)]
@@ -236,13 +248,14 @@ pub struct TargetDataLayout {
236248 pub f32_align: AbiAlign,
237249 pub f64_align: AbiAlign,
238250 pub f128_align: AbiAlign,
239- pub pointer_size: Size,
240- pub pointer_align: AbiAlign,
241251 pub aggregate_align: AbiAlign,
242252
243253 /// Alignments for vector types.
244254 pub vector_align: Vec<(Size, AbiAlign)>,
245255
256+ pub default_address_space: AddressSpace,
257+ pub address_space_info: FxHashMap<AddressSpace, AddressSpaceInfo>,
258+
246259 pub instruction_address_space: AddressSpace,
247260
248261 /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,14 +280,21 @@ impl Default for TargetDataLayout {
267280 f32_align: AbiAlign::new(align(32)),
268281 f64_align: AbiAlign::new(align(64)),
269282 f128_align: AbiAlign::new(align(128)),
270- pointer_size: Size::from_bits(64),
271- pointer_align: AbiAlign::new(align(64)),
272283 aggregate_align: AbiAlign { abi: align(8) },
273284 vector_align: vec![
274285 (Size::from_bits(64), AbiAlign::new(align(64))),
275286 (Size::from_bits(128), AbiAlign::new(align(128))),
276287 ],
277- instruction_address_space: AddressSpace::DATA,
288+ default_address_space: AddressSpace::ZERO,
289+ address_space_info: FxHashMap::from_iter([(
290+ AddressSpace::ZERO,
291+ AddressSpaceInfo {
292+ pointer_size: Size::from_bits(64),
293+ pointer_align: AbiAlign::new(align(64)),
294+ pointer_index: Size::from_bits(64),
295+ },
296+ )]),
297+ instruction_address_space: AddressSpace::ZERO,
278298 c_enum_min_size: Integer::I32,
279299 }
280300 }
@@ -288,6 +308,7 @@ pub enum TargetDataLayoutErrors<'a> {
288308 InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
289309 InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
290310 InvalidBitsSize { err: String },
311+ MissingAddressSpaceInfo { addr_space: AddressSpace },
291312}
292313
293314impl TargetDataLayout {
@@ -298,6 +319,7 @@ impl TargetDataLayout {
298319 /// determined from llvm string.
299320 pub fn parse_from_llvm_datalayout_string<'a>(
300321 input: &'a str,
322+ default_address_space: AddressSpace,
301323 ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
302324 // Parse an address space index from a string.
303325 let parse_address_space = |s: &'a str, cause: &'a str| {
@@ -334,6 +356,8 @@ impl TargetDataLayout {
334356 };
335357
336358 let mut dl = TargetDataLayout::default();
359+ dl.default_address_space = default_address_space;
360+
337361 let mut i128_align_src = 64;
338362 for spec in input.split('-') {
339363 let spec_parts = spec.split(':').collect::<Vec<_>>();
@@ -349,13 +373,48 @@ impl TargetDataLayout {
349373 ["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?,
350374 ["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?,
351375 ["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?,
352- // FIXME(erikdesjardins): we should be parsing nonzero address spaces
353- // this will require replacing TargetDataLayout::{pointer_size,pointer_align}
354- // with e.g. `fn pointer_size_in(AddressSpace)`
355- [p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => {
356- dl.pointer_size = parse_size(s, p)?;
357- dl.pointer_align = parse_align(a, p)?;
376+ [p, s, a @ ..] if p.starts_with("p") => {
377+ let p = p.strip_prefix(char::is_alphabetic).unwrap_or_default();
378+
379+ let addr_space = if !p.is_empty() {
380+ parse_address_space(p, "p")?
381+ } else {
382+ AddressSpace::ZERO
383+ };
384+
385+ let pointer_size = parse_size(s, p)?;
386+ let info = AddressSpaceInfo {
387+ pointer_index: pointer_size,
388+ pointer_size,
389+ pointer_align: parse_align(a, p)?,
390+ };
391+
392+ dl.address_space_info
393+ .entry(addr_space)
394+ .and_modify(|v| *v = info)
395+ .or_insert(info);
396+ }
397+ [p, s, _pr, i, a @ ..] if p.starts_with("p") => {
398+ let p = p.strip_prefix(char::is_alphabetic).unwrap_or_default();
399+
400+ let addr_space = if !p.is_empty() {
401+ parse_address_space(p, "p")?
402+ } else {
403+ AddressSpace::ZERO
404+ };
405+
406+ let info = AddressSpaceInfo {
407+ pointer_align: parse_align(a, p)?,
408+ pointer_size: parse_size(s, p)?,
409+ pointer_index: parse_size(i, p)?,
410+ };
411+
412+ dl.address_space_info
413+ .entry(addr_space)
414+ .and_modify(|v| *v = info)
415+ .or_insert(info);
358416 }
417+
359418 [s, a @ ..] if s.starts_with('i') => {
360419 let Ok(bits) = s[1..].parse::<u64>() else {
361420 parse_size(&s[1..], "i")?; // For the user error.
@@ -390,10 +449,28 @@ impl TargetDataLayout {
390449 _ => {} // Ignore everything else.
391450 }
392451 }
452+
453+ if !dl.address_space_info.contains_key(&default_address_space) {
454+ return Err(TargetDataLayoutErrors::MissingAddressSpaceInfo {
455+ addr_space: default_address_space,
456+ });
457+ }
458+
459+ // Inherit, if not given, address space informations for specific LLVM elements from the
460+ // default data address space.
461+
462+ if !dl.address_space_info.contains_key(&dl.instruction_address_space) {
463+ dl.address_space_info.insert(
464+ dl.instruction_address_space,
465+ dl.address_space_info.get(&default_address_space).unwrap().clone(),
466+ );
467+ }
468+
393469 Ok(dl)
394470 }
395471
396- /// Returns **exclusive** upper bound on object size in bytes.
472+ /// Returns **exclusive** upper bound on object size in bytes, in the default data address
473+ /// space.
397474 ///
398475 /// The theoretical maximum object size is defined as the maximum positive `isize` value.
399476 /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +481,21 @@ impl TargetDataLayout {
404481 /// so we adopt such a more-constrained size bound due to its technical limitations.
405482 #[inline]
406483 pub fn obj_size_bound(&self) -> u64 {
407- match self.pointer_size.bits() {
484+ self.obj_size_bound_in(self.default_address_space)
485+ }
486+
487+ /// Returns **exclusive** upper bound on object size in bytes.
488+ ///
489+ /// The theoretical maximum object size is defined as the maximum positive `isize` value.
490+ /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
491+ /// index every address within an object along with one byte past the end, along with allowing
492+ /// `isize` to store the difference between any two pointers into an object.
493+ ///
494+ /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
495+ /// so we adopt such a more-constrained size bound due to its technical limitations.
496+ #[inline]
497+ pub fn obj_size_bound_in(&self, address_space: AddressSpace) -> u64 {
498+ match self.pointer_size_in(address_space).bits() {
408499 16 => 1 << 15,
409500 32 => 1 << 31,
410501 64 => 1 << 61,
@@ -414,8 +505,13 @@ impl TargetDataLayout {
414505
415506 #[inline]
416507 pub fn ptr_sized_integer(&self) -> Integer {
508+ self.ptr_sized_integer_in(self.default_address_space)
509+ }
510+
511+ #[inline]
512+ pub fn ptr_sized_integer_in(&self, address_space: AddressSpace) -> Integer {
417513 use Integer::*;
418- match self.pointer_size .bits() {
514+ match self.pointer_index_in(address_space) .bits() {
419515 16 => I16,
420516 32 => I32,
421517 64 => I64,
@@ -439,6 +535,54 @@ impl TargetDataLayout {
439535 Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
440536 ))
441537 }
538+
539+ /// Get the pointer size in the default data address space.
540+ #[inline]
541+ pub fn pointer_size(&self) -> Size {
542+ self.pointer_size_in(self.default_address_space)
543+ }
544+
545+ /// Get the pointer size in a specific address space.
546+ #[inline]
547+ pub fn pointer_size_in(&self, c: AddressSpace) -> Size {
548+ if let Some(c) = self.address_space_info.get(&c) {
549+ c.pointer_size
550+ } else {
551+ panic!("Use of unknown address space {c:?}");
552+ }
553+ }
554+
555+ /// Get the pointer index in the default data address space.
556+ #[inline]
557+ pub fn pointer_index(&self) -> Size {
558+ self.pointer_index_in(self.default_address_space)
559+ }
560+
561+ /// Get the pointer index in a specific address space.
562+ #[inline]
563+ pub fn pointer_index_in(&self, c: AddressSpace) -> Size {
564+ if let Some(c) = self.address_space_info.get(&c) {
565+ c.pointer_index
566+ } else {
567+ panic!("Use of unknown address space {c:?}");
568+ }
569+ }
570+
571+ /// Get the pointer alignment in the default data address space.
572+ #[inline]
573+ pub fn pointer_align(&self) -> AbiAlign {
574+ self.pointer_align_in(self.default_address_space)
575+ }
576+
577+ /// Get the pointer alignment in a specific address space.
578+ #[inline]
579+ pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign {
580+ if let Some(c) = self.address_space_info.get(&c) {
581+ c.pointer_align
582+ } else {
583+ panic!("Use of unknown address space {c:?}");
584+ }
585+ }
442586}
443587
444588pub trait HasDataLayout {
@@ -1104,7 +1248,7 @@ impl Primitive {
11041248 // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11051249 // different address spaces can have different sizes
11061250 // (but TargetDataLayout doesn't currently parse that part of the DL string)
1107- Pointer(_ ) => dl.pointer_size ,
1251+ Pointer(a ) => dl.pointer_size_in(a) ,
11081252 }
11091253 }
11101254
@@ -1118,7 +1262,7 @@ impl Primitive {
11181262 // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11191263 // different address spaces can have different alignments
11201264 // (but TargetDataLayout doesn't currently parse that part of the DL string)
1121- Pointer(_ ) => dl.pointer_align ,
1265+ Pointer(a ) => dl.pointer_align_in(a) ,
11221266 }
11231267 }
11241268}
@@ -1422,8 +1566,8 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
14221566pub struct AddressSpace(pub u32);
14231567
14241568impl AddressSpace {
1425- /// The default address space, corresponding to data space.
1426- pub const DATA : Self = AddressSpace(0);
1569+ /// LLVM's `0` address space.
1570+ pub const ZERO : Self = AddressSpace(0);
14271571}
14281572
14291573/// The way we represent values to the backend
0 commit comments