diff options
Diffstat (limited to 'src/emscripten-optimizer/optimizer-shared.cpp')
-rw-r--r-- | src/emscripten-optimizer/optimizer-shared.cpp | 122 |
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)); +} + |