Add support for truncation operators
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Dec 2016 21:43:58 +0000 (21:43 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Dec 2016 21:43:58 +0000 (21:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165519

Reviewed by Geoffrey Garen.

JSTests:

* wasm/function-tests/i32-trunc-s-f32.js: Added.
* wasm/function-tests/i32-trunc-s-f64.js: Added.
* wasm/function-tests/i32-trunc-u-f32.js: Added.
* wasm/function-tests/i32-trunc-u-f64.js: Added.
* wasm/function-tests/i64-trunc-s-f32.js: Added.
* wasm/function-tests/i64-trunc-s-f64.js: Added.
* wasm/function-tests/i64-trunc-u-f32.js: Added.
* wasm/function-tests/i64-trunc-u-f64.js: Added.

Source/JavaScriptCore:

This patch adds initial support for truncation operators. The current patch
does range based out of bounds checking, in the future we should use system
register flags on ARM and other tricks on X86 improve the performance of
these opcodes.

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::branchTruncateDoubleToInt32):
(JSC::MacroAssemblerARM64::truncateDoubleToInt64):
(JSC::MacroAssemblerARM64::truncateDoubleToUint64):
(JSC::MacroAssemblerARM64::truncateFloatToInt32):
(JSC::MacroAssemblerARM64::truncateFloatToUint32):
(JSC::MacroAssemblerARM64::truncateFloatToInt64):
(JSC::MacroAssemblerARM64::truncateFloatToUint64):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::truncateFloatToInt32):
(JSC::MacroAssemblerX86Common::truncateDoubleToUint32): Deleted.
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::truncateDoubleToUint32):
(JSC::MacroAssemblerX86_64::truncateDoubleToInt64):
(JSC::MacroAssemblerX86_64::truncateDoubleToUint64):
(JSC::MacroAssemblerX86_64::truncateFloatToUint32):
(JSC::MacroAssemblerX86_64::truncateFloatToInt64):
(JSC::MacroAssemblerX86_64::truncateFloatToUint64):
* assembler/X86Assembler.h:
(JSC::X86Assembler::cvttss2si_rr):
(JSC::X86Assembler::cvttss2siq_rr):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncSF64>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncSF32>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncUF64>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncUF32>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncSF64>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncUF64>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncSF32>):
(JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncUF32>):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209476 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
JSTests/ChangeLog
JSTests/wasm/function-tests/i32-trunc-s-f32.js [new file with mode: 0644]
JSTests/wasm/function-tests/i32-trunc-s-f64.js [new file with mode: 0644]
JSTests/wasm/function-tests/i32-trunc-u-f32.js [new file with mode: 0644]
JSTests/wasm/function-tests/i32-trunc-u-f64.js [new file with mode: 0644]
JSTests/wasm/function-tests/i64-trunc-s-f32.js [new file with mode: 0644]
JSTests/wasm/function-tests/i64-trunc-s-f64.js [new file with mode: 0644]
JSTests/wasm/function-tests/i64-trunc-u-f32.js [new file with mode: 0644]
JSTests/wasm/function-tests/i64-trunc-u-f64.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmFunctionParser.h

index 3eaf786..a0610ad 100644 (file)
@@ -1,3 +1,19 @@
+2016-12-06  Keith Miller  <keith_miller@apple.com>
+
+        Add support for truncation operators
+        https://bugs.webkit.org/show_bug.cgi?id=165519
+
+        Reviewed by Geoffrey Garen.
+
+        * wasm/function-tests/i32-trunc-s-f32.js: Added.
+        * wasm/function-tests/i32-trunc-s-f64.js: Added.
+        * wasm/function-tests/i32-trunc-u-f32.js: Added.
+        * wasm/function-tests/i32-trunc-u-f64.js: Added.
+        * wasm/function-tests/i64-trunc-s-f32.js: Added.
+        * wasm/function-tests/i64-trunc-s-f64.js: Added.
+        * wasm/function-tests/i64-trunc-u-f32.js: Added.
+        * wasm/function-tests/i64-trunc-u-f64.js: Added.
+
 2016-12-06  Mark Lam  <mark.lam@apple.com>
 
         Introduce the concept of Immutable Prototype Exotic Objects to comply with the spec.
