@@ -221,6 +221,17 @@ impl ReprOptions {
221
221
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222
222
pub const MAX_SIMD_LANES : u64 = 1 << 0xF ;
223
223
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
+
224
235
/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225
236
/// for a target, which contains everything needed to compute layouts.
226
237
#[ derive( Debug , PartialEq , Eq ) ]
@@ -236,13 +247,14 @@ pub struct TargetDataLayout {
236
247
pub f32_align : AbiAlign ,
237
248
pub f64_align : AbiAlign ,
238
249
pub f128_align : AbiAlign ,
239
- pub pointer_size : Size ,
240
- pub pointer_align : AbiAlign ,
241
250
pub aggregate_align : AbiAlign ,
242
251
243
252
/// Alignments for vector types.
244
253
pub vector_align : Vec < ( Size , AbiAlign ) > ,
245
254
255
+ pub default_address_space : AddressSpace ,
256
+ pub address_space_info : Vec < ( AddressSpace , AddressSpaceInfo ) > ,
257
+
246
258
pub instruction_address_space : AddressSpace ,
247
259
248
260
/// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,14 +279,21 @@ impl Default for TargetDataLayout {
267
279
f32_align : AbiAlign :: new ( align ( 32 ) ) ,
268
280
f64_align : AbiAlign :: new ( align ( 64 ) ) ,
269
281
f128_align : AbiAlign :: new ( align ( 128 ) ) ,
270
- pointer_size : Size :: from_bits ( 64 ) ,
271
- pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
272
282
aggregate_align : AbiAlign { abi : align ( 8 ) } ,
273
283
vector_align : vec ! [
274
284
( Size :: from_bits( 64 ) , AbiAlign :: new( align( 64 ) ) ) ,
275
285
( Size :: from_bits( 128 ) , AbiAlign :: new( align( 128 ) ) ) ,
276
286
] ,
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 ,
278
297
c_enum_min_size : Integer :: I32 ,
279
298
}
280
299
}
@@ -288,6 +307,7 @@ pub enum TargetDataLayoutErrors<'a> {
288
307
InconsistentTargetArchitecture { dl : & ' a str , target : & ' a str } ,
289
308
InconsistentTargetPointerWidth { pointer_size : u64 , target : u32 } ,
290
309
InvalidBitsSize { err : String } ,
310
+ MissingAddressSpaceInfo { addr_space : AddressSpace } ,
291
311
}
292
312
293
313
impl TargetDataLayout {
@@ -298,6 +318,7 @@ impl TargetDataLayout {
298
318
/// determined from llvm string.
299
319
pub fn parse_from_llvm_datalayout_string < ' a > (
300
320
input : & ' a str ,
321
+ default_address_space : AddressSpace ,
301
322
) -> Result < TargetDataLayout , TargetDataLayoutErrors < ' a > > {
302
323
// Parse an address space index from a string.
303
324
let parse_address_space = |s : & ' a str , cause : & ' a str | {
@@ -334,6 +355,8 @@ impl TargetDataLayout {
334
355
} ;
335
356
336
357
let mut dl = TargetDataLayout :: default ( ) ;
358
+ dl. default_address_space = default_address_space;
359
+
337
360
let mut i128_align_src = 64 ;
338
361
for spec in input. split ( '-' ) {
339
362
let spec_parts = spec. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
@@ -349,13 +372,47 @@ impl TargetDataLayout {
349
372
[ "f32" , a @ ..] => dl. f32_align = parse_align ( a, "f32" ) ?,
350
373
[ "f64" , a @ ..] => dl. f64_align = parse_align ( a, "f64" ) ?,
351
374
[ "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
+ }
358
414
}
415
+
359
416
[ s, a @ ..] if s. starts_with ( 'i' ) => {
360
417
let Ok ( bits) = s[ 1 ..] . parse :: < u64 > ( ) else {
361
418
parse_size ( & s[ 1 ..] , "i" ) ?; // For the user error.
@@ -390,10 +447,34 @@ impl TargetDataLayout {
390
447
_ => { } // Ignore everything else.
391
448
}
392
449
}
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
+
393
473
Ok ( dl)
394
474
}
395
475
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.
397
478
///
398
479
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
399
480
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +485,21 @@ impl TargetDataLayout {
404
485
/// so we adopt such a more-constrained size bound due to its technical limitations.
405
486
#[ inline]
406
487
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 ( ) {
408
503
16 => 1 << 15 ,
409
504
32 => 1 << 31 ,
410
505
64 => 1 << 61 ,
@@ -414,8 +509,13 @@ impl TargetDataLayout {
414
509
415
510
#[ inline]
416
511
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 {
417
517
use Integer :: * ;
418
- match self . pointer_size . bits ( ) {
518
+ match self . pointer_index_in ( address_space ) . bits ( ) {
419
519
16 => I16 ,
420
520
32 => I32 ,
421
521
64 => I64 ,
@@ -439,6 +539,54 @@ impl TargetDataLayout {
439
539
Align :: from_bytes ( vec_size. bytes ( ) . next_power_of_two ( ) ) . unwrap ( ) ,
440
540
) )
441
541
}
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
+ }
442
590
}
443
591
444
592
pub trait HasDataLayout {
@@ -1104,7 +1252,7 @@ impl Primitive {
1104
1252
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1105
1253
// different address spaces can have different sizes
1106
1254
// (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 ) ,
1108
1256
}
1109
1257
}
1110
1258
@@ -1118,7 +1266,7 @@ impl Primitive {
1118
1266
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1119
1267
// different address spaces can have different alignments
1120
1268
// (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 ) ,
1122
1270
}
1123
1271
}
1124
1272
}
@@ -1422,8 +1570,8 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
1422
1570
pub struct AddressSpace ( pub u32 ) ;
1423
1571
1424
1572
impl 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 ) ;
1427
1575
}
1428
1576
1429
1577
/// The way we represent values to the backend
0 commit comments