diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 104 | ||||
-rw-r--r-- | src/ast/ExpressionAnalyzer.cpp | 56 | ||||
-rw-r--r-- | src/ast/ExpressionManipulator.cpp | 6 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 2 |
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; } |