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

f32::powi on Windows returns different results between 1.44 and 1.45 beta #73420

Closed
iliekturtles opened this issue Jun 16, 2020 · 17 comments
Closed
Labels
A-floating-point Area: Floating point numbers and arithmetic A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. O-windows Operating system: Windows P-low Low priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. relnotes Marks issues that should be documented in the release notes of the next release. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@iliekturtles
Copy link
Contributor

The issue was noticed because typenum::Pow::powi returns consistent results between rustc versions while f32::powi changes.

Given the following code the "std powi" results differ between stable and beta/nightly. Note that code below will run on https://play.rust-lang.org/ but the issue will not reproduce because the host is not Windows. The playground's output for stable/beta/nightly matches stable on my local machine.

extern crate typenum; // 2.12.0

fn main() {
    let v = 12.046623229980468750000000000000_f32;
    let a = a(v);
    let b = b(v);

    println!("std powi {:.30?}", a);
    println!("typenum  {:.30?}", b);
}

#[inline(never)]
fn a(v: f32) -> f32 {
    v.powi(3)
}

#[inline(never)]
fn b(v: f32) -> f32 {
    typenum::Pow::powi(v, typenum::P3::new())
}

On my Windows 10 machine (and the Travis Win 10 VMs) I get the following results. I'm in the process of bisecting down to a specific nightly right now.

/d/Code/Test/rust/tst (master)$ cargo run; rustc --version --verbose
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `target\debug\tst.exe`
std powi 1748.219482421875000000000000000000
typenum  1748.219482421875000000000000000000
rustc 1.44.0 (49cae5576 2020-06-01)
binary: rustc
commit-hash: 49cae55760da0a43428eba73abcb659bb70cf2e4
commit-date: 2020-06-01
host: x86_64-pc-windows-msvc
release: 1.44.0
LLVM version: 9.0
/d/Code/Test/rust/tst (master)$ cargo +beta run; rustc +beta --version --verbose
   Compiling tst v0.1.0 (D:\Code\Test\rust\tst)
    Finished dev [unoptimized + debuginfo] target(s) in 4.95s
     Running `target\debug\tst.exe`
std powi 1748.219604492187500000000000000000
typenum  1748.219482421875000000000000000000
rustc 1.45.0-beta.3359 (b7dc83a3f 2020-06-03)
binary: rustc
commit-hash: b7dc83a3f6ca9746fb3d121761c3605477b77d90
commit-date: 2020-06-03
host: x86_64-pc-windows-msvc
release: 1.45.0-beta.3359
LLVM version: 10.0

1748.2196044921875
1748.219482421875

@iliekturtles iliekturtles added the C-bug Category: This is a bug. label Jun 16, 2020
@ecstatic-morse ecstatic-morse added A-floating-point Area: Floating point numbers and arithmetic T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 16, 2020
@iliekturtles
Copy link
Contributor Author

iliekturtles commented Jun 16, 2020

Issue first appears in nightly-2020-05-22-x86_64-pc-windows-msvc - rustc 1.45.0-nightly (9310e3b 2020-05-21)

Commit comparison with the previous nightly: 0aa6751...9310e3b

I'm guessing 9f12823 (Update LLVM submodule) is the culprit since the f32::powi code just lowers to an LLVM intrisic.

    Finished dev [unoptimized + debuginfo] target(s) in 2.74s
     Running `target\debug\tst.exe`
std powi 1748.219482421875000000000000000000
typenum  1748.219482421875000000000000000000
rustc 1.45.0-nightly (0aa6751c1 2020-05-20)
binary: rustc
commit-hash: 0aa6751c19d3ba80df5b0b02c00bf44e13c97e80
commit-date: 2020-05-20
host: x86_64-pc-windows-msvc
release: 1.45.0-nightly
LLVM version: 9.0

    Finished dev [unoptimized + debuginfo] target(s) in 9.16s
     Running `target\debug\tst.exe`
std powi 1748.219604492187500000000000000000
typenum  1748.219482421875000000000000000000
rustc 1.45.0-nightly (9310e3bd4 2020-05-21)
binary: rustc
commit-hash: 9310e3bd4f425f84fc27878ebf2bda1f30935a63
commit-date: 2020-05-21
host: x86_64-pc-windows-msvc
release: 1.45.0-nightly
LLVM version: 10.0

@ecstatic-morse ecstatic-morse added the O-windows-msvc Toolchain: MSVC, Operating system: Windows label Jun 16, 2020
@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented Jun 16, 2020

I'm guessing that LLVM 10 started using the MSVC implementation of the powi intrinsic, which uses a higher precision for intermediate results. The result you see is equivalent to the one you would get from casting to and f64, multiplying and then casting back to and f32.

@ollie27
Copy link
Member

ollie27 commented Jun 16, 2020

Looking at the changes in assembly for powi on 1.44.0 we have:

	callq	__powisf2

but on beta that's replaced with:

	cvtsi2ss	%edx, %xmm1
	callq	powf

So LLVM has switched from calling the __powisf2 intrinsic from compiler-rt/compiler-builtins to calling powf. This looks like an intentional change from https://reviews.llvm.org/D69013 but it's not clear to me why that change was made.