diff --git a/JSTests/wasm/function-tests/i32-trunc-s-f32.js b/JSTests/wasm/function-tests/i32-trunc-s-f32.js
new file mode 100644 (file)
index 0000000..85e8c51
--- /dev/null
@@ -0,0 +1,31 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f32"], ret: "i32" }, [])
+    .GetLocal(0)
+    .I32TruncSF32()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i32", value: "0" }, [{ type: "f32", value: "0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "0x1p-149" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0x1p-149" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "1.0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "0x1.19999ap+0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "1.5" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f32", value: "-1.0" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f32", value: "-0x1.19999ap+0" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f32", value: "-1.5" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f32", value: "-1.9" }]],
+                         [{ type: "i32", value: "-2" }, [{ type: "f32", value: "-2.0" }]],
+                         [{ type: "i32", value: "2147483520" }, [{ type: "f32", value: "2147483520.0" }]],
+                         [{ type: "i32", value: "-2147483648" }, [{ type: "f32", value: "-2147483648.0" }]],
+                        ],
+
+                       );
diff --git a/JSTests/wasm/function-tests/i32-trunc-s-f64.js b/JSTests/wasm/function-tests/i32-trunc-s-f64.js
new file mode 100644 (file)
index 0000000..1bb1dd6
--- /dev/null
@@ -0,0 +1,31 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f64"], ret: "i32" }, [])
+    .GetLocal(0)
+    .I32TruncSF64()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i32", value: "0" }, [{ type: "f64", value: "0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "0x0.0000000000001p-1022" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0x0.0000000000001p-1022" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "1.0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "0x1.199999999999ap+0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "1.5" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f64", value: "-1.0" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f64", value: "-0x1.199999999999ap+0" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f64", value: "-1.5" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f64", value: "-1.9" }]],
+                         [{ type: "i32", value: "-2" }, [{ type: "f64", value: "-2.0" }]],
+                         [{ type: "i32", value: "2147483647" }, [{ type: "f64", value: "2147483647.0" }]],
+                         [{ type: "i32", value: "-2147483648" }, [{ type: "f64", value: "-2147483648.0" }]],
+                        ],
+
+                       );
diff --git a/JSTests/wasm/function-tests/i32-trunc-u-f32.js b/JSTests/wasm/function-tests/i32-trunc-u-f32.js
new file mode 100644 (file)
index 0000000..1dbbed6
--- /dev/null
@@ -0,0 +1,29 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f32"], ret: "i32" }, [])
+    .GetLocal(0)
+    .I32TruncUF32()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i32", value: "0" }, [{ type: "f32", value: "0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "0x1p-149" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0x1p-149" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "1.0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "0x1.19999ap+0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "1.5" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f32", value: "1.9" }]],
+                         [{ type: "i32", value: "2" }, [{ type: "f32", value: "2.0" }]],
+                         [{ type: "i32", value: "-2147483648" }, [{ type: "f32", value: "2147483648" }]],
+                         [{ type: "i32", value: "-256" }, [{ type: "f32", value: "4294967040.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0x1.ccccccp-1" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f32", value: "-0x1.fffffep-1" }]],
+                        ],
+                       );
diff --git a/JSTests/wasm/function-tests/i32-trunc-u-f64.js b/JSTests/wasm/function-tests/i32-trunc-u-f64.js
new file mode 100644 (file)
index 0000000..f494918
--- /dev/null
@@ -0,0 +1,30 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f64"], ret: "i32" }, [])
+    .GetLocal(0)
+    .I32TruncUF64()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i32", value: "0" }, [{ type: "f64", value: "0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "0x0.0000000000001p-1022" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0x0.0000000000001p-1022" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "1.0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "0x1.199999999999ap+0" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "1.5" }]],
+                         [{ type: "i32", value: "1" }, [{ type: "f64", value: "1.9" }]],
+                         [{ type: "i32", value: "2" }, [{ type: "f64", value: "2.0" }]],
+                         [{ type: "i32", value: "-2147483648" }, [{ type: "f64", value: "2147483648" }]],
+                         [{ type: "i32", value: "-1" }, [{ type: "f64", value: "4294967295.0" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0x1.ccccccccccccdp-1" }]],
+                         [{ type: "i32", value: "0" }, [{ type: "f64", value: "-0x1.fffffffffffffp-1" }]],
+                         [{ type: "i32", value: "100000000" }, [{ type: "f64", value: "1e8" }]],
+                        ],
+                       );
diff --git a/JSTests/wasm/function-tests/i64-trunc-s-f32.js b/JSTests/wasm/function-tests/i64-trunc-s-f32.js
new file mode 100644 (file)
index 0000000..feedc48
--- /dev/null
@@ -0,0 +1,33 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f32"], ret: "i64" }, [])
+    .GetLocal(0)
+    .I64TruncSF32()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i64", value: "0" }, [{ type: "f32", value: "0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "0x1p-149" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0x1p-149" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "1.0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "0x1.19999ap+0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "1.5" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f32", value: "-1.0" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f32", value: "-0x1.19999ap+0" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f32", value: "-1.5" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f32", value: "-1.9" }]],
+                         [{ type: "i64", value: "-2" }, [{ type: "f32", value: "-2.0" }]],
+                         [{ type: "i64", value: "4294967296" }, [{ type: "f32", value: "4294967296" }]],
+                         [{ type: "i64", value: "-4294967296" }, [{ type: "f32", value: "-4294967296" }]],
+                         [{ type: "i64", value: "9223371487098961920" }, [{ type: "f32", value: "9223371487098961920.0" }]],
+                         [{ type: "i64", value: "-9223372036854775808" }, [{ type: "f32", value: "-9223372036854775808.0" }]],
+                        ],
+
+                       );
diff --git a/JSTests/wasm/function-tests/i64-trunc-s-f64.js b/JSTests/wasm/function-tests/i64-trunc-s-f64.js
new file mode 100644 (file)
index 0000000..cf8a88c
--- /dev/null
@@ -0,0 +1,33 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f64"], ret: "i64" }, [])
+    .GetLocal(0)
+    .I64TruncSF64()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i64", value: "0" }, [{ type: "f64", value: "0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "0x0.0000000000001p-1022" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0x0.0000000000001p-1022" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "1.0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "0x1.199999999999ap+0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "1.5" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f64", value: "-1.0" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f64", value: "-0x1.199999999999ap+0" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f64", value: "-1.5" }]],
+                         [{ type: "i64", value: "-1" }, [{ type: "f64", value: "-1.9" }]],
+                         [{ type: "i64", value: "-2" }, [{ type: "f64", value: "-2.0" }]],
+                         [{ type: "i64", value: "4294967296" }, [{ type: "f64", value: "4294967296" }]],
+                         [{ type: "i64", value: "-4294967296" }, [{ type: "f64", value: "-4294967296" }]],
+                         [{ type: "i64", value: "9223372036854774784" }, [{ type: "f64", value: "9223372036854774784.0" }]],
+                         [{ type: "i64", value: "-9223372036854775808" }, [{ type: "f64", value: "-9223372036854775808.0" }]],
+                        ],
+
+                       );
diff --git a/JSTests/wasm/function-tests/i64-trunc-u-f32.js b/JSTests/wasm/function-tests/i64-trunc-u-f32.js
new file mode 100644 (file)
index 0000000..6cd9e24
--- /dev/null
@@ -0,0 +1,27 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f32"], ret: "i64" }, [])
+    .GetLocal(0)
+    .I64TruncUF32()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i64", value: "0" }, [{ type: "f32", value: "0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "0x1p-149" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0x1p-149" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "1.0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "0x1.19999ap+0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f32", value: "1.5" }]],
+                         [{ type: "i64", value: "4294967296" }, [{ type: "f32", value: "4294967296" }]],
+                         [{ type: "i64", value: "-1099511627776" }, [{ type: "f32", value: "18446742974197923840.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0x1.ccccccp-1" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f32", value: "-0x1.fffffep-1" }]],[{ type: "i64", value: "0" }, [{ type: "f32", value: "0.0" }]],
+                        ],
+                       );
diff --git a/JSTests/wasm/function-tests/i64-trunc-u-f64.js b/JSTests/wasm/function-tests/i64-trunc-u-f64.js
new file mode 100644 (file)
index 0000000..ee55148
--- /dev/null
@@ -0,0 +1,32 @@
+import Builder from '../Builder.js'
+
+const b = new Builder();
+b.Type().End()
+    .Function().End()
+    .Code()
+    .Function({ params: ["f64"], ret: "i64" }, [])
+    .GetLocal(0)
+    .I64TruncUF64()
+    .End()
+
+const bin = b.WebAssembly()
+bin.trim();
+testWasmModuleFunctions(bin.get(), 1,
+                        [[{ type: "i64", value: "0" }, [{ type: "f64", value: "0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "0x0.0000000000001p-1022" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0x0.0000000000001p-1022" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "1.0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "0x1.199999999999ap+0" }]],
+                         [{ type: "i64", value: "1" }, [{ type: "f64", value: "1.5" }]],
+                         [{ type: "i64", value: "0xffffffff" }, [{ type: "f64", value: "4294967295" }]],
+                         [{ type: "i64", value: "0x100000000" }, [{ type: "f64", value: "4294967296" }]],
+                         [{ type: "i64", value: "-2048" }, [{ type: "f64", value: "18446744073709549568.0" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0x1.ccccccccccccdp-1" }]],
+                         [{ type: "i64", value: "0" }, [{ type: "f64", value: "-0x1.fffffffffffffp-1" }]],
+                         [{ type: "i64", value: "100000000" }, [{ type: "f64", value: "1e8" }]],
+                         [{ type: "i64", value: "10000000000000000" }, [{ type: "f64", value: "1e16" }]],
+                         [{ type: "i64", value: "-9223372036854775808" }, [{ type: "f64", value: "9223372036854775808" }]],
+                        ],
+
+                       );
index 6ed757c..6b50d83 100644 (file)
@@ -1,3 +1,48 @@
+2016-12-06  Keith Miller  <keith_miller@apple.com>
+
+        Add support for truncation operators
+        https://bugs.webkit.org/show_bug.cgi?id=165519
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds initial support for truncation operators. The current patch
+        does range based out of bounds checking, in the future we should use system
+        register flags on ARM and other tricks on X86 improve the performance of
+        these opcodes.
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::branchTruncateDoubleToInt32):
+        (JSC::MacroAssemblerARM64::truncateDoubleToInt64):
+        (JSC::MacroAssemblerARM64::truncateDoubleToUint64):
+        (JSC::MacroAssemblerARM64::truncateFloatToInt32):
+        (JSC::MacroAssemblerARM64::truncateFloatToUint32):
+        (JSC::MacroAssemblerARM64::truncateFloatToInt64):
+        (JSC::MacroAssemblerARM64::truncateFloatToUint64):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::truncateFloatToInt32):
+        (JSC::MacroAssemblerX86Common::truncateDoubleToUint32): Deleted.
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::truncateDoubleToUint32):
+        (JSC::MacroAssemblerX86_64::truncateDoubleToInt64):
+        (JSC::MacroAssemblerX86_64::truncateDoubleToUint64):
+        (JSC::MacroAssemblerX86_64::truncateFloatToUint32):
+        (JSC::MacroAssemblerX86_64::truncateFloatToInt64):
+        (JSC::MacroAssemblerX86_64::truncateFloatToUint64):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::cvttss2si_rr):
+        (JSC::X86Assembler::cvttss2siq_rr):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncSF64>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncSF32>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncUF64>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I32TruncUF32>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncSF64>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncUF64>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncSF32>):
+        (JSC::Wasm::B3IRGenerator::addOp<OpType::I64TruncUF32>):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+
 2016-12-07  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Remove unused and mostly untested Page domain commands and events
index 6334fbf..d8d7b69 100644 (file)
@@ -1655,7 +1655,7 @@ public:
         // Truncate to a 64-bit integer in dataTempRegister, copy the low 32-bit to dest.
         m_assembler.fcvtzs<64, 64>(getCachedDataTempRegisterIDAndInvalidate(), src);
         zeroExtend32ToPtr(dataTempRegister, dest);
-        // Check thlow 32-bits sign extend to be equal to the full value.
+        // Check thlow 32-bits sign extend to be equal to the full value.
         m_assembler.cmp<64>(dataTempRegister, dataTempRegister, ARM64Assembler::SXTW, 0);
         return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
     }
@@ -2041,6 +2041,45 @@ public:
         m_assembler.fcvtzu<32, 64>(dest, src);
     }
 
