Skip to content

Commit 912d22e

Browse files
committed
Auto merge of #61673 - RalfJung:miri-no-hard-float, r=eddyb,oli-obk
Miri: convert to/from apfloat instead of host floats Cc @oli-obk @eddyb
2 parents 9d9c7ad + 8dfc8db commit 912d22e

File tree

5 files changed

+154
-124
lines changed

5 files changed

+154
-124
lines changed

src/librustc/mir/interpret/value.rs

+49-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::fmt;
22
use rustc_macros::HashStable;
3+
use rustc_apfloat::{Float, ieee::{Double, Single}};
34

45
use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef};
56
use crate::ty::PlaceholderConst;
@@ -131,6 +132,20 @@ impl<Tag> fmt::Display for Scalar<Tag> {
131132
}
132133
}
133134

135+
impl<Tag> From<Single> for Scalar<Tag> {
136+
#[inline(always)]
137+
fn from(f: Single) -> Self {
138+
Scalar::from_f32(f)
139+
}
140+
}
141+
142+
impl<Tag> From<Double> for Scalar<Tag> {
143+
#[inline(always)]
144+
fn from(f: Double) -> Self {
145+
Scalar::from_f64(f)
146+
}
147+
}
148+
134149
impl<'tcx> Scalar<()> {
135150
#[inline(always)]
136151
fn check_data(data: u128, size: u8) {
@@ -279,6 +294,26 @@ impl<'tcx, Tag> Scalar<Tag> {
279294
Scalar::Raw { data: i, size: size.bytes() as u8 }
280295
}
281296

297+
#[inline]
298+
pub fn from_u8(i: u8) -> Self {
299+
Scalar::Raw { data: i as u128, size: 1 }
300+
}
301+
302+
#[inline]
303+
pub fn from_u16(i: u16) -> Self {
304+
Scalar::Raw { data: i as u128, size: 2 }
305+
}
306+
307+
#[inline]
308+
pub fn from_u32(i: u32) -> Self {
309+
Scalar::Raw { data: i as u128, size: 4 }
310+
}
311+
312+
#[inline]
313+
pub fn from_u64(i: u64) -> Self {
314+
Scalar::Raw { data: i as u128, size: 8 }
315+
}
316+
282317
#[inline]
283318
pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
284319
let i = i.into();
@@ -292,13 +327,15 @@ impl<'tcx, Tag> Scalar<Tag> {
292327
}
293328

294329
#[inline]
295-
pub fn from_f32(f: f32) -> Self {
296-
Scalar::Raw { data: f.to_bits() as u128, size: 4 }
330+
pub fn from_f32(f: Single) -> Self {
331+
// We trust apfloat to give us properly truncated data.
332+
Scalar::Raw { data: f.to_bits(), size: 4 }
297333
}
298334

299335
#[inline]
300-
pub fn from_f64(f: f64) -> Self {
301-
Scalar::Raw { data: f.to_bits() as u128, size: 8 }
336+
pub fn from_f64(f: Double) -> Self {
337+
// We trust apfloat to give us properly truncated data.
338+
Scalar::Raw { data: f.to_bits(), size: 8 }
302339
}
303340

304341
#[inline]
@@ -427,13 +464,15 @@ impl<'tcx, Tag> Scalar<Tag> {
427464
}
428465

429466
#[inline]
430-
pub fn to_f32(self) -> InterpResult<'static, f32> {
431-
Ok(f32::from_bits(self.to_u32()?))
467+
pub fn to_f32(self) -> InterpResult<'static, Single> {
468+
// Going through `u32` to check size and truncation.
469+
Ok(Single::from_bits(self.to_u32()? as u128))
432470
}
433471

434472
#[inline]
435-
pub fn to_f64(self) -> InterpResult<'static, f64> {
436-
Ok(f64::from_bits(self.to_u64()?))
473+
pub fn to_f64(self) -> InterpResult<'static, Double> {
474+
// Going through `u64` to check size and truncation.
475+
Ok(Double::from_bits(self.to_u64()? as u128))
437476
}
438477
}
439478

@@ -517,12 +556,12 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
517556
}
518557

519558
#[inline(always)]
520-
pub fn to_f32(self) -> InterpResult<'tcx, f32> {
559+
pub fn to_f32(self) -> InterpResult<'tcx, Single> {
521560
self.not_undef()?.to_f32()
522561
}
523562

524563
#[inline(always)]
525-
pub fn to_f64(self) -> InterpResult<'tcx, f64> {
564+
pub fn to_f64(self) -> InterpResult<'tcx, Double> {
526565
self.not_undef()?.to_f64()
527566
}
528567

src/librustc/ty/sty.rs

+8
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
20352035
}
20362036
}
20372037

2038+
#[inline]
2039+
pub fn is_fn_ptr(&self) -> bool {
2040+
match self.sty {
2041+
FnPtr(_) => true,
2042+
_ => false,
2043+
}
2044+
}
2045+
20382046
pub fn is_impl_trait(&self) -> bool {
20392047
match self.sty {
20402048
Opaque(..) => true,

src/librustc_mir/hair/constant.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ fn parse_float<'tcx>(
6969
) -> Result<ConstValue<'tcx>, ()> {
7070
let num = num.as_str();
7171
use rustc_apfloat::ieee::{Single, Double};
72-
use rustc_apfloat::Float;
73-
let (data, size) = match fty {
72+
let scalar = match fty {
7473
ast::FloatTy::F32 => {
7574
num.parse::<f32>().map_err(|_| ())?;
7675
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
@@ -79,19 +78,19 @@ fn parse_float<'tcx>(
7978
if neg {
8079
f = -f;
8180
}
82-
(f.to_bits(), 4)
81+
Scalar::from_f32(f)
8382
}
8483
ast::FloatTy::F64 => {
8584
num.parse::<f64>().map_err(|_| ())?;
8685
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
87-
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
86+
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
8887
});
8988
if neg {
9089
f = -f;
9190
}
92-
(f.to_bits(), 8)
91+
Scalar::from_f64(f)
9392
}
9493
};
9594

