-
Notifications
You must be signed in to change notification settings - Fork 13.3k
clarify NaN propagation in fptrunc #68554
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
Conversation
@llvm/pr-subscribers-llvm-ir ChangesFollow-up to #66579: while implementing those semantics in Miri I realized there's a special case to be considered in truncating float casts. Cc @nunoplopes @nikic @jyknight @jcranmer-intel Full diff: https://github.com/llvm/llvm-project/pull/68554.diff 1 Files Affected:
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 1883e9f6290b151..e27d4e0ed695319 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11311,7 +11311,10 @@ environment <floatenv>`.
NaN values follow the usual :ref:`NaN behaviors <floatnan>`, except that _if_ a
NaN payload is propagated from the input ("Quieting NaN propagation" or
"Unchanged NaN propagation" cases), then the low order bits of the NaN payload
-which cannot fit in the resulting type are discarded.
+which cannot fit in the resulting type are discarded. Note that if discarding
+the low order bits leads to an all-0 payload, this cannot be represented as a
+signaling NaN (it would represent an infinity instead), so in that case
+"Unchanged NaN propagation" is not possible.
Example:
""""""""
|
So, discarding all 1-bits in the payload would give an Inf rather than a NaN then. FWIW, I tried x86, and it returns the canonical quiet NaN: https://gcc.godbolt.org/z/o1K6rrov9 |
They should always return a quiet NaN, so if all 1s in the payload get truncated away it will naturally be the preferred NaN, without any special case.
But LLVM might optimize away cast roundtrips and then a signaling NaN might be returned and then we have to exclude the special case where the sNaN has all-0 payloads.
|
Doesn't seem like: https://gcc.godbolt.org/z/z1sqhjnE8 |
Yeah removing the double-float-double roundtrip would be wrong to optimize away since the precision gets reduced (even ignoring NaNs, this cast changes the value and hence cannot be optimized away). But float-double-float should be legal, and LLVM does it. So in terms of the semantics, but fpext and fptruc can, under some conditions, return an sNaN -- but fptrunc can only return an sNaN if the input NaN is an sNaN and its payload has a 1 that is preserved by truncation. |
FWIW, I tried the suggested semantics on LLVM's test suite with Alive2 and it works fine. But without the fix also worked, so maybe there isn't sufficient coverage for these corner cases. |
Without the fix, this Rust function would be allowed to return pub fn test() -> bool {
let snan = f64::from_bits(0x7FF0_0000_0000_0001u64);
assert!(snan.is_nan());
let nan = snan as f32;
nan.is_nan()
} That's roughly the following IR
|
This seems the only reasonable answer, and I can't think of any valid optimization we might be doing now that could break it. |
Follow-up to #66579: while implementing those semantics in Miri I realized there's a special case to be considered in truncating float casts.
Cc @nunoplopes @nikic @jyknight @jcranmer-intel