+    void truncateDoubleToInt64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzs<64, 64>(dest, src);
+    }
+
+    void truncateDoubleToUint64(FPRegisterID src, RegisterID dest, FPRegisterID, FPRegisterID)
+    {
+        truncateDoubleToUint64(src, dest);
+    }
+
+    void truncateDoubleToUint64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzu<64, 64>(dest, src);
+    }
+
+    void truncateFloatToInt32(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzs<32, 32>(dest, src);
+    }
+
+    void truncateFloatToUint32(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzu<32, 32>(dest, src);
+    }
+
+    void truncateFloatToInt64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzs<64, 32>(dest, src);
+    }
+
+    void truncateFloatToUint64(FPRegisterID src, RegisterID dest, FPRegisterID, FPRegisterID)
+    {
+        truncateFloatToUint64(src, dest);
+    }
+
+    void truncateFloatToUint64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.fcvtzu<64, 32>(dest, src);
+    }
 
     // Stack manipulation operations:
     //
index bedb06b..3834214 100644 (file)
@@ -1678,15 +1678,13 @@ public:
         ASSERT(isSSE2Present());
         m_assembler.cvttsd2si_rr(src, dest);
     }
-    
-#if CPU(X86_64)
-    void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
+
+    void truncateFloatToInt32(FPRegisterID src, RegisterID dest)
     {
         ASSERT(isSSE2Present());
-        m_assembler.cvttsd2siq_rr(src, dest);
+        m_assembler.cvttss2si_rr(src, dest);
     }