@ollie27 ollie27 added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jun 16, 2020
@mati865

This comment has been minimized.

@rustbot rustbot added O-windows Operating system: Windows and removed O-windows-msvc Toolchain: MSVC, Operating system: Windows labels Jun 16, 2020
@iliekturtles
Copy link
Contributor Author

Thanks for digging into the details. Sounds like this issue should be closed as working as intended then?

@ollie27
Copy link
Member

ollie27 commented Jun 17, 2020

Sounds like this issue should be closed as working as intended then?

I don't know. I think minor changes to the output of float operations between versions are technically allowed breakage but it would be nice to know why this change was made.

Given that powi seemed to be working fine before, does anyone know why https://reviews.llvm.org/D69013 was done?

@ollie27 ollie27 added the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Jun 17, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 17, 2020
@iliekturtles
Copy link
Contributor Author

I'll leave the issue open for at least a little bit longer to see if there are any other opinions. I was able to resolve my specific case by refactoring internal code to use f32::powi instead of typenum::Pow::powi. My test code was using an explicit f32::powi and comparing the results against the internal code: iliekturtles/uom#193.

@iliekturtles
Copy link
Contributor Author

Closing since this is an allowed breakage.

@ecstatic-morse
Copy link
Contributor

Reopening. This is on the compiler team meeting agenda for this week.

@spastorino spastorino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Jun 24, 2020
@spastorino
Copy link
Member

Removing I-nominated label given that this was discussed briefly in today's meeting. Adding also relnotes as discussed.

I think we can close this issue now but just in case, @Mark-Simulacrum can you confirm this? and in particular I guess if you will be able to grab the relnotes label of a closed issue or how that process works.

@spastorino spastorino added relnotes Marks issues that should be documented in the release notes of the next release. and removed I-nominated labels Jun 25, 2020
@ollie27
Copy link
Member

ollie27 commented Jun 25, 2020

Did anyone actually figure out why this change was made?

@Mark-Simulacrum
Copy link
Member

My impression is no. I don't think we should close this out before it's a compat note in relnotes and we have some sense of why this is happening (beyond "LLVM patch"), if only to hopefully be better able to explain to users why things broke for them.

@eddyb
Copy link
Member

eddyb commented Jun 25, 2020

Looks like the intention was to avoid calling __powidf2 as it's (sometimes?) not available in MSVC (so this might be for compiling without compiler-rt?), and they assumed the expansion would be compatible. I'm not sure they were aware it might have a different result, or what the deal is with usecases that involve compiler-rt.

@spastorino
Copy link
Member

Given that this was added to release notes, I think this should be closed now?.

@spastorino spastorino added the P-low Low priority label Jul 16, 2020
@spastorino
Copy link
Member

Tagging as P-low until we find some answers for @Mark-Simulacrum's questions

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Aug 6, 2020
While here clean up all pkglint warnings.  Changes since 1.44.1:

Version 1.45.2 (2020-08-03)
==========================

* [Fix bindings in tuple struct patterns][74954]
* [Fix track_caller integration with trait objects][74784]

[74954]: rust-lang/rust#74954
[74784]: rust-lang/rust#74784

Version 1.45.1 (2020-07-30)
==========================

* [Fix const propagation with references.][73613]
* [rustfmt accepts rustfmt_skip in cfg_attr again.][73078]
* [Avoid spurious implicit region bound.][74509]
* [Install clippy on x.py install][74457]

[73613]: rust-lang/rust#73613
[73078]: rust-lang/rust#73078
[74509]: rust-lang/rust#74509
[74457]: rust-lang/rust#74457

Version 1.45.0 (2020-07-16)
==========================

Language
--------
- [Out of range float to int conversions using `as` has been defined as a saturating
  conversion.][71269] This was previously undefined behaviour, but you can use the
   `{f64, f32}::to_int_unchecked` methods to continue using the current behaviour, which
   may be desirable in rare performance sensitive situations.
- [`mem::Discriminant<T>` now uses `T`'s discriminant type instead of always
  using `u64`.][70705]
- [Function like procedural macros can now be used in expression, pattern, and  statement
  positions.][68717] This means you can now use a function-like procedural macro
  anywhere you can use a declarative (`macro_rules!`) macro.

Compiler
--------
- [You can now override individual target features through the `target-feature`
  flag.][72094] E.g. `-C target-feature=+avx2 -C target-feature=+fma` is now
  equivalent to `-C target-feature=+avx2,+fma`.
- [Added the `force-unwind-tables` flag.][69984] This option allows
  rustc to always generate unwind tables regardless of panic strategy.
- [Added the `embed-bitcode` flag.][71716] This codegen flag allows rustc
  to include LLVM bitcode into generated `rlib`s (this is on by default).
- [Added the `tiny` value to the `code-model` codegen flag.][72397]
- [Added tier 3 support\* for the `mipsel-sony-psp` target.][72062]
- [Added tier 3 support for the `thumbv7a-uwp-windows-msvc` target.][72133]

\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.


Libraries
---------
- [`net::{SocketAddr, SocketAddrV4, SocketAddrV6}` now implements `PartialOrd`
  and `Ord`.][72239]
