Skip to content

Commit deb0ff4

Browse files
authored
Merge pull request #764 from RalfJung/minmax
implement min and max floating point intrinsics
2 parents 48897d0 + 6a0d092 commit deb0ff4

File tree

7 files changed

+74
-26
lines changed

7 files changed

+74
-26
lines changed

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1cbd8a4d686d1411105f26cddf876c5994e69593
1+
8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be

src/fn_call.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
758758
this.machine.last_error = err;
759759
}
760760
"GetLastError" => {
761-
this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
761+
this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?;
762762
}
763763

764764
"AddVectoredExceptionHandler" => {
@@ -854,7 +854,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
854854
};
855855
// If there was no error, write back how much was written.
856856
if let Some(n) = written {
857-
this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
857+
this.write_scalar(Scalar::from_u32(n), written_place.into())?;
858858
}
859859
// Return whether this was a success.
860860
this.write_scalar(

src/intrinsic.rs

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_apfloat::Float;
12
use rustc::mir;
23
use rustc::mir::interpret::{InterpResult, PointerArithmetic};
34
use rustc::ty::layout::{self, LayoutOf, Size};
@@ -186,7 +187,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
186187

187188
"sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
188189
"log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => {
189-
let f = this.read_scalar(args[0])?.to_f32()?;
190+
// FIXME: Using host floats.
191+
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
190192
let f = match intrinsic_name.get() {
191193
"sinf32" => f.sin(),
192194
"fabsf32" => f.abs(),
@@ -202,12 +204,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
202204
"truncf32" => f.trunc(),
203205
_ => bug!(),
204206
};
205-
this.write_scalar(Scalar::from_f32(f), dest)?;
207+
this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?;
206208
}
207209

208210
"sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" |
209211
"log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => {
210-
let f = this.read_scalar(args[0])?.to_f64()?;
212+
// FIXME: Using host floats.
213+
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
211214
let f = match intrinsic_name.get() {
212215
"sinf64" => f.sin(),
213216
"fabsf64" => f.abs(),
@@ -223,7 +226,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
223226
"truncf64" => f.trunc(),
224227
_ => bug!(),
225228
};
226-
this.write_scalar(Scalar::from_f64(f), dest)?;
229+
this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
227230
}
228231

229232
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
@@ -240,6 +243,28 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
240243
this.binop_ignore_overflow(op, a, b, dest)?;
241244
}
242245

246+
"minnumf32" | "maxnumf32" => {
247+
let a = this.read_scalar(args[0])?.to_f32()?;
248+
let b = this.read_scalar(args[1])?.to_f32()?;
249+
let res = if intrinsic_name.get().starts_with("min") {
250+
a.min(b)
251+
} else {
252+
a.max(b)
253+
};
254+
this.write_scalar(Scalar::from_f32(res), dest)?;
255+
}
256+
257+
"minnumf64" | "maxnumf64" => {
258+
let a = this.read_scalar(args[0])?.to_f64()?;
259+
let b = this.read_scalar(args[1])?.to_f64()?;
260+
let res = if intrinsic_name.get().starts_with("min") {
261+
a.min(b)
262+
} else {
263+
a.max(b)
264+
};
265+
this.write_scalar(Scalar::from_f64(res), dest)?;
266+
}
267+
243268
"exact_div" => {
244269
// Performs an exact division, resulting in undefined behavior where
245270
// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`
@@ -320,19 +345,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
320345
}
321346

322347
"powf32" => {
323-
let f = this.read_scalar(args[0])?.to_f32()?;
324-
let f2 = this.read_scalar(args[1])?.to_f32()?;
348+
// FIXME: Using host floats.
349+
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
350+
let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?);
325351
this.write_scalar(
326-
Scalar::from_f32(f.powf(f2)),
352+
Scalar::from_u32(f.powf(f2).to_bits()),
327353
dest,
328354
)?;
329355
}
330356

