diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 23 | ||||
-rw-r--r-- | src/binaryen-c.h | 4 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 14 | ||||
-rw-r--r-- | src/ir/ExpressionAnalyzer.cpp | 1 | ||||
-rw-r--r-- | src/ir/ExpressionManipulator.cpp | 3 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/effects.h | 9 | ||||
-rw-r--r-- | src/ir/utils.h | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 36 | ||||
-rw-r--r-- | src/passes/DeadCodeElimination.cpp | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 6 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 1 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 6 | ||||
-rw-r--r-- | src/wasm-binary.h | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 6 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm-stack.h | 7 | ||||
-rw-r--r-- | src/wasm-traversal.h | 16 | ||||
-rw-r--r-- | src/wasm.h | 14 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 17 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 4 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 5 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 2 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
26 files changed, 186 insertions, 17 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index d8f8163c4..a06e32d87 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -331,6 +331,9 @@ BinaryenExpressionId BinaryenAtomicWaitId(void) { BinaryenExpressionId BinaryenAtomicNotifyId(void) { return Expression::Id::AtomicNotifyId; } +BinaryenExpressionId BinaryenAtomicFenceId(void) { + return Expression::Id::AtomicFenceId; +} BinaryenExpressionId BinaryenSIMDExtractId(void) { return Expression::Id::SIMDExtractId; } @@ -1466,6 +1469,15 @@ BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module, return static_cast<Expression*>(ret); } +BinaryenExpressionRef BinaryenAtomicFence(BinaryenModuleRef module) { + auto* ret = Builder(*(Module*)module).makeAtomicFence(); + + if (tracing) { + traceExpression(ret, "BinaryenAtomicFence"); + } + + return static_cast<Expression*>(ret); +} BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, @@ -2520,6 +2532,17 @@ BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr) { assert(expression->is<AtomicNotify>()); return static_cast<AtomicNotify*>(expression)->notifyCount; } +// AtomicFence +uint8_t BinaryenAtomicFenceGetOrder(BinaryenExpressionRef expr) { + if (tracing) { + std::cout << " BinaryenAtomicFenceGetOrder(expressions[" + << expressions[expr] << "]);\n"; + } + + auto* expression = (Expression*)expr; + assert(expression->is<AtomicFence>()); + return static_cast<AtomicFence*>(expression)->order; +} // SIMDExtract BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr) { if (tracing) { diff --git a/src/binaryen-c.h b/src/binaryen-c.h index b7c99ed1a..0637b65b0 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -119,6 +119,7 @@ BinaryenExpressionId BinaryenAtomicCmpxchgId(void); BinaryenExpressionId BinaryenAtomicRMWId(void); BinaryenExpressionId BinaryenAtomicWaitId(void); BinaryenExpressionId BinaryenAtomicNotifyId(void); +BinaryenExpressionId BinaryenAtomicFenceId(void); BinaryenExpressionId BinaryenSIMDExtractId(void); BinaryenExpressionId BinaryenSIMDReplaceId(void); BinaryenExpressionId BinaryenSIMDShuffleId(void); @@ -670,6 +671,7 @@ BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module, BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef notifyCount); +BinaryenExpressionRef BinaryenAtomicFence(BinaryenModuleRef module); BinaryenExpressionRef BinaryenSIMDExtract(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef vec, @@ -837,6 +839,8 @@ BinaryenExpressionRef BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr); BinaryenExpressionRef BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr); +uint8_t BinaryenAtomicFenceGetOrder(BinaryenExpressionRef expr); + BinaryenOp BinaryenSIMDExtractGetOp(BinaryenExpressionRef expr); BinaryenExpressionRef BinaryenSIMDExtractGetVec(BinaryenExpressionRef expr); uint8_t BinaryenSIMDExtractGetIndex(BinaryenExpressionRef expr); diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 15a73cdf2..68a8140a6 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -7,9 +7,17 @@ char op[27] = {'\0'}; strncpy(op, s[0]->c_str(), 26); switch (op[0]) { - case 'a': - if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); } - goto parse_error; + case 'a': { + switch (op[7]) { + case 'f': + if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); } + goto parse_error; + case 'n': + if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); } + goto parse_error; + default: goto parse_error; + } + } case 'b': { switch (op[1]) { case 'l': diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp index f8f96d5c8..a52d7af90 100644 --- a/src/ir/ExpressionAnalyzer.cpp +++ b/src/ir/ExpressionAnalyzer.cpp @@ -180,6 +180,7 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) { void visitAtomicNotify(AtomicNotify* curr) { visitor.visitAddress(curr->offset); } + void visitAtomicFence(AtomicFence* curr) { visitor.visitInt(curr->order); } void visitSIMDExtract(SIMDExtract* curr) { visitor.visitInt(curr->op); visitor.visitInt(curr->index); diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp index e650f40a7..7b0ee29d7 100644 --- a/src/ir/ExpressionManipulator.cpp +++ b/src/ir/ExpressionManipulator.cpp @@ -157,6 +157,9 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) { return builder.makeAtomicNotify( copy(curr->ptr), copy(curr->notifyCount), curr->offset); } + Expression* visitAtomicFence(AtomicFence* curr) { + return builder.makeAtomicFence(); + } Expression* visitSIMDExtract(SIMDExtract* curr) { return builder.makeSIMDExtract(curr->op, copy(curr->vec), curr->index); } diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 05abb76e1..49b70684b 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -141,6 +141,7 @@ void ReFinalize::visitAtomicRMW(AtomicRMW* curr) { curr->finalize(); } void ReFinalize::visitAtomicCmpxchg(AtomicCmpxchg* curr) { curr->finalize(); } void ReFinalize::visitAtomicWait(AtomicWait* curr) { curr->finalize(); } void ReFinalize::visitAtomicNotify(AtomicNotify* curr) { curr->finalize(); } +void ReFinalize::visitAtomicFence(AtomicFence* curr) { curr->finalize(); } void ReFinalize::visitSIMDExtract(SIMDExtract* curr) { curr->finalize(); } void ReFinalize::visitSIMDReplace(SIMDReplace* curr) { curr->finalize(); } void ReFinalize::visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); } diff --git a/src/ir/effects.h b/src/ir/effects.h index e3997f5d2..c175bed85 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -294,7 +294,14 @@ struct EffectAnalyzer if (!ignoreImplicitTraps) { implicitTrap = true; } - }; + } + void visitAtomicFence(AtomicFence* curr) { + // AtomicFence should not be reordered with any memory operations, so we set + // these to true. + readsMemory = true; + writesMemory = true; + isAtomic = true; + } void visitSIMDExtract(SIMDExtract* curr) {} void visitSIMDReplace(SIMDReplace* curr) {} void visitSIMDShuffle(SIMDShuffle* curr) {} diff --git a/src/ir/utils.h b/src/ir/utils.h index 5c6a09290..43ba2fdde 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -128,6 +128,7 @@ struct ReFinalize void visitAtomicCmpxchg(AtomicCmpxchg* curr); void visitAtomicWait(AtomicWait* curr); void visitAtomicNotify(AtomicNotify* curr); + void visitAtomicFence(AtomicFence* curr); void visitSIMDExtract(SIMDExtract* curr); void visitSIMDReplace(SIMDReplace* curr); void visitSIMDShuffle(SIMDShuffle* curr); @@ -191,6 +192,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> { void visitAtomicCmpxchg(AtomicCmpxchg* curr) { curr->finalize(); } void visitAtomicWait(AtomicWait* curr) { curr->finalize(); } void visitAtomicNotify(AtomicNotify* curr) { curr->finalize(); } + void visitAtomicFence(AtomicFence* curr) { curr->finalize(); } void visitSIMDExtract(SIMDExtract* curr) { curr->finalize(); } void visitSIMDReplace(SIMDReplace* curr) { curr->finalize(); } void visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); } diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 635a10577..799cb30e4 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -70,6 +70,7 @@ Module['AtomicCmpxchgId'] = Module['_BinaryenAtomicCmpxchgId'](); Module['AtomicRMWId'] = Module['_BinaryenAtomicRMWId'](); Module['AtomicWaitId'] = Module['_BinaryenAtomicWaitId'](); Module['AtomicNotifyId'] = Module['_BinaryenAtomicNotifyId'](); +Module['AtomicFenceId'] = Module['_BinaryenAtomicFenceId'](); Module['SIMDExtractId'] = Module['_BinaryenSIMDExtractId'](); Module['SIMDReplaceId'] = Module['_BinaryenSIMDReplaceId'](); Module['SIMDShuffleId'] = Module['_BinaryenSIMDShuffleId'](); @@ -676,7 +677,7 @@ function wrapModule(module, self) { 'ge_u': function(left, right) { return Module['_BinaryenBinary'](module, Module['GeUInt32'], left, right); }, - 'atomic':{ + 'atomic': { 'load': function(offset, ptr) { return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr); }, @@ -764,9 +765,9 @@ function wrapModule(module, self) { return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32']) }, }, - }, - 'wait': function(ptr, expected, timeout) { - return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32']); + 'wait': function(ptr, expected, timeout) { + return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32']); + } }, 'pop': function() { return Module['_BinaryenPop'](module, Module['i32']); @@ -951,7 +952,7 @@ function wrapModule(module, self) { 'ge_u': function(left, right) { return Module['_BinaryenBinary'](module, Module['GeUInt64'], left, right); }, - 'atomic':{ + 'atomic': { 'load': function(offset, ptr) { return Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr); }, @@ -1068,9 +1069,9 @@ function wrapModule(module, self) { return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64']) }, }, - }, - 'wait': function(ptr, expected, timeout) { - return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64']); + 'wait': function(ptr, expected, timeout) { + return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64']); + } }, 'pop': function() { return Module['_BinaryenPop'](module, Module['i64']); @@ -1773,9 +1774,16 @@ function wrapModule(module, self) { self['unreachable'] = function() { return Module['_BinaryenUnreachable'](module); }; - self['notify'] = function(ptr, notifyCount) { - return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount); + + self['atomic'] = { + 'notify': function(ptr, notifyCount) { + return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount); + }, + 'fence': function() { + return Module['_BinaryenAtomicFence'](module); + } }; + self['try'] = function(body, catchBody) { return Module['_BinaryenTry'](module, body, catchBody); }; @@ -1925,7 +1933,7 @@ function wrapModule(module, self) { ); }); }; - self['setMemory'] = function(initial, maximum, exportName, segments, flags, shared) { + self['setMemory'] = function(initial, maximum, exportName, segments, shared) { // segments are assumed to be { passive: bool, offset: expression ref, data: array of 8-bit data } if (!segments) segments = []; return preserveStack(function() { @@ -2321,6 +2329,12 @@ Module['getExpressionInfo'] = function(expr) { 'ptr': Module['_BinaryenAtomicNotifyGetPtr'](expr), 'notifyCount': Module['_BinaryenAtomicNotifyGetNotifyCount'](expr) }; + case Module['AtomicFenceId']: + return { + 'id': id, + 'type': type, + 'order': Module['_BinaryenAtomicFenceGetOrder'](expr) + }; case Module['SIMDExtractId']: return { 'id': id, diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp index f913c5a93..464451763 100644 --- a/src/passes/DeadCodeElimination.cpp +++ b/src/passes/DeadCodeElimination.cpp @@ -298,6 +298,8 @@ struct DeadCodeElimination DELEGATE(AtomicWait); case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify); + case Expression::Id::AtomicFenceId: + DELEGATE(AtomicFence); case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract); case Expression::Id::SIMDReplaceId: diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 0bf61e784..b1e1240ae 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -268,6 +268,7 @@ struct PrintExpressionContents o << " offset=" << curr->offset; } } + void visitAtomicFence(AtomicFence* curr) { printMedium(o, "atomic.fence"); } void visitSIMDExtract(SIMDExtract* curr) { prepareColor(o); switch (curr->op) { @@ -1505,6 +1506,11 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { printFullLine(curr->notifyCount); decIndent(); } + void visitAtomicFence(AtomicFence* curr) { + o << '('; + PrintExpressionContents(currFunction, o).visit(curr); + o << ')'; + } void visitSIMDExtract(SIMDExtract* curr) { o << '('; PrintExpressionContents(currFunction, o).visit(curr); diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 20c30d271..d4c6d5a5d 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -106,6 +106,7 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { void visitAtomicRMW(AtomicRMW* curr) { usesMemory = true; } void visitAtomicWait(AtomicWait* curr) { usesMemory = true; } void visitAtomicNotify(AtomicNotify* curr) { usesMemory = true; } + void visitAtomicFence(AtomicFence* curr) { usesMemory = true; } void visitMemoryInit(MemoryInit* curr) { usesMemory = true; } void visitDataDrop(DataDrop* curr) { usesMemory = true; } void visitMemoryCopy(MemoryCopy* curr) { usesMemory = true; } diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index baf42336d..dde8a0de7 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -953,7 +953,8 @@ private: &Self::makeDrop, &Self::makeNop, &Self::makeGlobalSet) - .add(FeatureSet::BulkMemory, &Self::makeBulkMemory); + .add(FeatureSet::BulkMemory, &Self::makeBulkMemory) + .add(FeatureSet::Atomics, &Self::makeAtomic); return (this->*pick(options))(none); } @@ -2240,6 +2241,9 @@ private: return makeTrivial(type); } wasm.memory.shared = true; + if (type == none) { + return builder.makeAtomicFence(); + } if (type == i32 && oneIn(2)) { if (ATOMIC_WAITS && oneIn(2)) { auto* ptr = makePointer(); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index d01502e9b..b3ac336ee 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -627,6 +627,7 @@ enum ASTNodes { AtomicNotify = 0x00, I32AtomicWait = 0x01, I64AtomicWait = 0x02, + AtomicFence = 0x03, I32AtomicLoad = 0x10, I64AtomicLoad = 0x11, @@ -1232,6 +1233,7 @@ public: bool maybeVisitAtomicCmpxchg(Expression*& out, uint8_t code); bool maybeVisitAtomicWait(Expression*& out, uint8_t code); bool maybeVisitAtomicNotify(Expression*& out, uint8_t code); + bool maybeVisitAtomicFence(Expression*& out, uint8_t code); bool maybeVisitConst(Expression*& out, uint8_t code); bool maybeVisitUnary(Expression*& out, uint8_t code); bool maybeVisitBinary(Expression*& out, uint8_t code); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 4258b9336..3e61b1a36 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -309,6 +309,7 @@ public: notify->finalize(); return notify; } + AtomicFence* makeAtomicFence() { return allocator.alloc<AtomicFence>(); } Store* makeStore(unsigned bytes, uint32_t offset, unsigned align, diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 05d00ed10..d854b20d3 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1029,6 +1029,12 @@ public: return Literal(uint64_t(val)); } } + Flow visitAtomicFence(AtomicFence*) { + // Wasm currently supports only sequentially consistent atomics, in which + // case atomic_fence can be lowered to nothing. + NOTE_ENTER("AtomicFence"); + return Flow(); + } Flow visitCall(Call*) { WASM_UNREACHABLE(); } Flow visitCallIndirect(CallIndirect*) { WASM_UNREACHABLE(); } diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index d6ec89319..b6ef320d5 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -194,6 +194,7 @@ private: makeAtomicCmpxchg(Element& s, Type type, uint8_t bytes, const char* extra); Expression* makeAtomicWait(Element& s, Type type); Expression* makeAtomicNotify(Element& s); + Expression* makeAtomicFence(Element& s); Expression* makeSIMDExtract(Element& s, SIMDExtractOp op, size_t lanes); Expression* makeSIMDReplace(Element& s, SIMDReplaceOp op, size_t lanes); Expression* makeSIMDShuffle(Element& s); diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 562a00684..3a7d7c38e 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -103,6 +103,7 @@ public: void visitAtomicCmpxchg(AtomicCmpxchg* curr); void visitAtomicWait(AtomicWait* curr); void visitAtomicNotify(AtomicNotify* curr); + void visitAtomicFence(AtomicFence* curr); void visitSIMDExtract(SIMDExtract* curr); void visitSIMDReplace(SIMDReplace* curr); void visitSIMDShuffle(SIMDShuffle* curr); @@ -178,6 +179,7 @@ public: void visitAtomicCmpxchg(AtomicCmpxchg* curr); void visitAtomicWait(AtomicWait* curr); void visitAtomicNotify(AtomicNotify* curr); + void visitAtomicFence(AtomicFence* curr); void visitSIMDExtract(SIMDExtract* curr); void visitSIMDReplace(SIMDReplace* curr); void visitSIMDShuffle(SIMDShuffle* curr); @@ -526,6 +528,11 @@ void BinaryenIRWriter<SubType>::visitAtomicNotify(AtomicNotify* curr) { } template<typename SubType> +void BinaryenIRWriter<SubType>::visitAtomicFence(AtomicFence* curr) { + emit(curr); +} + +template<typename SubType> void BinaryenIRWriter<SubType>::visitSIMDExtract(SIMDExtract* curr) { visit(curr->vec); if (curr->type == unreachable) { diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index 5e9925b63..202d136c8 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -54,6 +54,7 @@ template<typename SubType, typename ReturnType = void> struct Visitor { ReturnType visitAtomicCmpxchg(AtomicCmpxchg* curr) { return ReturnType(); } ReturnType visitAtomicWait(AtomicWait* curr) { return ReturnType(); } ReturnType visitAtomicNotify(AtomicNotify* curr) { return ReturnType(); } + ReturnType visitAtomicFence(AtomicFence* curr) { return ReturnType(); } ReturnType visitSIMDExtract(SIMDExtract* curr) { return ReturnType(); } ReturnType visitSIMDReplace(SIMDReplace* curr) { return ReturnType(); } ReturnType visitSIMDShuffle(SIMDShuffle* curr) { return ReturnType(); } @@ -130,6 +131,8 @@ template<typename SubType, typename ReturnType = void> struct Visitor { DELEGATE(AtomicWait); case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify); + case Expression::Id::AtomicFenceId: + DELEGATE(AtomicFence); case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract); case Expression::Id::SIMDReplaceId: @@ -218,6 +221,7 @@ struct OverriddenVisitor { UNIMPLEMENTED(AtomicCmpxchg); UNIMPLEMENTED(AtomicWait); UNIMPLEMENTED(AtomicNotify); + UNIMPLEMENTED(AtomicFence); UNIMPLEMENTED(SIMDExtract); UNIMPLEMENTED(SIMDReplace); UNIMPLEMENTED(SIMDShuffle); @@ -295,6 +299,8 @@ struct OverriddenVisitor { DELEGATE(AtomicWait); case Expression::Id::AtomicNotifyId: DELEGATE(AtomicNotify); + case Expression::Id::AtomicFenceId: + DELEGATE(AtomicFence); case Expression::Id::SIMDExtractId: DELEGATE(SIMDExtract); case Expression::Id::SIMDReplaceId: @@ -412,6 +418,9 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> { ReturnType visitAtomicNotify(AtomicNotify* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } + ReturnType visitAtomicFence(AtomicFence* curr) { + return static_cast<SubType*>(this)->visitExpression(curr); + } ReturnType visitSIMDExtract(SIMDExtract* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } @@ -711,6 +720,9 @@ struct Walker : public VisitorType { static void doVisitAtomicNotify(SubType* self, Expression** currp) { self->visitAtomicNotify((*currp)->cast<AtomicNotify>()); } + static void doVisitAtomicFence(SubType* self, Expression** currp) { + self->visitAtomicFence((*currp)->cast<AtomicFence>()); + } static void doVisitSIMDExtract(SubType* self, Expression** currp) { self->visitSIMDExtract((*currp)->cast<SIMDExtract>()); } @@ -913,6 +925,10 @@ struct PostWalker : public Walker<SubType, VisitorType> { self->pushTask(SubType::scan, &curr->cast<AtomicNotify>()->ptr); break; } + case Expression::Id::AtomicFenceId: { + self->pushTask(SubType::doVisitAtomicFence, currp); + break; + } case Expression::Id::SIMDExtractId: { self->pushTask(SubType::doVisitSIMDExtract, currp); self->pushTask(SubType::scan, &curr->cast<SIMDExtract>()->vec); diff --git a/src/wasm.h b/src/wasm.h index d4441259e..e7d83ace3 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -468,6 +468,7 @@ public: AtomicCmpxchgId, AtomicWaitId, AtomicNotifyId, + AtomicFenceId, SIMDExtractId, SIMDReplaceId, SIMDShuffleId, @@ -785,6 +786,17 @@ public: void finalize(); }; +class AtomicFence : public SpecificExpression<Expression::AtomicFenceId> { +public: + AtomicFence() = default; + AtomicFence(MixedArena& allocator) : AtomicFence() {} + + // Current wasm threads only supports sequentialy consistent atomics, but + // other orderings may be added in the future. This field is reserved for + // that, and currently set to 0. + uint8_t order = 0; +}; + class SIMDExtract : public SpecificExpression<Expression::SIMDExtractId> { public: SIMDExtract() = default; @@ -1243,7 +1255,7 @@ class Event : public Importable { public: Name name; // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible. - uint32_t attribute; + uint32_t attribute = WASM_EVENT_ATTRIBUTE_EXCEPTION; // Type string in the format of function type. Return type is considered as a // void type. So if you have an event whose type is (i32, i32), the type // string will be "vii". diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d75973ab0..b7daeda5a 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2302,6 +2302,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitAtomicNotify(curr, code)) { break; } + if (maybeVisitAtomicFence(curr, code)) { + break; + } throwError("invalid code after atomic prefix: " + std::to_string(code)); break; } @@ -3172,6 +3175,20 @@ bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) { return true; } +bool WasmBinaryBuilder::maybeVisitAtomicFence(Expression*& out, uint8_t code) { + if (code != BinaryConsts::AtomicFence) { + return false; + } + auto* curr = allocator.alloc<AtomicFence>(); + if (debug) { + std::cerr << "zz node: AtomicFence" << std::endl; + } + curr->order = getU32LEB(); + curr->finalize(); + out = curr; + return true; +} + bool WasmBinaryBuilder::maybeVisitConst(Expression*& out, uint8_t code) { Const* curr; if (debug) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 39f6b0a9f..3a1e0db09 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1421,6 +1421,10 @@ Expression* SExpressionWasmBuilder::makeAtomicNotify(Element& s) { return ret; } +Expression* SExpressionWasmBuilder::makeAtomicFence(Element& s) { + return allocator.alloc<AtomicFence>(); +} + static uint8_t parseLaneIndex(const Element* s, size_t lanes) { const char* str = s->c_str(); char* end; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index cb60c50f9..faa06330b 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -422,6 +422,11 @@ void BinaryInstWriter::visitAtomicNotify(AtomicNotify* curr) { emitMemoryAccess(4, 4, 0); } +void BinaryInstWriter::visitAtomicFence(AtomicFence* curr) { + o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicFence) + << int8_t(curr->order); +} + void BinaryInstWriter::visitSIMDExtract(SIMDExtract* curr) { o << int8_t(BinaryConsts::SIMDPrefix); switch (curr->op) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 339ad6f68..9b1220371 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -270,6 +270,7 @@ public: void visitAtomicCmpxchg(AtomicCmpxchg* curr); void visitAtomicWait(AtomicWait* curr); void visitAtomicNotify(AtomicNotify* curr); + void visitAtomicFence(AtomicFence* curr); void visitSIMDExtract(SIMDExtract* curr); void visitSIMDReplace(SIMDReplace* curr); void visitSIMDShuffle(SIMDShuffle* curr); @@ -917,6 +918,21 @@ void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) { "AtomicNotify notifyCount type must be i32"); } +void FunctionValidator::visitAtomicFence(AtomicFence* curr) { + shouldBeTrue( + getModule()->memory.exists, curr, "Memory operations require a memory"); + shouldBeTrue(getModule()->features.hasAtomics(), + curr, + "Atomic operation (atomics are disabled)"); + shouldBeFalse(!getModule()->memory.shared, + curr, + "Atomic operation with non-shared memory"); + shouldBeTrue(curr->order == 0, + curr, + "Currently only sequentially consistent atomics are supported, " + "so AtomicFence's order should be 0"); +} + void FunctionValidator::visitSIMDExtract(SIMDExtract* curr) { shouldBeTrue( getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index f8791286c..b13797c89 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -147,6 +147,8 @@ const char* getExpressionName(Expression* curr) { return "atomic_wait"; case Expression::Id::AtomicNotifyId: return "atomic_notify"; + case Expression::Id::AtomicFenceId: + return "atomic_fence"; case Expression::Id::SIMDExtractId: return "simd_extract"; case Expression::Id::SIMDReplaceId: diff --git a/src/wasm2js.h b/src/wasm2js.h index 624847f7d..54a06578f 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -1816,6 +1816,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE(); } + Ref visitAtomicFence(AtomicFence* curr) { + // Sequentially consistent fences can be lowered to no operation + return ValueBuilder::makeToplevel(); + } Ref visitSIMDExtract(SIMDExtract* curr) { unimplemented(curr); WASM_UNREACHABLE(); |