Skip to content

Commit 98e9cb2

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

File tree

3 files changed

+465
-19
lines changed

3 files changed

+465
-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`.
@@ -537,6 +550,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
537550
relative_discr,
538551
bx.cx().const_uint(tag_llty, relative_max as u64),
539552
);
553+
554+
// Thanks to parameter attributes and load metadata, LLVM already knows
555+
// the general valid range of the tag. It's possible, though, for there
556+
// to be an impossible value *in the middle*, which those ranges don't
557+
// communicate, so it's worth an `assume` to let the optimizer know.
558+
if niche_variants.contains(&untagged_variant)
559+
&& bx.cx().sess().opts.optimize != OptLevel::No
560+
{
561+
let impossible =
562+
u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32());
563+
let impossible = bx.cx().const_uint(tag_llty, impossible);
564+
let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible);
565+
bx.assume(ne);
566+
}
567+
540568
(is_niche, cast_tag, niche_variants.start().as_u32() as u128)
541569
};
542570

0 commit comments

Comments
 (0)