331357
"powf64" => {
332-
let f = this.read_scalar(args[0])?.to_f64()?;
333-
let f2 = this.read_scalar(args[1])?.to_f64()?;
358+
// FIXME: Using host floats.
359+
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
360+
let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?);
334361
this.write_scalar(
335-
Scalar::from_f64(f.powf(f2)),
362+
Scalar::from_u64(f.powf(f2).to_bits()),
336363
dest,
337364
)?;
338365
}
@@ -341,8 +368,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
341368
let a = this.read_scalar(args[0])?.to_f32()?;
342369
let b = this.read_scalar(args[1])?.to_f32()?;
343370
let c = this.read_scalar(args[2])?.to_f32()?;
371+
let res = a.mul_add(b, c).value;
344372
this.write_scalar(
345-
Scalar::from_f32(a * b + c),
373+
Scalar::from_f32(res),
346374
dest,
347375
)?;
348376
}
@@ -351,26 +379,29 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
351379
let a = this.read_scalar(args[0])?.to_f64()?;
352380
let b = this.read_scalar(args[1])?.to_f64()?;
353381
let c = this.read_scalar(args[2])?.to_f64()?;
382+
let res = a.mul_add(b, c).value;
354383
this.write_scalar(
355-
Scalar::from_f64(a * b + c),
384+
Scalar::from_f64(res),
356385
dest,
357386
)?;
358387
}
359388

360389
"powif32" => {
361-
let f = this.read_scalar(args[0])?.to_f32()?;
390+
// FIXME: Using host floats.
391+
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
362392
let i = this.read_scalar(args[1])?.to_i32()?;
363393
this.write_scalar(
364-
Scalar::from_f32(f.powi(i)),
394+
Scalar::from_u32(f.powi(i).to_bits()),
365395
dest,
366396
)?;
367397
}
368398

369399
"powif64" => {
370-
let f = this.read_scalar(args[0])?.to_f64()?;
400+
// FIXME: Using host floats.
401+
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
371402
let i = this.read_scalar(args[1])?.to_i32()?;
372403
this.write_scalar(
373-
Scalar::from_f64(f.powi(i)),
404+
Scalar::from_u64(f.powi(i).to_bits()),
374405
dest,
375406
)?;
376407
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
extern crate log;
77
// From rustc.
88
extern crate syntax;
9-
#[macro_use]
10-
extern crate rustc;
9+
extern crate rustc_apfloat;
10+
#[macro_use] extern crate rustc;
1111
extern crate rustc_data_structures;
1212
extern crate rustc_mir;
1313
extern crate rustc_target;

tests/run-pass/c_enums.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ enum Signed {
1111
}
1212

1313
fn foo() -> [u8; 3] {
14-
[Foo::Bar as u8, Foo::Baz as u8, Foo::Quux as u8]
14+
let baz = Foo::Baz; // let-expansion changes the MIR significantly
15+
[Foo::Bar as u8, baz as u8, Foo::Quux as u8]
1516
}
1617

1718
fn signed() -> [i8; 3] {
18-
[Signed::Bar as i8, Signed::Baz as i8, Signed::Quux as i8]
19+
let baz = Signed::Baz; // let-expansion changes the MIR significantly
20+
[Signed::Bar as i8, baz as i8, Signed::Quux as i8]
1921
}
2022

2123
fn unsafe_match() -> bool {

tests/run-pass/floats.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
fn main() {
32
assert_eq!(6.0_f32*6.0_f32, 36.0_f32);
43
assert_eq!(6.0_f64*6.0_f64, 36.0_f64);
@@ -12,4 +11,18 @@ fn main() {
1211
assert_eq!(5.0f32 as u32, 5);
1312
assert_eq!(5.0f32 as i32, 5);
1413
assert_eq!(-5.0f32 as i32, -5);
14+
15+
assert_eq!((1.0 as f32).max(-1.0), 1.0);
16+
assert_eq!((1.0 as f32).min(-1.0), -1.0);
17+
assert_eq!(std::f32::NAN.min(9.0), 9.0);
18+
assert_eq!(std::f32::NAN.max(-9.0), -9.0);
19+
assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0);
20+
assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0);
21+
22+
assert_eq!((1.0 as f64).max(-1.0), 1.0);
23+
assert_eq!((1.0 as f64).min(-1.0), -1.0);
24+
assert_eq!(std::f64::NAN.min(9.0), 9.0);
25+
assert_eq!(std::f64::NAN.max(-9.0), -9.0);
26+
assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0);
27+
assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0);
1528
}

tests/run-pass/intrinsics-math.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ pub fn main() {
5050
assert_approx_eq!(8f32.log2(), 3f32);
5151
assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E);
5252

53-
assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32);
54-
assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E);
53+
assert_approx_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
54+
assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
55+
assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
56+
assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E);
5557

5658
assert_approx_eq!((-1.0f32).abs(), 1.0f32);
5759
assert_approx_eq!(34.2f64.abs(), 34.2f64);

0 commit comments

Comments
 (0)