Skip to content

Commit 0529dc8

Browse files
committed
proide ptr_wrapping_offset on Scalars
1 parent 8730410 commit 0529dc8

File tree

2 files changed

+65
-43
lines changed

2 files changed

+65
-43
lines changed

src/librustc/mir/interpret/mod.rs

+43-36
Original file line numberDiff line numberDiff line change
@@ -91,42 +91,43 @@ pub trait PointerArithmetic: layout::HasDataLayout {
9191
}
9292

9393
//// Trunace the given value to the pointer size; also return whether there was an overflow
94+
#[inline]
9495
fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
9596
let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
9697
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
9798
}
9899

99-
// Overflow checking only works properly on the range from -u64 to +u64.
100-
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
101-
// FIXME: is it possible to over/underflow here?
102-
if i < 0 {
103-
// trickery to ensure that i64::min_value() works fine
104-
// this formula only works for true negative values, it panics for zero!
105-
let n = u64::max_value() - (i as u64) + 1;
106-
val.overflowing_sub(n)
107-
} else {
108-
self.overflowing_offset(val, i as u64)
109-
}
100+
#[inline]
101+
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
102+
let (res, over) = self.overflowing_offset(val, i);
103+
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
110104
}
111105

106+
#[inline]
112107
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
113108
let (res, over1) = val.overflowing_add(i);
114-
let (res, over2) = self.truncate_to_ptr(res as u128);
109+
let (res, over2) = self.truncate_to_ptr(u128::from(res));
115110
(res, over1 || over2)
116111
}
117112

113+
#[inline]
118114
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
119-
let (res, over) = self.overflowing_signed_offset(val, i as i128);
115+
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
120116
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
121117
}
122118

123-
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
124-
let (res, over) = self.overflowing_offset(val, i);
125-
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
126-
}
127-
128-
fn wrapping_signed_offset(&self, val: u64, i: i64) -> u64 {
129-
self.overflowing_signed_offset(val, i as i128).0
119+
// Overflow checking only works properly on the range from -u64 to +u64.
120+
#[inline]
121+
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
122+
// FIXME: is it possible to over/underflow here?
123+
if i < 0 {
124+
// trickery to ensure that i64::min_value() works fine
125+
// this formula only works for true negative values, it panics for zero!
126+
let n = u64::max_value() - (i as u64) + 1;
127+
val.overflowing_sub(n)
128+
} else {
129+
self.overflowing_offset(val, i as u64)
130+
}
130131
}
131132
}
132133

@@ -176,19 +177,27 @@ impl<'tcx, Tag> Pointer<Tag> {
176177
Pointer { alloc_id, offset, tag }
177178
}
178179

179-
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
180-
Pointer::new_with_tag(
180+
#[inline]
181+
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
182+
Ok(Pointer::new_with_tag(
181183
self.alloc_id,
182-
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
183-
self.tag,
184-
)
184+
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
185+
self.tag
186+
))
185187
}
186188

187-
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
188-
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
189+
#[inline]
190+
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
191+
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
189192
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
190193
}
191194

195+
#[inline(always)]
196+
pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
197+
self.overflowing_offset(i, cx).0
198+
}
199+
200+
#[inline]
192201
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
193202
Ok(Pointer::new_with_tag(
194203
self.alloc_id,
@@ -197,20 +206,18 @@ impl<'tcx, Tag> Pointer<Tag> {
197206
))
198207
}
199208

200-
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
201-
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
209+
#[inline]
210+
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
211+
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
202212
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
203213
}
204214

205-
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
206-
Ok(Pointer::new_with_tag(
207-
self.alloc_id,
208-
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
209-
self.tag
210-
))
215+
#[inline(always)]
216+
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
217+
self.overflowing_signed_offset(i128::from(i), cx).0
211218
}
212219

213-
#[inline]
220+
#[inline(always)]
214221
pub fn erase_tag(self) -> Pointer {
215222
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
216223
}

src/librustc/mir/interpret/value.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -143,32 +143,47 @@ impl<'tcx, Tag> Scalar<Tag> {
143143
}
144144

145145
#[inline]
146-
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
146+
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
147147
let dl = cx.data_layout();
148148
match self {
149149
Scalar::Bits { bits, size } => {
150150
assert_eq!(size as u64, dl.pointer_size.bytes());
151151
Ok(Scalar::Bits {
152-
bits: dl.signed_offset(bits as u64, i)? as u128,
152+
bits: dl.offset(bits as u64, i.bytes())? as u128,
153153
size,
154154
})
155155
}
156-
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
156+
Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr),
157157
}
158158
}
159159

160160
#[inline]
161-
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
161+
pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
162162
let dl = cx.data_layout();
163163
match self {
164164
Scalar::Bits { bits, size } => {
165165
assert_eq!(size as u64, dl.pointer_size.bytes());
166+
Scalar::Bits {
167+
bits: dl.overflowing_offset(bits as u64, i.bytes()).0 as u128,
168+
size,
169+
}
170+
}
171+
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)),
172+
}
173+
}
174+
175+
#[inline]
176+
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
177+
let dl = cx.data_layout();
178+
match self {
179+
Scalar::Bits { bits, size } => {
180+
assert_eq!(size as u64, dl.pointer_size().bytes());
166181
Ok(Scalar::Bits {
167-
bits: dl.offset(bits as u64, i.bytes())? as u128,
182+
bits: dl.signed_offset(bits as u64, i)? as u128,
168183
size,
169184
})
170185
}
171-
Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr),
186+
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
172187
}
173188
}
174189

@@ -179,7 +194,7 @@ impl<'tcx, Tag> Scalar<Tag> {
179194
Scalar::Bits { bits, size } => {
180195
assert_eq!(size as u64, dl.pointer_size.bytes());
181196
Scalar::Bits {
182-
bits: dl.wrapping_signed_offset(bits as u64, i) as u128,
197+
bits: dl.overflowing_signed_offset(bits as u64, i128::from(i)).0 as u128,
183198
size,
184199
}
185200
}

0 commit comments

Comments
 (0)