Skip to content

Commit c325ff6

Browse files
committed
Tell LLVM about impossible niche tags
1 parent ae8ab87 commit c325ff6

File tree

3 files changed

+449
-19
lines changed

3 files changed

+449
-19
lines changed

compiler/rustc_codegen_ssa/src/mir/operand.rs

+28
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue};
99
use rustc_middle::ty::Ty;
1010
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
1111
use rustc_middle::{bug, span_bug};
12+
use rustc_session::config::OptLevel;
1213
use tracing::{debug, instrument};
1314

1415
use super::place::{PlaceRef, PlaceValue};
@@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
496497
_ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
497498
};
498499

500+
// Layout ensures that we only get here for cases where the discriminant
501+
// value and the variant index match, since that's all `Niche` can encode.
502+
// But for emphasis and debugging, let's double-check one anyway.
503+
debug_assert_eq!(
504+
self.layout
505+
.ty
506+
.discriminant_for_variant(bx.tcx(), untagged_variant)
507+
.unwrap()
508+
.val,
509+
u128::from(untagged_variant.as_u32()),
510+
);
511+
499512
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
500513

501514
// We have a subrange `niche_start..=niche_end` inside `range`.
@@ -528,6 +541,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
528541
bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64);
529542
(is_niche, tagged_discr, 0)
530543
} else {
544+
// Thanks to parameter attributes and load metadata, LLVM already knows
545+
// the general valid range of the tag. It's possible, though, for there
546+
// to be an impossible value *in the middle*, which those ranges don't
547+
// communicate, so it's worth an `assume` to let the optimizer know.
548+
if niche_variants.contains(&untagged_variant)
549+
&& bx.cx().sess().opts.optimize != OptLevel::No
550+
{
551+
let impossible =
552+
untagged_variant.as_u32() - niche_variants.start().as_u32();
553+
let impossible = u128::from(impossible).wrapping_add(niche_start);
554+
let impossible = bx.cx().const_uint_big(tag_llty, impossible);
555+
let ne = bx.icmp(IntPredicate::IntNE, tag, impossible);
556+
bx.assume(ne);
557+
}
558+
531559
// The special cases don't apply, so we'll have to go with
532560
// the general algorithm.
533561
let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start));

0 commit comments

Comments
 (0)