96-
Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size))))
95+
Ok(ConstValue::Scalar(scalar))
9796
}

src/librustc_mir/interpret/cast.rs

+45-52
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
55
use syntax::symbol::sym;
66

77
use rustc_apfloat::ieee::{Single, Double};
8+
use rustc_apfloat::{Float, FloatConvert};
89
use rustc::mir::interpret::{
910
Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
1011
};
1112
use rustc::mir::CastKind;
12-
use rustc_apfloat::Float;
1313

1414
use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};
1515

@@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
126126
Ok(())
127127
}
128128

129-
pub(super) fn cast_scalar(
129+
fn cast_scalar(
130130
&self,
131131
val: Scalar<M::PointerTag>,
132132
src_layout: TyLayout<'tcx>,
@@ -135,23 +135,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
135135
use rustc::ty::TyKind::*;
136136
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
137137

138-
match val.to_bits_or_ptr(src_layout.size, self) {
139-
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
140-
Ok(data) => {
141-
match src_layout.ty.sty {
142-
Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
143-
_ => self.cast_from_int(data, src_layout, dest_layout),
138+
match src_layout.ty.sty {
139+
// Floating point
140+
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
141+
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
142+
// Integer(-like), including fn ptr casts and casts from enums that
143+
// are represented as integers (this excludes univariant enums, which
144+
// are handled in `cast` directly).
145+
_ => {
146+
assert!(
147+
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
148+
src_layout.ty.is_enum() || src_layout.ty.is_integral() ||
149+
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() ||
150+
src_layout.ty.is_region_ptr(),
151+
"Unexpected cast from type {:?}", src_layout.ty
152+
);
153+
match val.to_bits_or_ptr(src_layout.size, self) {
154+
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
155+
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
144156
}
145157
}
146158
}
147159
}
148160

149161
fn cast_from_int(
150162
&self,
151-
v: u128,
163+
v: u128, // raw bits
152164
src_layout: TyLayout<'tcx>,
153165
dest_layout: TyLayout<'tcx>,
154166
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
167+
// Let's make sure v is sign-extended *if* it has a signed type.
155168
let signed = src_layout.abi.is_signed();
156169
let v = if signed {
157170
self.sign_extend(v, src_layout)
@@ -166,21 +179,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
166179
Ok(Scalar::from_uint(v, dest_layout.size))
167180
}
168181

169-
Float(FloatTy::F32) if signed => Ok(Scalar::from_uint(
170-
Single::from_i128(v as i128).value.to_bits(),
171-
Size::from_bits(32)
182+
Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
183+
Single::from_i128(v as i128).value
172184
)),
173-
Float(FloatTy::F64) if signed => Ok(Scalar::from_uint(
174-
Double::from_i128(v as i128).value.to_bits(),
175-
Size::from_bits(64)
185+
Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
186+
Double::from_i128(v as i128).value
176187
)),
177-
Float(FloatTy::F32) => Ok(Scalar::from_uint(
178-
Single::from_u128(v).value.to_bits(),
179-
Size::from_bits(32)
188+
Float(FloatTy::F32) => Ok(Scalar::from_f32(
189+
Single::from_u128(v).value
180190
)),
181-
Float(FloatTy::F64) => Ok(Scalar::from_uint(
182-
Double::from_u128(v).value.to_bits(),
183-
Size::from_bits(64)
191+
Float(FloatTy::F64) => Ok(Scalar::from_f64(
192+
Double::from_u128(v).value
184193
)),
185194

186195
Char => {
@@ -194,52 +203,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
194203
}
195204
}
196205

197-
fn cast_from_float(
206+
fn cast_from_float<F>(
198207
&self,
199-
bits: u128,
200-
fty: FloatTy,
208+
f: F,
201209
dest_ty: Ty<'tcx>
202-
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
210+
) -> InterpResult<'tcx, Scalar<M::PointerTag>>
211+
where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
212+
{
203213
use rustc::ty::TyKind::*;
204-
use rustc_apfloat::FloatConvert;
205214
match dest_ty.sty {
206215
// float -> uint
207216
Uint(t) => {
208217
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
209-
let v = match fty {
210-
FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
211-
FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
212-
};
218+
let v = f.to_u128(width).value;
213219
// This should already fit the bit width
214220
Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
215221
},
216222
// float -> int
217223
Int(t) => {
218224
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
219-
let v = match fty {
220-
FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
221-
FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
222-
};
225+
let v = f.to_i128(width).value;
223226
Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
224227
},
225-
// f64 -> f32
226-
Float(FloatTy::F32) if fty == FloatTy::F64 => {
227-
Ok(Scalar::from_uint(
228-
Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
229-
Size::from_bits(32),
230-
))
231-
},
232-
// f32 -> f64
233-
Float(FloatTy::F64) if fty == FloatTy::F32 => {
234-
Ok(Scalar::from_uint(
235-
Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
236-
Size::from_bits(64),
237-
))
238-
},
239-
// identity cast
240-
Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))),
241-
Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))),
242-
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
228+
// float -> f32
229+
Float(FloatTy::F32) =>
230+
Ok(Scalar::from_f32(f.convert(&mut false).value)),
231+
// float -> f64
232+
Float(FloatTy::F64) =>
233+
Ok(Scalar::from_f64(f.convert(&mut false).value)),
234+
// That's it.
235+
_ => bug!("invalid float to {:?} cast", dest_ty),
243236
}
244237
}
245238

0 commit comments

Comments
 (0)