diff options
Diffstat (limited to 'src/literal.h')
-rw-r--r-- | src/literal.h | 45 |
1 files changed, 22 insertions, 23 deletions
diff --git a/src/literal.h b/src/literal.h index 9d9630ec4..318ab012a 100644 --- a/src/literal.h +++ b/src/literal.h @@ -249,6 +249,28 @@ public: lit.i32 = value | 0x80000000; return lit; } + // Wasm has nondeterministic rules for NaN propagation in some operations. For + // example. f32.neg is deterministic and just flips the sign, even of a NaN, + // but f32.add is nondeterministic, and if one or more of the inputs is a NaN, + // then + // + // * if all NaNs are canonical, the output is some arbitrary canonical NaN + // * otherwise the output is some arbitrary arithmetic NaN + // + // (canonical = NaN payload is 1000..000; arithmetic: 1???..???, that is, the + // high bit is 1 and all others can be 0 or 1) + // + // For many things we don't need to care, and can just do a normal C++ add for + // an f32.add, for example - the wasm rules are specified so that things like + // that just work (in order for such math to be fast). However, for our + // optimizer, it is useful to "standardize" NaNs when there is nondeterminism. + // That is, when there are multiple valid outputs, it's nice to emit the same + // one consistently, so that it doesn't look like the optimization changed + // something. In other words, if the valid output of an expression is a set of + // valid NaNs, and after optimization the output is still that same set, then + // the optimization is valid. And if the interpreter picks the same NaN in + // both cases from that identical set then nothing looks wrong to the fuzzer. + static Literal standardizeNaN(const Literal& input); Literal castToF32(); Literal castToF64(); @@ -706,29 +728,6 @@ struct GCData { GCData(HeapType type, Literals values) : type(type), values(values) {} }; -// Wasm has nondeterministic rules for NaN propagation in some operations. For -// example. f32.neg is deterministic and just flips the sign, even of a NaN, but -// f32.add is nondeterministic, and if one or more of the inputs is a NaN, then -// -// * if all NaNs are canonical NaNs, the output is some arbitrary canonical NaN -// * otherwise the output is some arbitrary arithmetic NaN -// -// (canonical = NaN payload is 1000..000; arithmetic: 1???..???, that is, the -// high bit is 1 and all others can be 0 or 1) -// -// For many things we don't need to care, and can just do a normal C++ add for -// an f32.add, for example - the wasm rules are specified so that things like -// that just work (in order for such math to be fast). However, for our -// optimizer, it is useful to "standardize" NaNs when there is nondeterminism. -// That is, when there are multiple valid outputs, it's nice to emit the same -// one consistently, so that it doesn't look like the optimization changed -// something. In other words, if the valid output of an expression is a set of -// valid NaNs, and after optimization the output is still that same set, then -// the optimization is valid. And if the interpreter picks the same NaN in both -// cases from that identical set then nothing looks wrong to the fuzzer. -Literal standardizeNaN(float result); -Literal standardizeNaN(double result); - } // namespace wasm namespace std { |