summaryrefslogtreecommitdiff
path: root/src/passes/I64ToI32Lowering.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-08-05 17:48:54 -0700
committerGitHub <noreply@github.com>2020-08-05 17:48:54 -0700
commite93fbc0c117bcfe645bab1b30d5802e619e68abc (patch)
tree3f11b6a9e189296988d9954b483f73a9aff5f2a1 /src/passes/I64ToI32Lowering.cpp
parent9c84d90712c1183f1d9ab3e5068d902eb7d627ea (diff)
downloadbinaryen-e93fbc0c117bcfe645bab1b30d5802e619e68abc.tar.gz
binaryen-e93fbc0c117bcfe645bab1b30d5802e619e68abc.tar.bz2
binaryen-e93fbc0c117bcfe645bab1b30d5802e619e68abc.zip
Add StubUnsupportedJSOps to remove operations that JS does not support (#3024)
This doesn't lower them - it just replaces the unsupported operation with a drop. This will be useful for fuzzing, where to compare JS to the correct semantics we must avoid operations where JS is not always accurate. Also fully document the i64 -> f32 conversion issue in JS.
Diffstat (limited to 'src/passes/I64ToI32Lowering.cpp')
-rw-r--r--src/passes/I64ToI32Lowering.cpp32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 78f15fcad..dfd0878f8 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -696,6 +696,38 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
// Mostly just shuffling things around here with coercions and whatnot!
// Note though that all arithmetic is done with f64 to have as much
// precision as we can.
+ //
+ // NB: this is *not* accurate for i64 -> f32. Using f64s for intermediate
+ // operations can give slightly inaccurate results in some cases, as we
+ // round to an f64, then round again to an f32, which is not always the
+ // same as a single rounding of i64 to f32 directly. Example:
+ //
+ // #include <stdio.h>
+ // int main() {
+ // unsigned long long x = 18446743523953737727ULL;
+ // float y = x;
+ // double z = x;
+ // float w = z;
+ // printf("i64 : %llu\n"
+ // "i64->f32 : %f\n"
+ // "i64->f64 : %f\n"
+ // "i64->f64->f32: %f\n", x, y, z, w);
+ // }
+ //
+ // i64 : 18446743523953737727
+ // i64->f32 : 18446742974197923840.000000 ;; correct rounding to f32
+ // i64->f64 : 18446743523953737728.000000 ;; correct rounding to f64
+ // i64->f64->f32: 18446744073709551616.000000 ;; incorrect rounding to f32
+ //
+ // This is even a problem if we use BigInts in JavaScript to represent
+ // i64s, as Math.fround(BigInt) is not supported - the BigInt must be
+ // converted to a Number first, so we again have that extra rounding.
+ //
+ // A more precise approach could use compiled floatdisf/floatundisf from
+ // compiler-rt, but that is much larger and slower. (Note that we are in the
+ // interesting situation of having f32 and f64 operations and only missing
+ // i64 ones, so we have a different problem to solve than compiler-rt, and
+ // maybe there is a better solution we haven't found yet.)
TempVar highBits = fetchOutParam(curr->value);
TempVar lowBits = getTemp();
TempVar highResult = getTemp();