diff options
Diffstat (limited to 'src/emscripten-optimizer/optimizer-shared.cpp')
-rw-r--r-- | src/emscripten-optimizer/optimizer-shared.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp new file mode 100644 index 000000000..1c36efc62 --- /dev/null +++ b/src/emscripten-optimizer/optimizer-shared.cpp @@ -0,0 +1,125 @@ + +#include "optimizer.h" + +using namespace cashew; + +IString ASM_FLOAT_ZERO; + +IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"), + SIMD_INT16X8_CHECK("SIMD_Int16x8_check"), + SIMD_INT32X4_CHECK("SIMD_Int32x4_check"), + SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"), + SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check"); + +bool isInteger(double x) { + return fmod(x, 1) == 0; +} + +bool isInteger32(double x) { + return isInteger(x) && (x == (int32_t)x || x == (uint32_t)x); +} + +int parseInt(const char *str) { + int ret = *str - '0'; + while (*(++str)) { + ret *= 10; + ret += *str - '0'; + } + return ret; +} + +HeapInfo parseHeap(const char *name) { + HeapInfo ret; + if (name[0] != 'H' || name[1] != 'E' || name[2] != 'A' || name[3] != 'P') { + ret.valid = false; + return ret; + } + ret.valid = true; + ret.unsign = name[4] == 'U'; + ret.floaty = name[4] == 'F'; + ret.bits = parseInt(name + (ret.unsign || ret.floaty ? 5 : 4)); + ret.type = !ret.floaty ? ASM_INT : (ret.bits == 64 ? ASM_DOUBLE : ASM_FLOAT); + return ret; +} + +AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) { + switch (node[0]->getCString()[0]) { + case 'n': { + if (node[0] == NUM) { + if (!isInteger(node[1]->getNumber())) return ASM_DOUBLE; + return ASM_INT; + } else if (node[0] == NAME) { + if (asmData) { + AsmType ret = asmData->getType(node[1]->getCString()); + if (ret != ASM_NONE) return ret; + } + if (!inVarDef) { + if (node[1] == INF || node[1] == NaN) return ASM_DOUBLE; + if (node[1] == TEMP_RET0) return ASM_INT; + return ASM_NONE; + } + // We are in a variable definition, where Math_fround(0) optimized into a global constant becomes f0 = Math_fround(0) + if (ASM_FLOAT_ZERO.isNull()) ASM_FLOAT_ZERO = node[1]->getIString(); + else assert(node[1] == ASM_FLOAT_ZERO); + return ASM_FLOAT; + } + break; + } + case 'u': { + if (node[0] == UNARY_PREFIX) { + switch (node[1]->getCString()[0]) { + case '+': return ASM_DOUBLE; + case '-': return detectType(node[2], asmData, inVarDef); + case '!': case '~': return ASM_INT; + } + break; + } + break; + } + case 'c': { + if (node[0] == CALL) { + if (node[1][0] == NAME) { + IString name = node[1][1]->getIString(); + if (name == MATH_FROUND) 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; + else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) return ASM_INT16X8; + else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) return ASM_INT32X4; + } + return ASM_NONE; + } else if (node[0] == CONDITIONAL) { + return detectType(node[2], asmData, inVarDef); + } + break; + } + case 'b': { + if (node[0] == BINARY) { + switch (node[1]->getCString()[0]) { + case '+': case '-': + case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef); + case '|': case '&': case '^': case '<': case '>': // handles <<, >>, >>=, <=, >= + case '=': case '!': { // handles ==, != + return ASM_INT; + } + } + } + break; + } + case 's': { + if (node[0] == SEQ) { + return detectType(node[2], asmData, inVarDef); + } else if (node[0] == SUB) { + assert(node[1][0] == NAME); + HeapInfo info = parseHeap(node[1][1]->getCString()); + if (info.valid) return ASM_NONE; + return info.floaty ? ASM_DOUBLE : ASM_INT; // XXX ASM_FLOAT? + } + break; + } + } + //dump("horrible", node); + //assert(0); + return ASM_NONE; +} + |