summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2015-11-17 15:18:31 -0800
committerAlon Zakai <alonzakai@gmail.com>2015-11-17 15:21:20 -0800
commit297d6048ea0c1350f7b6418084fc57ab560677a8 (patch)
treeb1292df286e2fc97e49cca5d08273de1e4deddba
parenteab9bb324d4a88fe94b044bf773fa27c3e842b7a (diff)
downloadbinaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.tar.gz
binaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.tar.bz2
binaryen-297d6048ea0c1350f7b6418084fc57ab560677a8.zip
port detectSign from emscripten asm optimizer, and use it
-rw-r--r--src/asm2wasm.h5
-rw-r--r--src/emscripten-optimizer/optimizer-shared.cpp38
-rw-r--r--src/emscripten-optimizer/optimizer.h9
-rw-r--r--test/unit.asm.js5
-rw-r--r--test/unit.wast15
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)
)