Skip to content

Commit 17bcac1

Browse files
committed
Extract single-niche-variant get discriminant to separate match arm
1 parent 4d4e51e commit 17bcac1

File tree

1 file changed

+27
-11
lines changed
  • compiler/rustc_codegen_ssa/src/mir

1 file changed

+27
-11
lines changed

compiler/rustc_codegen_ssa/src/mir/place.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
231231
let tag = self.project_field(bx, tag_field);
232232
let tag = bx.load_operand(tag);
233233

234+
let niche_llty = bx.cx().immediate_backend_type(tag.layout);
235+
let tag = tag.immediate();
236+
234237
// Decode the discriminant (specifically if it's niche-encoded).
235238
match *tag_encoding {
236239
TagEncoding::Direct => {
@@ -242,13 +245,32 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
242245
Int(_, signed) => !tag_scalar.is_bool() && signed,
243246
_ => false,
244247
};
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+
)
246267
}
247268
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+
248272
// Rebase from niche values to discriminants, and check
249273
// 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();
252274

253275
// We first compute the "relative discriminant" (wrt `niche_variants`),
254276
// that is, if `n = niche_variants.end() - niche_variants.start()`,
@@ -260,19 +282,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
260282
// that might not fit in the same type, on top of needing an extra
261283
// comparison (see also the comment on `let niche_discr`).
262284
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.
265285
tag
266286
} else {
287+
// Note: subtracting `0` wouldn't work for pointers.
267288
bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
268289
};
269290
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 = {
276292
let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64);
277293
bx.icmp(IntPredicate::IntULE, relative_discr, relative_max)
278294
};

0 commit comments

Comments
 (0)