Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify ConstValue::ScalarPair #57442

Merged
merged 3 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl_stable_hash_for!(struct ty::FieldDef {
impl_stable_hash_for!(
impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
Scalar(val),
ScalarPair(a, b),
Slice(a, b),
ByRef(id, alloc, offset),
}
);
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/mir/interpret/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub struct Pointer<Tag=(),Id=AllocId> {
pub tag: Tag,
}

static_assert!(POINTER_SIZE: ::std::mem::size_of::<Pointer>() == 16);

/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
#[inline(always)]
Expand Down
28 changes: 14 additions & 14 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,28 @@ pub enum ConstValue<'tcx> {
/// Not using the enum `Value` to encode that this must not be `Undef`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above needs an update as there is no more ScalarPair

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.

Scalar(Scalar),

/// Used only for *fat pointers* with layout::abi::ScalarPair
/// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box<str>`, ...)
///
/// Needed for pattern matching code related to slices and strings.
ScalarPair(Scalar, Scalar),
/// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to
/// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could
/// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth
/// it.
Slice(Scalar, u64),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this name change; ScalarPair felt a little bit cryptic.

RalfJung marked this conversation as resolved.
Show resolved Hide resolved

/// An allocation + offset into the allocation.
/// Invariant: The AllocId matches the allocation.
ByRef(AllocId, &'tcx Allocation, Size),
}

#[cfg(target_arch = "x86_64")]
static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 40);

impl<'tcx> ConstValue<'tcx> {
#[inline]
pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
ConstValue::ByRef(..) |
ConstValue::ScalarPair(..) => None,
ConstValue::Slice(..) => None,
ConstValue::Scalar(val) => Some(val),
}
}
Expand All @@ -56,17 +62,8 @@ impl<'tcx> ConstValue<'tcx> {
pub fn new_slice(
val: Scalar,
len: u64,
cx: &impl HasDataLayout
) -> Self {
ConstValue::ScalarPair(val, Scalar::Bits {
bits: len as u128,
size: cx.data_layout().pointer_size.bytes() as u8,
})
}

#[inline]
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
ConstValue::Slice(val, len)
}
}

Expand All @@ -90,6 +87,9 @@ pub enum Scalar<Tag=(), Id=AllocId> {
Ptr(Pointer<Tag, Id>),
}

#[cfg(target_arch = "x86_64")]
static_assert!(SCALAR_SIZE: ::std::mem::size_of::<Scalar>() == 24);

impl<Tag> fmt::Display for Scalar<Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand Down
30 changes: 14 additions & 16 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2702,23 +2702,21 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Resul
return write!(f, "{}", item_path_str(did));
}
// print string literals
if let ConstValue::ScalarPair(ptr, len) = value {
if let ConstValue::Slice(ptr, len) = value {
if let Scalar::Ptr(ptr) = ptr {
if let Scalar::Bits { bits: len, .. } = len {
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
assert_eq!(len as usize as u128, len);
let slice =
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
write!(f, "{:?}", s)
} else {
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
});
}
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
assert_eq!(len as usize as u64, len);
let slice =
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
write!(f, "{:?}", s)
} else {
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
});
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1767,7 +1767,7 @@ macro_rules! nop_list_lift {
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
type Lifted = &'tcx List<$lifted>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.is_empty() {
if self.is_empty() {
return Some(List::empty());
}
if tcx.interners.arena.in_arena(*self as *const _) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
ConstValue::ScalarPair(x, y) => Some(ConstValue::ScalarPair(x, y)),
ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)),
ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef(
x, alloc.lift_to_tcx(tcx)?, z,
)),
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,9 @@ pub enum LazyConst<'tcx> {
Evaluated(Const<'tcx>),
}

