@@ -8,7 +8,7 @@ use rspirv::spirv::{StorageClass, Word};
88use rustc_data_structures:: fx:: FxHashMap ;
99use rustc_errors:: ErrorGuaranteed ;
1010use rustc_index:: Idx ;
11- use rustc_middle:: query:: Providers ;
11+ use rustc_middle:: query:: { Key , Providers } ;
1212use rustc_middle:: ty:: layout:: { FnAbiOf , LayoutOf , TyAndLayout } ;
1313use rustc_middle:: ty:: GenericArgsRef ;
1414use rustc_middle:: ty:: {
@@ -21,7 +21,7 @@ use rustc_span::DUMMY_SP;
2121use rustc_span:: { Span , Symbol } ;
2222use rustc_target:: abi:: call:: { ArgAbi , ArgAttributes , FnAbi , PassMode } ;
2323use rustc_target:: abi:: {
24- Abi , Align , FieldsShape , LayoutS , Primitive , Scalar , Size , TagEncoding , VariantIdx , Variants ,
24+ Abi , Align , FieldsShape , LayoutS , Primitive , Scalar , Size , VariantIdx , Variants ,
2525} ;
2626use rustc_target:: spec:: abi:: Abi as SpecAbi ;
2727use std:: cell:: RefCell ;
@@ -94,86 +94,66 @@ pub(crate) fn provide(providers: &mut Providers) {
9494 Ok ( readjust_fn_abi ( tcx, result?) )
9595 } ;
9696
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- }
15697 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) ?;
15999
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 ;
165101
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) ;
172104
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+ } ;
173112 Ok ( TyAndLayout { ty, layout } )
174113 } ;
175114}
176115
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+
177157/// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk
178158/// of the fields will result in an infinite loop. Because pointers are the only thing that are
179159/// 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>
634614 }
635615 }
636616 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) ;
638619 if ty. is_unsized ( ) {
639620 // There's a potential for this array to be sized, but the element to be unsized, e.g. `[[u8]; 5]`.
640621 // 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>
653634 . sizeof ( cx)
654635 . expect ( "Unexpected unsized type in sized FieldsShape::Array" )
655636 . 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+ }
656640 assert_eq ! ( stride_spv, stride) ;
657641 SpirvType :: Array {
658642 element : element_type,
0 commit comments