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

Make float::from_bits transmute #46012

Merged
merged 1 commit into from
Nov 24, 2017
Merged

Conversation

Gankra
Copy link
Contributor

@Gankra Gankra commented Nov 15, 2017

See commit message for details.

See also this discussion here: #40470 (comment)

(may require libs team discussion before merging)

@Gankra
Copy link
Contributor Author

Gankra commented Nov 15, 2017

r? @sfackler

@Gankra
Copy link
Contributor Author

Gankra commented Nov 15, 2017

It's possible this is also valid on powerpc/sparc64/asmjs but I'm keeping this down to the platforms where I know this works and I actually care about them. :)

@sfackler sfackler added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Nov 15, 2017
@sfackler
Copy link
Member

I'm definitely on board with this, but I think we should get everyone's eyes on it.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Nov 15, 2017

Team member @sfackler has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Nov 15, 2017
Gankra added a commit to Gankra/byteorder that referenced this pull request Nov 15, 2017
// The check above only assumes IEEE 754-1985 to be
// valid.
v = unsafe { ::mem::transmute(NAN) };
if cfg!(not(any(
Copy link
Member

Choose a reason for hiding this comment

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

Can you add comments here and below noting why we only do this on some platforms?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The existing comment seems to address it, no?

Copy link
Member

Choose a reason for hiding this comment

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

The existing comment just says why we reset to a "canonical" NaN instead of just masking off the signal bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"While IEEE 754-2008 specifies encodings for quiet NaNs and signaling ones, certain MIPS and PA-RISC CPUs treat signaling NaNs differently."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Err wait, I think I don't follow what you're asking/saying?

Copy link
Member

Choose a reason for hiding this comment

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

The documentation to this function states that "due to the implications of Rust's safety promises being uncertain, if the representation of a signaling NaN "sNaN" float is passed to the function, the implementation is allowed to return a quiet NaN instead".

Someone looking at the implementation may wonder why those questions about safety promises are not a problem on these four architectures, but are on others. There should be a comment saying why this adjustment isn't needed.

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 would instead suggest changing the documentation to be "due to some platforms not conforming to IEEE 758-2008..."

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 understand what IEEE 758-2008 compliance has to do with LLVM treating sNaN as UB or not.

@kennytm kennytm added the S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). label Nov 15, 2017
@Gankra Gankra changed the title Make float::from_bits transmute on x86/x64/ARM/aarch64 Make float::from_bits transmute Nov 15, 2017
@Gankra
Copy link
Contributor Author

Gankra commented Nov 15, 2017

I have changed the PR to transmute on all platforms. The platform-specific cfg was based on me getting confused as a result of the implementation, documentation, and example all being inconsistent with eachother. See commit message for details.

Gankra added a commit to Gankra/byteorder that referenced this pull request Nov 15, 2017
Gankra added a commit to Gankra/byteorder that referenced this pull request Nov 15, 2017
@hanna-kruppe
Copy link
Contributor

Should the weasel words around sNaN be removed, i.e., should we commit to not masking sNaN?

And if so, should the the docs also include the note about non-IEEE platforms that's in the commit, to warn people against using it for platform-independent de-/serialization?

@Gankra
Copy link
Contributor Author

Gankra commented Nov 15, 2017

Note that the platforms in question are IEEE 758-1985 compliant. It's just how to interpret the signaling bit wasn't spec'd until the 2008 version. Upon reflection, this implementation is maximally good at network interop if you're doing NaN-boxing that just slurps up the mantissa bits. It's not as good if you're specifically just caring about whether the NaN signals or not.

The alternative would be to preserve signaling-ness, at the cost of clobbering the signaling bit across platforms.

On balance my submitted implementation seems the most useful, and if the alternative behaviour is desired, then it should be a seperate function (since this behaviour is still desirable).

In practice, I expect no one will notice or care.

@sfackler
Copy link
Member

sfackler commented Nov 16, 2017

I think the guarantees we want to document are that:

  • Non-NaN values will always round trip exactly between any set of architectures.
  • NaN values will remain NaN after a round trip between any set of architectures.
  • All values will always round trip exactly between the same architecture.

Does that seem right?

@Gankra
Copy link
Contributor Author

Gankra commented Nov 16, 2017

That is a reasonably minimal specification that I would be happy with, yes. (pushed test changes)

@sfackler
Copy link
Member

All values will always round trip exactly between the same architecture.

I think we also want to guarantee this, right?

@BurntSushi
Copy link
Member

@gankro Thanks for all the leg work on this. :-) I admit, I still feel a little squishy over this, but folks with more experience than me on these matters seem quite confident, so I'm content to move forward.

@alexcrichton
Copy link
Member

I think the docs may want to be updated here as well, but could we perhaps word them in such a way that implies that despite the current behavior we may change things in the future if necessary? (in that do we really trust LLVM to never change in this regard?)

@Gankra
Copy link
Contributor Author

Gankra commented Nov 20, 2017

Willing to change docs if desired (though they are still technically correct), but I'd like to get sign off from the rest of the libs team before digging into that. (the impl should be ~independent)

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Nov 20, 2017
@rfcbot
Copy link

rfcbot commented Nov 20, 2017

🔔 This is now entering its final comment period, as per the review above. 🔔

@aturon aturon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Nov 21, 2017
@sfackler
Copy link
Member

We discussed this at the last libs meeting and decided that the guarantees in #46012 (comment) seem reasonable.

@Gankra
Copy link
Contributor Author

Gankra commented Nov 23, 2017

After some discussion on IRC, it seems like it would be better to simply state "it's just transmute", and explain the implications of this. This ends up providing basically the same guarantees as the libs team agreed to (except guaranteeing that cross-platform transfer is in fact bit-exact).

Pushed updated docs.

/// to interpret the NaN signaling bit wasn't actually specified. Most platforms
/// (notably x86 and ARM) picked the interpretation that was ultimately
/// standardized in 2008, but some didn't (notably MIPS). As a result, all
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
Copy link
Member

Choose a reason for hiding this comment

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

Is this really the case, or is it that the signalingness is selected by some payload bit in the other encoding?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They literally agree on the bit, but one says 1=signaling, and the other says 0=signaling.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, lol

@sfackler
Copy link
Member

Build's red, but r=me otherwise.

…ect this).

