@@ -228,8 +228,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
228
228
}
229
229
} ;
230
230
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).
233
236
match * discr_kind {
234
237
layout:: DiscriminantKind :: Tag => {
235
238
let signed = match discr_scalar. value {
@@ -240,38 +243,49 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
240
243
layout:: Int ( _, signed) => !discr_scalar. is_bool ( ) && signed,
241
244
_ => false
242
245
} ;
243
- bx. intcast ( lldiscr , cast_to, signed)
246
+ bx. intcast ( encoded_discr . immediate ( ) , cast_to, signed)
244
247
}
245
248
layout:: DiscriminantKind :: Niche {
246
249
dataful_variant,
247
250
ref niche_variants,
248
251
niche_start,
249
252
} => {
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.
252
258
// FIXME(eddyb): check the actual primitive type here.
253
- let niche_llval = if niche_start == 0 {
259
+ let encoded_niche = if niche_start == 0 {
254
260
// HACK(eddyb): using `c_null` as it works on all types.
255
261
bx. cx ( ) . const_null ( niche_llty)
256
262
} else {
257
263
bx. cx ( ) . const_uint_big ( niche_llty, niche_start)
258
264
} ;
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 ) ,
261
267
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
+ )
263
269
} 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.
265
273
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 =
268
277
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
+ )
275
289
}
276
290
}
277
291
}
0 commit comments