- [`proc_macro::TokenStream` now implements `Default`.][72234]
- [You can now use `char` with
  `ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}` to iterate over
  a range of codepoints.][72413] E.g.
  you can now write the following;
  ```rust
  for ch in 'a'..='z' {
      print!("{}", ch);
  }
  println!();
  // Prints "abcdefghijklmnopqrstuvwxyz"
  ```
- [`OsString` now implements `FromStr`.][71662]
- [The `saturating_neg` method as been added to all signed integer primitive
  types, and the `saturating_abs` method has been added for all integer
  primitive types.][71886]
- [`Arc<T>`, `Rc<T>` now implement  `From<Cow<'_, T>>`, and `Box` now
  implements `From<Cow>` when `T` is `[T: Copy]`, `str`, `CStr`, `OsStr`,
  or `Path`.][71447]
- [`Box<[T]>` now implements `From<[T; N]>`.][71095]
- [`BitOr` and `BitOrAssign` are implemented for all `NonZero`
  integer types.][69813]
- [The `fetch_min`, and `fetch_max` methods have been added to all atomic
  integer types.][72324]
- [The `fetch_update` method has been added to all atomic integer types.][71843]

Stabilized APIs
---------------
- [`Arc::as_ptr`]
- [`BTreeMap::remove_entry`]
- [`Rc::as_ptr`]
- [`rc::Weak::as_ptr`]
- [`rc::Weak::from_raw`]
- [`rc::Weak::into_raw`]
- [`str::strip_prefix`]
- [`str::strip_suffix`]
- [`sync::Weak::as_ptr`]
- [`sync::Weak::from_raw`]
- [`sync::Weak::into_raw`]
- [`char::UNICODE_VERSION`]
- [`Span::resolved_at`]
- [`Span::located_at`]
- [`Span::mixed_site`]
- [`unix::process::CommandExt::arg0`]

Cargo
-----

Misc
----
- [Rustdoc now supports strikethrough text in Markdown.][71928] E.g.
  `~~outdated information~~` becomes "~~outdated information~~".
- [Added an emoji to Rustdoc's deprecated API message.][72014]

Compatibility Notes
-------------------
- [Trying to self initialize a static value (that is creating a value using
  itself) is unsound and now causes a compile error.][71140]
- [`{f32, f64}::powi` now returns a slightly different value on Windows.][73420]
  This is due to changes in LLVM's intrinsics which `{f32, f64}::powi` uses.
- [Rustdoc's CLI's extra error exit codes have been removed.][71900] These were
  previously undocumented and not intended for public use. Rustdoc still provides
  a non-zero exit code on errors.

Internals Only
--------------
- [Make clippy a git subtree instead of a git submodule][70655]
- [Unify the undo log of all snapshot types][69464]

[73420]: rust-lang/rust#73420
[72324]: rust-lang/rust#72324
[71843]: rust-lang/rust#71843
[71886]: rust-lang/rust#71886
[72234]: rust-lang/rust#72234
[72239]: rust-lang/rust#72239
[72397]: rust-lang/rust#72397
[72413]: rust-lang/rust#72413
[72014]: rust-lang/rust#72014
[72062]: rust-lang/rust#72062
[72094]: rust-lang/rust#72094
[72133]: rust-lang/rust#72133
[71900]: rust-lang/rust#71900
[71928]: rust-lang/rust#71928
[71662]: rust-lang/rust#71662
[71716]: rust-lang/rust#71716
[71447]: rust-lang/rust#71447
[71269]: rust-lang/rust#71269
[71095]: rust-lang/rust#71095
[71140]: rust-lang/rust#71140
[70655]: rust-lang/rust#70655
[70705]: rust-lang/rust#70705
[69984]: rust-lang/rust#69984
[69813]: rust-lang/rust#69813
[69464]: rust-lang/rust#69464
[68717]: rust-lang/rust#68717
[`Arc::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.as_ptr
[`BTreeMap::remove_entry`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.remove_entry
[`Rc::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.as_ptr
[`rc::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.as_ptr
[`rc::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.from_raw
[`rc::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.into_raw
[`sync::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.as_ptr
[`sync::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.from_raw
[`sync::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.into_raw
[`str::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_prefix
[`str::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix
[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/stable/std/char/constant.UNICODE_VERSION.html
[`Span::resolved_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.resolved_at
[`Span::located_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.located_at
[`Span::mixed_site`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.mixed_site
[`unix::process::CommandExt::arg0`]: https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0
@pietroalbini pietroalbini added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-from-stable-to-beta Performance or correctness regression from stable to beta. labels Aug 21, 2020
@iliekturtles
Copy link
Contributor Author

@Mark-Simulacrum @spastorino With this documented in the 1.45.0 compatability notes are there still open questions that need action or are we good to close this issue?

@Mark-Simulacrum
Copy link
Member

I think we can close. I'm not fully happy about the explanation we have, but it seems good enough for the time being.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-floating-point Area: Floating point numbers and arithmetic A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. O-windows Operating system: Windows P-low Low priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. relnotes Marks issues that should be documented in the release notes of the next release. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants