fix(backend): float != must be UNORDERED so nan != nan is true [F0.9]

emitCmpNe lowered float `!=` to `LLVMRealONE` (ordered not-equal), which
is false when either operand is NaN. That made `nan != nan` false in
native code — breaking the canonical `x != x` NaN test, making `!=`
non-complementary with `==` for NaN, and disagreeing with the interpreter.

Change the float predicate to `LLVMRealUNE` (unordered not-equal): true
if either operand is NaN OR they are unequal. For all non-NaN operands
`UNE` ≡ `ONE`, so only NaN-involving comparisons change (toward correct).
The integer predicate (`LLVMIntNE`) and `emitCmpEq` (`OEQ`) are unchanged,
so `nan == nan` stays false and `!=` is now the exact complement of `==`.

- Regression: examples/0150-types-float-ne-unordered-nan.sx (fails before,
  passes after; also pins #run/comptime == runtime agreement).
- specs.md: documents float comparison / NaN semantics (Operators).
- Resolves issue 0091 (issues/0091-float-ne-ordered-nan.md).
This commit is contained in:
agra
2026-06-04 17:04:41 +03:00
parent b5a2535ab6
commit 5afbc65414
7 changed files with 137 additions and 1 deletions

View File

@@ -85,6 +85,15 @@ GLSL;
| `<<=` | left shift assign |
| `>>=` | right shift assign |
**Float comparison and NaN.** Float `==` is *ordered* and `!=` is *unordered*,
matching IEEE 754: `==` is false whenever either operand is NaN (`nan == x` is
false for every `x`, including `nan`), and `!=` is true whenever either operand
is NaN (`nan != x` is true for every `x`, including `nan`). So `!=` is the exact
complement of `==` for all float inputs, and the canonical NaN test `x != x` is
true exactly when `x` is NaN. The ordered relations `<`, `<=`, `>`, `>=` are all
false when either operand is NaN. For all non-NaN operands these reduce to the
ordinary comparisons. Native codegen and the comptime interpreter agree on this.
### Delimiters and Punctuation
| Token | Meaning |