summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2019-04-18 09:33:40 -0700
committerGitHub <noreply@github.com>2019-04-18 09:33:40 -0700
commit77c44ecded323174d79a98bd43c3d2c064ac08e4 (patch)
tree2d31ace4491b200d30b8f7d335da103e0db6db7b
parent13dd8771d57161618acec8907f739bcdbdcf66cb (diff)
downloadbinaryen-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.cpp54
-rw-r--r--src/wasm/wasm.cpp4
-rw-r--r--src/wasm2js.h7
-rw-r--r--test/passes/flatten_i64-to-i32-lowering.txt58
-rw-r--r--test/passes/flatten_i64-to-i32-lowering.wast10
-rw-r--r--test/wasm2js/global_i64.2asm.js51
-rw-r--r--test/wasm2js/global_i64.wast9
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))
+ )
+)