@@ -231,6 +231,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
231
231
let tag = self . project_field ( bx, tag_field) ;
232
232
let tag = bx. load_operand ( tag) ;
233
233
234
+ let niche_llty = bx. cx ( ) . immediate_backend_type ( tag. layout ) ;
235
+ let tag = tag. immediate ( ) ;
236
+
234
237
// Decode the discriminant (specifically if it's niche-encoded).
235
238
match * tag_encoding {
236
239
TagEncoding :: Direct => {
@@ -242,13 +245,32 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
242
245
Int ( _, signed) => !tag_scalar. is_bool ( ) && signed,
243
246
_ => false ,
244
247
} ;
245
- bx. intcast ( tag. immediate ( ) , cast_to, signed)
248
+ bx. intcast ( tag, cast_to, signed)
249
+ }
250
+ // Handle single-variant-niche separately.
251
+ // Note: this also cover pointer-based niches.
252
+ TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start }
253
+ if niche_variants. end ( ) . as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) == 0 =>
254
+ {
255
+ let niche_start = if niche_start == 0 {
256
+ // Avoid calling `const_uint`, which wouldn't work for pointers.
257
+ bx. cx ( ) . const_null ( niche_llty)
258
+ } else {
259
+ bx. cx ( ) . const_uint_big ( niche_llty, niche_start)
260
+ } ;
261
+ let is_niche = bx. icmp ( IntPredicate :: IntEQ , tag, niche_start) ;
262
+ bx. select (
263
+ is_niche,
264
+ bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ,
265
+ bx. cx ( ) . const_uint ( cast_to, untagged_variant. as_u32 ( ) as u64 ) ,
266
+ )
246
267
}
247
268
TagEncoding :: Niche { untagged_variant, ref niche_variants, niche_start } => {
269
+ // Assumption: here, llty should not be pointer.
270
+ // FIXME(eddyb) check the actual primitive type here.
271
+
248
272
// Rebase from niche values to discriminants, and check
249
273
// 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 ( ) ;
252
274
253
275
// We first compute the "relative discriminant" (wrt `niche_variants`),
254
276
// that is, if `n = niche_variants.end() - niche_variants.start()`,
@@ -260,19 +282,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
260
282
// that might not fit in the same type, on top of needing an extra
261
283
// comparison (see also the comment on `let niche_discr`).
262
284
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
285
tag
266
286
} else {
287
+ // Note: subtracting `0` wouldn't work for pointers.
267
288
bx. sub ( tag, bx. cx ( ) . const_uint_big ( niche_llty, niche_start) )
268
289
} ;
269
290
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 {
291
+ let is_niche = {
276
292
let relative_max = bx. cx ( ) . const_uint ( niche_llty, relative_max as u64 ) ;
277
293
bx. icmp ( IntPredicate :: IntULE , relative_discr, relative_max)
278
294
} ;
0 commit comments