@@ -13,7 +13,6 @@ use rustc_span::symbol::Symbol;
13
13
use rustc_span:: { Span , DUMMY_SP } ;
14
14
use std:: assert_matches:: assert_matches;
15
15
use std:: cell:: { RefCell , RefMut } ;
16
- use std:: rc:: Rc ;
17
16
use std:: { fs:: File , io:: Write , path:: Path } ;
18
17
19
18
#[ derive( Copy , Clone , Debug , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
@@ -68,7 +67,7 @@ impl SpirvValue {
68
67
pub fn const_fold_load ( self , cx : & CodegenCx < ' _ > ) -> Option < Self > {
69
68
match self . kind {
70
69
SpirvValueKind :: Def ( id) | SpirvValueKind :: IllegalConst ( id) => {
71
- let entry = cx. builder . id_to_const . borrow ( ) . get ( & id) ?. clone ( ) ;
70
+ let & entry = cx. builder . id_to_const . borrow ( ) . get ( & id) ?;
72
71
match entry. val {
73
72
SpirvConst :: PtrTo { pointee } => {
74
73
let ty = match cx. lookup_type ( self . ty ) {
@@ -213,8 +212,8 @@ impl SpirvValueExt for Word {
213
212
}
214
213
}
215
214
216
- #[ derive( Debug , Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
217
- pub enum SpirvConst {
215
+ #[ derive( Debug , Copy , Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
216
+ pub enum SpirvConst < ' tcx > {
218
217
U32 ( u32 ) ,
219
218
U64 ( u64 ) ,
220
219
/// f32 isn't hash, so store bits
@@ -232,8 +231,7 @@ pub enum SpirvConst {
232
231
// different functions, but of the same type, don't overlap their zombies.
233
232
ZombieUndefForFnAddr ,
234
233
235
- // FIXME(eddyb) use `tcx.arena.dropless` to get `&'tcx [_]`, instead of `Rc`.
236
- Composite ( Rc < [ Word ] > ) ,
234
+ Composite ( & ' tcx [ Word ] ) ,
237
235
238
236
/// Pointer to constant data, i.e. `&pointee`, represented as an `OpVariable`
239
237
/// in the `Private` storage class, and with `pointee` as its initializer.
@@ -242,6 +240,40 @@ pub enum SpirvConst {
242
240
} ,
243
241
}
244
242
243
+ impl SpirvConst < ' _ > {
244
+ /// Replace `&[T]` fields with `&'tcx [T]` ones produced by calling
245
+ /// `tcx.arena.dropless.alloc_slice(...)` - this is done late for two reasons:
246
+ /// 1. it avoids allocating in the arena when the cache would be hit anyway,
247
+ /// which would create "garbage" (as in, unreachable allocations)
248
+ /// (ideally these would also be interned, but that's even more refactors)
249
+ /// 2. an empty slice is disallowed (as it's usually handled as a special
250
+ /// case elsewhere, e.g. `rustc`'s `ty::List` - sadly we can't use that)
251
+ fn tcx_arena_alloc_slices < ' tcx > ( self , cx : & CodegenCx < ' tcx > ) -> SpirvConst < ' tcx > {
252
+ fn arena_alloc_slice < ' tcx , T : Copy > ( cx : & CodegenCx < ' tcx > , xs : & [ T ] ) -> & ' tcx [ T ] {
253
+ if xs. is_empty ( ) {
254
+ & [ ]
255
+ } else {
256
+ cx. tcx . arena . dropless . alloc_slice ( xs)
257
+ }
258
+ }
259
+
260
+ match self {
261
+ // FIXME(eddyb) these are all noop cases, could they be automated?
262
+ SpirvConst :: U32 ( v) => SpirvConst :: U32 ( v) ,
263
+ SpirvConst :: U64 ( v) => SpirvConst :: U64 ( v) ,
264
+ SpirvConst :: F32 ( v) => SpirvConst :: F32 ( v) ,
265
+ SpirvConst :: F64 ( v) => SpirvConst :: F64 ( v) ,
266
+ SpirvConst :: Bool ( v) => SpirvConst :: Bool ( v) ,
267
+ SpirvConst :: Null => SpirvConst :: Null ,
268
+ SpirvConst :: Undef => SpirvConst :: Undef ,
269
+ SpirvConst :: ZombieUndefForFnAddr => SpirvConst :: ZombieUndefForFnAddr ,
270
+ SpirvConst :: PtrTo { pointee } => SpirvConst :: PtrTo { pointee } ,
271
+
272
+ SpirvConst :: Composite ( fields) => SpirvConst :: Composite ( arena_alloc_slice ( cx, fields) ) ,
273
+ }
274
+ }
275
+ }
276
+
245
277
#[ derive( Debug , Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
246
278
struct WithType < V > {
247
279
ty : Word ,
@@ -317,22 +349,22 @@ pub struct BuilderCursor {
317
349
pub block : Option < usize > ,
318
350
}
319
351
320
- pub struct BuilderSpirv {
352
+ pub struct BuilderSpirv < ' tcx > {
321
353
builder : RefCell < Builder > ,
322
354
323
355
// Bidirectional maps between `SpirvConst` and the ID of the defined global
324
356
// (e.g. `OpConstant...`) instruction.
325
357
// NOTE(eddyb) both maps have `WithConstLegality` around their keys, which
326
358
// allows getting that legality information without additional lookups.
327
- const_to_id : RefCell < FxHashMap < WithType < SpirvConst > , WithConstLegality < Word > > > ,
328
- id_to_const : RefCell < FxHashMap < Word , WithConstLegality < SpirvConst > > > ,
359
+ const_to_id : RefCell < FxHashMap < WithType < SpirvConst < ' tcx > > , WithConstLegality < Word > > > ,
360
+ id_to_const : RefCell < FxHashMap < Word , WithConstLegality < SpirvConst < ' tcx > > > > ,
329
361
string_cache : RefCell < FxHashMap < String , Word > > ,
330
362
331
363
enabled_capabilities : FxHashSet < Capability > ,
332
364
enabled_extensions : FxHashSet < Symbol > ,
333
365
}
334
366
335
- impl BuilderSpirv {
367
+ impl < ' tcx > BuilderSpirv < ' tcx > {
336
368
pub fn new ( sym : & Symbols , target : & SpirvTarget , features : & [ TargetFeature ] ) -> Self {
337
369
let version = target. spirv_version ( ) ;
338
370
let memory_model = target. memory_model ( ) ;
@@ -457,7 +489,12 @@ impl BuilderSpirv {
457
489
bug ! ( "Function not found: {}" , id) ;
458
490
}
459
491
460
- pub fn def_constant ( & self , ty : Word , val : SpirvConst ) -> SpirvValue {
492
+ pub ( crate ) fn def_constant_cx (
493
+ & self ,
494
+ ty : Word ,
495
+ val : SpirvConst < ' _ > ,
496
+ cx : & CodegenCx < ' tcx > ,
497
+ ) -> SpirvValue {
461
498
let val_with_type = WithType { ty, val } ;
462
499
let mut builder = self . builder ( BuilderCursor :: default ( ) ) ;
463
500
if let Some ( entry) = self . const_to_id . borrow ( ) . get ( & val_with_type) {
@@ -486,7 +523,7 @@ impl BuilderSpirv {
486
523
SpirvConst :: Null => builder. constant_null ( ty) ,
487
524
SpirvConst :: Undef | SpirvConst :: ZombieUndefForFnAddr => builder. undef ( ty, None ) ,
488
525
489
- SpirvConst :: Composite ( ref v) => builder. constant_composite ( ty, v. iter ( ) . copied ( ) ) ,
526
+ SpirvConst :: Composite ( v) => builder. constant_composite ( ty, v. iter ( ) . copied ( ) ) ,
490
527
491
528
SpirvConst :: PtrTo { pointee } => {
492
529
builder. variable ( ty, None , StorageClass :: Private , Some ( pointee) )
@@ -517,7 +554,7 @@ impl BuilderSpirv {
517
554
Ok ( ( ) )
518
555
}
519
556
520
- SpirvConst :: Composite ( ref v) => v. iter ( ) . fold ( Ok ( ( ) ) , |composite_legal, field| {
557
+ SpirvConst :: Composite ( v) => v. iter ( ) . fold ( Ok ( ( ) ) , |composite_legal, field| {
521
558
let field_entry = & self . id_to_const . borrow ( ) [ field] ;
522
559
let field_legal_in_composite = field_entry. legal . and (
523
560
// `field` is itself some legal `SpirvConst`, but can we have
@@ -556,14 +593,11 @@ impl BuilderSpirv {
556
593
}
557
594
} ,
558
595
} ;
596
+ let val = val. tcx_arena_alloc_slices ( cx) ;
559
597
assert_matches ! (
560
- self . const_to_id. borrow_mut( ) . insert(
561
- WithType {
562
- ty,
563
- val: val. clone( )
564
- } ,
565
- WithConstLegality { val: id, legal }
566
- ) ,
598
+ self . const_to_id
599
+ . borrow_mut( )
600
+ . insert( WithType { ty, val } , WithConstLegality { val: id, legal } ) ,
567
601
None
568
602
) ;
569
603
assert_matches ! (
@@ -581,10 +615,10 @@ impl BuilderSpirv {
581
615
SpirvValue { kind, ty }
582
616
}
583
617
584
- pub fn lookup_const ( & self , def : SpirvValue ) -> Option < SpirvConst > {
618
+ pub fn lookup_const ( & self , def : SpirvValue ) -> Option < SpirvConst < ' tcx > > {
585
619
match def. kind {
586
620
SpirvValueKind :: Def ( id) | SpirvValueKind :: IllegalConst ( id) => {
587
- Some ( self . id_to_const . borrow ( ) . get ( & id) ?. val . clone ( ) )
621
+ Some ( self . id_to_const . borrow ( ) . get ( & id) ?. val )
588
622
}
589
623
_ => None ,
590
624
}
0 commit comments