<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/80472>80472</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Clarify documentation on propagating signalling NaNs through (non-strict) fp-operations
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          quaternic
      </td>
    </tr>
</table>

<pre>
    As documented in [the reference](https://llvm.org/docs/LangRef.html#behavior-of-floating-point-nan-values), LLVM is allowed to perform optimizations such as
- `x * -1.0` -> `-x`
- `x + (-0.0)` -> `x`
- `pow(1.0, x)` -> `1.0`

These are seen as sufficiently useful to knowingly diverge from the rules required by IEEE-754. (Specifically, that they should return QNaN for any SNaN-input.) For more details you can see the discussion in https://github.com/llvm/llvm-project/issues/43070 . That led to documenting the current rule, which has been further revised in at least https://github.com/llvm/llvm-project/pull/66579 .

However, the rule as written also allows many other transformations such as:
- `x * y` -> `y` (when `y` is statically known to be some NaN)
- `x * y` -> `is_signalling_nan(y) ? y : x * y`

(Neither is much of an optimization compared to doing the correct thing, and LLVM does not perform them, but they are considered allowed by Alive2: https://alive2.llvm.org/ce/z/PenjbC)

These seem much more surprising to me, and more likely to break non-strictfp code that handles potentially signalling values, which it might obtain from, and pass to, a library using strictfp.

Are there cases where LLVM may currently propagate an SNaN untouched through an operation that would change a numeric value (other than just the sign)?

Preferably, it could be guaranteed in some form, that the "Unchanged NaN propagation" only applies transforming operations that pass the magnitude untouched, such as `x * -1.0` -> `-x`, and that those cases treat the sign as the substitution would, so that `x * -1.0` may never return an SNaN with the same sign as `x` (but can of course return an arbitrary QNaN).

If on the other hand, the intention is to allow all such transformations, and treat SNaN as a QNaN that just can't be created "from thin air", the documentation should point it out more directly, by reproducing such examples.

This came up in https://github.com/rust-lang/rfcs/pull/3514, on specifying Rust floating point behavior.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJycVsuO2zoS_Rp6U5Ah0--FF06njblAxrj3JjPboCSVJCYUqfDRbuXrB0VZtrsDTDCzcVtuqh7nnDpF9F41hugg1h_E-uMMY2itO_yIGMgZVc4KWw2Ho4fKlrEjE6gCZUCsP4SWwFFNjkxJYv1RyF0bQu_F8ijkSciT1i_d3LpGyFNlSy_k6ROa5m-q523otJDLglp8UdZlts5qbTEo02S9VSZkBk32gjqSF3Iv5BN8-vTvf4LygFrbC1UQLPTkaus6sH1QnfqJQVnjwceyBfQi_yjyYwZik7-CkEfIFvNcbHLIxPKZf81exSZ_d-oDCLnL8nnOSR_Ovjva24uQO44nn-D13dkxzXh6_PzSkidAR-CJDCDXWNeqVGSCHiB6qqPmhr4be1Gm0QNU6oVcQ1A720ECOmry4OhHVI4qKAb44_n5OduuV3Ou-XNPpapViVoPXFRoMfB7A_jWRl2BoxCdgb_OeIbaOkAzwOcznjNl-hjmQu7hZB101hFUFFBpD4ONUKLhqlMNlfJl9F5Zwwp4y3WjQhuLeWm7K_HXP1nv7Dcqg5An5X2i87Ra5tsc5vCFi9Qjl5O6lGlSrjI6RyakvrmhS6vKFlr0UDCGdXShJQeOXpQfFZlioQ__e2F91FrI02az3u5h_sjcP-yFXsiNiI4kMH0Xp0JgJrW3oyA9dIyoTUUFh8azMt8pcnn8RZTDo3LSg5C7S0vm9qw8-IBhpDYpxDBeBYG3HcEZz6y__xpX-a8846i1Ms1Xg0bI3cCMi-UJBhDLI9zfemxfyN2ZVOpJeei4DVsDmjcTB6XtenQTjTcCrXNUsgiVaRhANNU4xJUlD8aG2_yGljo-UcSrZnlUSmu8qojjTiNfDHDU6oUkV_yWZUy_zx8cpyQhTz-FPP1J5lvxdAPpcSQ9UTe2lXTvo-ud8qkDCx1NVad_avWd9JCgd4TfwViT-eBUGeoeSlvROHMtmoontbeB1ZxIu4MPk6VNglYBOtW0AWwRUJk071PaHr2HYNMjaFU4dGwWHGZK_EasR5fGlLFDTx4u6XuCvMNhmig9QO9sjw0GYirZBCCaYGPZMoets7FpR5LJjQynzi7JR8oWTUOAYGJHTpVjR6zaq_ZbNPAt-sRk6pyRX54eC_0zbQ0sRqtSAcoUuiBoIjo0gcaJTgJnhTw6Gggp_2XGMiqW_60dZY2QEqzRA2Dfa0X-PoqM2q0hP0YbAW4JOmyMCrGiOxCc8jq3v1shV7quBVo_4R8c4R0GDpS-x8IHFWICNmGaUtnx_V9SMXOGPWhy8ImyiwrtGBC7e4brrmI-eJrYvW3N-DpPDxHQFSokPf01GsgbIf1RQyKdrn7Gmp4sUJmka14BLM5xNvlzROud9d2wSVCkutEDjmsoNZykUrIlbQMroOSTVDHL193H1q6ckHIqYVoVozav-y3dGlhLNobrFlPsP6PGigEc9c5WsUzjw6XSK3a9Jj9_6wvKQ8mIxv43S85FHzKNbG4nV6frzXWRLNeLFWfl6tJeHjjp39zpdMu51jtdgOaz6rCs9ss9zuiw2Oab3X67k5tZe6hoTavtZrtY7CRhjrv9ZlPn-3wrN4ualsuZOshcrnKZy8Vusc3Xcyp3xaLebrbltqBiW4hVTh0qfTPHWVrEh12-2sqZxoK0ny5_7pBWYxEbL1a5Vj74-2tBBU2HJ41O1cM7Fqy5jyEDfHe8M579zVWE3N19kzdQ3Wf3qZxFpw___7UiNfSfAAAA__8WD5Oa">