-#endif
-    
+
     // Convert 'src' to an integer, and places the resulting 'dest'.
     // If the result is not representable as a 32 bit value, branch.
     // May also branch for some values that are representable in 32 bits
index 5076aeb..7e18412 100644 (file)
@@ -1295,6 +1295,72 @@ public:
         return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister()), mask8);
     }
 
+    void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.cvttsd2siq_rr(src, dest);
+    }
+
+    void truncateDoubleToInt64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.cvttsd2siq_rr(src, dest);
+    }
+
+    // int64Min should contain exactly 0x43E0000000000000 == static_cast<double>(int64_t::min()). scratch may
+    // be the same FPR as src.
+    void truncateDoubleToUint64(FPRegisterID src, RegisterID dest, FPRegisterID scratch, FPRegisterID int64Min)
+    {
+        ASSERT(scratch != int64Min);
+
+        // Since X86 does not have a floating point to unsigned integer instruction, we need to use the signed
+        // integer conversion instruction. If the src is less than int64_t::min() then the results of the two
+        // instructions are the same. Otherwise, we need to: subtract int64_t::min(); truncate double to
+        // uint64_t; then add back int64_t::min() in the destination gpr.
+
+        Jump large = branchDouble(DoubleGreaterThanOrEqual, src, int64Min);
+        m_assembler.cvttsd2siq_rr(src, dest);
+        Jump done = jump();
+        large.link(this);
+        moveDouble(src, scratch);
+        m_assembler.subsd_rr(int64Min, scratch);
+        m_assembler.movq_i64r(0x8000000000000000, scratchRegister());
+        m_assembler.cvttsd2siq_rr(scratch, dest);
+        m_assembler.orq_rr(scratchRegister(), dest);
+        done.link(this);
+    }
+
+    void truncateFloatToUint32(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.cvttss2siq_rr(src, dest);
+    }
+
+    void truncateFloatToInt64(FPRegisterID src, RegisterID dest)
+    {
+        m_assembler.cvttss2siq_rr(src, dest);
+    }
+
+    // int64Min should contain exactly 0x5f000000 == static_cast<float>(int64_t::min()). scratch may be the
+    // same FPR as src.
+    void truncateFloatToUint64(FPRegisterID src, RegisterID dest, FPRegisterID scratch, FPRegisterID int64Min)
+    {
+        ASSERT(scratch != int64Min);
+
+        // Since X86 does not have a floating point to unsigned integer instruction, we need to use the signed
+        // integer conversion instruction. If the src is less than int64_t::min() then the results of the two
+        // instructions are the same. Otherwise, we need to: subtract int64_t::min(); truncate double to
+        // uint64_t; then add back int64_t::min() in the destination gpr.
+
+        Jump large = branchFloat(DoubleGreaterThanOrEqual, src, int64Min);
+        m_assembler.cvttss2siq_rr(src, dest);
+        Jump done = jump();
+        large.link(this);
+        moveDouble(src, scratch);
+        m_assembler.subss_rr(int64Min, scratch);
+        m_assembler.movq_i64r(0x8000000000000000, scratchRegister());
+        m_assembler.cvttss2siq_rr(scratch, dest);
+        m_assembler.orq_rr(scratchRegister(), dest);
+        done.link(this);
+    }
+
     void convertInt64ToDouble(RegisterID src, FPRegisterID dest)
     {
         m_assembler.cvtsi2sdq_rr(src, dest);
index d2ddff8..a65e695 100644 (file)
@@ -267,6 +267,7 @@ private:
         OP2_MOVAPS_VpdWpd   = 0x28,
         OP2_CVTSI2SD_VsdEd  = 0x2A,
         OP2_CVTTSD2SI_GdWsd = 0x2C,
+        OP2_CVTTSS2SI_GdWsd = 0x2C,
         OP2_UCOMISD_VsdWsd  = 0x2E,
         OP2_3BYTE_ESCAPE_3A = 0x3A,
         OP2_CMOVCC          = 0x40,
@@ -2293,6 +2294,20 @@ public:
         m_formatter.twoByteOp(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src);
     }
 
