diff options
-rw-r--r-- | src/asm2wasm.h | 60 | ||||
-rw-r--r-- | test/min.asm.js | 18 | ||||
-rw-r--r-- | test/min.fromasm | 13 | ||||
-rw-r--r-- | test/min.fromasm.imprecise | 13 | ||||
-rw-r--r-- | test/unit.asm.js | 19 | ||||
-rw-r--r-- | test/unit.fromasm | 13 | ||||
-rw-r--r-- | test/unit.fromasm.imprecise | 13 |
7 files changed, 148 insertions, 1 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 4c37b7705..7d9b9652b 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -202,6 +202,8 @@ private: IString Math_ceil; IString Math_sqrt; + IString tempDoublePtr; // imported name of tempDoublePtr + // function types. we fill in this information as we see // uses, in the first pass @@ -483,6 +485,13 @@ void Asm2WasmBuilder::processAsm(Ref ast) { } else { assert(module[0] == NAME); moduleName = module[1]->getIString(); + if (moduleName == ENV) { + if (imported[2] == TEMP_DOUBLE_PTR) { + assert(tempDoublePtr.isNull()); + tempDoublePtr = name; + // we don't return here, as we can only optimize out some uses of tDP. So it remains imported + } + } } auto import = allocator.alloc<Import>(); import->name = name; @@ -1404,6 +1413,57 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->type = ret->ifTrue->type; return ret; } else if (what == SEQ) { + // Some (x, y) patterns can be optimized, like bitcasts, + // (HEAP32[tempDoublePtr >> 2] = i, Math_fround(HEAPF32[tempDoublePtr >> 2])); // i32->f32 + // (HEAP32[tempDoublePtr >> 2] = i, +HEAPF32[tempDoublePtr >> 2]); // i32->f32, no fround + // (HEAPF32[tempDoublePtr >> 2] = f, HEAP32[tempDoublePtr >> 2] | 0); // f32->i32 + if (ast[1][0] == ASSIGN && ast[1][2][0] == SUB && ast[1][2][1][0] == NAME && ast[1][2][2][0] == BINARY && ast[1][2][2][1] == RSHIFT && + ast[1][2][2][2][0] == NAME && ast[1][2][2][2][1] == tempDoublePtr && ast[1][2][2][3][0] == NUM && ast[1][2][2][3][1]->getNumber() == 2) { + // (?[tempDoublePtr >> 2] = ?, ?) so far + auto heap = ast[1][2][1][1]->getIString(); + if (views.find(heap) != views.end()) { + AsmType writeType = views[heap].type; + AsmType readType = ASM_NONE; + Ref readValue; + if (ast[2][0] == BINARY && ast[2][1] == OR && ast[2][3][0] == NUM && ast[2][3][1]->getNumber() == 0) { + readType = ASM_INT; + readValue = ast[2][2]; + } else if (ast[2][0] == UNARY_PREFIX && ast[2][1] == PLUS) { + readType = ASM_DOUBLE; + readValue = ast[2][2]; + } else if (ast[2][0] == CALL && ast[2][1][0] == NAME && ast[2][1][1] == Math_fround) { + readType = ASM_FLOAT; + readValue = ast[2][2][0]; + } + if (readType != ASM_NONE) { + if (readValue[0] == SUB && readValue[1][0] == NAME && readValue[2][0] == BINARY && readValue[2][1] == RSHIFT && + readValue[2][2][0] == NAME && readValue[2][2][1] == tempDoublePtr && readValue[2][3][0] == NUM && readValue[2][3][1]->getNumber() == 2) { + // pattern looks right! + Ref writtenValue = ast[1][3]; + if (writeType == ASM_INT && (readType == ASM_FLOAT || readType == ASM_DOUBLE)) { + auto conv = allocator.alloc<Unary>(); + conv->op = ReinterpretInt; + conv->value = process(writtenValue); + conv->type = WasmType::f32; + if (readType == ASM_DOUBLE) { + auto promote = allocator.alloc<Unary>(); + promote->op = PromoteFloat32; + promote->value = conv; + promote->type = WasmType::f64; + return promote; + } + return conv; + } else if (writeType == ASM_FLOAT && readType == ASM_INT) { + auto conv = allocator.alloc<Unary>(); + conv->op = ReinterpretFloat; + conv->value = process(writtenValue); + conv->type = WasmType::i32; + return conv; + } + } + } + } + } auto ret = allocator.alloc<Block>(); ret->list.push_back(process(ast[1])); ret->list.push_back(process(ast[2])); diff --git a/test/min.asm.js b/test/min.asm.js index 77e54caab..ed5d186f5 100644 --- a/test/min.asm.js +++ b/test/min.asm.js @@ -6,6 +6,17 @@ function (global, env, buffer) { var fr = global.Math.fround; + var tDP = env.tempDoublePtr | 0; + + var h8 = new global.Int8Array(buffer); + var h16 = new global.Int16Array(buffer); + var h32 = new global.Int32Array(buffer); + var hU8 = new global.Uint8Array(buffer); + var hU16 = new global.Uint16Array(buffer); + var hU32 = new global.Uint32Array(buffer); + var hF32 = new global.Float32Array(buffer); + var hF64 = new global.Float64Array(buffer); + function floats(f) { f = fr(f); var t = fr(0); @@ -18,6 +29,13 @@ function (global, env, buffer) { n = fr(-(c[k >> 2] = p, fr(g[k >> 2]))); return n; } + function bitcasts(i, f) { + i = i | 0; + f = Math_fround(f); + (h32[tDP >> 2] = i, fr(hF32[tDP >> 2])); // i32->f32 + (h32[tDP >> 2] = i, +hF32[tDP >> 2]); // i32->f32, no fround + (hF32[tDP >> 2] = f, h32[tDP >> 2] | 0); // f32->i32 + } return { floats: floats }; } diff --git a/test/min.fromasm b/test/min.fromasm index 839fd167c..564980a96 100644 --- a/test/min.fromasm +++ b/test/min.fromasm @@ -30,4 +30,17 @@ (get_local $n) ) ) + (func $bitcasts (param $i i32) (param $f f32) + (f32.reinterpret/i32 + (get_local $i) + ) + (f64.promote/f32 + (f32.reinterpret/i32 + (get_local $i) + ) + ) + (i32.reinterpret/f32 + (get_local $f) + ) + ) ) diff --git a/test/min.fromasm.imprecise b/test/min.fromasm.imprecise index 839fd167c..564980a96 100644 --- a/test/min.fromasm.imprecise +++ b/test/min.fromasm.imprecise @@ -30,4 +30,17 @@ (get_local $n) ) ) + (func $bitcasts (param $i i32) (param $f f32) + (f32.reinterpret/i32 + (get_local $i) + ) + (f64.promote/f32 + (f32.reinterpret/i32 + (get_local $i) + ) + ) + (i32.reinterpret/f32 + (get_local $f) + ) + ) ) diff --git a/test/unit.asm.js b/test/unit.asm.js index 5bb84bdcd..cd432da5c 100644 --- a/test/unit.asm.js +++ b/test/unit.asm.js @@ -1,4 +1,4 @@ -function asm() { +function asm(global, env, buffer) { "use asm"; var t = global.NaN, u = global.Infinity; @@ -7,11 +7,21 @@ function asm() { var Math_fround = global.Math.fround; var Math_abs = global.Math.abs; var Math_ceil = global.Math.ceil; + var tempDoublePtr = env.tempDoublePtr | 0; var abort = env.abort; var print = env.print; var h = env.h; + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); + function big_negative() { var temp = 0.0; temp = +-2147483648; @@ -190,6 +200,13 @@ function asm() { print(2); } } + function bitcasts(i, f) { + i = i | 0; + f = Math_fround(f); + (HEAP32[tempDoublePtr >> 2] = i, Math_fround(HEAPF32[tempDoublePtr >> 2])); // i32->f32 + (HEAP32[tempDoublePtr >> 2] = i, +HEAPF32[tempDoublePtr >> 2]); // i32->f32, no fround + (HEAPF32[tempDoublePtr >> 2] = f, HEAP32[tempDoublePtr >> 2] | 0); // f32->i32 + } function z() { } diff --git a/test/unit.fromasm b/test/unit.fromasm index 3db25c78b..d7fce8b8f 100644 --- a/test/unit.fromasm +++ b/test/unit.fromasm @@ -516,6 +516,19 @@ (br $while-in$1) ) ) + (func $bitcasts (param $i i32) (param $f f32) + (f32.reinterpret/i32 + (get_local $i) + ) + (f64.promote/f32 + (f32.reinterpret/i32 + (get_local $i) + ) + ) + (i32.reinterpret/f32 + (get_local $f) + ) + ) (func $z (nop) ) diff --git a/test/unit.fromasm.imprecise b/test/unit.fromasm.imprecise index ef9ccaa5d..6383d6e87 100644 --- a/test/unit.fromasm.imprecise +++ b/test/unit.fromasm.imprecise @@ -512,6 +512,19 @@ (br $while-in$1) ) ) + (func $bitcasts (param $i i32) (param $f f32) + (f32.reinterpret/i32 + (get_local $i) + ) + (f64.promote/f32 + (f32.reinterpret/i32 + (get_local $i) + ) + ) + (i32.reinterpret/f32 + (get_local $f) + ) + ) (func $z (nop) ) |