@@ -16,7 +16,6 @@ use rustc_abi::Size;
1616use  rustc_arena:: DroplessArena ; 
1717use  rustc_codegen_ssa:: traits:: ConstCodegenMethods  as  _; 
1818use  rustc_data_structures:: fx:: { FxHashMap ,  FxHashSet } ; 
19- use  rustc_middle:: bug; 
2019use  rustc_middle:: mir:: interpret:: ConstAllocation ; 
2120use  rustc_middle:: ty:: TyCtxt ; 
2221use  rustc_span:: source_map:: SourceMap ; 
@@ -31,84 +30,86 @@ use std::str;
3130use  std:: sync:: Arc ; 
3231use  std:: { fs:: File ,  io:: Write ,  path:: Path } ; 
3332
33+ // HACK(eddyb) silence warnings that are inaccurate wrt future changes. 
34+ #[ non_exhaustive]  
3435#[ derive( Copy ,  Clone ,  Debug ,  Ord ,  PartialOrd ,  Eq ,  PartialEq ,  Hash ) ]  
3536pub  enum  SpirvValueKind  { 
36-     Def ( Word ) , 
37+     Def  { 
38+         id :  Word , 
39+ 
40+         /// If `id` is a pointer cast, this will be `Some`, and contain all the 
41+          /// information necessary to regenerate the original `SpirvValue` before 
42+          /// *any* pointer casts were applied, effectively deferring the casts 
43+          /// (as long as all downstream uses apply `.strip_ptrcasts()` first), 
44+          /// and bypassing errors they might cause (due to SPIR-V limitations). 
45+          // 
46+         // FIXME(eddyb) wouldn't it be easier to use this for *any* bitcasts? 
47+         // (with some caveats around dedicated int<->ptr casts vs bitcasts) 
48+         original_ptr_before_casts :  Option < SpirvValue < Word > > , 
49+     } , 
3750
3851    // FIXME(eddyb) this shouldn't be needed, but `rustc_codegen_ssa` still relies 
3952    // on converting `Function`s to `Value`s even for direct calls, the `Builder` 
4053    // should just have direct and indirect `call` variants (or a `Callee` enum). 
4154    FnAddr  { 
4255        function :  Word , 
43-     } , 
44- 
45-     /// Deferred pointer cast, for the `Logical` addressing model (which doesn't 
46-      /// really support raw pointers in the way Rust expects to be able to use). 
47-      /// 
48-      /// The cast's target pointer type is the `ty` of the `SpirvValue` that has 
49-      /// `LogicalPtrCast` as its `kind`, as it would be redundant to have it here. 
50-      LogicalPtrCast  { 
51-         /// Pointer value being cast. 
52-          original_ptr :  Word , 
5356
54-         /// Pointer type of `original_ptr`. 
55-          original_ptr_ty :  Word , 
56- 
57-         /// Result ID for the `OpBitcast` instruction representing the cast, 
58-          /// to attach zombies to. 
59-          // 
60-         // HACK(eddyb) having an `OpBitcast` only works by being DCE'd away, 
61-         // or by being replaced with a noop in `qptr::lower`. 
62-         bitcast_result_id :  Word , 
57+         // FIXME(eddyb) replace this ad-hoc zombie with a proper `SpirvConst`. 
58+         zombie_id :  Word , 
6359    } , 
6460} 
6561
6662#[ derive( Copy ,  Clone ,  Debug ,  Ord ,  PartialOrd ,  Eq ,  PartialEq ,  Hash ) ]  
67- pub  struct  SpirvValue  { 
63+ pub  struct  SpirvValue < K  =  SpirvValueKind >  { 
6864    // HACK(eddyb) used to cheaply check whether this is a SPIR-V value ID 
6965    // with a "zombie" (deferred error) attached to it, that may need a `Span` 
7066    // still (e.g. such as constants, which can't easily take a `Span`). 
7167    // FIXME(eddyb) a whole `bool` field is sadly inefficient, but anything 
7268    // which may make `SpirvValue` smaller requires far too much impl effort. 
7369    pub  zombie_waiting_for_span :  bool , 
7470
75-     pub  kind :  SpirvValueKind , 
71+     pub  kind :  K , 
7672    pub  ty :  Word , 
7773} 
7874
75+ impl < K >  SpirvValue < K >  { 
76+     fn  map_kind < K2 > ( self ,  f :  impl  FnOnce ( K )  -> K2 )  -> SpirvValue < K2 >  { 
77+         let  SpirvValue  { 
78+             zombie_waiting_for_span, 
79+             kind, 
80+             ty, 
81+         }  = self ; 
82+         SpirvValue  { 
83+             zombie_waiting_for_span, 
84+             kind :  f ( kind) , 
85+             ty, 
86+         } 
87+     } 
88+ } 
89+ 
7990impl  SpirvValue  { 
8091    pub  fn  strip_ptrcasts ( self )  -> Self  { 
8192        match  self . kind  { 
82-             SpirvValueKind :: LogicalPtrCast  { 
83-                 original_ptr, 
84-                 original_ptr_ty, 
85-                 bitcast_result_id :  _, 
86-             }  => original_ptr. with_type ( original_ptr_ty) , 
93+             SpirvValueKind :: Def  { 
94+                 id :  _, 
95+                 original_ptr_before_casts :  Some ( original_ptr) , 
96+             }  => original_ptr. map_kind ( |id| SpirvValueKind :: Def  { 
97+                 id, 
98+                 original_ptr_before_casts :  None , 
99+             } ) , 
87100
88101            _ => self , 
89102        } 
90103    } 
91104
92105    pub  fn  const_fold_load ( self ,  cx :  & CodegenCx < ' _ > )  -> Option < Self >  { 
93-         match  self . kind  { 
94-             SpirvValueKind :: Def ( id)  => { 
95-                 let  & entry = cx. builder . id_to_const . borrow ( ) . get ( & id) ?; 
96-                 match  entry. val  { 
97-                     SpirvConst :: PtrTo  {  pointee }  => { 
98-                         let  ty = match  cx. lookup_type ( self . ty )  { 
99-                             SpirvType :: Pointer  {  pointee }  => pointee, 
100-                             ty => bug ! ( "load called on value that wasn't a pointer: {:?}" ,  ty) , 
101-                         } ; 
102-                         Some ( SpirvValue  { 
103-                             zombie_waiting_for_span :  entry. legal . is_err ( ) , 
104-                             kind :  SpirvValueKind :: Def ( pointee) , 
105-                             ty, 
106-                         } ) 
107-                     } 
108-                     _ => None , 
109-                 } 
106+         match  cx. builder . lookup_const ( self ) ? { 
107+             SpirvConst :: PtrTo  {  pointee }  => { 
108+                 // HACK(eddyb) this obtains a `SpirvValue` from the ID it contains, 
109+                 // so there's some conceptual inefficiency there, but it does 
110+                 // prevent any of the other details from being lost accidentally. 
111+                 Some ( cx. builder . id_to_const_and_val . borrow ( ) . get ( & pointee) ?. val . 1 ) 
110112            } 
111- 
112113            _ => None , 
113114        } 
114115    } 
@@ -128,24 +129,7 @@ impl SpirvValue {
128129
129130    pub  fn  def_with_span ( self ,  cx :  & CodegenCx < ' _ > ,  span :  Span )  -> Word  { 
130131        let  id = match  self . kind  { 
131-             SpirvValueKind :: FnAddr  {  .. }  => { 
132-                 cx. builder 
133-                     . const_to_id 
134-                     . borrow ( ) 
135-                     . get ( & WithType  { 
136-                         ty :  self . ty , 
137-                         val :  SpirvConst :: ZombieUndefForFnAddr , 
138-                     } ) 
139-                     . expect ( "FnAddr didn't go through proper undef registration" ) 
140-                     . val 
141-             } 
142- 
143-             SpirvValueKind :: Def ( id) 
144-             | SpirvValueKind :: LogicalPtrCast  { 
145-                 original_ptr :  _, 
146-                 original_ptr_ty :  _, 
147-                 bitcast_result_id :  id, 
148-             }  => id, 
132+             SpirvValueKind :: Def  {  id,  .. }  | SpirvValueKind :: FnAddr  {  zombie_id :  id,  .. }  => id, 
149133        } ; 
150134        if  self . zombie_waiting_for_span  { 
151135            cx. add_span_to_zombie_if_missing ( id,  span) ; 
@@ -162,7 +146,10 @@ impl SpirvValueExt for Word {
162146    fn  with_type ( self ,  ty :  Word )  -> SpirvValue  { 
163147        SpirvValue  { 
164148            zombie_waiting_for_span :  false , 
165-             kind :  SpirvValueKind :: Def ( self ) , 
149+             kind :  SpirvValueKind :: Def  { 
150+                 id :  self , 
151+                 original_ptr_before_casts :  None , 
152+             } , 
166153            ty, 
167154        } 
168155    } 
@@ -380,11 +367,12 @@ pub struct BuilderSpirv<'tcx> {
380367    builder :  RefCell < Builder > , 
381368
382369    // Bidirectional maps between `SpirvConst` and the ID of the defined global 
383-     // (e.g. `OpConstant...`) instruction. 
384-     // NOTE(eddyb) both maps have `WithConstLegality` around their keys, which 
385-     // allows getting that legality information without additional lookups. 
386-     const_to_id :  RefCell < FxHashMap < WithType < SpirvConst < ' tcx ,  ' tcx > > ,  WithConstLegality < Word > > > , 
387-     id_to_const :  RefCell < FxHashMap < Word ,  WithConstLegality < SpirvConst < ' tcx ,  ' tcx > > > > , 
370+     // (e.g. `OpConstant...`) instruction, with additional information in values 
371+     // (i.e. each map is keyed by only some part of the other map's value type), 
372+     // as needed to streamline operations (e.g. avoiding rederiving `SpirvValue`). 
373+     const_to_val :  RefCell < FxHashMap < WithType < SpirvConst < ' tcx ,  ' tcx > > ,  SpirvValue > > , 
374+     id_to_const_and_val : 
375+         RefCell < FxHashMap < Word ,  WithConstLegality < ( SpirvConst < ' tcx ,  ' tcx > ,  SpirvValue ) > > > , 
388376
389377    debug_file_cache :  RefCell < FxHashMap < DebugFileKey ,  DebugFileSpirv < ' tcx > > > , 
390378
@@ -455,8 +443,8 @@ impl<'tcx> BuilderSpirv<'tcx> {
455443            source_map :  tcx. sess . source_map ( ) , 
456444            dropless_arena :  & tcx. arena . dropless , 
457445            builder :  RefCell :: new ( builder) , 
458-             const_to_id :  Default :: default ( ) , 
459-             id_to_const :  Default :: default ( ) , 
446+             const_to_val :  Default :: default ( ) , 
447+             id_to_const_and_val :  Default :: default ( ) , 
460448            debug_file_cache :  Default :: default ( ) , 
461449            enabled_capabilities, 
462450        } 
@@ -560,12 +548,8 @@ impl<'tcx> BuilderSpirv<'tcx> {
560548        } ; 
561549
562550        let  val_with_type = WithType  {  ty,  val } ; 
563-         if  let  Some ( entry)  = self . const_to_id . borrow ( ) . get ( & val_with_type)  { 
564-             return  SpirvValue  { 
565-                 zombie_waiting_for_span :  entry. legal . is_err ( ) , 
566-                 kind :  SpirvValueKind :: Def ( entry. val ) , 
567-                 ty, 
568-             } ; 
551+         if  let  Some ( & v)  = self . const_to_val . borrow ( ) . get ( & val_with_type)  { 
552+             return  v; 
569553        } 
570554        let  val = val_with_type. val ; 
571555
@@ -697,11 +681,11 @@ impl<'tcx> BuilderSpirv<'tcx> {
697681            SpirvConst :: Composite ( v)  => v
698682                . iter ( ) 
699683                . map ( |field| { 
700-                     let  field_entry = & self . id_to_const . borrow ( ) [ field] ; 
684+                     let  field_entry = & self . id_to_const_and_val . borrow ( ) [ field] ; 
701685                    field_entry. legal . and ( 
702686                        // `field` is itself some legal `SpirvConst`, but can we have 
703687                        // it as part of an `OpConstantComposite`? 
704-                         match  field_entry. val  { 
688+                         match  field_entry. val . 0  { 
705689                            SpirvConst :: PtrTo  {  .. }  => Err ( IllegalConst :: Shallow ( 
706690                                LeafIllegalConst :: CompositeContainsPtrTo , 
707691                            ) ) , 
@@ -729,14 +713,16 @@ impl<'tcx> BuilderSpirv<'tcx> {
729713                } ) 
730714                . unwrap_or ( Ok ( ( ) ) ) , 
731715
732-             SpirvConst :: PtrTo  {  pointee }  => match  self . id_to_const . borrow ( ) [ & pointee] . legal  { 
733-                 Ok ( ( ) )  => Ok ( ( ) ) , 
716+             SpirvConst :: PtrTo  {  pointee }  => { 
717+                 match  self . id_to_const_and_val . borrow ( ) [ & pointee] . legal  { 
718+                     Ok ( ( ) )  => Ok ( ( ) ) , 
734719
735-                 // `Shallow` becomes `Indirect` when placed behind a pointer. 
736-                 Err ( IllegalConst :: Shallow ( cause)  | IllegalConst :: Indirect ( cause) )  => { 
737-                     Err ( IllegalConst :: Indirect ( cause) ) 
720+                     // `Shallow` becomes `Indirect` when placed behind a pointer. 
721+                     Err ( IllegalConst :: Shallow ( cause)  | IllegalConst :: Indirect ( cause) )  => { 
722+                         Err ( IllegalConst :: Indirect ( cause) ) 
723+                     } 
738724                } 
739-             } , 
725+             } 
740726
741727            SpirvConst :: ConstDataFromAlloc ( _)  => Err ( IllegalConst :: Shallow ( 
742728                LeafIllegalConst :: UntypedConstDataFromAlloc , 
@@ -754,32 +740,44 @@ impl<'tcx> BuilderSpirv<'tcx> {
754740        } 
755741
756742        let  val = val. tcx_arena_alloc_slices ( cx) ; 
743+ 
744+         // FIXME(eddyb) the `val`/`v` name clash is a bit unfortunate. 
745+         let  v = SpirvValue  { 
746+             zombie_waiting_for_span :  legal. is_err ( ) , 
747+             kind :  SpirvValueKind :: Def  { 
748+                 id, 
749+                 original_ptr_before_casts :  None , 
750+             } , 
751+             ty, 
752+         } ; 
753+ 
757754        assert_matches ! ( 
758-             self . const_to_id 
755+             self . const_to_val 
759756                . borrow_mut( ) 
760-                 . insert( WithType  {  ty,  val } ,  WithConstLegality   {  val :  id ,  legal  } ) , 
757+                 . insert( WithType  {  ty,  val } ,  v ) , 
761758            None 
762759        ) ; 
763760        assert_matches ! ( 
764-             self . id_to_const
765-                 . borrow_mut( ) 
766-                 . insert( id,  WithConstLegality  {  val,  legal } ) , 
761+             self . id_to_const_and_val. borrow_mut( ) . insert( 
762+                 id, 
763+                 WithConstLegality  { 
764+                     val:  ( val,  v) , 
765+                     legal
766+                 } 
767+             ) , 
767768            None 
768769        ) ; 
769-         SpirvValue  { 
770-             zombie_waiting_for_span :  legal. is_err ( ) , 
771-             kind :  SpirvValueKind :: Def ( id) , 
772-             ty, 
773-         } 
770+ 
771+         v
774772    } 
775773
776774    pub  fn  lookup_const_by_id ( & self ,  id :  Word )  -> Option < SpirvConst < ' tcx ,  ' tcx > >  { 
777-         Some ( self . id_to_const . borrow ( ) . get ( & id) ?. val ) 
775+         Some ( self . id_to_const_and_val . borrow ( ) . get ( & id) ?. val . 0 ) 
778776    } 
779777
780778    pub  fn  lookup_const ( & self ,  def :  SpirvValue )  -> Option < SpirvConst < ' tcx ,  ' tcx > >  { 
781779        match  def. kind  { 
782-             SpirvValueKind :: Def ( id )  => self . lookup_const_by_id ( id) , 
780+             SpirvValueKind :: Def   {  id ,  ..  }  => self . lookup_const_by_id ( id) , 
783781            _ => None , 
784782        } 
785783    } 
0 commit comments