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

Saturating casts between integers and floats #45205

Merged
merged 7 commits into from
Nov 8, 2017

Conversation

hanna-kruppe
Copy link
Contributor

@hanna-kruppe hanna-kruppe commented Oct 11, 2017

Introduces a new flag, -Z saturating-float-casts, which makes code generation for int->float and float->int casts safe (undef-free), implementing the saturating semantics laid out by @jorendorff for float->int casts and overflowing to infinity for u128::MAX -> f32.
Constant evaluation in trans was changed to behave like HIR const eval already did, i.e., saturate for u128->f32 and report an error for problematic float->int casts.

Many thanks to @eddyb, whose APFloat port simplified many parts of this patch, and made HIR constant evaluation recognize dangerous float casts as mentioned above.
Also thanks to @ActuallyaDeviloper whose branchless implementation served as inspiration for this implementation.

cc #10184 #41799
fixes #45134

@rust-highfive
Copy link
Collaborator

r? @eddyb

(rust_highfive has picked a reviewer for you, use r? to override)

test!(2147483648., f32 -> i32, 2147483647);
// With 24 significand bits, floats in [2^30 + 1, 2^31] are rounded to multiples of 2^7.
// Therefore, the next smallest f32 is 2^31 - 128:
test!(2147483520., f32 -> i32, 2147483520);
Copy link
Member

Choose a reason for hiding this comment

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

Since you have tests on both sides of the boundary for positive values, the other interesting value to test here is -2147483904., which is the other side of the boundary for negative values.

Also, if it's interesting to test these boundaries for signed conversions, the unsigned boundaries may also be interesting: 4294967040. and 4294967296.0 on the upper boundary, and -0.99999994 and -1. on the lower.

test!(-0., $fty -> $ity, 0);
test!(-$fty::MIN_POSITIVE, $fty -> $ity, 0);
test!(-1., $fty -> $ity, 0);
test!(-100., $fty -> $ity, 0);
Copy link
Member

Choose a reason for hiding this comment

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

It'd also be interesting to test a number in (-1,-0.5), such as -0.9, to make sure it's properly rounded up to 0.