+    void cvttss2si_rr(XMMRegisterID src, RegisterID dst)
+    {
+        m_formatter.prefix(PRE_SSE_F3);
+        m_formatter.twoByteOp(OP2_CVTTSS2SI_GdWsd, dst, (RegisterID)src);
+    }
+
+#if CPU(X86_64)
+    void cvttss2siq_rr(XMMRegisterID src, RegisterID dst)
+    {
+        m_formatter.prefix(PRE_SSE_F3);
+        m_formatter.twoByteOp64(OP2_CVTTSS2SI_GdWsd, dst, (RegisterID)src);
+    }
+#endif
+
     void cvtsd2ss_rr(XMMRegisterID src, XMMRegisterID dst)
     {
         m_formatter.prefix(PRE_SSE_F2);
index c4100f9..6dcee37 100644 (file)
@@ -905,6 +905,229 @@ bool B3IRGenerator::addOp<OpType::F32Trunc>(ExpressionType arg, ExpressionType&
     return true;
 }
 
+template<>
+bool B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int32_t>::min()));
+    Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()));
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateDoubleToInt32(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int32_t>::min()));
+    Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()));
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateFloatToInt32(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+
+template<>
+bool B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int32_t>::min()) * -2.0);
+    Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -1.0);
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateDoubleToUint32(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int32_t>::min()) * -2.0);
+    Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -1.0);
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateFloatToUint32(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -static_cast<double>(std::numeric_limits<int64_t>::min()));
+    Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()));
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateDoubleToInt64(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<int64_t>::min()) * -2.0);
+    Value* min = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), -1.0);
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+
+    Value* constant;
+    if (isX86()) {
+        // Since x86 doesn't have an instruction to convert floating points to unsigned integers, we at least try to do the smart thing if
+        // the numbers are would be positive anyway as a signed integer. Since we cannot materialize constants into fprs we have b3 do it
+        // so we can pool them if needed.
+        constant = m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), static_cast<double>(std::numeric_limits<uint64_t>::max() - std::numeric_limits<int64_t>::max()));
+    }
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    if (isX86()) {
+        patchpoint->append(constant, ValueRep::SomeRegister);
+        patchpoint->numFPScratchRegisters = 1;
+    }
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        AllowMacroScratchRegisterUsage allowScratch(jit);
+        FPRReg scratch = InvalidFPRReg;
+        FPRReg constant = InvalidFPRReg;
+        if (isX86()) {
+            scratch = params.fpScratch(0);
+            constant = params[2].fpr();
+        }
+        jit.truncateDoubleToUint64(params[1].fpr(), params[0].gpr(), scratch, constant);
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -static_cast<float>(std::numeric_limits<int64_t>::min()));
+    Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()));
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        jit.truncateFloatToInt64(params[1].fpr(), params[0].gpr());
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
+template<>
+bool B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionType& result)
+{
+    Value* max = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<int64_t>::min()) * -2.0);
+    Value* min = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), -1.0);
+    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(),
+        m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), arg, max),
+        m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
+    outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
+    CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
+    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+
+    Value* constant;
+    if (isX86()) {
+        // Since x86 doesn't have an instruction to convert floating points to unsigned integers, we at least try to do the smart thing if
+        // the numbers are would be positive anyway as a signed integer. Since we cannot materialize constants into fprs we have b3 do it
+        // so we can pool them if needed.
+        constant = m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), static_cast<float>(std::numeric_limits<uint64_t>::max() - std::numeric_limits<int64_t>::max()));
+    }
+    PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
+    patchpoint->append(arg, ValueRep::SomeRegister);
+    if (isX86()) {
+        patchpoint->append(constant, ValueRep::SomeRegister);
+        patchpoint->numFPScratchRegisters = 1;
+    }
+    patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+        AllowMacroScratchRegisterUsage allowScratch(jit);
+        FPRReg scratch = InvalidFPRReg;
+        FPRReg constant = InvalidFPRReg;
+        if (isX86()) {
+            scratch = params.fpScratch(0);
+            constant = params[2].fpr();
+        }
+        jit.truncateFloatToUint64(params[1].fpr(), params[0].gpr(), scratch, constant);
+    });
+    patchpoint->effects = Effects::none();
+    result = patchpoint;
+    return true;
+}
+
 } } // namespace JSC::Wasm
 
 #include "WasmB3IRGeneratorInlines.h"
