Skip to content

Commit 05cd48b

Browse files
committed
Add methods for checking for full ranges to Scalar and WrappingRange
Move *_max methods back to util change to inline instead of inline(always) Remove valid_range_exclusive from scalar Use WrappingRange instead implement always_valid_for in a safer way Fix accidental edit
1 parent c5cbf78 commit 05cd48b

File tree

7 files changed

+41
-56
lines changed

7 files changed

+41
-56
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -541,11 +541,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
541541
// become 0..0 when the type becomes i1, which would be rejected
542542
// by the LLVM verifier.
543543
if let Int(..) = scalar.value {
544-
if !scalar.is_bool() {
545-
let range = scalar.valid_range_exclusive(bx);
546-
if range.start != range.end {
547-
bx.range_metadata(callsite, range);
548-
}
544+
if !scalar.is_bool() && !scalar.is_always_valid_for(bx) {
545+
bx.range_metadata(callsite, &scalar.valid_range);
549546
}
550547
}
551548
}

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ use rustc_hir::def_id::DefId;
1818
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
1919
use rustc_middle::ty::{self, Ty, TyCtxt};
2020
use rustc_span::Span;
21-
use rustc_target::abi::{self, Align, Size};
21+
use rustc_target::abi::{self, Align, Size, WrappingRange};
2222
use rustc_target::spec::{HasTargetSpec, Target};
2323
use std::borrow::Cow;
2424
use std::ffi::CStr;
2525
use std::iter;
26-
use std::ops::{Deref, Range};
26+
use std::ops::Deref;
2727
use std::ptr;
2828
use tracing::debug;
2929