let infinity_bits = match float_ty.float_width() {
32 => C_u32(ccx, ieee::Single::INFINITY.to_bits() as u32),
64 => C_u64(ccx, ieee::Double::INFINITY.to_bits() as u64),
n => bug!("unsupported float width {}", n),
Copy link
Member

Choose a reason for hiding this comment

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

Only u128 → f32 is the problematic cast here, so the 64 => branch should never be entered (i.e. it should be a bug!). There's no problem representing u128::MAX in f64 as a finite number.

let infinity_bits = match float_ty.float_width() {
32 => C_u32(bcx.ccx, ieee::Single::INFINITY.to_bits() as u32),
64 => C_u64(bcx.ccx, ieee::Double::INFINITY.to_bits() as u64),
n => bug!("unsupported float width {}", n),
Copy link
Member

Choose a reason for hiding this comment

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

ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it should be, and that would have caught a bug - I applied the f32 overflow check even when casting to f64. Will add tests for that.

@hanna-kruppe
Copy link
Contributor Author

hanna-kruppe commented Oct 11, 2017

Incorportated the suggestions by @sunfishcode and @kennytm.

// If this is an u128 cast and the value is > f32::MAX + 0.5 ULP, round up to infinity.
if signed {
llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
} else if value >= 0xffffff80000000000000000000000000_u128 && float_ty.float_width() == 32 {
Copy link
Member

Choose a reason for hiding this comment

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

Do you really need to hardcode this value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't need to, I just didn't see a way to calculate it from existing constants that is simpler to understand and verify, at least to me. However, I didn't put too much thought into it and suggestions are welcome.

Copy link
Member

@est31 est31 Oct 11, 2017

Choose a reason for hiding this comment

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

Where does the 8 come from? The float mantissa has 23 bits. Add the implicit bit, you get 24, which is six times f. println!("{:x}", std::f32::MAX as u128); gives me six times f as well, and its the same according to the internet. UPDATE: see comment below

Copy link
Member

@est31 est31 Oct 11, 2017

Choose a reason for hiding this comment

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

IMO it would be best to have a constant somewhere (maybe in the file?) and use it in both places, e.g. representing it as 0xffffff_u128 << (128 - 24), which is IMO the clearest way to display the number.

Copy link
Member

Choose a reason for hiding this comment

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

OH I get it, the 8 is needed due to rounding. Disregard my last 2 comments! I still think a constant somewhere with a nice explanation would be cool.

Copy link
Member

@eddyb eddyb Oct 11, 2017

Choose a reason for hiding this comment

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

Since it seems to be a number of 1s at the top of u128, how about computing it from the number of significand bits?

EDIT: Oh wow, github didn't show me @est31's comments.

Copy link
Contributor Author

@hanna-kruppe hanna-kruppe Oct 11, 2017

Choose a reason for hiding this comment

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

Regardless of whether it's hardcoded or computed, I'm not sure where it should live if it's a shared definition. I guess I could chuck it in common or something, but ehhhh

Copy link
Member

Choose a reason for hiding this comment

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

I'd put it in rustc_const_math::float.

if is_u128_to_f32 && bcx.sess().opts.debugging_opts.saturating_float_casts {
// f32::MAX + 0.5 ULP as u128. All inputs greater or equal to this should be
// rounded to infinity, for everything else LLVM's uitofp works just fine.
let max = C_big_integral(int_ty, 0xffffff80000000000000000000000000_u128);
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

@eddyb
Copy link
Member

eddyb commented Oct 11, 2017

cc @est31 @nagisa @alexcrichton Who's better qualified to review floating-point code?

@@ -955,6 +952,55 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}

unsafe fn const_cast_from_float(operand: &Const, signed: bool, int_ty: Type) -> ValueRef {
let llval = operand.llval;
// Note: this breaks if addresses can be turned into integers (is that possible?)
Copy link
Member

Choose a reason for hiding this comment

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

This is valid rust code, isn't it?

println!("{}", {let w: * const u32 = {let v = 0u32; &v}; w} as usize);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but this is constant evaluation and pointer->integer casts in constant expression do not compile:

static Y: i32 = 0;
static Z: usize = &Y as usize;

// rounded to infinity, for everything else LLVM's uitofp works just fine.
let max = C_big_integral(int_ty, 0xffffff80000000000000000000000000_u128);
let overflow = bcx.icmp(llvm::IntUGE, x, max);
let infinity_bits = match float_ty.float_width() {
Copy link
Member

@est31 est31 Oct 11, 2017

Choose a reason for hiding this comment

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

You don't need the match here, the width is checked above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess that's true now. It wasn't before @kennytm pointed out that I needed the width check up there. (Same in constant evaluation.)

@hanna-kruppe
Copy link
Contributor Author

hanna-kruppe commented Oct 11, 2017

What's up with travis? The run-pass test fails with an error that looks plausible and platform-independent, but I can't reproduce it (on x86_64-windows-msvc).

[00:48:14] error: internal compiler error: unexpected panic
[00:48:14] 
[00:48:14] note: the compiler unexpectedly panicked. this is a bug.
[00:48:14] 
[00:48:14] note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
[00:48:14] 
[00:48:14] note: rustc 1.22.0-dev running on x86_64-unknown-linux-gnu
[00:48:14] 
[00:48:14] thread 'rustc' panicked at 'attempt to negate with overflow', /checkout/src/librustc_apfloat/lib.rs:383:31
[00:48:14] note: Run with `RUST_BACKTRACE=1` for a backtrace.

if signed {
llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
} else if value >= 0xffffff80000000000000000000000000_u128 && float_ty.float_width() == 32 {
let infinity_bits = match float_ty.float_width() {
Copy link
Member

Choose a reason for hiding this comment

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

Same here, the match is not needed.

// If this is an u128 cast and the value is > f32::MAX + 0.5 ULP, round up to infinity.
if signed {
llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
} else if value >= 0xffffff80000000000000000000000000_u128 && float_ty.float_width() == 32 {
Copy link
Member

@est31 est31 Oct 11, 2017

Choose a reason for hiding this comment

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

Where does the 8 come from? The float mantissa has 23 bits. Add the implicit bit, you get 24, which is six times f. println!("{:x}", std::f32::MAX as u128); gives me six times f as well, and its the same according to the internet. UPDATE: see comment below

@hanna-kruppe
Copy link
Contributor Author

hanna-kruppe commented Oct 11, 2017

@est31 This constant isn't f32::MAX, it's f32::MAX + 0.5 ULP. Evidently the constant is not as clear as I'd hoped, so I'll figure out a way to compute it that hopefully makes it clearer what's happening.

How about

ieee::Single::largest().to_u128(128).value + (1 << (128 - ieee::Single::PRECISION - 1))

The -1 is pretty ugly as well ¯\_(ツ)_/¯

let max = C_big_integral(int_ty, 0xffffff80000000000000000000000000_u128);
let overflow = bcx.icmp(llvm::IntUGE, x, max);
let infinity_bits = C_u32(bcx.ccx, ieee::Single::INFINITY.to_bits() as u32);
let infinity = consts::bitcast(, float_ty);
Copy link
Member

Choose a reason for hiding this comment

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

🤣

[00:13:30] error: expected expression, found `,`
[00:13:30]    --> /checkout/src/librustc_trans/mir/rvalue.rs:835:40
[00:13:30]     |
[00:13:30] 835 |         let infinity = consts::bitcast(, float_ty);
[00:13:30]     |                                        ^

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😱

bcx.select(bcx.fcmp(llvm::RealOGT, x, f_max), int_max, cast_result)
} else {
cast_result
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't know if you're interested in micro-optimizing at this point, but if you are: it looks like this code does 4 selects for f32->i32; it would be a little shorter to take advantage of the fact that fptoui/fptosi in LLVM return undef rather than having UB, so you could do the fptosi/fptoui first, and then use selects to pick between the fptosi/fptui result value and the integer min/max/0 values in the various exceptional cases. That way, you'd always need at most 3 selects.

Copy link
Contributor Author

@hanna-kruppe hanna-kruppe Oct 13, 2017

Choose a reason for hiding this comment

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

I played around with this option a bit but I didn't quickly find a way to write the first two selects do the clipping with two selects such that ity::MIN comes out if x is NaN. If that's not possible, i.e., a separate NaN check is always necessary, the current code is shorter (two selects) for casts such as f32 -> u16 or f64 -> f32. But perhaps I'm missing the forest for the trees? If someone can come up with a way to do three selects for signed types and two for unsigned casts, I'd gladly implement that (after I find time to address the other nits).

Copy link
Member

Choose a reason for hiding this comment

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

Here's a way to do three selects for signed and two for unsigned, which should be generalizable to other bitwidths:

define i32 @fptosi(float %f) {
  %t = fptosi float %f to i32
  %c0 = fcmp olt float %f, 0xC1E0000000000000 ; -0x1p31
  %c1 = fcmp oge float %f, 0x41E0000000000000 ; 0x1p31
  %c2 = fcmp uno float %f, 0.000000e+00
  %s0 = select i1 %c0, i32 -2147483648, i32 %t
  %s1 = select i1 %c1, i32 2147483647, i32 %s0
  %s2 = select i1 %c2, i32 0, i32 %s1
  ret i32 %s2
}
define i32 @fptoui(float %f) {
  %t = fptoui float %f to i32
  %c0 = fcmp ule float %f, 0.000000e+00
  %c1 = fcmp oge float %f, 0x41F0000000000000 ; 0x1p32
  %s0 = select i1 %c0, i32 0, i32 %t
  %s1 = select i1 %c1, i32 -1, i32 %s0
  ret i32 %s1
}

@shepmaster shepmaster added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 15, 2017
@@ -380,7 +380,9 @@ pub trait Float
fn from_bits(input: u128) -> Self;
fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> {
if input < 0 {
Self::from_u128_r(-input as u128, -round).map(|r| -r)
// This is equivalent to `(-input) as u128` except it doesn't overflow on i128::MIN
let abs_input = !(input as u128) + 1;
Copy link
Member

Choose a reason for hiding this comment

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

Ehm, just use wrapping_neg? Somehow I forgot to.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, right, that's a thing.

@hanna-kruppe hanna-kruppe force-pushed the saturating-casts branch 2 times, most recently from 763bf51 to 7a894a8 Compare October 15, 2017 20:36
@hanna-kruppe
Copy link
Contributor Author

@eddyb IIRC you wanted to run crater with the variant that errors on overflow/NaN in trans const eval? That's implemented now.

(That it's implemented now also means this shouldn't be merged in the current state until we've had a crater run.)

@kennytm kennytm added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 18, 2017
@kennytm
Copy link
Member

kennytm commented Oct 18, 2017

@bors try

@bors
Copy link
Contributor

bors commented Oct 18, 2017

⌛ Trying commit 3c3082fe0763462f05c8cee7c9abe14092fa171d with merge cc787eba2ca6e3cf90a5e6b04f4fedd924787b68...

@hanna-kruppe hanna-kruppe force-pushed the saturating-casts branch 2 times, most recently from 3cf487c to 21a89f9 Compare November 7, 2017 16:43
@bors
Copy link
Contributor

bors commented Nov 7, 2017

☔ The latest upstream changes (presumably #45666) made this pull request unmergeable. Please resolve the merge conflicts.

Robin Kruppe added 6 commits November 7, 2017 20:13
This affects regular code generation as well as constant evaluation in trans,
but not the HIR constant evaluator because that one returns an error for
overflowing casts and NaN-to-int casts. That error is conservatively
correct and we should be careful to not accept more code in constant
expressions.
The changes to code generation are guarded by a new -Z flag, to be able
to evaluate the performance impact. The trans constant evaluation changes
are unconditional because they have no run time impact and don't affect
type checking either.
@hanna-kruppe
Copy link
Contributor Author

Rebased. Travis is green.

@eddyb
Copy link
Member

eddyb commented Nov 7, 2017

@bors r+

@bors
Copy link
Contributor

bors commented Nov 7, 2017

📌 Commit ce46649 has been approved by eddyb

@bors
Copy link
Contributor

bors commented Nov 7, 2017

⌛ Testing commit ce46649 with merge 3da399728e98a72205b3563482de647c49972154...

@bors
Copy link
Contributor

bors commented Nov 8, 2017

💔 Test failed - status-travis

@kennytm
Copy link
Member

kennytm commented Nov 8, 2017

asmjs does not support i128 (Unsupported: %1826 = fptosi float %1825 to i128)

cc #45676.

[01:32:24] failures:
[01:32:24] 
[01:32:24] ---- [run-pass] run-pass/saturating-float-casts.rs stdout ----
[01:32:24] 	
[01:32:24] error: compilation failed!
[01:32:24] status: exit code: 101
[01:32:24] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/run-pass/saturating-float-casts.rs" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass" "--target=asmjs-unknown-emscripten" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.stage2-asmjs-unknown-emscripten.js" "-Crpath" "-O" "-Lnative=/checkout/obj/build/asmjs-unknown-emscripten/native/rust-test-helpers" "-Z" "saturating-float-casts" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.stage2-asmjs-unknown-emscripten.aux"
[01:32:24] stdout:
[01:32:24] ------------------------------------------
[01:32:24] 
[01:32:24] ------------------------------------------
[01:32:24] stderr:
[01:32:24] ------------------------------------------
[01:32:24] error: linking with `emcc` failed: exit code: 1
[01:32:24]   |
[01:32:24]   = note: "emcc" "-s" "DISABLE_EXCEPTION_CATCHING=0" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.saturating_float_casts0.rcgu.o" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.stage2-asmjs-unknown-emscripten.js" "-s" "EXPORTED_FUNCTIONS=[\"_main\",\"_rust_eh_personality\"]" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.crate.allocator.rcgu.o" "-O2" "--memory-init-file" "0" "-g0" "-s" "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass" "-L" "/checkout/obj/build/asmjs-unknown-emscripten/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/saturating-float-casts.stage2-asmjs-unknown-emscripten.aux" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libtest-183e233b7c075ec2.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libterm-08fb69f2f719b59c.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libgetopts-4f65f6654127877d.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libstd-2b35d1b36dfa7e3a.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libpanic_unwind-5bef2c52ac19d279.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libunwind-3830ae5679a0b739.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liballoc_system-9ff2c67f40fe5858.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liblibc-e1c7eeeb00260d82.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/liballoc-bad119b0f880de53.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libstd_unicode-c87147d9878a34a6.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/librand-efb9ae917b0ef713.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libcore-f61c023fb8fcfea8.rlib" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/asmjs-unknown-emscripten/lib/libcompiler_builtins-709204c2e3fe5ec9.rlib" "-l" "c" "-s" "ERROR_ON_UNDEFINED_SYMBOLS=1"
[01:32:24]   = note: Unsupported:   %1826 = fptosi float %1825 to i128
[01:32:24]           LLVM ERROR: Instruction not yet supported for integer types larger than 64 bits
[01:32:24]           Traceback (most recent call last):
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13//emcc", line 13, in <module>
[01:32:24]               emcc.run()
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emcc.py", line 1526, in run
[01:32:24]               final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/tools/shared.py", line 1963, in emscripten
[01:32:24]               call_emscripten(cmdline)
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emscripten.py", line 2190, in _main
[01:32:24]               temp_files.run_and_clean(lambda: main(
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/tools/tempfiles.py", line 78, in run_and_clean
[01:32:24]               return func()
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emscripten.py", line 2195, in <lambda>
[01:32:24]               DEBUG=DEBUG,
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emscripten.py", line 2095, in main
[01:32:24]               temp_files=temp_files, DEBUG=DEBUG)
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emscripten.py", line 93, in emscript
[01:32:24]               backend_output = compile_js(infile, settings, temp_files, DEBUG)
[01:32:24]             File "/emsdk-portable/emscripten/1.37.13/emscripten.py", line 127, in compile_js
[01:32:24]               backend_output = open(temp_js).read()
[01:32:24]           IOError: [Errno 2] No such file or directory: '/tmp/tmptj926K.4.js'
[01:32:24]           
[01:32:24] 
[01:32:24] error: aborting due to previous error
[01:32:24] 
[01:32:24] 
[01:32:24] ------------------------------------------
[01:32:24] 
[01:32:24] thread '[run-pass] run-pass/saturating-float-casts.rs' panicked at 'explicit panic', /checkout/src/tools/compiletest/src/runtest.rs:2498:8
[01:32:24] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[01:32:24] 
[01:32:24] 
[01:32:24] failures:
[01:32:24]     [run-pass] run-pass/saturating-float-casts.rs
[01:32:24] 
[01:32:24] test result: �[31mFAILED�(B�[m. 2678 passed; 1 failed; 144 ignored; 0 measured; 0 filtered out

@eddyb
Copy link
Member

eddyb commented Nov 8, 2017

@bors r+

@bors
Copy link
Contributor

bors commented Nov 8, 2017

📌 Commit ef0b999 has been approved by eddyb

@kennytm kennytm added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 8, 2017
@bors
Copy link
Contributor

bors commented Nov 8, 2017

⌛ Testing commit ef0b999 with merge 7ca430d...

bors added a commit that referenced this pull request Nov 8, 2017
Saturating casts between integers and floats

Introduces a new flag, `-Z saturating-float-casts`, which makes code generation for int->float and float->int casts safe (`undef`-free), implementing [the saturating semantics laid out by](#10184 (comment)) @jorendorff for float->int casts and overflowing to infinity for `u128::MAX` -> `f32`.
Constant evaluation in trans was changed to behave like HIR const eval already did, i.e., saturate for u128->f32 and report an error for problematic float->int casts.

Many thanks to @eddyb, whose APFloat port simplified many parts of this patch, and made HIR constant evaluation recognize dangerous float casts as mentioned above.
Also thanks to @ActuallyaDeviloper whose branchless implementation served as inspiration for this implementation.

cc #10184 #41799
fixes #45134
@bors
Copy link
Contributor

bors commented Nov 8, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: eddyb
Pushing 7ca430d to master...

}

#[no_mangle]
pub fn f64_to_u8(x: f32) -> u16 {
Copy link
Contributor

@kpp kpp Jul 19, 2020

Choose a reason for hiding this comment

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

Arg types does not match function name. Should be either f32_to_u16(x: f32) -> u16 or f64_to_u8(x: f64) -> u8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ICE when casting float to integer (out-of-bounds)