@@ -8,7 +8,7 @@ use rspirv::spirv::{StorageClass, Word};
8
8
use rustc_data_structures:: fx:: FxHashMap ;
9
9
use rustc_errors:: ErrorGuaranteed ;
10
10
use rustc_index:: Idx ;
11
- use rustc_middle:: query:: Providers ;
11
+ use rustc_middle:: query:: { Key , Providers } ;
12
12
use rustc_middle:: ty:: layout:: { FnAbiOf , LayoutOf , TyAndLayout } ;
13
13
use rustc_middle:: ty:: GenericArgsRef ;
14
14
use rustc_middle:: ty:: {
@@ -21,7 +21,7 @@ use rustc_span::DUMMY_SP;
21
21
use rustc_span:: { Span , Symbol } ;
22
22
use rustc_target:: abi:: call:: { ArgAbi , ArgAttributes , FnAbi , PassMode } ;
23
23
use rustc_target:: abi:: {
24
- Abi , Align , FieldsShape , LayoutS , Primitive , Scalar , Size , TagEncoding , VariantIdx , Variants ,
24
+ Abi , Align , FieldsShape , LayoutS , Primitive , Scalar , Size , VariantIdx , Variants ,
25
25
} ;
26
26
use rustc_target:: spec:: abi:: Abi as SpecAbi ;
27
27
use std:: cell:: RefCell ;
@@ -94,86 +94,66 @@ pub(crate) fn provide(providers: &mut Providers) {
94
94
Ok ( readjust_fn_abi ( tcx, result?) )
95
95
} ;
96
96
97
- // FIXME(eddyb) remove this by deriving `Clone` for `LayoutS` upstream.
98
- // FIXME(eddyb) the `S` suffix is a naming antipattern, rename upstream.
99
- fn clone_layout ( layout : & LayoutS ) -> LayoutS {
100
- let LayoutS {
101
- ref fields,
102
- ref variants,
103
- abi,
104
- largest_niche,
105
- align,
106
- size,
107
- max_repr_align,
108
- unadjusted_abi_align,
109
- } = * layout;
110
- LayoutS {
111
- fields : match * fields {
112
- FieldsShape :: Primitive => FieldsShape :: Primitive ,
113
- FieldsShape :: Union ( count) => FieldsShape :: Union ( count) ,
114
- FieldsShape :: Array { stride, count } => FieldsShape :: Array { stride, count } ,
115
- FieldsShape :: Arbitrary {
116
- ref offsets,
117
- ref memory_index,
118
- } => FieldsShape :: Arbitrary {
119
- offsets : offsets. clone ( ) ,
120
- memory_index : memory_index. clone ( ) ,
121
- } ,
122
- } ,
123
- variants : match * variants {
124
- Variants :: Single { index } => Variants :: Single { index } ,
125
- Variants :: Multiple {
126
- tag,
127
- ref tag_encoding,
128
- tag_field,
129
- ref variants,
130
- } => Variants :: Multiple {
131
- tag,
132
- tag_encoding : match * tag_encoding {
133
- TagEncoding :: Direct => TagEncoding :: Direct ,
134
- TagEncoding :: Niche {
135
- untagged_variant,
136
- ref niche_variants,
137
- niche_start,
138
- } => TagEncoding :: Niche {
139
- untagged_variant,
140
- niche_variants : niche_variants. clone ( ) ,
141
- niche_start,
142
- } ,
143
- } ,
144
- tag_field,
145
- variants : variants. clone ( ) ,
146
- } ,
147
- } ,
148
- abi,
149
- largest_niche,
150
- align,
151
- size,
152
- max_repr_align,
153
- unadjusted_abi_align,
154
- }
155
- }
156
97
providers. layout_of = |tcx, key| {
157
- let TyAndLayout { ty, mut layout } =
158
- ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
98
+ let orig = ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
159
99
160
- #[ allow( clippy:: match_like_matches_macro) ]
161
- let hide_niche = match ty. kind ( ) {
162
- ty:: Bool => true ,
163
- _ => false ,
164
- } ;
100
+ let mut modified: Option < LayoutS > = None ;
165
101
166
- if hide_niche {
167
- layout = tcx. mk_layout ( LayoutS {
168
- largest_niche : None ,
169
- ..clone_layout ( layout. 0 . 0 )
170
- } ) ;
171
- }
102
+ hide_bool_niche ( & tcx, orig, & mut modified) ;
103
+ adjust_vector_layout ( & tcx, orig, & mut modified) ;
172
104
105
+ let ty = orig. ty ;
106
+
107
+ let layout = if let Some ( modified) = modified {
108
+ tcx. mk_layout ( modified)
109
+ } else {
110
+ orig. layout
111
+ } ;
173
112
Ok ( TyAndLayout { ty, layout } )
174
113
} ;
175
114
}
176
115
116
+ fn hide_bool_niche < ' tcx > ( _cx : & TyCtxt < ' tcx > , orig : TyAndLayout < ' tcx > , modified : & mut Option < LayoutS > ) {
117
+ #[ allow( clippy:: match_like_matches_macro) ]
118
+ let hide_niche = match orig. ty . kind ( ) {
119
+ ty:: Bool => true ,
120
+ _ => false ,
121
+ } ;
122
+
123
+ if hide_niche {
124
+ let layout = modified. get_or_insert_with ( || orig. layout . 0 . 0 . clone ( ) ) ;
125
+ layout. largest_niche = None ;
126
+ }
127
+ }
128
+
129
+ fn adjust_vector_layout < ' tcx > ( cx : & TyCtxt < ' tcx > , orig : TyAndLayout < ' tcx > , modified : & mut Option < LayoutS > ) {
130
+ // in spirv, in most cases vectors have align equal to their element type. in block resource
131
+ // contexts (storage, uniform, etc) the rules are sometimes more restrictive than that, but
132
+ // it's best to use the least common denominator here since if a layout get somputed that is
133
+ // not valid under the given vulkan environment then spirv-val will catch it and the user
134
+ // can manually adjust the block layout, whereas if we use the most restrictive rules then
135
+ // everywhere else suffers.
136
+ //
137
+ // it may be possible for us to figure out whether we're in a block context and what the
138
+ // currently enabled restrictions allow and compute this more intelligently, but I'm not sure
139
+ // whether that can break rustc assumptions about abi (what if the same type is used in
140
+ // multiple places with competing requirements?)
141
+ if let Abi :: Vector { element, count } = orig. abi {
142
+ let layout = modified. get_or_insert_with ( || orig. layout . 0 . 0 . clone ( ) ) ;
143
+ let element_align = element. align ( cx) . abi ;
144
+ let element_size = element. size ( cx) ;
145
+ let repr_align_align = orig. ty . ty_adt_id ( )
146
+ . and_then ( |did| cx. repr_options_of_def ( did) . align ) ;
147
+ if let Some ( align) = repr_align_align {
148
+ layout. align . abi = align. max ( element_align) ;
149
+ } else {
150
+ layout. align . abi = element_align;
151
+ }
152
+ layout. align . pref = layout. align . abi ;
153
+ layout. size = ( element_size * count) . align_to ( layout. align . abi ) ;
154
+ }
155
+ }
156
+
177
157
/// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk
178
158
/// of the fields will result in an infinite loop. Because pointers are the only thing that are
179
159
/// allowed to be recursive, keep track of what pointers we've translated, or are currently in the
@@ -634,7 +614,8 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>
634
614
}
635
615
}
636
616
FieldsShape :: Array { stride, count } => {
637
- let element_type = ty. field ( cx, 0 ) . spirv_type ( span, cx) ;
617
+ let element_type_hl = ty. field ( cx, 0 ) ;
618
+ let element_type = element_type_hl. spirv_type ( span, cx) ;
638
619
if ty. is_unsized ( ) {
639
620
// There's a potential for this array to be sized, but the element to be unsized, e.g. `[[u8]; 5]`.
640
621
// However, I think rust disallows all these cases, so assert this here.
@@ -653,6 +634,9 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>
653
634
. sizeof ( cx)
654
635
. expect ( "Unexpected unsized type in sized FieldsShape::Array" )
655
636
. align_to ( element_spv. alignof ( cx) ) ;
637
+ if stride_spv != stride {
638
+ eprintln ! ( "element type: {:?}\n element spv type: {:?}" , & element_type_hl, & element_spv) ;
639
+ }
656
640
assert_eq ! ( stride_spv, stride) ;
657
641
SpirvType :: Array {
658
642
element : element_type,
0 commit comments