summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/asm2wasm.h104
-rw-r--r--src/ast/ExpressionAnalyzer.cpp56
-rw-r--r--src/ast/ExpressionManipulator.cpp6
-rw-r--r--src/passes/Vacuum.cpp2
-rw-r--r--src/wasm-builder.h2
-rw-r--r--test/threads.asm.js144
-rw-r--r--test/threads.fromasm69
-rw-r--r--test/threads.fromasm.clamp69
-rw-r--r--test/threads.fromasm.clamp.no-opts122
-rw-r--r--test/threads.fromasm.imprecise68
-rw-r--r--test/threads.fromasm.imprecise.no-opts122
-rw-r--r--test/threads.fromasm.no-opts122
12 files changed, 884 insertions, 2 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index e8349627f..044517d12 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -110,6 +110,16 @@ Name I32_CTTZ("i32_cttz"),
MFTCALL("mftCall_"),
MAX_("max"),
MIN_("min"),
+ ATOMICS("Atomics"),
+ ATOMICS_LOAD("load"),
+ ATOMICS_STORE("store"),
+ ATOMICS_EXCHANGE("exchange"),
+ ATOMICS_COMPARE_EXCHANGE("compareExchange"),
+ ATOMICS_ADD("add"),
+ ATOMICS_SUB("sub"),
+ ATOMICS_AND("and"),
+ ATOMICS_OR("or"),
+ ATOMICS_XOR("xor"),
EMSCRIPTEN_DEBUGINFO("emscripten_debuginfo");
// Utilities
@@ -424,6 +434,17 @@ private:
IString Math_max;
IString Math_min;
+ // Imported names of Atomics.*
+ IString Atomics_load;
+ IString Atomics_store;
+ IString Atomics_exchange;
+ IString Atomics_compareExchange;
+ IString Atomics_add;
+ IString Atomics_sub;
+ IString Atomics_and;
+ IString Atomics_or;
+ IString Atomics_xor;
+
IString llvm_cttz_i32;
IString tempDoublePtr; // imported name of tempDoublePtr
@@ -1014,6 +1035,44 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
Math_min = name;
return;
}
+ } else if (module[2] == ATOMICS) {
+ if (imported[2] == ATOMICS_LOAD) {
+ assert(Atomics_load.isNull());
+ Atomics_load = name;
+ return;
+ } else if (imported[2] == ATOMICS_STORE) {
+ assert(Atomics_store.isNull());
+ Atomics_store = name;
+ return;
+ } else if (imported[2] == ATOMICS_EXCHANGE) {
+ assert(Atomics_exchange.isNull());
+ Atomics_exchange = name;
+ return;
+ } else if (imported[2] == ATOMICS_COMPARE_EXCHANGE) {
+ assert(Atomics_compareExchange.isNull());
+ Atomics_compareExchange = name;
+ return;
+ } else if (imported[2] == ATOMICS_ADD) {
+ assert(Atomics_add.isNull());
+ Atomics_add = name;
+ return;
+ } else if (imported[2] == ATOMICS_SUB) {
+ assert(Atomics_sub.isNull());
+ Atomics_sub = name;
+ return;
+ } else if (imported[2] == ATOMICS_AND) {
+ assert(Atomics_and.isNull());
+ Atomics_and = name;
+ return;
+ } else if (imported[2] == ATOMICS_OR) {
+ assert(Atomics_or.isNull());
+ Atomics_or = name;
+ return;
+ } else if (imported[2] == ATOMICS_XOR) {
+ assert(Atomics_xor.isNull());
+ Atomics_xor = name;
+ return;
+ }
}
std::string fullName = module[1]->getCString();
fullName += '.';
@@ -2057,6 +2116,51 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
ret->type = ret->left->type;
return ret;
}
+ if (name == Atomics_load ||
+ name == Atomics_store ||
+ name == Atomics_exchange ||
+ name == Atomics_compareExchange ||
+ name == Atomics_add ||
+ name == Atomics_sub ||
+ name == Atomics_and ||
+ name == Atomics_or ||
+ name == Atomics_xor) {
+ // atomic operation
+ Ref target = ast[2][0];
+ assert(target->isString());
+ IString heap = target->getIString();
+ assert(views.find(heap) != views.end());
+ View& view = views[heap];
+ wasm.memory.shared = true;
+ if (name == Atomics_load) {
+ return builder.makeAtomicLoad(view.bytes, view.signed_, 0, processUnshifted(ast[2][1], view.bytes), asmToWasmType(view.type));
+ } else if (name == Atomics_store) {
+ // asm.js stores return the value, wasm does not
+ auto type = asmToWasmType(view.type);
+ auto temp = Builder::addVar(function, type);
+ return builder.makeSequence(
+ builder.makeAtomicStore(view.bytes, 0, processUnshifted(ast[2][1], view.bytes),
+ builder.makeTeeLocal(temp, process(ast[2][2])),
+ type),
+ builder.makeGetLocal(temp, type)
+ );
+ } else if (name == Atomics_exchange) {
+ return builder.makeAtomicRMW(AtomicRMWOp::Xchg, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ } else if (name == Atomics_compareExchange) {
+ return builder.makeAtomicCmpxchg(view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), process(ast[2][3]), asmToWasmType(view.type));
+ } else if (name == Atomics_add) {
+ return builder.makeAtomicRMW(AtomicRMWOp::Add, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ } else if (name == Atomics_sub) {
+ return builder.makeAtomicRMW(AtomicRMWOp::Sub, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ } else if (name == Atomics_and) {
+ return builder.makeAtomicRMW(AtomicRMWOp::And, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ } else if (name == Atomics_or) {
+ return builder.makeAtomicRMW(AtomicRMWOp::Or, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ } else if (name == Atomics_xor) {
+ return builder.makeAtomicRMW(AtomicRMWOp::Xor, view.bytes, 0, processUnshifted(ast[2][1], view.bytes), process(ast[2][2]), asmToWasmType(view.type));
+ }
+ WASM_UNREACHABLE();
+ }
bool tableCall = false;
if (wasmOnly) {
auto num = ast[2]->size();
diff --git a/src/ast/ExpressionAnalyzer.cpp b/src/ast/ExpressionAnalyzer.cpp
index 421206706..b8e2ae34c 100644
--- a/src/ast/ExpressionAnalyzer.cpp
+++ b/src/ast/ExpressionAnalyzer.cpp
@@ -223,6 +223,34 @@ bool ExpressionAnalyzer::flexibleEqual(Expression* left, Expression* right, Expr
PUSH(Store, value);
break;
}
+ case Expression::Id::AtomicCmpxchgId: {
+ CHECK(AtomicCmpxchg, bytes);
+ CHECK(AtomicCmpxchg, offset);
+ PUSH(AtomicCmpxchg, ptr);
+ PUSH(AtomicCmpxchg, expected);
+ PUSH(AtomicCmpxchg, replacement);
+ break;
+ }
+ case Expression::Id::AtomicRMWId: {
+ CHECK(AtomicRMW, op);
+ CHECK(AtomicRMW, bytes);
+ CHECK(AtomicRMW, offset);
+ PUSH(AtomicRMW, ptr);
+ PUSH(AtomicRMW, value);
+ break;
+ }
+ case Expression::Id::AtomicWaitId: {
+ CHECK(AtomicWait, expectedType);
+ PUSH(AtomicWait, ptr);
+ PUSH(AtomicWait, expected);
+ PUSH(AtomicWait, timeout);
+ break;
+ }
+ case Expression::Id::AtomicWakeId: {
+ PUSH(AtomicWake, ptr);
+ PUSH(AtomicWake, wakeCount);
+ break;
+ }
case Expression::Id::ConstId: {
CHECK(Const, value);
break;
@@ -440,6 +468,34 @@ uint32_t ExpressionAnalyzer::hash(Expression* curr) {
PUSH(Store, value);
break;
}
+ case Expression::Id::AtomicCmpxchgId: {
+ HASH(AtomicCmpxchg, bytes);
+ HASH(AtomicCmpxchg, offset);
+ PUSH(AtomicCmpxchg, ptr);
+ PUSH(AtomicCmpxchg, expected);
+ PUSH(AtomicCmpxchg, replacement);
+ break;
+ }
+ case Expression::Id::AtomicRMWId: {
+ HASH(AtomicRMW, op);
+ HASH(AtomicRMW, bytes);
+ HASH(AtomicRMW, offset);
+ PUSH(AtomicRMW, ptr);
+ PUSH(AtomicRMW, value);
+ break;
+ }
+ case Expression::Id::AtomicWaitId: {
+ HASH(AtomicWait, expectedType);
+ PUSH(AtomicWait, ptr);
+ PUSH(AtomicWait, expected);
+ PUSH(AtomicWait, timeout);
+ break;
+ }
+ case Expression::Id::AtomicWakeId: {
+ PUSH(AtomicWake, ptr);
+ PUSH(AtomicWake, wakeCount);
+ break;
+ }
case Expression::Id::ConstId: {
HASH(Const, value.type);
HASH64(Const, value.getBits());
diff --git a/src/ast/ExpressionManipulator.cpp b/src/ast/ExpressionManipulator.cpp
index cca799e10..f5b303488 100644
--- a/src/ast/ExpressionManipulator.cpp
+++ b/src/ast/ExpressionManipulator.cpp
@@ -117,6 +117,12 @@ Expression* flexibleCopy(Expression* original, Module& wasm, CustomCopier custom
copy(curr->ptr), copy(curr->expected), copy(curr->replacement),
curr->type);
}
+ Expression* visitAtomicWait(AtomicWait* curr) {
+ return builder.makeAtomicWait(copy(curr->ptr), copy(curr->expected), copy(curr->timeout), curr->type);
+ }
+ Expression* visitAtomicWake(AtomicWake* curr) {
+ return builder.makeAtomicWake(copy(curr->ptr), copy(curr->wakeCount));
+ }
Expression* visitConst(Const *curr) {
return builder.makeConst(curr->value);
}
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index bb6c7c296..30b28a75d 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -162,7 +162,7 @@ struct Vacuum : public WalkerPass<PostWalker<Vacuum>> {
}
}
- default: WASM_UNREACHABLE();
+ default: return curr; // assume needed
}
}
}
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 5acac65ee..ad404c337 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -194,7 +194,7 @@ public:
return ret;
}
Load* makeAtomicLoad(unsigned bytes, bool signed_, uint32_t offset, Expression* ptr, WasmType type) {
- Load* load = makeLoad(bytes, signed_, offset, getWasmTypeSize(type), ptr, type);
+ Load* load = makeLoad(bytes, signed_, offset, bytes, ptr, type);
load->isAtomic = true;
return load;
}
diff --git a/test/threads.asm.js b/test/threads.asm.js
new file mode 100644
index 000000000..1253e8c42
--- /dev/null
+++ b/test/threads.asm.js
@@ -0,0 +1,144 @@
+Module["asm"] = (function(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 DYNAMICTOP_PTR=env.DYNAMICTOP_PTR|0;
+ var tempDoublePtr=env.tempDoublePtr|0;
+ var ABORT=env.ABORT|0;
+ var STACKTOP=env.STACKTOP|0;
+ var STACK_MAX=env.STACK_MAX|0;
+
+ var __THREW__ = 0;
+ var threwValue = 0;
+ var setjmpId = 0;
+ var undef = 0;
+ var nan = global.NaN, inf = global.Infinity;
+ var tempInt = 0, tempBigInt = 0, tempBigIntS = 0, tempValue = 0, tempDouble = 0.0;
+ var tempRet0 = 0;
+
+ var __pthread_ptr = 0;
+ var __pthread_is_main_runtime_thread = 0;
+ var __pthread_is_main_browser_thread = 0;
+
+ var Math_floor=global.Math.floor;
+ var Math_abs=global.Math.abs;
+ var Math_sqrt=global.Math.sqrt;
+ var Math_pow=global.Math.pow;
+ var Math_cos=global.Math.cos;
+ var Math_sin=global.Math.sin;
+ var Math_tan=global.Math.tan;
+ var Math_acos=global.Math.acos;
+ var Math_asin=global.Math.asin;
+ var Math_atan=global.Math.atan;
+ var Math_atan2=global.Math.atan2;
+ var Math_exp=global.Math.exp;
+ var Math_log=global.Math.log;
+ var Math_ceil=global.Math.ceil;
+ var Math_imul=global.Math.imul;
+ var Math_min=global.Math.min;
+ var Math_max=global.Math.max;
+ var Math_clz32=global.Math.clz32;
+ var Math_fround=global.Math.fround;
+ var abort=env.abort;
+ var assert=env.assert;
+ var enlargeMemory=env.enlargeMemory;
+ var getTotalMemory=env.getTotalMemory;
+ var abortOnCannotGrowMemory=env.abortOnCannotGrowMemory;
+ var abortStackOverflow=env.abortStackOverflow;
+ var nullFunc_iiii=env.nullFunc_iiii;
+ var nullFunc_i=env.nullFunc_i;
+ var nullFunc_vi=env.nullFunc_vi;
+ var nullFunc_vii=env.nullFunc_vii;
+ var nullFunc_ii=env.nullFunc_ii;
+ var nullFunc_viii=env.nullFunc_viii;
+ var nullFunc_v=env.nullFunc_v;
+ var nullFunc_iii=env.nullFunc_iii;
+ var invoke_iiii=env.invoke_iiii;
+ var invoke_i=env.invoke_i;
+ var invoke_vi=env.invoke_vi;
+ var invoke_vii=env.invoke_vii;
+ var invoke_ii=env.invoke_ii;
+ var invoke_viii=env.invoke_viii;
+ var invoke_v=env.invoke_v;
+ var invoke_iii=env.invoke_iii;
+ var __spawn_thread=env.__spawn_thread;
+ var _putenv=env._putenv;
+ var _emscripten_get_now_is_monotonic=env._emscripten_get_now_is_monotonic;
+ var _fpathconf=env._fpathconf;
+ var ___unlock=env.___unlock;
+ var _emscripten_syscall=env._emscripten_syscall;
+ var ___assert_fail=env.___assert_fail;
+ var _utimes=env._utimes;
+ var ___buildEnvironment=env.___buildEnvironment;
+ var _emscripten_asm_const_i=env._emscripten_asm_const_i;
+ var _clock_gettime=env._clock_gettime;
+ var _emscripten_futex_wait=env._emscripten_futex_wait;
+ var _tzset=env._tzset;
+ var ___setErrNo=env.___setErrNo;
+ var _emscripten_set_current_thread_status_js=env._emscripten_set_current_thread_status_js;
+ var _pthread_getschedparam=env._pthread_getschedparam;
+ var _clearenv=env._clearenv;
+ var _emscripten_futex_wake=env._emscripten_futex_wake;
+ var _sysconf=env._sysconf;
+ var _utime=env._utime;
+ var ___call_main=env.___call_main;
+ var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+ var _confstr=env._confstr;
+ var _getenv=env._getenv;
+ var ___syscall54=env.___syscall54;
+ var _emscripten_has_threading_support=env._emscripten_has_threading_support;
+ var _pthread_create=env._pthread_create;
+ var _emscripten_get_now=env._emscripten_get_now;
+ var _chroot=env._chroot;
+ var ___lock=env.___lock;
+ var ___syscall6=env.___syscall6;
+ var _unsetenv=env._unsetenv;
+ var ___clock_gettime=env.___clock_gettime;
+ var _gettimeofday=env._gettimeofday;
+ var _atexit=env._atexit;
+ var ___syscall140=env.___syscall140;
+ var _emscripten_set_thread_name_js=env._emscripten_set_thread_name_js;
+ var _setenv=env._setenv;
+ var ___syscall146=env.___syscall146;
+ var _emscripten_conditional_set_current_thread_status_js=env._emscripten_conditional_set_current_thread_status_js;
+ var Atomics_load=global.Atomics.load;
+ var Atomics_store=global.Atomics.store;
+ var Atomics_exchange=global.Atomics.exchange;
+ var Atomics_compareExchange=global.Atomics.compareExchange;
+ var Atomics_add=global.Atomics.add;
+ var Atomics_sub=global.Atomics.sub;
+ var Atomics_and=global.Atomics.and;
+ var Atomics_or=global.Atomics.or;
+ var Atomics_xor=global.Atomics.xor;
+ var tempFloat = Math_fround(0);
+ const f0 = Math_fround(0);
+
+ function test() {
+ var $temp = 0;
+ $temp = (Atomics_load(HEAP32, 1229)|0);
+ $temp = (Atomics_load(HEAPU16, 1229)|0);
+ $temp = (Atomics_store(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_exchange(HEAP32, $temp>>2, 1)|0);
+ $temp = (Atomics_compareExchange(HEAP32, $temp>>2, 1, 2)|0);
+ $temp = (Atomics_add(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_sub(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_and(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_or(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_xor(HEAP32, $temp>>2, 0)|0);
+ $temp = (Atomics_xor(HEAPU32, 1024, 0)|0);
+ $temp = (Atomics_xor(HEAP16, 1024, 0)|0);
+ $temp = (Atomics_xor(HEAPU8, 1024, 0)|0);
+ }
+
+ return { test: test };
+})
+;
diff --git a/test/threads.fromasm b/test/threads.fromasm
new file mode 100644
index 000000000..5114d985a
--- /dev/null
+++ b/test/threads.fromasm
@@ -0,0 +1,69 @@
+(module
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (data (get_global $memoryBase) "threads.asm.js")
+ (export "test" (func $test))
+ (func $test
+ (local $0 i32)
+ (drop
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.atomic.rmw.or
+ (i32.atomic.rmw.and
+ (i32.atomic.rmw.sub
+ (i32.atomic.rmw.add
+ (i32.atomic.rmw.cmpxchg
+ (block (result i32)
+ (i32.atomic.store
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ (tee_local $0
+ (i32.const 0)
+ )
+ )
+ (i32.atomic.rmw.xchg
+ (get_local $0)
+ (i32.const 1)
+ )
+ )
+ (i32.const 1)
+ (i32.const 2)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/threads.fromasm.clamp b/test/threads.fromasm.clamp
new file mode 100644
index 000000000..5114d985a
--- /dev/null
+++ b/test/threads.fromasm.clamp
@@ -0,0 +1,69 @@
+(module
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (data (get_global $memoryBase) "threads.asm.js")
+ (export "test" (func $test))
+ (func $test
+ (local $0 i32)
+ (drop
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.atomic.rmw.or
+ (i32.atomic.rmw.and
+ (i32.atomic.rmw.sub
+ (i32.atomic.rmw.add
+ (i32.atomic.rmw.cmpxchg
+ (block (result i32)
+ (i32.atomic.store
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ (tee_local $0
+ (i32.const 0)
+ )
+ )
+ (i32.atomic.rmw.xchg
+ (get_local $0)
+ (i32.const 1)
+ )
+ )
+ (i32.const 1)
+ (i32.const 2)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/threads.fromasm.clamp.no-opts b/test/threads.fromasm.clamp.no-opts
new file mode 100644
index 000000000..1c65d0d36
--- /dev/null
+++ b/test/threads.fromasm.clamp.no-opts
@@ -0,0 +1,122 @@
+(module
+ (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
+ (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
+ (import "env" "ABORT" (global $ABORT$asm2wasm$import i32))
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+ (import "global" "NaN" (global $nan$asm2wasm$import f64))
+ (import "global" "Infinity" (global $inf$asm2wasm$import f64))
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (global $DYNAMICTOP_PTR (mut i32) (get_global $DYNAMICTOP_PTR$asm2wasm$import))
+ (global $tempDoublePtr (mut i32) (get_global $tempDoublePtr$asm2wasm$import))
+ (global $ABORT (mut i32) (get_global $ABORT$asm2wasm$import))
+ (global $STACKTOP (mut i32) (get_global $STACKTOP$asm2wasm$import))
+ (global $STACK_MAX (mut i32) (get_global $STACK_MAX$asm2wasm$import))
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $threwValue (mut i32) (i32.const 0))
+ (global $setjmpId (mut i32) (i32.const 0))
+ (global $undef (mut i32) (i32.const 0))
+ (global $nan (mut f64) (get_global $nan$asm2wasm$import))
+ (global $inf (mut f64) (get_global $inf$asm2wasm$import))
+ (global $tempInt (mut i32) (i32.const 0))
+ (global $tempBigInt (mut i32) (i32.const 0))
+ (global $tempBigIntS (mut i32) (i32.const 0))
+ (global $tempValue (mut i32) (i32.const 0))
+ (global $tempDouble (mut f64) (f64.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (global $__pthread_ptr (mut i32) (i32.const 0))
+ (global $__pthread_is_main_runtime_thread (mut i32) (i32.const 0))
+ (global $__pthread_is_main_browser_thread (mut i32) (i32.const 0))
+ (global $tempFloat (mut f32) (f32.const 0))
+ (global $f0 (mut f32) (f32.const 0))
+ (export "test" (func $test))
+ (func $test
+ (local $$temp i32)
+ (local $1 i32)
+ (set_local $$temp
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ )
+ (set_local $$temp
+ (block (result i32)
+ (i32.atomic.store
+ (get_local $$temp)
+ (tee_local $1
+ (i32.const 0)
+ )
+ )
+ (get_local $1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xchg
+ (get_local $$temp)
+ (i32.const 1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.cmpxchg
+ (get_local $$temp)
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.add
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.sub
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.and
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.or
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/threads.fromasm.imprecise b/test/threads.fromasm.imprecise
new file mode 100644
index 000000000..bad9963c8
--- /dev/null
+++ b/test/threads.fromasm.imprecise
@@ -0,0 +1,68 @@
+(module
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (export "test" (func $test))
+ (func $test
+ (local $0 i32)
+ (drop
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.atomic.rmw.or
+ (i32.atomic.rmw.and
+ (i32.atomic.rmw.sub
+ (i32.atomic.rmw.add
+ (i32.atomic.rmw.cmpxchg
+ (block (result i32)
+ (i32.atomic.store
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ (tee_local $0
+ (i32.const 0)
+ )
+ )
+ (i32.atomic.rmw.xchg
+ (get_local $0)
+ (i32.const 1)
+ )
+ )
+ (i32.const 1)
+ (i32.const 2)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/threads.fromasm.imprecise.no-opts b/test/threads.fromasm.imprecise.no-opts
new file mode 100644
index 000000000..1c65d0d36
--- /dev/null
+++ b/test/threads.fromasm.imprecise.no-opts
@@ -0,0 +1,122 @@
+(module
+ (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
+ (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
+ (import "env" "ABORT" (global $ABORT$asm2wasm$import i32))
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+ (import "global" "NaN" (global $nan$asm2wasm$import f64))
+ (import "global" "Infinity" (global $inf$asm2wasm$import f64))
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (global $DYNAMICTOP_PTR (mut i32) (get_global $DYNAMICTOP_PTR$asm2wasm$import))
+ (global $tempDoublePtr (mut i32) (get_global $tempDoublePtr$asm2wasm$import))
+ (global $ABORT (mut i32) (get_global $ABORT$asm2wasm$import))
+ (global $STACKTOP (mut i32) (get_global $STACKTOP$asm2wasm$import))
+ (global $STACK_MAX (mut i32) (get_global $STACK_MAX$asm2wasm$import))
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $threwValue (mut i32) (i32.const 0))
+ (global $setjmpId (mut i32) (i32.const 0))
+ (global $undef (mut i32) (i32.const 0))
+ (global $nan (mut f64) (get_global $nan$asm2wasm$import))
+ (global $inf (mut f64) (get_global $inf$asm2wasm$import))
+ (global $tempInt (mut i32) (i32.const 0))
+ (global $tempBigInt (mut i32) (i32.const 0))
+ (global $tempBigIntS (mut i32) (i32.const 0))
+ (global $tempValue (mut i32) (i32.const 0))
+ (global $tempDouble (mut f64) (f64.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (global $__pthread_ptr (mut i32) (i32.const 0))
+ (global $__pthread_is_main_runtime_thread (mut i32) (i32.const 0))
+ (global $__pthread_is_main_browser_thread (mut i32) (i32.const 0))
+ (global $tempFloat (mut f32) (f32.const 0))
+ (global $f0 (mut f32) (f32.const 0))
+ (export "test" (func $test))
+ (func $test
+ (local $$temp i32)
+ (local $1 i32)
+ (set_local $$temp
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ )
+ (set_local $$temp
+ (block (result i32)
+ (i32.atomic.store
+ (get_local $$temp)
+ (tee_local $1
+ (i32.const 0)
+ )
+ )
+ (get_local $1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xchg
+ (get_local $$temp)
+ (i32.const 1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.cmpxchg
+ (get_local $$temp)
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.add
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.sub
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.and
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.or
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)
diff --git a/test/threads.fromasm.no-opts b/test/threads.fromasm.no-opts
new file mode 100644
index 000000000..1c65d0d36
--- /dev/null
+++ b/test/threads.fromasm.no-opts
@@ -0,0 +1,122 @@
+(module
+ (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
+ (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
+ (import "env" "ABORT" (global $ABORT$asm2wasm$import i32))
+ (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
+ (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
+ (import "global" "NaN" (global $nan$asm2wasm$import f64))
+ (import "global" "Infinity" (global $inf$asm2wasm$import f64))
+ (import "env" "memory" (memory $0 256 256 shared))
+ (import "env" "table" (table 0 0 anyfunc))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (import "env" "tableBase" (global $tableBase i32))
+ (global $DYNAMICTOP_PTR (mut i32) (get_global $DYNAMICTOP_PTR$asm2wasm$import))
+ (global $tempDoublePtr (mut i32) (get_global $tempDoublePtr$asm2wasm$import))
+ (global $ABORT (mut i32) (get_global $ABORT$asm2wasm$import))
+ (global $STACKTOP (mut i32) (get_global $STACKTOP$asm2wasm$import))
+ (global $STACK_MAX (mut i32) (get_global $STACK_MAX$asm2wasm$import))
+ (global $__THREW__ (mut i32) (i32.const 0))
+ (global $threwValue (mut i32) (i32.const 0))
+ (global $setjmpId (mut i32) (i32.const 0))
+ (global $undef (mut i32) (i32.const 0))
+ (global $nan (mut f64) (get_global $nan$asm2wasm$import))
+ (global $inf (mut f64) (get_global $inf$asm2wasm$import))
+ (global $tempInt (mut i32) (i32.const 0))
+ (global $tempBigInt (mut i32) (i32.const 0))
+ (global $tempBigIntS (mut i32) (i32.const 0))
+ (global $tempValue (mut i32) (i32.const 0))
+ (global $tempDouble (mut f64) (f64.const 0))
+ (global $tempRet0 (mut i32) (i32.const 0))
+ (global $__pthread_ptr (mut i32) (i32.const 0))
+ (global $__pthread_is_main_runtime_thread (mut i32) (i32.const 0))
+ (global $__pthread_is_main_browser_thread (mut i32) (i32.const 0))
+ (global $tempFloat (mut f32) (f32.const 0))
+ (global $f0 (mut f32) (f32.const 0))
+ (export "test" (func $test))
+ (func $test
+ (local $$temp i32)
+ (local $1 i32)
+ (set_local $$temp
+ (i32.atomic.load
+ (i32.const 4916)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.load16_u
+ (i32.const 2458)
+ )
+ )
+ (set_local $$temp
+ (block (result i32)
+ (i32.atomic.store
+ (get_local $$temp)
+ (tee_local $1
+ (i32.const 0)
+ )
+ )
+ (get_local $1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xchg
+ (get_local $$temp)
+ (i32.const 1)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.cmpxchg
+ (get_local $$temp)
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.add
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.sub
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.and
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.or
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (get_local $$temp)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw.xor
+ (i32.const 4096)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw16_u.xor
+ (i32.const 2048)
+ (i32.const 0)
+ )
+ )
+ (set_local $$temp
+ (i32.atomic.rmw8_u.xor
+ (i32.const 1024)
+ (i32.const 0)
+ )
+ )
+ )
+)