@@ -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