@@ -228,8 +228,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
228228 }
229229 } ;
230230
231- let discr = self . project_field ( bx, discr_index) ;
232- let lldiscr = bx. load_operand ( discr) . immediate ( ) ;
231+ // Read the tag/niche-encoded discriminant from memory.
232+ let encoded_discr = self . project_field ( bx, discr_index) ;
233+ let encoded_discr = bx. load_operand ( encoded_discr) ;
234+
235+ // Decode the discriminant (specifically if it's niche-encoded).
233236 match * discr_kind {
234237 layout:: DiscriminantKind :: Tag => {
235238 let signed = match discr_scalar. value {
@@ -240,38 +243,49 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
240243 layout:: Int ( _, signed) => !discr_scalar. is_bool ( ) && signed,
241244 _ => false
242245 } ;
243- bx. intcast ( lldiscr , cast_to, signed)
246+ bx. intcast ( encoded_discr . immediate ( ) , cast_to, signed)
244247 }
245248 layout:: DiscriminantKind :: Niche {
246249 dataful_variant,
247250 ref niche_variants,
248251 niche_start,
249252 } => {
250- let niche_llty = bx. cx ( ) . immediate_backend_type ( discr. layout ) ;
251- if niche_variants. start ( ) == niche_variants. end ( ) {
253+ let niche_llty = bx. cx ( ) . immediate_backend_type ( encoded_discr. layout ) ;
254+ let encoded_discr = encoded_discr. immediate ( ) ;
255+ let ( is_niche, niche_discr) = if niche_variants. start ( ) == niche_variants. end ( ) {
256+ // Special case for when we can use a simple equality check,
257+ // which covers null pointers, and needs simpler codegen.
252258 // FIXME(eddyb): check the actual primitive type here.
253- let niche_llval = if niche_start == 0 {
259+ let encoded_niche = if niche_start == 0 {
254260 // HACK(eddyb): using `c_null` as it works on all types.
255261 bx. cx ( ) . const_null ( niche_llty)
256262 } else {
257263 bx. cx ( ) . const_uint_big ( niche_llty, niche_start)
258264 } ;
259- let select_arg = bx . icmp ( IntPredicate :: IntEQ , lldiscr , niche_llval ) ;
260- bx. select ( select_arg ,
265+ (
266+ bx. icmp ( IntPredicate :: IntEQ , encoded_discr , encoded_niche ) ,
261267 bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ,
262- bx . cx ( ) . const_uint ( cast_to , dataful_variant . as_u32 ( ) as u64 ) )
268+ )
263269 } else {
264- // Rebase from niche values to discriminant values.
270+ // Rebase from niche values to discriminants, and check
271+ // whether the result is in range for the niche variants.
272+ // FIXME(#61696) the range check is sometimes incorrect.
265273 let delta = niche_start. wrapping_sub ( niche_variants. start ( ) . as_u32 ( ) as u128 ) ;
266- let lldiscr = bx. sub ( lldiscr, bx. cx ( ) . const_uint_big ( niche_llty, delta) ) ;
267- let lldiscr_max =
274+ let niche_discr =
275+ bx. sub ( encoded_discr, bx. cx ( ) . const_uint_big ( niche_llty, delta) ) ;
276+ let niche_discr_max =
268277 bx. cx ( ) . const_uint ( niche_llty, niche_variants. end ( ) . as_u32 ( ) as u64 ) ;
269- let select_arg = bx. icmp ( IntPredicate :: IntULE , lldiscr, lldiscr_max) ;
270- let cast = bx. intcast ( lldiscr, cast_to, false ) ;
271- bx. select ( select_arg,
272- cast,
273- bx. cx ( ) . const_uint ( cast_to, dataful_variant. as_u32 ( ) as u64 ) )
274- }
278+ (
279+ bx. icmp ( IntPredicate :: IntULE , niche_discr, niche_discr_max) ,
280+ niche_discr,
281+ )
282+ } ;
283+ let niche_discr = bx. intcast ( niche_discr, cast_to, false ) ;
284+ bx. select (
285+ is_niche,
286+ niche_discr,
287+ bx. cx ( ) . const_uint ( cast_to, dataful_variant. as_u32 ( ) as u64 ) ,
288+ )
275289 }
276290 }
277291 }
0 commit comments