#[cfg(target_arch = "x86_64")]
static_assert!(LAZY_CONST_SIZE: ::std::mem::size_of::<LazyConst<'static>>() == 56);

impl<'tcx> LazyConst<'tcx> {
pub fn map_evaluated<R>(self, f: impl FnOnce(Const<'tcx>) -> Option<R>) -> Option<R> {
match self {
Expand All @@ -2089,6 +2092,9 @@ pub struct Const<'tcx> {
pub val: ConstValue<'tcx>,
}

#[cfg(target_arch = "x86_64")]
static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);

impl<'tcx> Const<'tcx> {
#[inline]
pub fn from_scalar(
Expand Down
12 changes: 4 additions & 8 deletions src/librustc_codegen_ssa/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,17 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
);
OperandValue::Immediate(llval)
},
ConstValue::ScalarPair(a, b) => {
let (a_scalar, b_scalar) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
ConstValue::Slice(a, b) => {
let a_scalar = match layout.abi {
layout::Abi::ScalarPair(ref a, _) => a,
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
};
let a_llval = bx.cx().scalar_to_backend(
a,
a_scalar,
bx.cx().scalar_pair_element_backend_type(layout, 0, true),
);
let b_llval = bx.cx().scalar_to_backend(
b,
b_scalar,
bx.cx().scalar_pair_element_backend_type(layout, 1, true),
);
let b_llval = bx.cx().const_usize(b);
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(_, alloc, offset) => {
Expand Down
9 changes: 3 additions & 6 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,11 @@ pub fn op_to_const<'tcx>(
op: OpTy<'tcx>,
may_normalize: bool,
) -> EvalResult<'tcx, ty::Const<'tcx>> {
// We do not normalize just any data. Only scalar layout and fat pointers.
// We do not normalize just any data. Only scalar layout and slices.
let normalize = may_normalize
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
&& match op.layout.abi {
layout::Abi::Scalar(..) => true,
layout::Abi::ScalarPair(..) => {
// Must be a fat pointer
op.layout.ty.builtin_deref(true).is_some()
},
layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
_ => false,
};
let normalized_op = if normalize {
Expand Down Expand Up @@ -103,7 +100,7 @@ pub fn op_to_const<'tcx>(
Ok(Immediate::Scalar(x)) =>
ConstValue::Scalar(x.not_undef()?),
Ok(Immediate::ScalarPair(a, b)) =>
ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?),
ConstValue::Slice(a.not_undef()?, b.to_usize(ecx)?),
};
Ok(ty::Const { val, ty: op.layout.ty })
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/hair/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = tcx.allocate_bytes(s.as_bytes());
ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx)
ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64)
},
LitKind::Err(ref s) => {
let s = s.as_str();
let id = tcx.allocate_bytes(s.as_bytes());
return Ok(ty::Const {
val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx),
val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
ty: tcx.types.err,
});
},
Expand Down
23 changes: 12 additions & 11 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,16 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
// unsize array to slice if pattern is array but match value or other patterns are slice
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
assert_eq!(t, u);
ConstValue::ScalarPair(
ConstValue::Slice(
Scalar::Ptr(p),
n.map_evaluated(|val| val.val.try_to_scalar()).unwrap(),
n.map_evaluated(|val| val.val.try_to_scalar())
.unwrap()
.to_usize(&self.tcx)
.unwrap(),
)
},
// fat pointers stay the same
(ConstValue::ScalarPair(..), _, _) => val,
(ConstValue::Slice(..), _, _) => val,
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
}
Expand Down Expand Up @@ -788,9 +791,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
max_fixed_len,
n.unwrap_usize(cx.tcx),
),
(ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
(ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
max_fixed_len,
n.to_usize(&cx.tcx).unwrap(),
n,
),
_ => {},
}
Expand Down Expand Up @@ -1432,27 +1435,25 @@ fn slice_pat_covered_by_const<'tcx>(
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
},
// a slice fat pointer to a zero length slice
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => {
(ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => {
if *t != tcx.types.u8 {
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
// any sort of exhaustiveness/unreachable check yet
// This solely means that we don't lint about unreachable patterns, even if some
// are definitely unreachable.
return Ok(false);
}
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
&[]
},
//
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
(ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
if *t != tcx.types.u8 {
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
// any sort of exhaustiveness/unreachable check yet
// This solely means that we don't lint about unreachable patterns, even if some
// are definitely unreachable.
return Ok(false);
}
let n = n.to_usize(&tcx).unwrap();
tcx.alloc_map
.lock()
.unwrap_memory(ptr.alloc_id)
Expand Down Expand Up @@ -1784,12 +1785,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
},
ty::TyKind::Slice(t) => {
match value.val {
ConstValue::ScalarPair(ptr, n) => (
ConstValue::Slice(ptr, n) => (
ptr.to_ptr().ok().map(|ptr| (
ptr,
cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
)),
n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
n,
t,
),
_ => span_bug!(
Expand Down
20 changes: 8 additions & 12 deletions src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,25 +1218,21 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>(
if let ty::Str = ty.value.sty {
match (a.val, b.val) {
(
ConstValue::ScalarPair(
ConstValue::Slice(
Scalar::Ptr(ptr_a),
len_a,
),
ConstValue::ScalarPair(
ConstValue::Slice(
Scalar::Ptr(ptr_b),
len_b,
),
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
if len_a == len_b {
let map = tcx.alloc_map.lock();
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
if alloc_a.bytes.len() as u128 == len_a {
return from_bool(alloc_a == alloc_b);
}
}
if len_a == len_b {
let map = tcx.alloc_map.lock();
let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
if alloc_a.bytes.len() as u64 == len_a {
return from_bool(alloc_a == alloc_b);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
).with_default_tag())
},
ConstValue::ScalarPair(a, b) =>
ConstValue::Slice(a, b) =>
Ok(Operand::Immediate(Immediate::ScalarPair(
a.into(),
b.into(),
Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(),
)).with_default_tag()),
ConstValue::Scalar(x) =>
Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()),
Expand Down
7 changes: 1 addition & 6 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,12 +1254,7 @@ fn collect_const<'a, 'tcx>(
debug!("visiting const {:?}", constant);

match constant.val {
ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) |
ConstValue::ScalarPair(Scalar::Ptr(ptr), _) |
ConstValue::Slice(Scalar::Ptr(ptr), _) |
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
ConstValue::ByRef(_id, alloc, _offset) => {
Expand Down