@@ -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,22 @@ 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 default_address_space_info : AddressSpaceInfo ,
257+
258+ /// The address space informations relative to all the known address spaces.
259+ ///
260+ /// # Note
261+ ///
262+ /// This vector does not contain the [`AddressSpaceInfo`] relative to the default address space,
263+ /// which instead lives in [`Self::default_address_space_info`].
264+ address_space_info : Vec < ( AddressSpace , AddressSpaceInfo ) > ,
265+
246266 pub instruction_address_space : AddressSpace ,
247267
248268 /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,13 +287,18 @@ impl Default for TargetDataLayout {
267287 f32_align : AbiAlign :: new ( align ( 32 ) ) ,
268288 f64_align : AbiAlign :: new ( align ( 64 ) ) ,
269289 f128_align : AbiAlign :: new ( align ( 128 ) ) ,
270- pointer_size : Size :: from_bits ( 64 ) ,
271- pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
272290 aggregate_align : AbiAlign { abi : align ( 8 ) } ,
273291 vector_align : vec ! [
274292 ( Size :: from_bits( 64 ) , AbiAlign :: new( align( 64 ) ) ) ,
275293 ( Size :: from_bits( 128 ) , AbiAlign :: new( align( 128 ) ) ) ,
276294 ] ,
295+ default_address_space : AddressSpace :: ZERO ,
296+ default_address_space_info : AddressSpaceInfo {
297+ pointer_size : Size :: from_bits ( 64 ) ,
298+ pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
299+ pointer_index : Size :: from_bits ( 64 ) ,
300+ } ,
301+ address_space_info : vec ! [ ] ,
277302 instruction_address_space : AddressSpace :: ZERO ,
278303 c_enum_min_size : Integer :: I32 ,
279304 }
@@ -298,6 +323,7 @@ impl TargetDataLayout {
298323 /// determined from llvm string.
299324 pub fn parse_from_llvm_datalayout_string < ' a > (
300325 input : & ' a str ,
326+ default_address_space : AddressSpace ,
301327 ) -> Result < TargetDataLayout , TargetDataLayoutErrors < ' a > > {
302328 // Parse an address space index from a string.
303329 let parse_address_space = |s : & ' a str , cause : & ' a str | {
@@ -334,6 +360,8 @@ impl TargetDataLayout {
334360 } ;
335361
336362 let mut dl = TargetDataLayout :: default ( ) ;
363+ dl. default_address_space = default_address_space;
364+
337365 let mut i128_align_src = 64 ;
338366 for spec in input. split ( '-' ) {
339367 let spec_parts = spec. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
@@ -349,13 +377,63 @@ impl TargetDataLayout {
349377 [ "f32" , a @ ..] => dl. f32_align = parse_align ( a, "f32" ) ?,
350378 [ "f64" , a @ ..] => dl. f64_align = parse_align ( a, "f64" ) ?,
351379 [ "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) ?;
380+ [ p, s, a @ ..] if p. starts_with ( "p" ) => {
381+ // Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that
382+ // they use 'fat' pointers. The resulting prefix may look like `pf<addr_space>`.
383+ let p = p. trim_start_matches ( char:: is_alphabetic) ;
384+
385+ let addr_space = if !p. is_empty ( ) {
386+ parse_address_space ( p, "p" ) ?
387+ } else {
388+ AddressSpace :: ZERO
389+ } ;
390+
391+ let pointer_size = parse_size ( s, p) ?;
392+ let info = AddressSpaceInfo {
393+ pointer_index : pointer_size,
394+ pointer_size,
395+ pointer_align : parse_align ( a, p) ?,
396+ } ;
397+ if addr_space == default_address_space {
398+ dl. default_address_space_info = info;
399+ } else {
400+ match dl. address_space_info . iter_mut ( ) . find ( |( a, _) | * a == addr_space) {
401+ Some ( e) => e. 1 = info,
402+ None => {
403+ dl. address_space_info . push ( ( addr_space, info) ) ;
404+ }
405+ }
406+ }
407+ }
408+ [ p, s, _pr, i, a @ ..] if p. starts_with ( "p" ) => {
409+ // Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that
410+ // they use 'fat' pointers. The resulting prefix may look like `pf<addr_space>`.
411+ let p = p. trim_start_matches ( char:: is_alphabetic) ;
412+
413+ let addr_space = if !p. is_empty ( ) {
414+ parse_address_space ( p, "p" ) ?
415+ } else {
416+ AddressSpace :: ZERO
417+ } ;
418+
419+ let info = AddressSpaceInfo {
420+ pointer_align : parse_align ( a, p) ?,
421+ pointer_size : parse_size ( s, p) ?,
422+ pointer_index : parse_size ( i, p) ?,
423+ } ;
424+
425+ if addr_space == default_address_space {
426+ dl. default_address_space_info = info;
427+ } else {
428+ match dl. address_space_info . iter_mut ( ) . find ( |( a, _) | * a == addr_space) {
429+ Some ( e) => e. 1 = info,
430+ None => {
431+ dl. address_space_info . push ( ( addr_space, info) ) ;
432+ }
433+ }
434+ }
358435 }
436+
359437 [ s, a @ ..] if s. starts_with ( 'i' ) => {
360438 let Ok ( bits) = s[ 1 ..] . parse :: < u64 > ( ) else {
361439 parse_size ( & s[ 1 ..] , "i" ) ?; // For the user error.
@@ -390,10 +468,25 @@ impl TargetDataLayout {
390468 _ => { } // Ignore everything else.
391469 }
392470 }
471+
472+ // Inherit, if not given, address space informations for specific LLVM elements from the
473+ // default data address space.
474+ if ( dl. instruction_address_space != dl. default_address_space )
475+ && dl
476+ . address_space_info
477+ . iter ( )
478+ . find ( |( a, _) | * a == dl. instruction_address_space )
479+ . is_none ( )
480+ {
481+ dl. address_space_info
482+ . push ( ( dl. instruction_address_space , dl. default_address_space_info . clone ( ) ) ) ;
483+ }
484+
393485 Ok ( dl)
394486 }
395487
396- /// Returns **exclusive** upper bound on object size in bytes.
488+ /// Returns **exclusive** upper bound on object size in bytes, in the default data address
489+ /// space.
397490 ///
398491 /// The theoretical maximum object size is defined as the maximum positive `isize` value.
399492 /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +497,26 @@ impl TargetDataLayout {
404497 /// so we adopt such a more-constrained size bound due to its technical limitations.
405498 #[ inline]
406499 pub fn obj_size_bound ( & self ) -> u64 {
407- match self . pointer_size . bits ( ) {
500+ match self . pointer_size ( ) . bits ( ) {
501+ 16 => 1 << 15 ,
502+ 32 => 1 << 31 ,
503+ 64 => 1 << 61 ,
504+ bits => panic ! ( "obj_size_bound: unknown pointer bit size {bits}" ) ,
505+ }
506+ }
507+
508+ /// Returns **exclusive** upper bound on object size in bytes.
509+ ///
510+ /// The theoretical maximum object size is defined as the maximum positive `isize` value.
511+ /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
512+ /// index every address within an object along with one byte past the end, along with allowing
513+ /// `isize` to store the difference between any two pointers into an object.
514+ ///
515+ /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
516+ /// so we adopt such a more-constrained size bound due to its technical limitations.
517+ #[ inline]
518+ pub fn obj_size_bound_in ( & self , address_space : AddressSpace ) -> u64 {
519+ match self . pointer_size_in ( address_space) . bits ( ) {
408520 16 => 1 << 15 ,
409521 32 => 1 << 31 ,
410522 64 => 1 << 61 ,
@@ -415,7 +527,18 @@ impl TargetDataLayout {
415527 #[ inline]
416528 pub fn ptr_sized_integer ( & self ) -> Integer {
417529 use Integer :: * ;
418- match self . pointer_size . bits ( ) {
530+ match self . pointer_index ( ) . bits ( ) {
531+ 16 => I16 ,
532+ 32 => I32 ,
533+ 64 => I64 ,
534+ bits => panic ! ( "ptr_sized_integer: unknown pointer bit size {bits}" ) ,
535+ }
536+ }
537+
538+ #[ inline]
539+ pub fn ptr_sized_integer_in ( & self , address_space : AddressSpace ) -> Integer {
540+ use Integer :: * ;
541+ match self . pointer_index_in ( address_space) . bits ( ) {
419542 16 => I16 ,
420543 32 => I32 ,
421544 64 => I64 ,
@@ -439,6 +562,66 @@ impl TargetDataLayout {
439562 Align :: from_bytes ( vec_size. bytes ( ) . next_power_of_two ( ) ) . unwrap ( ) ,
440563 ) )
441564 }
565+
566+ /// Get the pointer size in the default data address space.
567+ #[ inline]
568+ pub fn pointer_size ( & self ) -> Size {
569+ self . default_address_space_info . pointer_size
570+ }
571+
572+ /// Get the pointer size in a specific address space.
573+ #[ inline]
574+ pub fn pointer_size_in ( & self , c : AddressSpace ) -> Size {
575+ if c == self . default_address_space {
576+ return self . default_address_space_info . pointer_size ;
577+ }
578+
579+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
580+ e. 1 . pointer_size
581+ } else {
582+ panic ! ( "Use of unknown address space {c:?}" ) ;
583+ }
584+ }
585+
586+ /// Get the pointer index in the default data address space.
587+ #[ inline]
588+ pub fn pointer_index ( & self ) -> Size {
589+ self . default_address_space_info . pointer_index
590+ }
591+
592+ /// Get the pointer index in a specific address space.
593+ #[ inline]
594+ pub fn pointer_index_in ( & self , c : AddressSpace ) -> Size {
595+ if c == self . default_address_space {
596+ return self . default_address_space_info . pointer_index ;
597+ }
598+
599+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
600+ e. 1 . pointer_index
601+ } else {
602+ panic ! ( "Use of unknown address space {c:?}" ) ;
603+ }
604+ }
605+
606+ /// Get the pointer alignment in the default data address space.
607+ #[ inline]
608+ pub fn pointer_align ( & self ) -> AbiAlign {
609+ self . default_address_space_info . pointer_align
610+ }
611+
612+ /// Get the pointer alignment in a specific address space.
613+ #[ inline]
614+ pub fn pointer_align_in ( & self , c : AddressSpace ) -> AbiAlign {
615+ if c == self . default_address_space {
616+ return self . default_address_space_info . pointer_align ;
617+ }
618+
619+ if let Some ( e) = self . address_space_info . iter ( ) . find ( |( a, _) | a == & c) {
620+ e. 1 . pointer_align
621+ } else {
622+ panic ! ( "Use of unknown address space {c:?}" ) ;
623+ }
624+ }
442625}
443626
444627pub trait HasDataLayout {
@@ -1101,10 +1284,7 @@ impl Primitive {
11011284 match self {
11021285 Int ( i, _) => i. size ( ) ,
11031286 Float ( f) => f. size ( ) ,
1104- // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1105- // different address spaces can have different sizes
1106- // (but TargetDataLayout doesn't currently parse that part of the DL string)
1107- Pointer ( _) => dl. pointer_size ,
1287+ Pointer ( a) => dl. pointer_size_in ( a) ,
11081288 }
11091289 }
11101290
@@ -1115,10 +1295,7 @@ impl Primitive {
11151295 match self {
11161296 Int ( i, _) => i. align ( dl) ,
11171297 Float ( f) => f. align ( dl) ,
1118- // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1119- // different address spaces can have different alignments
1120- // (but TargetDataLayout doesn't currently parse that part of the DL string)
1121- Pointer ( _) => dl. pointer_align ,
1298+ Pointer ( a) => dl. pointer_align_in ( a) ,
11221299 }
11231300 }
11241301}
0 commit comments