@@ -221,6 +221,17 @@ impl ReprOptions {
221221/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222222pub const MAX_SIMD_LANES : u64 = 1 << 0xF ;
223223
224+ /// Informations relative to a specific address space.
225+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
226+ pub struct AddressSpaceInfo {
227+ /// The size of the bitwise representation of the pointer.
228+ pointer_size : Size ,
229+ /// The alignment requirements for pointers in this address space.
230+ pointer_align : AbiAlign ,
231+ /// The size of the index that used for address calculations on pointers in this address space.
232+ pointer_index : Size ,
233+ }
234+
224235/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225236/// for a target, which contains everything needed to compute layouts.
226237#[ derive( Debug , PartialEq , Eq ) ]
@@ -236,13 +247,14 @@ pub struct TargetDataLayout {
236247 pub f32_align : AbiAlign ,
237248 pub f64_align : AbiAlign ,
238249 pub f128_align : AbiAlign ,
239- pub pointer_size : Size ,
240- pub pointer_align : AbiAlign ,
241250 pub aggregate_align : AbiAlign ,
242251
243252 /// Alignments for vector types.
244253 pub vector_align : Vec < ( Size , AbiAlign ) > ,
245254
255+ pub default_address_space : AddressSpace ,
256+ pub address_space_info : Vec < ( AddressSpace , AddressSpaceInfo ) > ,
257+
246258 pub instruction_address_space : AddressSpace ,
247259
248260 /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,14 +279,21 @@ impl Default for TargetDataLayout {
267279 f32_align : AbiAlign :: new ( align ( 32 ) ) ,
268280 f64_align : AbiAlign :: new ( align ( 64 ) ) ,
269281 f128_align : AbiAlign :: new ( align ( 128 ) ) ,
270- pointer_size : Size :: from_bits ( 64 ) ,
271- pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
272282 aggregate_align : AbiAlign { abi : align ( 8 ) } ,
273283 vector_align : vec ! [
274284 ( Size :: from_bits( 64 ) , AbiAlign :: new( align( 64 ) ) ) ,
275285 ( Size :: from_bits( 128 ) , AbiAlign :: new( align( 128 ) ) ) ,
276286 ] ,
277- instruction_address_space : AddressSpace :: DATA ,
287+ default_address_space : AddressSpace :: ZERO ,
288+ address_space_info : vec ! [ (
289+ AddressSpace :: ZERO ,
290+ AddressSpaceInfo {
291+ pointer_size: Size :: from_bits( 64 ) ,
292+ pointer_align: AbiAlign :: new( align( 64 ) ) ,
293+ pointer_index: Size :: from_bits( 64 ) ,
294+ } ,
295+ ) ] ,
296+ instruction_address_space : AddressSpace :: ZERO ,
278297 c_enum_min_size : Integer :: I32 ,
279298 }
280299 }
@@ -288,6 +307,7 @@ pub enum TargetDataLayoutErrors<'a> {
288307 InconsistentTargetArchitecture { dl : & ' a str , target : & ' a str } ,
289308 InconsistentTargetPointerWidth { pointer_size : u64 , target : u32 } ,
290309 InvalidBitsSize { err : String } ,
310+ MissingAddressSpaceInfo { addr_space : AddressSpace } ,
291311}
292312
293313impl TargetDataLayout {
@@ -298,6 +318,7 @@ impl TargetDataLayout {
298318 /// determined from llvm string.
299319 pub fn parse_from_llvm_datalayout_string < ' a > (
300320 input : & ' a str ,
321+ default_address_space : AddressSpace ,
301322 ) -> Result < TargetDataLayout , TargetDataLayoutErrors < ' a > > {
302323 // Parse an address space index from a string.
303324 let parse_address_space = |s : & ' a str , cause : & ' a str | {
@@ -334,6 +355,8 @@ impl TargetDataLayout {
334355 } ;
335356
336357 let mut dl = TargetDataLayout :: default ( ) ;
358+ dl. default_address_space = default_address_space;
359+
337360 let mut i128_align_src = 64 ;
338361 for spec in input. split ( '-' ) {
339362 let spec_parts = spec. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
@@ -349,13 +372,47 @@ impl TargetDataLayout {
349372 [ "f32" , a @ ..] => dl. f32_align = parse_align ( a, "f32" ) ?,
350373 [ "f64" , a @ ..] => dl. f64_align = parse_align ( a, "f64" ) ?,
351374 [ "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) ?;
375+ [ p, s, a @ ..] if p. starts_with ( "p" ) => {
376+ let p = p. strip_prefix ( char:: is_alphabetic) . unwrap_or_default ( ) ;
377+
378+ let addr_space = if !p. is_empty ( ) {
379+ parse_address_space ( p, "p" ) ?
380+ } else {
381+ AddressSpace :: ZERO
382+ } ;
383+
384+ let pointer_size = parse_size ( s, p) ?;
385+ let info = AddressSpaceInfo {
386+ pointer_index : pointer_size,
387+ pointer_size,
388+ pointer_align : parse_align ( a, p) ?,
389+ } ;
390+ match dl. address_space_info . iter_mut ( ) . find ( |( a, _) | * a == addr_space) {
391+ Some ( e) => e. 1 = info,
392+ None => dl. address_space_info . push ( ( addr_space, info) ) ,
393+ }
394+ }
395+ [ p, s, _pr, i, a @ ..] if p. starts_with ( "p" ) => {
396+ let p = p. strip_prefix ( char:: is_alphabetic) . unwrap_or_default ( ) ;
397+
398+ let addr_space = if !p. is_empty ( ) {
399+ parse_address_space ( p, "p" ) ?
400+ } else {
401+ AddressSpace :: ZERO
402+ } ;
403+
404+ let info = AddressSpaceInfo {
405+ pointer_align : parse_align ( a, p) ?,
406+ pointer_size : parse_size ( s, p) ?,
407+ pointer_index : parse_size ( i, p) ?,
408+ } ;
409+
410+ match dl. address_space_info . iter_mut ( ) . find ( |( a, _) | * a == addr_space) {
411+ Some ( e) => e. 1 = info,
412+ None => dl. address_space_info . push ( ( addr_space, info) ) ,
413+ }
358414 }
415+
359416 [ s, a @ ..] if s. starts_with ( 'i' ) => {
360417 let Ok ( bits) = s[ 1 ..] . parse :: < u64 > ( ) else {
361418 parse_size ( & s[ 1 ..] , "i" ) ?; // For the user error.
@@ -390,10 +447,34 @@ impl TargetDataLayout {
390447 _ => { } // Ignore everything else.
391448 }
392449 }
450+
451+ if dl. address_space_info . iter ( ) . find ( |( a, _) | * a == default_address_space) . is_none ( ) {
452+ return Err ( TargetDataLayoutErrors :: MissingAddressSpaceInfo {
453+ addr_space : default_address_space,
454+ } ) ;
455+ }
456+
457+ // Inherit, if not given, address space informations for specific LLVM elements from the
458+ // default data address space.
459+
460+ if dl. address_space_info . iter ( ) . find ( |( a, _) | * a == dl. instruction_address_space ) . is_none ( )
461+ {
462+ dl. address_space_info . push ( (
463+ dl. instruction_address_space ,
464+ dl. address_space_info
465+ . iter ( )
466+ . find ( |( a, _) | * a == default_address_space)
467+ . unwrap ( )
468+ . 1
469+ . clone ( ) ,
470+ ) ) ;
471+ }
472+
393473 Ok ( dl)
394474 }
395475
396- /// Returns **exclusive** upper bound on object size in bytes.
476+ /// Returns **exclusive** upper bound on object size in bytes, in the default data address
477+ /// space.
397478 ///
398479 /// The theoretical maximum object size is defined as the maximum positive `isize` value.
399480 /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +485,21 @@ impl TargetDataLayout {
404485 /// so we adopt such a more-constrained size bound due to its technical limitations.
405486 #[ inline]
406487 pub fn obj_size_bound ( & self ) -> u64 {
407- match self . pointer_size . bits ( ) {
488+ self . obj_size_bound_in ( self . default_address_space )
489+ }
490+
491+ /// Returns **exclusive** upper bound on object size in bytes.
492+ ///
493+ /// The theoretical maximum object size is defined as the maximum positive `isize` value.
494+ /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
495+ /// index every address within an object along with one byte past the end, along with allowing
496+ /// `isize` to store the difference between any two pointers into an object.
497+ ///
498+ /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
499+ /// so we adopt such a more-constrained size bound due to its technical limitations.
500+ #[ inline]
501+ pub fn obj_size_bound_in ( & self , address_space : AddressSpace ) -> u64 {
502+ match self . pointer_size_in ( address_space) . bits ( ) {
408503 16 => 1 << 15 ,
409504 32 => 1 << 31 ,
410505 64 => 1 << 61 ,
@@ -414,8 +509,13 @@ impl TargetDataLayout {
414509
415510 #[ inline]
416511 pub fn ptr_sized_integer ( & self ) -> Integer {
512+ self . ptr_sized_integer_in ( self . default_address_space )
513+ }
514+
515+ #[ inline]
516+ pub fn ptr_sized_integer_in ( & self , address_space : AddressSpace ) -> Integer {
417517 use Integer :: * ;
418- match self . pointer_size . bits ( ) {
518+ match self . pointer_index_in ( address_space ) . bits ( ) {
419519 16 => I16 ,
420520 32 => I32 ,
421521 64 => I64 ,
@@ -439,6 +539,54 @@ impl TargetDataLayout {
439539 Align :: from_bytes ( vec_size. bytes ( ) . next_power_of_two ( ) ) . unwrap ( ) ,
440540 ) )
441541 }
542+
543+ /// Get the pointer size in the default data address space.
544+ #[ inline]
545+ pub fn pointer_size ( & self ) -> Size {
546+ self . pointer_size_in ( self . default_address_space )
547+ }
548+
549+ /// Get the pointer size in a specific address space.
550+ #[ inline]
551+ pub fn pointer_size_in ( & self , c : AddressSpace ) -> Size {
552+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
553+ e. 1 . pointer_size
554+ } else {
555+ panic ! ( "Use of unknown address space {c:?}" ) ;
556+ }
557+ }
558+
559+ /// Get the pointer index in the default data address space.
560+ #[ inline]
561+ pub fn pointer_index ( & self ) -> Size {
562+ self . pointer_index_in ( self . default_address_space )
563+ }
564+
565+ /// Get the pointer index in a specific address space.
566+ #[ inline]
567+ pub fn pointer_index_in ( & self , c : AddressSpace ) -> Size {
568+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
569+ e. 1 . pointer_index
570+ } else {
571+ panic ! ( "Use of unknown address space {c:?}" ) ;
572+ }
573+ }
574+
575+ /// Get the pointer alignment in the default data address space.
576+ #[ inline]
577+ pub fn pointer_align ( & self ) -> AbiAlign {
578+ self . pointer_align_in ( self . default_address_space )
579+ }
580+
581+ /// Get the pointer alignment in a specific address space.
582+ #[ inline]
583+ pub fn pointer_align_in ( & self , c : AddressSpace ) -> AbiAlign {
584+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
585+ e. 1 . pointer_align
586+ } else {
587+ panic ! ( "Use of unknown address space {c:?}" ) ;
588+ }
589+ }
442590}
443591
444592pub trait HasDataLayout {
@@ -1104,7 +1252,7 @@ impl Primitive {
11041252 // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11051253 // different address spaces can have different sizes
11061254 // (but TargetDataLayout doesn't currently parse that part of the DL string)
1107- Pointer ( _ ) => dl. pointer_size ,
1255+ Pointer ( a ) => dl. pointer_size_in ( a ) ,
11081256 }
11091257 }
11101258
@@ -1118,7 +1266,7 @@ impl Primitive {
11181266 // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11191267 // different address spaces can have different alignments
11201268 // (but TargetDataLayout doesn't currently parse that part of the DL string)
1121- Pointer ( _ ) => dl. pointer_align ,
1269+ Pointer ( a ) => dl. pointer_align_in ( a ) ,
11221270 }
11231271 }
11241272}
@@ -1422,8 +1570,8 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
14221570pub struct AddressSpace ( pub u32 ) ;
14231571
14241572impl AddressSpace {
1425- /// The default address space, corresponding to data space.
1426- pub const DATA : Self = AddressSpace ( 0 ) ;
1573+ /// LLVM's `0` address space.
1574+ pub const ZERO : Self = AddressSpace ( 0 ) ;
14271575}
14281576
14291577/// The way we represent values to the backend
0 commit comments