@@ -47,6 +47,7 @@ use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
47
47
use std:: str:: FromStr ;
48
48
49
49
use bitflags:: bitflags;
50
+ use rustc_data_structures:: fx:: FxHashMap ;
50
51
#[ cfg( feature = "nightly" ) ]
51
52
use rustc_data_structures:: stable_hasher:: StableOrd ;
52
53
use rustc_hashes:: Hash64 ;
@@ -221,6 +222,17 @@ impl ReprOptions {
221
222
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222
223
pub const MAX_SIMD_LANES : u64 = 1 << 0xF ;
223
224
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
+
224
236
/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225
237
/// for a target, which contains everything needed to compute layouts.
226
238
#[ derive( Debug , PartialEq , Eq ) ]
@@ -236,13 +248,14 @@ pub struct TargetDataLayout {
236
248
pub f32_align : AbiAlign ,
237
249
pub f64_align : AbiAlign ,
238
250
pub f128_align : AbiAlign ,
239
- pub pointer_size : Size ,
240
- pub pointer_align : AbiAlign ,
241
251
pub aggregate_align : AbiAlign ,
242
252
243
253
/// Alignments for vector types.
244
254
pub vector_align : Vec < ( Size , AbiAlign ) > ,
245
255
256
+ pub default_address_space : AddressSpace ,
257
+ pub address_space_info : FxHashMap < AddressSpace , AddressSpaceInfo > ,
258
+
246
259
pub instruction_address_space : AddressSpace ,
247
260
248
261
/// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,13 +280,20 @@ impl Default for TargetDataLayout {
267
280
f32_align : AbiAlign :: new ( align ( 32 ) ) ,
268
281
f64_align : AbiAlign :: new ( align ( 64 ) ) ,
269
282
f128_align : AbiAlign :: new ( align ( 128 ) ) ,
270
- pointer_size : Size :: from_bits ( 64 ) ,
271
- pointer_align : AbiAlign :: new ( align ( 64 ) ) ,
272
283
aggregate_align : AbiAlign { abi : align ( 8 ) } ,
273
284
vector_align : vec ! [
274
285
( Size :: from_bits( 64 ) , AbiAlign :: new( align( 64 ) ) ) ,
275
286
( Size :: from_bits( 128 ) , AbiAlign :: new( align( 128 ) ) ) ,
276
287
] ,
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
+ ) ] ) ,
277
297
instruction_address_space : AddressSpace :: ZERO ,
278
298
c_enum_min_size : Integer :: I32 ,
279
299
}
@@ -288,6 +308,7 @@ pub enum TargetDataLayoutErrors<'a> {
288
308
InconsistentTargetArchitecture { dl : & ' a str , target : & ' a str } ,
289
309
InconsistentTargetPointerWidth { pointer_size : u64 , target : u32 } ,
290
310
InvalidBitsSize { err : String } ,
311
+ MissingAddressSpaceInfo { addr_space : AddressSpace } ,
291
312
}
292
313
293
314
impl TargetDataLayout {
@@ -298,6 +319,7 @@ impl TargetDataLayout {
298
319
/// determined from llvm string.
299
320
pub fn parse_from_llvm_datalayout_string < ' a > (
300
321
input : & ' a str ,
322
+ default_address_space : AddressSpace ,
301
323
) -> Result < TargetDataLayout , TargetDataLayoutErrors < ' a > > {
302
324
// Parse an address space index from a string.
303
325
let parse_address_space = |s : & ' a str , cause : & ' a str | {
@@ -334,6 +356,8 @@ impl TargetDataLayout {
334
356
} ;
335
357
336
358
let mut dl = TargetDataLayout :: default ( ) ;
359
+ dl. default_address_space = default_address_space;
360
+
337
361
let mut i128_align_src = 64 ;
338
362
for spec in input. split ( '-' ) {
339
363
let spec_parts = spec. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
@@ -349,13 +373,48 @@ impl TargetDataLayout {
349
373
[ "f32" , a @ ..] => dl. f32_align = parse_align ( a, "f32" ) ?,
350
374
[ "f64" , a @ ..] => dl. f64_align = parse_align ( a, "f64" ) ?,
351
375
[ "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) ;
358
416
}
417
+
359
418
[ s, a @ ..] if s. starts_with ( 'i' ) => {
360
419
let Ok ( bits) = s[ 1 ..] . parse :: < u64 > ( ) else {
361
420
parse_size ( & s[ 1 ..] , "i" ) ?; // For the user error.
@@ -390,10 +449,28 @@ impl TargetDataLayout {
390
449
_ => { } // Ignore everything else.
391
450
}
392
451
}
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
+
393
469
Ok ( dl)
394
470
}
395
471
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.
397
474
///
398
475
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
399
476
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +481,21 @@ impl TargetDataLayout {
404
481
/// so we adopt such a more-constrained size bound due to its technical limitations.
405
482
#[ inline]
406
483
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 ( ) {
408
499
16 => 1 << 15 ,
409
500
32 => 1 << 31 ,
410
501
64 => 1 << 61 ,
@@ -414,8 +505,13 @@ impl TargetDataLayout {
414
505
415
506
#[ inline]
416
507
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 {
417
513
use Integer :: * ;
418
- match self . pointer_size . bits ( ) {
514
+ match self . pointer_index_in ( address_space ) . bits ( ) {
419
515
16 => I16 ,
420
516
32 => I32 ,
421
517
64 => I64 ,
@@ -439,6 +535,54 @@ impl TargetDataLayout {
439
535
Align :: from_bytes ( vec_size. bytes ( ) . next_power_of_two ( ) ) . unwrap ( ) ,
440
536
) )
441
537
}
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
+ }
442
586
}
443
587
444
588
pub trait HasDataLayout {
@@ -1104,7 +1248,7 @@ impl Primitive {
1104
1248
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1105
1249
// different address spaces can have different sizes
1106
1250
// (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 ) ,
1108
1252
}
1109
1253
}
1110
1254
@@ -1118,7 +1262,7 @@ impl Primitive {
1118
1262
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1119
1263
// different address spaces can have different alignments
1120
1264
// (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 ) ,
1122
1266
}
1123
1267
}
1124
1268
}
0 commit comments