diff options
author | Alon Zakai <alonzakai@gmail.com> | 2019-04-18 09:33:40 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-18 09:33:40 -0700 |
commit | 77c44ecded323174d79a98bd43c3d2c064ac08e4 (patch) | |
tree | 2d31ace4491b200d30b8f7d335da103e0db6db7b | |
parent | 13dd8771d57161618acec8907f739bcdbdcf66cb (diff) | |
download | binaryen-77c44ecded323174d79a98bd43c3d2c064ac08e4.tar.gz binaryen-77c44ecded323174d79a98bd43c3d2c064ac08e4.tar.bz2 binaryen-77c44ecded323174d79a98bd43c3d2c064ac08e4.zip |
Wasm2js: support i64 globals (#2021)
Split them into two i32 globals.
-rw-r--r-- | src/passes/I64ToI32Lowering.cpp | 54 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 4 | ||||
-rw-r--r-- | src/wasm2js.h | 7 | ||||
-rw-r--r-- | test/passes/flatten_i64-to-i32-lowering.txt | 58 | ||||
-rw-r--r-- | test/passes/flatten_i64-to-i32-lowering.wast | 10 | ||||
-rw-r--r-- | test/wasm2js/global_i64.2asm.js | 51 | ||||
-rw-r--r-- | test/wasm2js/global_i64.wast | 9 |
7 files changed, 180 insertions, 13 deletions
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index 42566c0e2..a1686d27d 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -36,9 +36,7 @@ namespace wasm { static Name makeHighName(Name n) { - return Name( - cashew::IString((std::string(n.c_str()) + "$hi").c_str(), false) - ); + return std::string(n.c_str()) + "$hi"; } struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { @@ -104,12 +102,27 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { if (!builder) builder = make_unique<Builder>(*module); // add new globals for high bits for (size_t i = 0, globals = module->globals.size(); i < globals; ++i) { - auto& curr = module->globals[i]; + auto* curr = module->globals[i].get(); if (curr->type != i64) continue; + originallyI64Globals.insert(curr->name); curr->type = i32; - auto* high = ModuleUtils::copyGlobal(curr.get(), *module); - high->name = makeHighName(curr->name); + auto* high = builder->makeGlobal(makeHighName(curr->name), i32, builder->makeConst(Literal(int32_t(0))), Builder::Mutable); module->addGlobal(high); + if (curr->imported()) { + Fatal() << "TODO: imported i64 globals"; + } else { + if (auto* c = curr->init->dynCast<Const>()) { + uint64_t value = c->value.geti64(); + c->value = Literal(uint32_t(value)); + c->type = i32; + high->init = builder->makeConst(Literal(uint32_t(value >> 32))); + } else if (auto* get = curr->init->dynCast<GetGlobal>()) { + high->init = builder->makeGetGlobal(makeHighName(get->name), i32); + } else { + WASM_UNREACHABLE(); + } + curr->init->type = i32; + } } // For functions that return 64-bit values, we use this global variable @@ -425,7 +438,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { return; } TempVar highBits = fetchOutParam(curr->value); - SetLocal* setHigh = builder->makeSetLocal( + auto* setHigh = builder->makeSetLocal( mappedIndex + 1, builder->makeGetLocal(highBits, i32) ); @@ -434,13 +447,30 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { } void visitGetGlobal(GetGlobal* curr) { - if (curr->type != i64) return; - assert(false && "GetGlobal not implemented"); + if (!getFunction()) return; // if in a global init, skip - we already handled that. + if (!originallyI64Globals.count(curr->name)) return; + curr->type = i32; + TempVar highBits = getTemp(); + SetLocal *setHighBits = builder->makeSetLocal( + highBits, + builder->makeGetGlobal( + makeHighName(curr->name), + i32 + ) + ); + Block* result = builder->blockify(setHighBits, curr); + replaceCurrent(result); + setOutParam(result, std::move(highBits)); } void visitSetGlobal(SetGlobal* curr) { - if (curr->type != i64) return; - assert(false && "SetGlobal not implemented"); + if (!originallyI64Globals.count(curr->name)) return; + TempVar highBits = fetchOutParam(curr->value); + auto* setHigh = builder->makeSetGlobal( + makeHighName(curr->name), + builder->makeGetLocal(highBits, i32) + ); + replaceCurrent(builder->makeSequence(curr, setHigh)); } void visitLoad(Load* curr) { @@ -526,6 +556,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { } void visitConst(Const* curr) { + if (!getFunction()) return; // if in a global init, skip - we already handled that. if (curr->type != i64) return; TempVar highBits = getTemp(); Const* lowVal = builder->makeConst( @@ -1606,6 +1637,7 @@ private: std::unordered_map<Expression*, TempVar> highBitVars; std::unordered_map<Name, TempVar> labelHighBitVars; std::unordered_map<Index, Type> tempTypes; + std::unordered_set<Name> originallyI64Globals; Index nextTemp; TempVar getTemp(Type ty = i32) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 8b8285e35..519814cb7 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -907,7 +907,9 @@ Global* Module::addGlobal(Global* curr) { if (getGlobalOrNull(curr->name)) { Fatal() << "Module::addGlobal: " << curr->name << " already exists"; } - globals.push_back(std::unique_ptr<Global>(curr)); + + globals.emplace_back(curr); + globalsMap[curr->name] = curr; return curr; } diff --git a/src/wasm2js.h b/src/wasm2js.h index 927dbac24..ee682f58d 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -638,6 +638,13 @@ void Wasm2JSBuilder::addGlobal(Ref ast, Global* global) { fromName(global->name, NameScope::Top), theValue ); + } else if (auto* get = global->init->dynCast<GetGlobal>()) { + Ref theVar = ValueBuilder::makeVar(); + ast->push_back(theVar); + ValueBuilder::appendToVar(theVar, + fromName(global->name, NameScope::Top), + ValueBuilder::makeName(fromName(get->name, NameScope::Top)) + ); } else { assert(false && "Top init type not supported"); } diff --git a/test/passes/flatten_i64-to-i32-lowering.txt b/test/passes/flatten_i64-to-i32-lowering.txt index 3c3535e53..6863be7e8 100644 --- a/test/passes/flatten_i64-to-i32-lowering.txt +++ b/test/passes/flatten_i64-to-i32-lowering.txt @@ -79,3 +79,61 @@ ) ) ) +(module + (type $0 (func (param i32 i32))) + (type $1 (func)) + (global $f (mut i32) (i32.const -1412567121)) + (global $g (mut i32) (global.get $f)) + (global $f$hi (mut i32) (i32.const 305419896)) + (global $g$hi (mut i32) (global.get $f$hi)) + (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0)) + (export "exp" (func $1)) + (func $call (; 0 ;) (type $0) (param $0 i32) (param $0$hi i32) + (nop) + ) + (func $1 (; 1 ;) (type $1) + (local $0 i32) + (local $0$hi i32) + (local $i64toi32_i32$0 i32) + (block + (block + (local.set $0 + (block (result i32) + (local.set $i64toi32_i32$0 + (global.get $f$hi) + ) + (global.get $f) + ) + ) + (local.set $0$hi + (local.get $i64toi32_i32$0) + ) + ) + (call $call + (block (result i32) + (local.set $i64toi32_i32$0 + (local.get $0$hi) + ) + (local.get $0) + ) + (local.get $i64toi32_i32$0) + ) + (nop) + (block + (global.set $f + (block (result i32) + (local.set $i64toi32_i32$0 + (i32.const 287454020) + ) + (i32.const 1432778632) + ) + ) + (global.set $f$hi + (local.get $i64toi32_i32$0) + ) + ) + (nop) + ) + (nop) + ) +) diff --git a/test/passes/flatten_i64-to-i32-lowering.wast b/test/passes/flatten_i64-to-i32-lowering.wast index 179cac467..def4f3a34 100644 --- a/test/passes/flatten_i64-to-i32-lowering.wast +++ b/test/passes/flatten_i64-to-i32-lowering.wast @@ -4,4 +4,12 @@ (i64.add (i64.const 1) (i64.const 2)) ) ) - +(module + (global $f (mut i64) (i64.const 0x12345678ABCDEFAF)) + (global $g (mut i64) (global.get $f)) + (func $call (param i64)) + (func "exp" + (call $call (global.get $f)) + (global.set $f (i64.const 0x1122334455667788)) + ) +) diff --git a/test/wasm2js/global_i64.2asm.js b/test/wasm2js/global_i64.2asm.js new file mode 100644 index 000000000..8b279f956 --- /dev/null +++ b/test/wasm2js/global_i64.2asm.js @@ -0,0 +1,51 @@ + +function asmFunc(global, env, buffer) { + "use asm"; + 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); + var Math_imul = global.Math.imul; + var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; + var Math_clz32 = global.Math.clz32; + var Math_min = global.Math.min; + var Math_max = global.Math.max; + var Math_floor = global.Math.floor; + var Math_ceil = global.Math.ceil; + var Math_sqrt = global.Math.sqrt; + var abort = env.abort; + var nan = global.NaN; + var infinity = global.Infinity; + var f = 2882400175; + var g = f; + var f$hi = 305419896; + var g$hi = f$hi; + var i64toi32_i32$HIGH_BITS = 0; + function call($0, $0$hi) { + $0 = $0 | 0; + $0$hi = $0$hi | 0; + } + + function $1() { + var i64toi32_i32$0 = 0; + i64toi32_i32$0 = f$hi; + call(f | 0, i64toi32_i32$0 | 0); + i64toi32_i32$0 = 287454020; + f = 1432778632; + f$hi = i64toi32_i32$0; + } + + var FUNCTION_TABLE = []; + return { + exp: $1 + }; +} + +const memasmFunc = new ArrayBuffer(65536); +const retasmFunc = asmFunc({Math,Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,NaN,Infinity}, {abort:function() { throw new Error('abort'); }},memasmFunc); +export const exp = retasmFunc.exp; diff --git a/test/wasm2js/global_i64.wast b/test/wasm2js/global_i64.wast new file mode 100644 index 000000000..99fa419c1 --- /dev/null +++ b/test/wasm2js/global_i64.wast @@ -0,0 +1,9 @@ +(module + (global $f (mut i64) (i64.const 0x12345678ABCDEFAF)) + (global $g (mut i64) (global.get $f)) + (func $call (param i64)) + (func "exp" + (call $call (global.get $f)) + (global.set $f (i64.const 0x1122334455667788)) + ) +) |