summaryrefslogtreecommitdiff
path: root/src/emscripten-optimizer/optimizer-shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emscripten-optimizer/optimizer-shared.cpp')
-rw-r--r--src/emscripten-optimizer/optimizer-shared.cpp122
1 files changed, 116 insertions, 6 deletions
diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp
index 1c36efc62..7fe91eeab 100644
--- a/src/emscripten-optimizer/optimizer-shared.cpp
+++ b/src/emscripten-optimizer/optimizer-shared.cpp
@@ -19,6 +19,12 @@ bool isInteger32(double x) {
return isInteger(x) && (x == (int32_t)x || x == (uint32_t)x);
}
+int32_t toInteger32(double x) {
+ if (x == (int32_t)x) return (int32_t)x;
+ assert(x == (uint32_t)x);
+ return (uint32_t)x;
+}
+
int parseInt(const char *str) {
int ret = *str - '0';
while (*(++str)) {
@@ -42,7 +48,7 @@ HeapInfo parseHeap(const char *name) {
return ret;
}
-AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
+AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFround) {
switch (node[0]->getCString()[0]) {
case 'n': {
if (node[0] == NUM) {
@@ -69,7 +75,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
if (node[0] == UNARY_PREFIX) {
switch (node[1]->getCString()[0]) {
case '+': return ASM_DOUBLE;
- case '-': return detectType(node[2], asmData, inVarDef);
+ case '-': return detectType(node[2], asmData, inVarDef, minifiedFround);
case '!': case '~': return ASM_INT;
}
break;
@@ -80,7 +86,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
if (node[0] == CALL) {
if (node[1][0] == NAME) {
IString name = node[1][1]->getIString();
- if (name == MATH_FROUND) return ASM_FLOAT;
+ if (name == MATH_FROUND || name == minifiedFround) return ASM_FLOAT;
else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) return ASM_FLOAT32X4;
else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) return ASM_FLOAT64X2;
else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) return ASM_INT8X16;
@@ -89,7 +95,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
}
return ASM_NONE;
} else if (node[0] == CONDITIONAL) {
- return detectType(node[2], asmData, inVarDef);
+ return detectType(node[2], asmData, inVarDef, minifiedFround);
}
break;
}
@@ -97,7 +103,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
if (node[0] == BINARY) {
switch (node[1]->getCString()[0]) {
case '+': case '-':
- case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef);
+ case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef, minifiedFround);
case '|': case '&': case '^': case '<': case '>': // handles <<, >>, >>=, <=, >=
case '=': case '!': { // handles ==, !=
return ASM_INT;
@@ -108,7 +114,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
}
case 's': {
if (node[0] == SEQ) {
- return detectType(node[2], asmData, inVarDef);
+ return detectType(node[2], asmData, inVarDef, minifiedFround);
} else if (node[0] == SUB) {
assert(node[1][0] == NAME);
HeapInfo info = parseHeap(node[1][1]->getCString());
@@ -123,3 +129,107 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
return ASM_NONE;
}
+static void abort_on(Ref node) {
+ node->stringify(std::cerr);
+ std::cerr << '\n';
+ abort();
+}
+
+AsmSign detectSign(Ref node, IString minifiedFround) {
+ 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_on(node);
+ }
+ } 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_on(node);
+ }
+ } 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], minifiedFround);
+ } else if (type == CALL) {
+ if (node[1][0] == NAME && (node[1][1] == MATH_FROUND || node[1][1] == minifiedFround)) return ASM_NONSIGNED;
+ } else if (type == SEQ) {
+ return detectSign(node[2], minifiedFround);
+ }
+ abort_on(node);
+ abort(); // avoid warning
+}
+
+Ref makeAsmCoercedZero(AsmType type) {
+ switch (type) {
+ case ASM_INT: return ValueBuilder::makeNum(0); break;
+ case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0)); break;
+ case ASM_FLOAT: {
+ if (!ASM_FLOAT_ZERO.isNull()) {
+ return ValueBuilder::makeName(ASM_FLOAT_ZERO);
+ } else {
+ return ValueBuilder::makeCall(MATH_FROUND, ValueBuilder::makeNum(0));
+ }
+ break;
+ }
+ case ASM_FLOAT32X4: {
+ return ValueBuilder::makeCall(SIMD_FLOAT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ break;
+ }
+ case ASM_FLOAT64X2: {
+ return ValueBuilder::makeCall(SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ break;
+ }
+ case ASM_INT8X16: {
+ return ValueBuilder::makeCall(SIMD_INT8X16, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ break;
+ }
+ case ASM_INT16X8: {
+ return ValueBuilder::makeCall(SIMD_INT16X8, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ break;
+ }
+ case ASM_INT32X4: {
+ return ValueBuilder::makeCall(SIMD_INT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0));
+ break;
+ }
+ default: assert(0);
+ }
+ abort();
+}
+
+Ref makeAsmCoercion(Ref node, AsmType type) {
+ switch (type) {
+ case ASM_INT: return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0));
+ case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, node);
+ case ASM_FLOAT: return ValueBuilder::makeCall(MATH_FROUND, node);
+ case ASM_FLOAT32X4: return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node);
+ case ASM_FLOAT64X2: return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node);
+ case ASM_INT8X16: return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node);
+ case ASM_INT16X8: return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node);
+ case ASM_INT32X4: return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node);
+ case ASM_NONE:
+ default: return node; // non-validating code, emit nothing XXX this is dangerous, we should only allow this when we know we are not validating
+ }
+}
+
+Ref makeSigning(Ref node, AsmSign sign) {
+ assert(sign == ASM_SIGNED || sign == ASM_UNSIGNED);
+ return ValueBuilder::makeBinary(node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0));
+}
+