@@ -464,9 +464,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
464464
) {
465465
match scalar.value {
466466
abi::Int(..) => {
467-
let range = scalar.valid_range_exclusive(bx);
468-
if range.start != range.end {
469-
bx.range_metadata(load, range);
467+
if !scalar.is_always_valid_for(bx) {
468+
bx.range_metadata(load, &scalar.valid_range);
470469
}
471470
}
472471
abi::Pointer if !scalar.valid_range.contains_zero() => {
@@ -555,7 +554,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
555554
next_bx
556555
}
557556

558-
fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) {
557+
fn range_metadata(&mut self, load: &'ll Value, range: &WrappingRange) {
559558
if self.sess().target.arch == "amdgpu" {
560559
// amdgpu/LLVM does something weird and thinks an i64 value is
561560
// split into a v2i32, halving the bitwidth LLVM expects,
@@ -568,7 +567,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
568567
let llty = self.cx.val_ty(load);
569568
let v = [
570569
self.cx.const_uint_big(llty, range.start),
571-
self.cx.const_uint_big(llty, range.end),
570+
self.cx.const_uint_big(llty, range.end.wrapping_add(1)),
572571
];
573572

574573
llvm::LLVMSetMetadata(

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
2020
use rustc_span::source_map::Span;
2121
use rustc_span::{sym, Symbol};
2222
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
23-
use rustc_target::abi::{self, HasDataLayout};
23+
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
2424
use rustc_target::spec::abi::Abi;
2525

2626
/// Used by `FunctionCx::codegen_terminator` for emitting common patterns
@@ -1104,7 +1104,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11041104
llval = bx.load(bx.backend_type(arg.layout), llval, align);
11051105
if let abi::Abi::Scalar(ref scalar) = arg.layout.abi {
11061106
if scalar.is_bool() {
1107-
bx.range_metadata(llval, 0..2);
1107+
bx.range_metadata(llval, &WrappingRange { start: 0, end: 1 });
11081108
}
11091109
}
11101110
// We store bools as `i8` so we need to truncate to `i1`.

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
308308
// then `i1 1` (i.e., E::B) is effectively `i8 -1`.
309309
signed = !scalar.is_bool() && s;
310310

311-
let er = scalar.valid_range_exclusive(bx.cx());
312-
if er.end != er.start
311+
if !scalar.is_always_valid_for(bx.cx())
313312
&& scalar.valid_range.end >= scalar.valid_range.start
314313
{
315314
// We want `table[e as usize ± k]` to not

compiler/rustc_codegen_ssa/src/traits/builder.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ use crate::MemFlags;
1616
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
1717
use rustc_middle::ty::Ty;
1818
use rustc_span::Span;
19-
use rustc_target::abi::{Abi, Align, Scalar, Size};
19+
use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
2020
use rustc_target::spec::HasTargetSpec;
2121

22-
use std::ops::Range;
23-
2422
#[derive(Copy, Clone)]
2523
pub enum OverflowOp {
2624
Add,
@@ -158,7 +156,7 @@ pub trait BuilderMethods<'a, 'tcx>:
158156
dest: PlaceRef<'tcx, Self::Value>,
159157
) -> Self;
160158

161-
fn range_metadata(&mut self, load: Self::Value, range: Range<u128>);
159+
fn range_metadata(&mut self, load: Self::Value, range: &WrappingRange);
162160
fn nonnull_metadata(&mut self, load: Self::Value);
163161

164162
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -620,38 +620,36 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
620620
op: &OpTy<'tcx, M::PointerTag>,
621621
scalar_layout: &ScalarAbi,
622622
) -> InterpResult<'tcx> {
623-
let value = self.read_scalar(op)?;
624-
let valid_range = scalar_layout.valid_range.clone();
625-
let WrappingRange { start: lo, end: hi } = valid_range;
626-
// Determine the allowed range
627-
// `max_hi` is as big as the size fits
628-
let max_hi = u128::MAX >> (128 - op.layout.size.bits());
629-
assert!(hi <= max_hi);
630-
// We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
631-
if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
623+
if scalar_layout.valid_range.is_full_for(op.layout.size) {
632624
// Nothing to check
633625
return Ok(());
634626
}
635-
// At least one value is excluded. Get the bits.
627+
// At least one value is excluded.
628+
let valid_range = scalar_layout.valid_range.clone();
629+
let WrappingRange { start, end } = valid_range;
630+
let max_value = u128::MAX >> (128 - op.layout.size.bits());
631+
assert!(end <= max_value);
632+
// Determine the allowed range
633+
let value = self.read_scalar(op)?;
636634
let value = try_validation!(
637635
value.check_init(),
638636
self.path,
639637
err_ub!(InvalidUninitBytes(None)) => { "{}", value }
640-
expected { "something {}", wrapping_range_format(valid_range, max_hi) },
638+
expected { "something {}", wrapping_range_format(valid_range, max_value) },
641639
);
642640
let bits = match value.try_to_int() {
643641
Err(_) => {
644642
// So this is a pointer then, and casting to an int failed.
645643
// Can only happen during CTFE.
646644
let ptr = self.ecx.scalar_to_ptr(value);
647-
if lo == 1 && hi == max_hi {
645+
if start == 1 && end == max_value {
648646
// Only null is the niche. So make sure the ptr is NOT null.
649647
if self.ecx.memory.ptr_may_be_null(ptr) {
650648
throw_validation_failure!(self.path,
651649
{ "a potentially null pointer" }
652650
expected {
653651
"something that cannot possibly fail to be {}",
654-
wrapping_range_format(valid_range, max_hi)
652+
wrapping_range_format(valid_range, max_value)
655653
}
656654
)
657655
}
@@ -663,7 +661,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
663661
{ "a pointer" }
664662
expected {
665663
"something that cannot possibly fail to be {}",
666-
wrapping_range_format(valid_range, max_hi)
664+
wrapping_range_format(valid_range, max_value)
667665
}
668666
)
669667
}
@@ -676,7 +674,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
676674
} else {
677675
throw_validation_failure!(self.path,
678676
{ "{}", bits }
679-
expected { "something {}", wrapping_range_format(valid_range, max_hi) }
677+
expected { "something {}", wrapping_range_format(valid_range, max_value) }
680678
)
681679
}
682680
}

compiler/rustc_target/src/abi/mod.rs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::convert::{TryFrom, TryInto};
77
use std::fmt;
88
use std::iter::Step;
99
use std::num::NonZeroUsize;
10-
use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub};
10+
use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
1111
use std::str::FromStr;
1212

1313
use rustc_index::vec::{Idx, IndexVec};
@@ -779,6 +779,14 @@ impl WrappingRange {
779779
self.end = end;
780780
self
781781
}
782+
783+
/// Returns `true` if `size` completely fills the range.
784+
#[inline]
785+
pub fn is_full_for(&self, size: Size) -> bool {
786+
let max_value = u128::MAX >> (128 - size.bits());
787+
debug_assert!(self.start <= max_value && self.end <= max_value);
788+
(self.start == 0 && self.end == max_value) || (self.end + 1 == self.start)
789+
}
782790
}
783791

784792
impl fmt::Debug for WrappingRange {
@@ -807,21 +815,10 @@ impl Scalar {
807815
&& matches!(self.valid_range, WrappingRange { start: 0, end: 1 })
808816
}
809817

810-
/// Returns the valid range as a `x..y` range.
811-
///
812-
/// If `x` and `y` are equal, the range is full, not empty.
813-
pub fn valid_range_exclusive<C: HasDataLayout>(&self, cx: &C) -> Range<u128> {
814-
// For a (max) value of -1, max will be `-1 as usize`, which overflows.
815-
// However, that is fine here (it would still represent the full range),
816-
// i.e., if the range is everything.
817-
let bits = self.value.size(cx).bits();
818-
assert!(bits <= 128);
819-
let mask = !0u128 >> (128 - bits);
820-
let start = self.valid_range.start;
821-
let end = self.valid_range.end;
822-
assert_eq!(start, start & mask);
823-
assert_eq!(end, end & mask);
824-
start..(end.wrapping_add(1) & mask)
818+
/// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
819+
#[inline]
820+
pub fn is_always_valid_for<C: HasDataLayout>(&self, cx: &C) -> bool {
821+
self.valid_range.is_full_for(self.value.size(cx))
825822
}
826823
}
827824

@@ -1269,11 +1266,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
12691266
// The range must contain 0.
12701267
s.valid_range.contains_zero()
12711268
} else {
1272-
// The range must include all values. `valid_range_exclusive` handles
1273-
// the wrap-around using target arithmetic; with wrap-around then the full
1274-
// range is one where `start == end`.
1275-
let range = s.valid_range_exclusive(cx);
1276-
range.start == range.end
1269+
// The range must include all values.
1270+
s.is_always_valid_for(cx)
12771271
}
12781272
};
12791273

0 commit comments

Comments
 (0)