diff options
-rw-r--r-- | src/pass.h | 6 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 5 | ||||
-rw-r--r-- | src/wasm2js.h | 3 | ||||
-rw-r--r-- | test/wasm2js/target_js.2asm.js | 27 | ||||
-rw-r--r-- | test/wasm2js/target_js.2asm.js.opt | 27 | ||||
-rw-r--r-- | test/wasm2js/target_js.wast | 13 |
6 files changed, 80 insertions, 1 deletions
diff --git a/src/pass.h b/src/pass.h index 4ab0a8c34..36d49f7b7 100644 --- a/src/pass.h +++ b/src/pass.h @@ -217,6 +217,12 @@ struct PassOptions { bool closedWorld = false; // Whether to try to preserve debug info through, which are special calls. bool debugInfo = false; + // Whether we are targeting JS. In that case we want to avoid emitting things + // in the optimizer that do not translate well to JS, or that could cause us + // to need extra lowering work or even a loop (where we optimize to something + // that needs lowering, then we lower it, then we can optimize it again to the + // original form). + bool targetJS = false; // Arbitrary string arguments from the commandline, which we forward to // passes. std::unordered_map<std::string, std::string> arguments; diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index e61373711..ad51d7cd4 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -3669,7 +3669,10 @@ private: { // ~(1 << x) aka (1 << x) ^ -1 ==> rotl(-2, x) Expression* x; - if (matches(curr, binary(Xor, binary(Shl, ival(1), any(&x)), ival(-1)))) { + // Note that we avoid this in JS mode, as emitting a rotation would + // require lowering that rotation for JS in another cycle of work. + if (matches(curr, binary(Xor, binary(Shl, ival(1), any(&x)), ival(-1))) && + !getPassOptions().targetJS) { curr->op = Abstract::getBinary(type, RotL); right->value = Literal::makeFromInt32(-2, type); curr->left = right; diff --git a/src/wasm2js.h b/src/wasm2js.h index 982184510..db394c36c 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -173,8 +173,11 @@ public: // and store would need to do a check. Given that, we can just ignore // implicit traps like those when optimizing. (When not optimizing, it's // nice to see codegen that matches wasm more precisely.) + // It is also important to prevent the optimizer from adding new things that + // require additional lowering, as we could hit a cycle. if (options.optimizeLevel > 0) { options.ignoreImplicitTraps = true; + options.targetJS = true; } } diff --git a/test/wasm2js/target_js.2asm.js b/test/wasm2js/target_js.2asm.js new file mode 100644 index 000000000..f9f4b4a67 --- /dev/null +++ b/test/wasm2js/target_js.2asm.js @@ -0,0 +1,27 @@ + +function asmFunc(imports) { + var Math_imul = Math.imul; + var Math_fround = Math.fround; + var Math_abs = Math.abs; + var Math_clz32 = Math.clz32; + var Math_min = Math.min; + var Math_max = Math.max; + var Math_floor = Math.floor; + var Math_ceil = Math.ceil; + var Math_trunc = Math.trunc; + var Math_sqrt = Math.sqrt; + var nan = NaN; + var infinity = Infinity; + function func(x) { + x = x | 0; + return (1 << x | 0) ^ -1 | 0 | 0; + } + + return { + "func": func + }; +} + +var retasmFunc = asmFunc({ +}); +export var func = retasmFunc.func; diff --git a/test/wasm2js/target_js.2asm.js.opt b/test/wasm2js/target_js.2asm.js.opt new file mode 100644 index 000000000..12e1a475b --- /dev/null +++ b/test/wasm2js/target_js.2asm.js.opt @@ -0,0 +1,27 @@ + +function asmFunc(imports) { + var Math_imul = Math.imul; + var Math_fround = Math.fround; + var Math_abs = Math.abs; + var Math_clz32 = Math.clz32; + var Math_min = Math.min; + var Math_max = Math.max; + var Math_floor = Math.floor; + var Math_ceil = Math.ceil; + var Math_trunc = Math.trunc; + var Math_sqrt = Math.sqrt; + var nan = NaN; + var infinity = Infinity; + function func($0) { + $0 = $0 | 0; + return 1 << $0 ^ -1; + } + + return { + "func": func + }; +} + +var retasmFunc = asmFunc({ +}); +export var func = retasmFunc.func; diff --git a/test/wasm2js/target_js.wast b/test/wasm2js/target_js.wast new file mode 100644 index 000000000..27373f98e --- /dev/null +++ b/test/wasm2js/target_js.wast @@ -0,0 +1,13 @@ +(module + (func $func (export "func") (param $x i32) (result i32) + ;; Do not turn xor into something that does not express well in JS + ;; when optimizing. + (i32.xor + (i32.shl + (i32.const 1) + (local.get $x) + ) + (i32.const -1) + ) + ) +) |