Merge pull request #764 from RalfJung/minmax

implement min and max floating point intrinsics
This commit is contained in:
Ralf Jung 2019-06-11 20:06:00 +02:00 committed by GitHub
commit deb0ff46eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 26 deletions

View File

@ -1 +1 @@
1cbd8a4d686d1411105f26cddf876c5994e69593 8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be

View File

@ -758,7 +758,7 @@ fn emulate_foreign_item(
this.machine.last_error = err; this.machine.last_error = err;
} }
"GetLastError" => { "GetLastError" => {
this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?; this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?;
} }
"AddVectoredExceptionHandler" => { "AddVectoredExceptionHandler" => {
@ -854,7 +854,7 @@ fn emulate_foreign_item(
}; };
// If there was no error, write back how much was written. // If there was no error, write back how much was written.
if let Some(n) = written { if let Some(n) = written {
this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; this.write_scalar(Scalar::from_u32(n), written_place.into())?;
} }
// Return whether this was a success. // Return whether this was a success.
this.write_scalar( this.write_scalar(

View File

@ -1,3 +1,4 @@
use rustc_apfloat::Float;
use rustc::mir; use rustc::mir;
use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::mir::interpret::{InterpResult, PointerArithmetic};
use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty::layout::{self, LayoutOf, Size};
@ -186,7 +187,8 @@ fn call_intrinsic(
"sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
"log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => {
let f = this.read_scalar(args[0])?.to_f32()?; // FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
let f = match intrinsic_name.get() { let f = match intrinsic_name.get() {
"sinf32" => f.sin(), "sinf32" => f.sin(),
"fabsf32" => f.abs(), "fabsf32" => f.abs(),
@ -202,12 +204,13 @@ fn call_intrinsic(
"truncf32" => f.trunc(), "truncf32" => f.trunc(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_f32(f), dest)?; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?;
} }
"sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" |
"log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => {
let f = this.read_scalar(args[0])?.to_f64()?; // FIXME: Using host floats.
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
let f = match intrinsic_name.get() { let f = match intrinsic_name.get() {
"sinf64" => f.sin(), "sinf64" => f.sin(),
"fabsf64" => f.abs(), "fabsf64" => f.abs(),
@ -223,7 +226,7 @@ fn call_intrinsic(
"truncf64" => f.trunc(), "truncf64" => f.trunc(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_f64(f), dest)?; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
} }
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
@ -240,6 +243,28 @@ fn call_intrinsic(
this.binop_ignore_overflow(op, a, b, dest)?; this.binop_ignore_overflow(op, a, b, dest)?;
} }
"minnumf32" | "maxnumf32" => {
let a = this.read_scalar(args[0])?.to_f32()?;
let b = this.read_scalar(args[1])?.to_f32()?;
let res = if intrinsic_name.get().starts_with("min") {
a.min(b)
} else {
a.max(b)
};
this.write_scalar(Scalar::from_f32(res), dest)?;
}
"minnumf64" | "maxnumf64" => {
let a = this.read_scalar(args[0])?.to_f64()?;
let b = this.read_scalar(args[1])?.to_f64()?;
let res = if intrinsic_name.get().starts_with("min") {
a.min(b)
} else {
a.max(b)
};
this.write_scalar(Scalar::from_f64(res), dest)?;
}
"exact_div" => { "exact_div" => {
// Performs an exact division, resulting in undefined behavior where // Performs an exact division, resulting in undefined behavior where
// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`
@ -320,19 +345,21 @@ fn call_intrinsic(
} }
"powf32" => { "powf32" => {
let f = this.read_scalar(args[0])?.to_f32()?; // FIXME: Using host floats.
let f2 = this.read_scalar(args[1])?.to_f32()?; let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?);
this.write_scalar( this.write_scalar(
Scalar::from_f32(f.powf(f2)), Scalar::from_u32(f.powf(f2).to_bits()),
dest, dest,
)?; )?;
} }
"powf64" => { "powf64" => {
let f = this.read_scalar(args[0])?.to_f64()?; // FIXME: Using host floats.
let f2 = this.read_scalar(args[1])?.to_f64()?; let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?);
this.write_scalar( this.write_scalar(
Scalar::from_f64(f.powf(f2)), Scalar::from_u64(f.powf(f2).to_bits()),
dest, dest,
)?; )?;
} }
@ -341,8 +368,9 @@ fn call_intrinsic(
let a = this.read_scalar(args[0])?.to_f32()?; let a = this.read_scalar(args[0])?.to_f32()?;
let b = this.read_scalar(args[1])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?;
let c = this.read_scalar(args[2])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?;
let res = a.mul_add(b, c).value;
this.write_scalar( this.write_scalar(
Scalar::from_f32(a * b + c), Scalar::from_f32(res),
dest, dest,
)?; )?;
} }
@ -351,26 +379,29 @@ fn call_intrinsic(
let a = this.read_scalar(args[0])?.to_f64()?; let a = this.read_scalar(args[0])?.to_f64()?;
let b = this.read_scalar(args[1])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?;
let c = this.read_scalar(args[2])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?;
let res = a.mul_add(b, c).value;
this.write_scalar( this.write_scalar(
Scalar::from_f64(a * b + c), Scalar::from_f64(res),
dest, dest,
)?; )?;
} }
"powif32" => { "powif32" => {
let f = this.read_scalar(args[0])?.to_f32()?; // FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
let i = this.read_scalar(args[1])?.to_i32()?; let i = this.read_scalar(args[1])?.to_i32()?;
this.write_scalar( this.write_scalar(
Scalar::from_f32(f.powi(i)), Scalar::from_u32(f.powi(i).to_bits()),
dest, dest,
)?; )?;
} }
"powif64" => { "powif64" => {
let f = this.read_scalar(args[0])?.to_f64()?; // FIXME: Using host floats.
let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
let i = this.read_scalar(args[1])?.to_i32()?; let i = this.read_scalar(args[1])?.to_i32()?;
this.write_scalar( this.write_scalar(
Scalar::from_f64(f.powi(i)), Scalar::from_u64(f.powi(i).to_bits()),
dest, dest,
)?; )?;
} }

View File

@ -6,8 +6,8 @@
extern crate log; extern crate log;
// From rustc. // From rustc.
extern crate syntax; extern crate syntax;
#[macro_use] extern crate rustc_apfloat;
extern crate rustc; #[macro_use] extern crate rustc;
extern crate rustc_data_structures; extern crate rustc_data_structures;
extern crate rustc_mir; extern crate rustc_mir;
extern crate rustc_target; extern crate rustc_target;

View File

@ -11,11 +11,13 @@ enum Signed {
} }
fn foo() -> [u8; 3] { fn foo() -> [u8; 3] {
[Foo::Bar as u8, Foo::Baz as u8, Foo::Quux as u8] let baz = Foo::Baz; // let-expansion changes the MIR significantly
[Foo::Bar as u8, baz as u8, Foo::Quux as u8]
} }
fn signed() -> [i8; 3] { fn signed() -> [i8; 3] {
[Signed::Bar as i8, Signed::Baz as i8, Signed::Quux as i8] let baz = Signed::Baz; // let-expansion changes the MIR significantly
[Signed::Bar as i8, baz as i8, Signed::Quux as i8]
} }
fn unsafe_match() -> bool { fn unsafe_match() -> bool {

View File

@ -1,4 +1,3 @@
fn main() { fn main() {
assert_eq!(6.0_f32*6.0_f32, 36.0_f32); assert_eq!(6.0_f32*6.0_f32, 36.0_f32);
assert_eq!(6.0_f64*6.0_f64, 36.0_f64); assert_eq!(6.0_f64*6.0_f64, 36.0_f64);
@ -12,4 +11,18 @@ fn main() {
assert_eq!(5.0f32 as u32, 5); assert_eq!(5.0f32 as u32, 5);
assert_eq!(5.0f32 as i32, 5); assert_eq!(5.0f32 as i32, 5);
assert_eq!(-5.0f32 as i32, -5); assert_eq!(-5.0f32 as i32, -5);
assert_eq!((1.0 as f32).max(-1.0), 1.0);
assert_eq!((1.0 as f32).min(-1.0), -1.0);
assert_eq!(std::f32::NAN.min(9.0), 9.0);
assert_eq!(std::f32::NAN.max(-9.0), -9.0);
assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0);
assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0);
assert_eq!((1.0 as f64).max(-1.0), 1.0);
assert_eq!((1.0 as f64).min(-1.0), -1.0);
assert_eq!(std::f64::NAN.min(9.0), 9.0);
assert_eq!(std::f64::NAN.max(-9.0), -9.0);
assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0);
assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0);
} }

View File

@ -50,8 +50,10 @@ pub fn main() {
assert_approx_eq!(8f32.log2(), 3f32); assert_approx_eq!(8f32.log2(), 3f32);
assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E);
assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32); assert_approx_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E);
assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!((-1.0f32).abs(), 1.0f32);
assert_approx_eq!(34.2f64.abs(), 34.2f64); assert_approx_eq!(34.2f64.abs(), 34.2f64);