@@ -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,22 @@ 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 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
+
246
266
pub instruction_address_space : AddressSpace ,
247
267
248
268
/// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,13 +287,18 @@ impl Default for TargetDataLayout {
267
287
f32_align : AbiAlign :: new ( align ( 32 ) ) ,
268
288
f64_align : AbiAlign :: new ( align ( 64 ) ) ,
269
289
f128_align : AbiAlign :: new ( align ( 128 ) ) ,
270
- pointer_size : Size :: from_bits ( 64 ) ,
271
- pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
272
290
aggregate_align : AbiAlign { abi : align ( 8 ) } ,
273
291
vector_align : vec ! [
274
292
( Size :: from_bits( 64 ) , AbiAlign :: new( align( 64 ) ) ) ,
275
293
( Size :: from_bits( 128 ) , AbiAlign :: new( align( 128 ) ) ) ,
276
294
] ,
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 ! [ ] ,
277
302
instruction_address_space : AddressSpace :: ZERO ,
278
303
c_enum_min_size : Integer :: I32 ,
279
304
}
@@ -298,6 +323,7 @@ impl TargetDataLayout {
298
323
/// determined from llvm string.
299
324
pub fn parse_from_llvm_datalayout_string < ' a > (
300
325
input : & ' a str ,
326
+ default_address_space : AddressSpace ,
301
327
) -> Result < TargetDataLayout , TargetDataLayoutErrors < ' a > > {
302
328
// Parse an address space index from a string.
303
329
let parse_address_space = |s : & ' a str , cause : & ' a str | {
@@ -334,6 +360,8 @@ impl TargetDataLayout {
334
360
} ;
335
361
336
362
let mut dl = TargetDataLayout :: default ( ) ;
363
+ dl. default_address_space = default_address_space;
364
+
337
365
let mut i128_align_src = 64 ;
338
366
for spec in input. split ( '-' ) {
339
367
let spec_parts = spec. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
@@ -349,13 +377,63 @@ impl TargetDataLayout {
349
377
[ "f32" , a @ ..] => dl. f32_align = parse_align ( a, "f32" ) ?,
350
378
[ "f64" , a @ ..] => dl. f64_align = parse_align ( a, "f64" ) ?,
351
379
[ "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
+ }
358
435
}
436
+
359
437
[ s, a @ ..] if s. starts_with ( 'i' ) => {
360
438
let Ok ( bits) = s[ 1 ..] . parse :: < u64 > ( ) else {
361
439
parse_size ( & s[ 1 ..] , "i" ) ?; // For the user error.
@@ -390,10 +468,25 @@ impl TargetDataLayout {
390
468
_ => { } // Ignore everything else.
391
469
}
392
470
}
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
+
393
485
Ok ( dl)
394
486
}
395
487
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.
397
490
///
398
491
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
399
492
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +497,26 @@ impl TargetDataLayout {
404
497
/// so we adopt such a more-constrained size bound due to its technical limitations.
405
498
#[ inline]
406
499
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 ( ) {
408
520
16 => 1 << 15 ,
409
521
32 => 1 << 31 ,
410
522
64 => 1 << 61 ,
@@ -415,7 +527,18 @@ impl TargetDataLayout {
415
527
#[ inline]
416
528
pub fn ptr_sized_integer ( & self ) -> Integer {
417
529
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 ( ) {
419
542
16 => I16 ,
420
543
32 => I32 ,
421
544
64 => I64 ,
@@ -439,6 +562,66 @@ impl TargetDataLayout {
439
562
Align :: from_bytes ( vec_size. bytes ( ) . next_power_of_two ( ) ) . unwrap ( ) ,
440
563
) )
441
564
}
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
+ }
442
625
}
443
626
444
627
pub trait HasDataLayout {
@@ -1101,10 +1284,7 @@ impl Primitive {
1101
1284
match self {
1102
1285
Int ( i, _) => i. size ( ) ,
1103
1286
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) ,
1108
1288
}
1109
1289
}
1110
1290
@@ -1115,10 +1295,7 @@ impl Primitive {
1115
1295
match self {
1116
1296
Int ( i, _) => i. align ( dl) ,
1117
1297
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) ,
1122
1299
}
1123
1300
}
1124
1301
}
0 commit comments