summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
5 files changed, 168 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;
}