11use super :: operand:: OperandValue ;
22use super :: { FunctionCx , LocalRef } ;
33
4- use crate :: common:: IntPredicate ;
4+ use crate :: common:: { IntPredicate , TypeKind } ;
55use crate :: glue;
66use crate :: traits:: * ;
77
@@ -227,13 +227,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
227227 }
228228 } ;
229229
230- // Read the tag/niche-encoded discriminant from memory.
231- let tag = self . project_field ( bx, tag_field) ;
232- let tag = bx. load_operand ( tag) ;
230+ let tag_place = self . project_field ( bx, tag_field) ;
233231
234232 // Decode the discriminant (specifically if it's niche-encoded).
235233 match * tag_encoding {
236234 TagEncoding :: Direct => {
235+ // Read the tag from memory.
236+ let tag = bx. load_operand ( tag_place) ;
237237 let signed = match tag_scalar. primitive ( ) {
238238 // We use `i1` for bytes that are always `0` or `1`,
239239 // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
@@ -244,11 +244,30 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
244244 } ;
245245 bx. intcast ( tag. immediate ( ) , cast_to, signed)
246246 }
247- TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start } => {
248- // Rebase from niche values to discriminants, and check
249- // whether the result is in range for the niche variants.
250- let niche_llty = bx. cx ( ) . immediate_backend_type ( tag. layout ) ;
251- let tag = tag. immediate ( ) ;
247+ TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start, ref flag, } => {
248+ let read = |bx : & mut Bx , place : Self | -> ( V , <Bx as BackendTypes >:: Type ) {
249+ let ty = bx. cx ( ) . immediate_backend_type ( place. layout ) ;
250+ let op = bx. load_operand ( place) ;
251+ let val = op. immediate ( ) ;
252+ if bx. cx ( ) . type_kind ( ty) == TypeKind :: Pointer {
253+ let new_ty = bx. cx ( ) . type_isize ( ) ;
254+ let new_val = bx. ptrtoint ( val, new_ty) ;
255+ ( new_val, new_ty)
256+ } else {
257+ ( val, ty)
258+ }
259+ } ;
260+
261+ let ( tag, niche_llty) = read ( bx, tag_place) ;
262+
263+ let ( untagged_in_niche, flag_eq_magic_value_opt) = if let Some ( flag) = flag {
264+ let flag_place = self . project_field ( bx, flag. field ) ;
265+ let ( flag_imm, flag_llty) = read ( bx, flag_place) ;
266+ let magic_value = bx. cx ( ) . const_uint_big ( flag_llty, flag. magic_value ) ;
267+ ( flag. untagged_in_niche , Some ( bx. icmp ( IntPredicate :: IntEQ , flag_imm, magic_value) ) )
268+ } else {
269+ ( true , None )
270+ } ;
252271
253272 // We first compute the "relative discriminant" (wrt `niche_variants`),
254273 // that is, if `n = niche_variants.end() - niche_variants.start()`,
@@ -259,23 +278,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
259278 // and check that it is in the range `niche_variants`, because
260279 // that might not fit in the same type, on top of needing an extra
261280 // comparison (see also the comment on `let niche_discr`).
262- let relative_discr = if niche_start == 0 {
263- // Avoid subtracting `0`, which wouldn't work for pointers.
264- // FIXME(eddyb) check the actual primitive type here.
265- tag
266- } else {
267- bx. sub ( tag, bx. cx ( ) . const_uint_big ( niche_llty, niche_start) )
268- } ;
281+ let relative_discr = bx. sub ( tag, bx. cx ( ) . const_uint_big ( niche_llty, niche_start) ) ;
269282 let relative_max = niche_variants. end ( ) . as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) ;
270- let is_niche = if relative_max == 0 {
271- // Avoid calling `const_uint`, which wouldn't work for pointers.
272- // Also use canonical == 0 instead of non-canonical u<= 0.
273- // FIXME(eddyb) check the actual primitive type here.
274- bx. icmp ( IntPredicate :: IntEQ , relative_discr, bx. cx ( ) . const_null ( niche_llty) )
275- } else {
276- let relative_max = bx. cx ( ) . const_uint ( niche_llty, relative_max as u64 ) ;
277- bx. icmp ( IntPredicate :: IntULE , relative_discr, relative_max)
278- } ;
279283
280284 // NOTE(eddyb) this addition needs to be performed on the final
281285 // type, in case the niche itself can't represent all variant
@@ -285,7 +289,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
285289 // In other words, `niche_variants.end - niche_variants.start`
286290 // is representable in the niche, but `niche_variants.end`
287291 // might not be, in extreme cases.
288- let niche_discr = {
292+ let potential_niche_discr = {
289293 let relative_discr = if relative_max == 0 {
290294 // HACK(eddyb) since we have only one niche, we know which
291295 // one it is, and we can avoid having a dynamic value here.
@@ -299,11 +303,29 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
299303 )
300304 } ;
301305
302- bx. select (
303- is_niche,
304- niche_discr,
305- bx. cx ( ) . const_uint ( cast_to, untagged_variant. as_u32 ( ) as u64 ) ,
306- )
306+ let untagged_discr = bx. cx ( ) . const_uint ( cast_to, untagged_variant. as_u32 ( ) as u64 ) ;
307+
308+ let niche_discr = if untagged_in_niche {
309+ let relative_max_const = bx. cx ( ) . const_uint ( niche_llty, relative_max as u64 ) ;
310+ let is_niche = bx. icmp ( IntPredicate :: IntULE , relative_discr, relative_max_const) ;
311+ bx. select (
312+ is_niche,
313+ potential_niche_discr,
314+ untagged_discr,
315+ )
316+ } else {
317+ potential_niche_discr
318+ } ;
319+
320+ if let Some ( flag_eq_magic_value) = flag_eq_magic_value_opt {
321+ bx. select (
322+ flag_eq_magic_value,
323+ niche_discr,
324+ untagged_discr,
325+ )
326+ } else {
327+ niche_discr
328+ }
307329 }
308330 }
309331 }
@@ -337,23 +359,30 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
337359 }
338360 Variants :: Multiple {
339361 tag_encoding :
340- TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start } ,
362+ TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start, ref flag , } ,
341363 tag_field,
342364 ..
343365 } => {
366+ let store = |bx : & mut Bx , value : u128 , place : Self | {
367+ let ty = bx. cx ( ) . immediate_backend_type ( place. layout ) ;
368+ let val = if bx. cx ( ) . type_kind ( ty) == TypeKind :: Pointer {
369+ let ty_isize = bx. cx ( ) . type_isize ( ) ;
370+ let llvalue = bx. cx ( ) . const_uint_big ( ty_isize, value) ;
371+ bx. inttoptr ( llvalue, ty)
372+ } else {
373+ bx. cx ( ) . const_uint_big ( ty, value)
374+ } ;
375+ OperandValue :: Immediate ( val) . store ( bx, place) ;
376+ } ;
344377 if variant_index != untagged_variant {
378+ if let Some ( flag) = flag {
379+ let place = self . project_field ( bx, flag. field ) ;
380+ store ( bx, flag. magic_value , place) ;
381+ }
345382 let niche = self . project_field ( bx, tag_field) ;
346- let niche_llty = bx. cx ( ) . immediate_backend_type ( niche. layout ) ;
347383 let niche_value = variant_index. as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) ;
348384 let niche_value = ( niche_value as u128 ) . wrapping_add ( niche_start) ;
349- // FIXME(eddyb): check the actual primitive type here.
350- let niche_llval = if niche_value == 0 {
351- // HACK(eddyb): using `c_null` as it works on all types.
352- bx. cx ( ) . const_null ( niche_llty)
353- } else {
354- bx. cx ( ) . const_uint_big ( niche_llty, niche_value)
355- } ;
356- OperandValue :: Immediate ( niche_llval) . store ( bx, niche) ;
385+ store ( bx, niche_value, niche) ;
357386 }
358387 }
359388 }
0 commit comments