summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp23
-rw-r--r--src/binaryen-c.h4
-rw-r--r--src/gen-s-parser.inc14
-rw-r--r--src/ir/ExpressionAnalyzer.cpp1
-rw-r--r--src/ir/ExpressionManipulator.cpp3
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/effects.h9
-rw-r--r--src/ir/utils.h2
-rw-r--r--src/js/binaryen.js-post.js36
-rw-r--r--src/passes/DeadCodeElimination.cpp2
-rw-r--r--src/passes/Print.cpp6
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp1
-rw-r--r--src/tools/fuzzing.h6
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-builder.h1
-rw-r--r--src/wasm-interpreter.h6
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm-stack.h7
-rw-r--r--src/wasm-traversal.h16
-rw-r--r--src/wasm.h14
-rw-r--r--src/wasm/wasm-binary.cpp17
-rw-r--r--src/wasm/wasm-s-parser.cpp4
-rw-r--r--src/wasm/wasm-stack.cpp5
-rw-r--r--src/wasm/wasm-validator.cpp16
-rw-r--r--src/wasm/wasm.cpp2
-rw-r--r--src/wasm2js.h4
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();