@@ -16,7 +16,6 @@ use rustc_abi::Size;
16
16
use rustc_arena:: DroplessArena ;
17
17
use rustc_codegen_ssa:: traits:: ConstCodegenMethods as _;
18
18
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
19
- use rustc_middle:: bug;
20
19
use rustc_middle:: mir:: interpret:: ConstAllocation ;
21
20
use rustc_middle:: ty:: TyCtxt ;
22
21
use rustc_span:: source_map:: SourceMap ;
@@ -31,84 +30,86 @@ use std::str;
31
30
use std:: sync:: Arc ;
32
31
use std:: { fs:: File , io:: Write , path:: Path } ;
33
32
33
+ // HACK(eddyb) silence warnings that are inaccurate wrt future changes.
34
+ #[ non_exhaustive]
34
35
#[ derive( Copy , Clone , Debug , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
35
36
pub 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
+ } ,
37
50
38
51
// FIXME(eddyb) this shouldn't be needed, but `rustc_codegen_ssa` still relies
39
52
// on converting `Function`s to `Value`s even for direct calls, the `Builder`
40
53
// should just have direct and indirect `call` variants (or a `Callee` enum).
41
54
FnAddr {
42
55
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 ,
53
56
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 ,
63
59
} ,
64
60
}
65
61
66
62
#[ derive( Copy , Clone , Debug , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
67
- pub struct SpirvValue {
63
+ pub struct SpirvValue < K = SpirvValueKind > {
68
64
// HACK(eddyb) used to cheaply check whether this is a SPIR-V value ID
69
65
// with a "zombie" (deferred error) attached to it, that may need a `Span`
70
66
// still (e.g. such as constants, which can't easily take a `Span`).
71
67
// FIXME(eddyb) a whole `bool` field is sadly inefficient, but anything
72
68
// which may make `SpirvValue` smaller requires far too much impl effort.
73
69
pub zombie_waiting_for_span : bool ,
74
70
75
- pub kind : SpirvValueKind ,
71
+ pub kind : K ,
76
72
pub ty : Word ,
77
73
}
78
74
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
+
79
90
impl SpirvValue {
80
91
pub fn strip_ptrcasts ( self ) -> Self {
81
92
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
+ } ) ,
87
100
88
101
_ => self ,
89
102
}
90
103
}
91
104
92
105
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 )
110
112
}
111
-
112
113
_ => None ,
113
114
}
114
115
}
@@ -128,24 +129,7 @@ impl SpirvValue {
128
129
129
130
pub fn def_with_span ( self , cx : & CodegenCx < ' _ > , span : Span ) -> Word {
130
131
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,
149
133
} ;
150
134
if self . zombie_waiting_for_span {
151
135
cx. add_span_to_zombie_if_missing ( id, span) ;
@@ -162,7 +146,10 @@ impl SpirvValueExt for Word {
162
146
fn with_type ( self , ty : Word ) -> SpirvValue {
163
147
SpirvValue {
164
148
zombie_waiting_for_span : false ,
165
- kind : SpirvValueKind :: Def ( self ) ,
149
+ kind : SpirvValueKind :: Def {
150
+ id : self ,
151
+ original_ptr_before_casts : None ,
152
+ } ,
166
153
ty,
167
154
}
168
155
}
@@ -380,11 +367,12 @@ pub struct BuilderSpirv<'tcx> {
380
367
builder : RefCell < Builder > ,
381
368
382
369
// 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 ) > > > ,
388
376
389
377
debug_file_cache : RefCell < FxHashMap < DebugFileKey , DebugFileSpirv < ' tcx > > > ,
390
378
@@ -455,8 +443,8 @@ impl<'tcx> BuilderSpirv<'tcx> {
455
443
source_map : tcx. sess . source_map ( ) ,
456
444
dropless_arena : & tcx. arena . dropless ,
457
445
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 ( ) ,
460
448
debug_file_cache : Default :: default ( ) ,
461
449
enabled_capabilities,
462
450
}
@@ -560,12 +548,8 @@ impl<'tcx> BuilderSpirv<'tcx> {
560
548
} ;
561
549
562
550
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;
569
553
}
570
554
let val = val_with_type. val ;
571
555
@@ -697,11 +681,11 @@ impl<'tcx> BuilderSpirv<'tcx> {
697
681
SpirvConst :: Composite ( v) => v
698
682
. iter ( )
699
683
. map ( |field| {
700
- let field_entry = & self . id_to_const . borrow ( ) [ field] ;
684
+ let field_entry = & self . id_to_const_and_val . borrow ( ) [ field] ;
701
685
field_entry. legal . and (
702
686
// `field` is itself some legal `SpirvConst`, but can we have
703
687
// it as part of an `OpConstantComposite`?
704
- match field_entry. val {
688
+ match field_entry. val . 0 {
705
689
SpirvConst :: PtrTo { .. } => Err ( IllegalConst :: Shallow (
706
690
LeafIllegalConst :: CompositeContainsPtrTo ,
707
691
) ) ,
@@ -729,14 +713,16 @@ impl<'tcx> BuilderSpirv<'tcx> {
729
713
} )
730
714
. unwrap_or ( Ok ( ( ) ) ) ,
731
715
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 ( ( ) ) ,
734
719
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
+ }
738
724
}
739
- } ,
725
+ }
740
726
741
727
SpirvConst :: ConstDataFromAlloc ( _) => Err ( IllegalConst :: Shallow (
742
728
LeafIllegalConst :: UntypedConstDataFromAlloc ,
@@ -754,32 +740,44 @@ impl<'tcx> BuilderSpirv<'tcx> {
754
740
}
755
741
756
742
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
+
757
754
assert_matches ! (
758
- self . const_to_id
755
+ self . const_to_val
759
756
. borrow_mut( )
760
- . insert( WithType { ty, val } , WithConstLegality { val : id , legal } ) ,
757
+ . insert( WithType { ty, val } , v ) ,
761
758
None
762
759
) ;
763
760
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
+ ) ,
767
768
None
768
769
) ;
769
- SpirvValue {
770
- zombie_waiting_for_span : legal. is_err ( ) ,
771
- kind : SpirvValueKind :: Def ( id) ,
772
- ty,
773
- }
770
+
771
+ v
774
772
}
775
773
776
774
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 )
778
776
}
779
777
780
778
pub fn lookup_const ( & self , def : SpirvValue ) -> Option < SpirvConst < ' tcx , ' tcx > > {
781
779
match def. kind {
782
- SpirvValueKind :: Def ( id ) => self . lookup_const_by_id ( id) ,
780
+ SpirvValueKind :: Def { id , .. } => self . lookup_const_by_id ( id) ,
783
781
_ => None ,
784
782
}
785
783
}
0 commit comments