summaryrefslogtreecommitdiff
path: root/src/asm2wasm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/asm2wasm.h')
-rw-r--r--src/asm2wasm.h104
1 files changed, 104 insertions, 0 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();