index 16d1311..89b0ab3 100644 (file)
@@ -221,6 +221,14 @@ bool FunctionParser<Context>::parseExpression(OpType op)
     case OpType::I64Ctz: return unaryCase<OpType::I64Ctz>();
     case OpType::I32Popcnt: return unaryCase<OpType::I32Popcnt>();
     case OpType::I64Popcnt: return unaryCase<OpType::I64Popcnt>();
+    case OpType::I32TruncSF32: return unaryCase<OpType::I32TruncSF32>();
+    case OpType::I32TruncUF32: return unaryCase<OpType::I32TruncUF32>();
+    case OpType::I32TruncSF64: return unaryCase<OpType::I32TruncSF64>();
+    case OpType::I32TruncUF64: return unaryCase<OpType::I32TruncUF64>();
+    case OpType::I64TruncSF32: return unaryCase<OpType::I64TruncSF32>();
+    case OpType::I64TruncUF32: return unaryCase<OpType::I64TruncUF32>();
+    case OpType::I64TruncSF64: return unaryCase<OpType::I64TruncSF64>();
+    case OpType::I64TruncUF64: return unaryCase<OpType::I64TruncUF64>();
 #define CREATE_CASE(name, id, b3op, inc) case OpType::name: return unaryCase<OpType::name>();
     FOR_EACH_WASM_SIMPLE_UNARY_OP(CREATE_CASE)
 #undef CREATE_CASE