The current implementation/documentation was made to avoid sNaN because of
potential safety issues implied by old/bad LLVM documentation. These issues
aren't real, so we can just make the implementation transmute (as permitted
by the existing documentation of this method).

Also the documentation didn't actually match the behaviour: it said we may
change sNaNs, but in fact we canonicalized *all* NaNs.

Also an example in the documentation was wrong: it said we *always* change
sNaNs, when the documentation was explicitly written to indicate it was
implementation-defined.

This makes to_bits and from_bits perfectly roundtrip cross-platform, except
for one caveat: although the 2008 edition of IEEE-754 specifies how to
interpet the signaling bit, earlier editions didn't. This lead to some platforms
picking the opposite interpretation, so all signaling NaNs on x86/ARM are quiet
on MIPS, and vice-versa.

NaN-boxing is a fairly important optimization, while we don't even guarantee
that float operations properly preserve signalingness. As such, this seems like
the more natural strategy to take (as opposed to trying to mangle the signaling
bit on a per-platform basis).

This implementation is also, of course, faster.
@Gankra
Copy link
Contributor Author

Gankra commented Nov 23, 2017

Fixed? (tidy whitespace)

@sfackler
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Nov 23, 2017

📌 Commit 439576f has been approved by sfackler

@sfackler sfackler added the relnotes Marks issues that should be documented in the release notes of the next release. label Nov 23, 2017
Gankra added a commit to Gankra/byteorder that referenced this pull request Nov 24, 2017
@bors
Copy link
Contributor

bors commented Nov 24, 2017

⌛ Testing commit 439576f with merge 078fbe4...

bors added a commit that referenced this pull request Nov 24, 2017
Make float::from_bits transmute

See commit message for details.

See also this discussion here: #40470 (comment)

(may require libs team discussion before merging)
@kennytm
Copy link
Member

kennytm commented Nov 24, 2017

@bors retry

The AppVeyor dist i686-pc-windows-msvc job was "cancelled by user" with this message but the failure is not notified to GitHub:

Timeout performing HVALS account_clouds_0, inst: 1, mgr: PrepareActiveSockets, err: never, queue: 4, qu: 0, qs: 2, qc: 2, wr: 0, wq: 0, in: 0, ar: 0, clientName: AppVeyor-Appveyor.Worker_IN_1, IOCP: (Busy=1,Free=999,Min=200,Max=1000), WORKER: (Busy=24,Free=32743,Min=200,Max=32767), Local-CPU: 4.09% (Please take a look at this article for some common client-side issues that can cause timeouts: https://github.com/StackExchange/StackExchange.Redis/tree/master/Docs/Timeouts.md)

@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 24, 2017
@bors
Copy link
Contributor

bors commented Nov 24, 2017

⌛ Testing commit 439576f with merge 85d50ce...

bors added a commit that referenced this pull request Nov 24, 2017
Make float::from_bits transmute

See commit message for details.

See also this discussion here: #40470 (comment)

(may require libs team discussion before merging)
@bors
Copy link
Contributor

bors commented Nov 24, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: sfackler
Pushing 85d50ce to master...

@bors bors merged commit 439576f into rust-lang:master Nov 24, 2017
@Gankra
Copy link
Contributor Author

Gankra commented Nov 24, 2017

The Curse Is Lifted

BurntSushi pushed a commit to BurntSushi/byteorder that referenced this pull request Nov 29, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants