diff options
author | Alon Zakai <alonzakai@gmail.com> | 2015-11-17 15:18:31 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2015-11-17 15:21:20 -0800 |
commit | 297d6048ea0c1350f7b6418084fc57ab560677a8 (patch) | |
tree | b1292df286e2fc97e49cca5d08273de1e4deddba | |
parent | eab9bb324d4a88fe94b044bf773fa27c3e842b7a (diff) | |
download | binaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.tar.gz binaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.tar.bz2 binaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.zip |
port detectSign from emscripten asm optimizer, and use it
-rw-r--r-- | src/asm2wasm.h | 5 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer-shared.cpp | 38 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer.h | 9 | ||||
-rw-r--r-- | test/unit.asm.js | 5 | ||||
-rw-r--r-- | test/unit.wast | 15 |
5 files changed, 69 insertions, 3 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 92ef589d2..e44d2b5b1 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -251,9 +251,8 @@ private: return asmToWasmType(detectAsmType(ast, data)); } - bool isUnsignedCoercion(Ref ast) { // TODO: use detectSign? - if (ast[0] == BINARY && ast[1] == TRSHIFT) return true; - return false; + bool isUnsignedCoercion(Ref ast) { + return detectSign(ast) == ASM_UNSIGNED; } // an asm.js binary op can either be a binary or a relational in wasm diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp index 1c36efc62..054716b14 100644 --- a/src/emscripten-optimizer/optimizer-shared.cpp +++ b/src/emscripten-optimizer/optimizer-shared.cpp @@ -123,3 +123,41 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) { return ASM_NONE; } +AsmSign detectSign(Ref node) { + IString type = node[0]->getIString(); + if (type == BINARY) { + IString op = node[1]->getIString(); + switch (op.str[0]) { + case '>': { + if (op == TRSHIFT) return ASM_UNSIGNED; + // fallthrough + } + case '|': case '&': case '^': case '<': case '=': case '!': return ASM_SIGNED; + case '+': case '-': return ASM_FLEXIBLE; + case '*': case '/': return ASM_NONSIGNED; // without a coercion, these are double + default: abort(); + } + } else if (type == UNARY_PREFIX) { + IString op = node[1]->getIString(); + switch (op.str[0]) { + case '-': return ASM_FLEXIBLE; + case '+': return ASM_NONSIGNED; // XXX double + case '~': return ASM_SIGNED; + default: abort(); + } + } else if (type == NUM) { + double value = node[1]->getNumber(); + if (value < 0) return ASM_SIGNED; + if (value > uint32_t(-1) || fmod(value, 1) != 0) return ASM_NONSIGNED; + if (value == int32_t(value)) return ASM_FLEXIBLE; + return ASM_UNSIGNED; + } else if (type == NAME) { + return ASM_FLEXIBLE; + } else if (type == CONDITIONAL) { + return detectSign(node[2]); + } else if (type == CALL) { + if (node[1][0] == NAME && node[1][1] == MATH_FROUND) return ASM_NONSIGNED; + } + abort(); +} + diff --git a/src/emscripten-optimizer/optimizer.h b/src/emscripten-optimizer/optimizer.h index 5edcaad87..fe1c18770 100644 --- a/src/emscripten-optimizer/optimizer.h +++ b/src/emscripten-optimizer/optimizer.h @@ -123,5 +123,14 @@ struct HeapInfo { HeapInfo parseHeap(const char *name); +enum AsmSign { + ASM_FLEXIBLE = 0, // small constants can be signed or unsigned, variables are also flexible + ASM_SIGNED = 1, + ASM_UNSIGNED = 2, + ASM_NONSIGNED = 3, +}; + +extern AsmSign detectSign(cashew::Ref node); + #endif // __optimizer_h__ diff --git a/test/unit.asm.js b/test/unit.asm.js index 686535077..77e2c5585 100644 --- a/test/unit.asm.js +++ b/test/unit.asm.js @@ -59,6 +59,11 @@ function () { function frem() { return +(5.5 % 1.2); } + function big_uint_div_u() { + var x = 0; + x = (4294967295 / 2)&-1; + return x | 0; + } function z() { } diff --git a/test/unit.wast b/test/unit.wast index 34f8a9d50..170236efc 100644 --- a/test/unit.wast +++ b/test/unit.wast @@ -217,6 +217,21 @@ (f64.const 1.2) ) ) + (func $big_uint_div_u (result i32) + (local $x i32) + (block $topmost + (set_local $x + (i32.and + (i32.div_u + (i32.const -2147483648) + (i32.const 2) + ) + (i32.const -1) + ) + ) + (get_local $x) + ) + ) (func $z (nop) ) |