summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/ExpressionManipulator.cpp375
-rw-r--r--src/wasm-delegations-fields.h584
2 files changed, 664 insertions, 295 deletions
diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp
index 648a872fc..51fc5af27 100644
--- a/src/ir/ExpressionManipulator.cpp
+++ b/src/ir/ExpressionManipulator.cpp
@@ -23,306 +23,91 @@ namespace ExpressionManipulator {
Expression*
flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
- struct Copier : public OverriddenVisitor<Copier, Expression*> {
- Module& wasm;
- CustomCopier custom;
+ // Perform the copy using a stack of tasks (avoiding recusion).
+ struct CopyTask {
+ // The thing to copy.
+ Expression* original;
+ // The location of the pointer to write the copy to.
+ Expression** destPointer;
+ };
+ std::vector<CopyTask> tasks;
+ Expression* ret;
+ tasks.push_back({original, &ret});
+ while (!tasks.empty()) {
+ auto task = tasks.back();
+ tasks.pop_back();
+ // If the custom copier handled this one, we have nothing to do.
+ auto* copy = custom(task.original);
+ if (copy) {
+ *task.destPointer = copy;
+ continue;
+ }
+ // If the original is a null, just copy that. (This can happen for an
+ // optional child.)
+ auto* original = task.original;
+ if (original == nullptr) {
+ *task.destPointer = nullptr;
+ continue;
+ }
+ // Allocate a new copy, and copy the fields.
- Builder builder;
+#define DELEGATE_ID original->_id
- Copier(Module& wasm, CustomCopier custom)
- : wasm(wasm), custom(custom), builder(wasm) {}
+// Allocate a new expression of the right type, and create cast versions of it
+// for later operations.
+#define DELEGATE_START(id) \
+ copy = wasm.allocator.alloc<id>(); \
+ auto* castOriginal = original->cast<id>(); \
+ WASM_UNUSED(castOriginal); \
+ auto* castCopy = copy->cast<id>(); \
+ WASM_UNUSED(castCopy);
- Expression* copy(Expression* curr) {
- if (!curr) {
- return nullptr;
- }
- auto* ret = custom(curr);
- if (ret) {
- return ret;
- }
- return OverriddenVisitor<Copier, Expression*>::visit(curr);
- }
+// Handle each type of field, copying it appropriately.
+#define DELEGATE_FIELD_CHILD(id, name) \
+ tasks.push_back({castOriginal->name, &castCopy->name});
- Expression* visitBlock(Block* curr) {
- ExpressionList list(wasm.allocator);
- for (Index i = 0; i < curr->list.size(); i++) {
- list.push_back(copy(curr->list[i]));
- }
- return builder.makeBlock(curr->name, list, curr->type);
- }
- Expression* visitIf(If* curr) {
- return builder.makeIf(copy(curr->condition),
- copy(curr->ifTrue),
- copy(curr->ifFalse),
- curr->type);
- }
- Expression* visitLoop(Loop* curr) {
- return builder.makeLoop(curr->name, copy(curr->body), curr->type);
- }
- Expression* visitBreak(Break* curr) {
- return builder.makeBreak(
- curr->name, copy(curr->value), copy(curr->condition));
- }
- Expression* visitSwitch(Switch* curr) {
- return builder.makeSwitch(curr->targets,
- curr->default_,
- copy(curr->condition),
- copy(curr->value));
- }
- Expression* visitCall(Call* curr) {
- auto* ret =
- builder.makeCall(curr->target, {}, curr->type, curr->isReturn);
- for (Index i = 0; i < curr->operands.size(); i++) {
- ret->operands.push_back(copy(curr->operands[i]));
- }
- return ret;
- }
- Expression* visitCallIndirect(CallIndirect* curr) {
- std::vector<Expression*> copiedOps;
- for (auto op : curr->operands) {
- copiedOps.push_back(copy(op));
- }
- return builder.makeCallIndirect(
- copy(curr->target), copiedOps, curr->sig, curr->isReturn);
- }
- Expression* visitLocalGet(LocalGet* curr) {
- return builder.makeLocalGet(curr->index, curr->type);
- }
- Expression* visitLocalSet(LocalSet* curr) {
- if (curr->isTee()) {
- return builder.makeLocalTee(curr->index, copy(curr->value), curr->type);
- } else {
- return builder.makeLocalSet(curr->index, copy(curr->value));
- }
- }
- Expression* visitGlobalGet(GlobalGet* curr) {
- return builder.makeGlobalGet(curr->name, curr->type);
- }
- Expression* visitGlobalSet(GlobalSet* curr) {
- return builder.makeGlobalSet(curr->name, copy(curr->value));
- }
- Expression* visitLoad(Load* curr) {
- if (curr->isAtomic) {
- return builder.makeAtomicLoad(
- curr->bytes, curr->offset, copy(curr->ptr), curr->type);
- }
- return builder.makeLoad(curr->bytes,
- LoadUtils::isSignRelevant(curr) ? curr->signed_
- : false,
- curr->offset,
- curr->align,
- copy(curr->ptr),
- curr->type);
- }
- Expression* visitStore(Store* curr) {
- if (curr->isAtomic) {
- return builder.makeAtomicStore(curr->bytes,
- curr->offset,
- copy(curr->ptr),
- copy(curr->value),
- curr->valueType);
- }
- return builder.makeStore(curr->bytes,
- curr->offset,
- curr->align,
- copy(curr->ptr),
- copy(curr->value),
- curr->valueType);
- }
- Expression* visitAtomicRMW(AtomicRMW* curr) {
- return builder.makeAtomicRMW(curr->op,
- curr->bytes,
- curr->offset,
- copy(curr->ptr),
- copy(curr->value),
- curr->type);
- }
- Expression* visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- return builder.makeAtomicCmpxchg(curr->bytes,
- curr->offset,
- 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->expectedType,
- curr->offset);
- }
- Expression* visitAtomicNotify(AtomicNotify* curr) {
- 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);
- }
- Expression* visitSIMDReplace(SIMDReplace* curr) {
- return builder.makeSIMDReplace(
- curr->op, copy(curr->vec), curr->index, copy(curr->value));
- }
- Expression* visitSIMDShuffle(SIMDShuffle* curr) {
- return builder.makeSIMDShuffle(
- copy(curr->left), copy(curr->right), curr->mask);
- }
- Expression* visitSIMDTernary(SIMDTernary* curr) {
- return builder.makeSIMDTernary(
- curr->op, copy(curr->a), copy(curr->b), copy(curr->c));
- }
- Expression* visitSIMDShift(SIMDShift* curr) {
- return builder.makeSIMDShift(
- curr->op, copy(curr->vec), copy(curr->shift));
- }
- Expression* visitSIMDLoad(SIMDLoad* curr) {
- return builder.makeSIMDLoad(
- curr->op, curr->offset, curr->align, copy(curr->ptr));
- }
- Expression* visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
- return builder.makeSIMDLoadStoreLane(curr->op,
- curr->offset,
- curr->align,
- curr->index,
- copy(curr->ptr),
- copy(curr->vec));
- }
- Expression* visitConst(Const* curr) {
- return builder.makeConst(curr->value);
- }
- Expression* visitMemoryInit(MemoryInit* curr) {
- return builder.makeMemoryInit(
- curr->segment, copy(curr->dest), copy(curr->offset), copy(curr->size));
- }
- Expression* visitDataDrop(DataDrop* curr) {
- return builder.makeDataDrop(curr->segment);
- }
- Expression* visitMemoryCopy(MemoryCopy* curr) {
- return builder.makeMemoryCopy(
- copy(curr->dest), copy(curr->source), copy(curr->size));
- }
- Expression* visitMemoryFill(MemoryFill* curr) {
- return builder.makeMemoryFill(
- copy(curr->dest), copy(curr->value), copy(curr->size));
- }
- Expression* visitUnary(Unary* curr) {
- return builder.makeUnary(curr->op, copy(curr->value));
- }
- Expression* visitBinary(Binary* curr) {
- return builder.makeBinary(curr->op, copy(curr->left), copy(curr->right));
- }
- Expression* visitSelect(Select* curr) {
- return builder.makeSelect(copy(curr->condition),
- copy(curr->ifTrue),
- copy(curr->ifFalse),
- curr->type);
- }
- Expression* visitDrop(Drop* curr) {
- return builder.makeDrop(copy(curr->value));
- }
- Expression* visitReturn(Return* curr) {
- return builder.makeReturn(copy(curr->value));
- }
- Expression* visitMemorySize(MemorySize* curr) {
- return builder.makeMemorySize();
- }
- Expression* visitMemoryGrow(MemoryGrow* curr) {
- return builder.makeMemoryGrow(copy(curr->delta));
- }
- Expression* visitRefNull(RefNull* curr) {
- return builder.makeRefNull(curr->type);
- }
- Expression* visitRefIsNull(RefIsNull* curr) {
- return builder.makeRefIsNull(copy(curr->value));
- }
- Expression* visitRefFunc(RefFunc* curr) {
- return builder.makeRefFunc(curr->func);
- }
- Expression* visitRefEq(RefEq* curr) {
- return builder.makeRefEq(copy(curr->left), copy(curr->right));
- }
- Expression* visitTry(Try* curr) {
- return builder.makeTry(
- copy(curr->body), copy(curr->catchBody), curr->type);
- }
- Expression* visitThrow(Throw* curr) {
- std::vector<Expression*> operands;
- for (Index i = 0; i < curr->operands.size(); i++) {
- operands.push_back(copy(curr->operands[i]));
- }
- return builder.makeThrow(curr->event, std::move(operands));
- }
- Expression* visitRethrow(Rethrow* curr) {
- return builder.makeRethrow(copy(curr->exnref));
- }
- Expression* visitBrOnExn(BrOnExn* curr) {
- return builder.makeBrOnExn(
- curr->name, curr->event, copy(curr->exnref), curr->sent);
- }
- Expression* visitNop(Nop* curr) { return builder.makeNop(); }
- Expression* visitUnreachable(Unreachable* curr) {
- return builder.makeUnreachable();
- }
- Expression* visitPop(Pop* curr) { return builder.makePop(curr->type); }
- Expression* visitTupleMake(TupleMake* curr) {
- std::vector<Expression*> operands;
- for (auto* op : curr->operands) {
- operands.push_back(copy(op));
- }
- return builder.makeTupleMake(std::move(operands));
- }
- Expression* visitTupleExtract(TupleExtract* curr) {
- return builder.makeTupleExtract(copy(curr->tuple), curr->index);
- }
- Expression* visitI31New(I31New* curr) {
- return builder.makeI31New(copy(curr->value));
- }
- Expression* visitI31Get(I31Get* curr) {
- return builder.makeI31Get(copy(curr->i31), curr->signed_);
- }
- Expression* visitRefTest(RefTest* curr) {
- WASM_UNREACHABLE("TODO (gc): ref.test");
- }
- Expression* visitRefCast(RefCast* curr) {
- WASM_UNREACHABLE("TODO (gc): ref.cast");
- }
- Expression* visitBrOnCast(BrOnCast* curr) {
- WASM_UNREACHABLE("TODO (gc): br_on_cast");
- }
- Expression* visitRttCanon(RttCanon* curr) {
- WASM_UNREACHABLE("TODO (gc): rtt.canon");
- }
- Expression* visitRttSub(RttSub* curr) {
- WASM_UNREACHABLE("TODO (gc): rtt.sub");
- }
- Expression* visitStructNew(StructNew* curr) {
- WASM_UNREACHABLE("TODO (gc): struct.new");
- }
- Expression* visitStructGet(StructGet* curr) {
- WASM_UNREACHABLE("TODO (gc): struct.get");
- }
- Expression* visitStructSet(StructSet* curr) {
- WASM_UNREACHABLE("TODO (gc): struct.set");
- }
- Expression* visitArrayNew(ArrayNew* curr) {
- WASM_UNREACHABLE("TODO (gc): array.new");
- }
- Expression* visitArrayGet(ArrayGet* curr) {
- WASM_UNREACHABLE("TODO (gc): array.get");
- }
- Expression* visitArraySet(ArraySet* curr) {
- WASM_UNREACHABLE("TODO (gc): array.set");
- }
- Expression* visitArrayLen(ArrayLen* curr) {
- WASM_UNREACHABLE("TODO (gc): array.len");
- }
- };
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name) \
+ castCopy->name.resize(castOriginal->name.size()); \
+ for (Index i = 0; i < castOriginal->name.size(); i++) { \
+ tasks.push_back({castOriginal->name[i], &castCopy->name[i]}); \
+ }
+
+#define COPY_FIELD(name) castCopy->name = castOriginal->name;
+
+#define DELEGATE_FIELD_INT(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_LITERAL(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_NAME(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_SCOPE_NAME(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_SIGNATURE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_TYPE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_ADDRESS(id, name) COPY_FIELD(name)
- Copier copier(wasm, custom);
- return copier.copy(original);
+#define COPY_FIELD_LIST(name) \
+ for (Index i = 0; i < castOriginal->name.size(); i++) { \
+ castCopy->name[i] = castOriginal->name[i]; \
+ }
+
+#define COPY_VECTOR(name) \
+ castCopy->name.resize(castOriginal->name.size()); \
+ COPY_FIELD_LIST(name)
+
+#define COPY_ARRAY(name) \
+ assert(castCopy->name.size() == castOriginal->name.size()); \
+ COPY_FIELD_LIST(name)
+
+#define DELEGATE_FIELD_SCOPE_NAME_VECTOR(id, name) COPY_VECTOR(name)
+
+#define DELEGATE_FIELD_INT_ARRAY(id, name) COPY_ARRAY(name)
+
+#include "wasm-delegations-fields.h"
+
+ // The type can be simply copied.
+ copy->type = original->type;
+
+ // Write the copy to where it should be referred to.
+ *task.destPointer = copy;
+ }
+ return ret;
}
// Splice an item into the middle of a block's list
diff --git a/src/wasm-delegations-fields.h b/src/wasm-delegations-fields.h
new file mode 100644
index 000000000..fef4a9f7c
--- /dev/null
+++ b/src/wasm-delegations-fields.h
@@ -0,0 +1,584 @@
+/*
+ * Copyright 2020 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Implements a switch on an expression class ID, and has a case for each id
+// in which it runs delegates on the fields and immediates. All the delegates
+// are optional, so you can just provide what you want, and no code will be
+// emitted for the others.
+//
+// (The only mandatory thing to define is DELEGATE_ID which is the key for the
+// switch.)
+//
+// All #defines used here are undefed automatically at the end for you.
+//
+// Child pointers are emitted in reverse order (which is convenient for walking
+// by pushing them to a stack first).
+
+// Emits code at the start of the case for a class.
+#ifndef DELEGATE_START
+#define DELEGATE_START(id)
+#endif
+
+// Emits code at the end of the case for a class.
+#ifndef DELEGATE_END
+#define DELEGATE_END(id)
+#endif
+
+// Emits code to handle a child pointer.
+#ifndef DELEGATE_FIELD_CHILD
+#define DELEGATE_FIELD_CHILD(id, name)
+#endif
+
+// Emits code to handle an optional child pointer (if this is not defined, then
+// DELEGATE_FIELD_CHILD is called on it).
+#ifndef DELEGATE_FIELD_OPTIONAL_CHILD
+#define DELEGATE_FIELD_OPTIONAL_CHILD(id, name) DELEGATE_FIELD_CHILD(id, name)
+#endif
+
+// Emits code to handle a variable-sized vector of child pointers.
+#ifndef DELEGATE_FIELD_CHILD_VECTOR
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#endif
+
+// Emits code to handle an integer value (bool, enum, Index, int32, or int64).
+#ifndef DELEGATE_FIELD_INT
+#define DELEGATE_FIELD_INT(id, name)
+#endif
+
+// Emits code to handle a std::array of fixed size of integer values (like a
+// SIMD mask).
+#ifndef DELEGATE_FIELD_INT_ARRAY
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+#endif
+
+// Emits code to handle a Literal.
+#ifndef DELEGATE_FIELD_LITERAL
+#define DELEGATE_FIELD_LITERAL(id, name)
+#endif
+
+// Emits code to handle a name (like a call target).
+#ifndef DELEGATE_FIELD_NAME
+#define DELEGATE_FIELD_NAME(id, name)
+#endif
+
+// Emits code to handle a scope name (like a br target).
+#ifndef DELEGATE_FIELD_SCOPE_NAME
+#define DELEGATE_FIELD_SCOPE_NAME(id, name)
+#endif
+
+// Emits code to handle a variable-sized vector of scope names (like a switch's
+// targets).
+#ifndef DELEGATE_FIELD_SCOPE_NAME_VECTOR
+#define DELEGATE_FIELD_SCOPE_NAME_VECTOR(id, name)
+#endif
+
+// Emits code to handle a Signature.
+#ifndef DELEGATE_FIELD_SIGNATURE
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#endif
+
+// Emits code to handle a type.
+#ifndef DELEGATE_FIELD_TYPE
+#define DELEGATE_FIELD_TYPE(id, name)
+#endif
+
+// Emits code to handle an address.
+#ifndef DELEGATE_FIELD_ADDRESS
+#define DELEGATE_FIELD_ADDRESS(id, name)
+#endif
+
+switch (DELEGATE_ID) {
+ case Expression::Id::InvalidId:
+ case Expression::Id::NumExpressionIds: {
+ WASM_UNREACHABLE("unexpected expression type");
+ }
+ case Expression::Id::BlockId: {
+ DELEGATE_START(Block);
+ DELEGATE_FIELD_CHILD_VECTOR(Block, list);
+ DELEGATE_FIELD_SCOPE_NAME(Block, name);
+ DELEGATE_END(Block);
+ break;
+ }
+ case Expression::Id::IfId: {
+ DELEGATE_START(If);
+ DELEGATE_FIELD_OPTIONAL_CHILD(If, ifFalse);
+ DELEGATE_FIELD_CHILD(If, ifTrue);
+ DELEGATE_FIELD_CHILD(If, condition);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::LoopId: {
+ DELEGATE_START(Loop);
+ DELEGATE_FIELD_CHILD(Loop, body);
+ DELEGATE_FIELD_SCOPE_NAME(Loop, name);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::BreakId: {
+ DELEGATE_START(Break);
+ DELEGATE_FIELD_OPTIONAL_CHILD(Break, condition);
+ DELEGATE_FIELD_OPTIONAL_CHILD(Break, value);
+ DELEGATE_FIELD_SCOPE_NAME(Break, name);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SwitchId: {
+ DELEGATE_START(Switch);
+ DELEGATE_FIELD_CHILD(Switch, condition);
+ DELEGATE_FIELD_OPTIONAL_CHILD(Switch, value);
+ DELEGATE_FIELD_SCOPE_NAME(Switch, default_);
+ DELEGATE_FIELD_SCOPE_NAME_VECTOR(Switch, targets);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::CallId: {
+ DELEGATE_START(Call);
+ DELEGATE_FIELD_CHILD_VECTOR(Call, operands);
+ DELEGATE_FIELD_NAME(Call, target);
+ DELEGATE_FIELD_INT(Call, isReturn);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::CallIndirectId: {
+ DELEGATE_START(CallIndirect);
+ DELEGATE_FIELD_CHILD(CallIndirect, target);
+ DELEGATE_FIELD_CHILD_VECTOR(CallIndirect, operands);
+ DELEGATE_FIELD_SIGNATURE(CallIndirect, sig);
+ DELEGATE_FIELD_INT(CallIndirect, isReturn);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::LocalGetId: {
+ DELEGATE_START(LocalGet);
+ DELEGATE_FIELD_INT(LocalGet, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::LocalSetId: {
+ DELEGATE_START(LocalSet);
+ DELEGATE_FIELD_CHILD(LocalSet, value);
+ DELEGATE_FIELD_INT(LocalSet, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::GlobalGetId: {
+ DELEGATE_START(GlobalGet);
+ DELEGATE_FIELD_INT(GlobalGet, name);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::GlobalSetId: {
+ DELEGATE_START(GlobalSet);
+ DELEGATE_FIELD_CHILD(GlobalSet, value);
+ DELEGATE_FIELD_INT(GlobalSet, name);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::LoadId: {
+ DELEGATE_START(Load);
+ DELEGATE_FIELD_CHILD(Load, ptr);
+ DELEGATE_FIELD_INT(Load, bytes);
+ DELEGATE_FIELD_INT(Load, signed_);
+ DELEGATE_FIELD_ADDRESS(Load, offset);
+ DELEGATE_FIELD_ADDRESS(Load, align);
+ DELEGATE_FIELD_INT(Load, isAtomic);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::StoreId: {
+ DELEGATE_START(Store);
+ DELEGATE_FIELD_CHILD(Store, value);
+ DELEGATE_FIELD_CHILD(Store, ptr);
+ DELEGATE_FIELD_INT(Store, bytes);
+ DELEGATE_FIELD_ADDRESS(Store, offset);
+ DELEGATE_FIELD_ADDRESS(Store, align);
+ DELEGATE_FIELD_INT(Store, isAtomic);
+ DELEGATE_FIELD_TYPE(Store, valueType);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::AtomicRMWId: {
+ DELEGATE_START(AtomicRMW);
+ DELEGATE_FIELD_CHILD(AtomicRMW, value);
+ DELEGATE_FIELD_CHILD(AtomicRMW, ptr);
+ DELEGATE_FIELD_INT(AtomicRMW, op);
+ DELEGATE_FIELD_INT(AtomicRMW, bytes);
+ DELEGATE_FIELD_ADDRESS(AtomicRMW, offset);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::AtomicCmpxchgId: {
+ DELEGATE_START(AtomicCmpxchg);
+ DELEGATE_FIELD_CHILD(AtomicCmpxchg, replacement);
+ DELEGATE_FIELD_CHILD(AtomicCmpxchg, expected);
+ DELEGATE_FIELD_CHILD(AtomicCmpxchg, ptr);
+ DELEGATE_FIELD_INT(AtomicCmpxchg, bytes);
+ DELEGATE_FIELD_ADDRESS(AtomicCmpxchg, offset);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::AtomicWaitId: {
+ DELEGATE_START(AtomicWait);
+ DELEGATE_FIELD_CHILD(AtomicWait, timeout);
+ DELEGATE_FIELD_CHILD(AtomicWait, expected);
+ DELEGATE_FIELD_CHILD(AtomicWait, ptr);
+ DELEGATE_FIELD_ADDRESS(AtomicWait, offset);
+ DELEGATE_FIELD_TYPE(AtomicWait, expectedType);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::AtomicNotifyId: {
+ DELEGATE_START(AtomicNotify);
+ DELEGATE_FIELD_CHILD(AtomicNotify, notifyCount);
+ DELEGATE_FIELD_CHILD(AtomicNotify, ptr);
+ DELEGATE_FIELD_ADDRESS(AtomicNotify, offset);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::AtomicFenceId: {
+ DELEGATE_START(AtomicFence);
+ DELEGATE_FIELD_INT(AtomicFence, order);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDExtractId: {
+ DELEGATE_START(SIMDExtract);
+ DELEGATE_FIELD_CHILD(SIMDExtract, vec);
+ DELEGATE_FIELD_INT(SIMDExtract, op);
+ DELEGATE_FIELD_INT(SIMDExtract, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDReplaceId: {
+ DELEGATE_START(SIMDReplace);
+ DELEGATE_FIELD_CHILD(SIMDReplace, value);
+ DELEGATE_FIELD_CHILD(SIMDReplace, vec);
+ DELEGATE_FIELD_INT(SIMDReplace, op);
+ DELEGATE_FIELD_INT(SIMDReplace, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDShuffleId: {
+ DELEGATE_START(SIMDShuffle);
+ DELEGATE_FIELD_CHILD(SIMDShuffle, right);
+ DELEGATE_FIELD_CHILD(SIMDShuffle, left);
+ DELEGATE_FIELD_INT_ARRAY(SIMDShuffle, mask);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDTernaryId: {
+ DELEGATE_START(SIMDTernary);
+ DELEGATE_FIELD_CHILD(SIMDTernary, c);
+ DELEGATE_FIELD_CHILD(SIMDTernary, b);
+ DELEGATE_FIELD_CHILD(SIMDTernary, a);
+ DELEGATE_FIELD_INT(SIMDTernary, op);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDShiftId: {
+ DELEGATE_START(SIMDShift);
+ DELEGATE_FIELD_CHILD(SIMDShift, shift);
+ DELEGATE_FIELD_CHILD(SIMDShift, vec);
+ DELEGATE_FIELD_INT(SIMDShift, op);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDLoadId: {
+ DELEGATE_START(SIMDLoad);
+ DELEGATE_FIELD_CHILD(SIMDLoad, ptr);
+ DELEGATE_FIELD_INT(SIMDLoad, op);
+ DELEGATE_FIELD_ADDRESS(SIMDLoad, offset);
+ DELEGATE_FIELD_ADDRESS(SIMDLoad, align);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SIMDLoadStoreLaneId: {
+ DELEGATE_START(SIMDLoadStoreLane);
+ DELEGATE_FIELD_CHILD(SIMDLoadStoreLane, vec);
+ DELEGATE_FIELD_CHILD(SIMDLoadStoreLane, ptr);
+ DELEGATE_FIELD_INT(SIMDLoadStoreLane, op);
+ DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, offset);
+ DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, align);
+ DELEGATE_FIELD_INT(SIMDLoadStoreLane, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::MemoryInitId: {
+ DELEGATE_START(MemoryInit);
+ DELEGATE_FIELD_CHILD(MemoryInit, size);
+ DELEGATE_FIELD_CHILD(MemoryInit, offset);
+ DELEGATE_FIELD_CHILD(MemoryInit, dest);
+ DELEGATE_FIELD_INT(MemoryInit, segment);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::DataDropId: {
+ DELEGATE_START(DataDrop);
+ DELEGATE_FIELD_INT(DataDrop, segment);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::MemoryCopyId: {
+ DELEGATE_START(MemoryCopy);
+ DELEGATE_FIELD_CHILD(MemoryCopy, size);
+ DELEGATE_FIELD_CHILD(MemoryCopy, source);
+ DELEGATE_FIELD_CHILD(MemoryCopy, dest);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::MemoryFillId: {
+ DELEGATE_START(MemoryFill);
+ DELEGATE_FIELD_CHILD(MemoryFill, size);
+ DELEGATE_FIELD_CHILD(MemoryFill, value);
+ DELEGATE_FIELD_CHILD(MemoryFill, dest);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ConstId: {
+ DELEGATE_START(Const);
+ DELEGATE_FIELD_LITERAL(Const, value);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::UnaryId: {
+ DELEGATE_START(Unary);
+ DELEGATE_FIELD_CHILD(Unary, value);
+ DELEGATE_FIELD_INT(Unary, op);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::BinaryId: {
+ DELEGATE_START(Binary);
+ DELEGATE_FIELD_CHILD(Binary, right);
+ DELEGATE_FIELD_CHILD(Binary, left);
+ DELEGATE_FIELD_INT(Binary, op);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::SelectId: {
+ DELEGATE_START(Select);
+ DELEGATE_FIELD_CHILD(Select, condition);
+ DELEGATE_FIELD_CHILD(Select, ifFalse);
+ DELEGATE_FIELD_CHILD(Select, ifTrue);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::DropId: {
+ DELEGATE_START(Drop);
+ DELEGATE_FIELD_CHILD(Drop, value);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ReturnId: {
+ DELEGATE_START(Return);
+ DELEGATE_FIELD_OPTIONAL_CHILD(Return, value);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::MemorySizeId: {
+ DELEGATE_START(MemorySize);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::MemoryGrowId: {
+ DELEGATE_START(MemoryGrow);
+ DELEGATE_FIELD_CHILD(MemoryGrow, delta);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefNullId: {
+ DELEGATE_START(RefNull);
+ DELEGATE_FIELD_TYPE(RefNull, type);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefIsNullId: {
+ DELEGATE_START(RefIsNull);
+ DELEGATE_FIELD_CHILD(RefIsNull, value);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefFuncId: {
+ DELEGATE_START(RefFunc);
+ DELEGATE_FIELD_NAME(RefFunc, func);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefEqId: {
+ DELEGATE_START(RefEq);
+ DELEGATE_FIELD_CHILD(RefEq, right);
+ DELEGATE_FIELD_CHILD(RefEq, left);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::TryId: {
+ DELEGATE_START(Try);
+ DELEGATE_FIELD_CHILD(Try, catchBody);
+ DELEGATE_FIELD_CHILD(Try, body);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ThrowId: {
+ DELEGATE_START(Throw);
+ DELEGATE_FIELD_CHILD_VECTOR(Throw, operands);
+ DELEGATE_FIELD_NAME(Throw, event);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RethrowId: {
+ DELEGATE_START(Rethrow);
+ DELEGATE_FIELD_CHILD(Rethrow, exnref);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::BrOnExnId: {
+ DELEGATE_START(BrOnExn);
+ DELEGATE_FIELD_CHILD(BrOnExn, exnref);
+ DELEGATE_FIELD_SCOPE_NAME(BrOnExn, name);
+ DELEGATE_FIELD_NAME(BrOnExn, event);
+ DELEGATE_FIELD_TYPE(BrOnExn, sent);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::NopId: {
+ DELEGATE_START(Nop);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::UnreachableId: {
+ DELEGATE_START(Unreachable);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::PopId: {
+ DELEGATE_START(Pop);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::TupleMakeId: {
+ DELEGATE_START(TupleMake);
+ DELEGATE_FIELD_CHILD_VECTOR(Tuple, operands);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::TupleExtractId: {
+ DELEGATE_START(TupleExtract);
+ DELEGATE_FIELD_CHILD(TupleExtract, tuple);
+ DELEGATE_FIELD_INT(TupleExtract, index);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::I31NewId: {
+ DELEGATE_START(I31New);
+ DELEGATE_FIELD_CHILD(I31New, value);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::I31GetId: {
+ DELEGATE_START(I31Get);
+ DELEGATE_FIELD_CHILD(I31Get, i31);
+ DELEGATE_FIELD_INT(I31Get, signed_);
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefTestId: {
+ DELEGATE_START(RefTest);
+ WASM_UNREACHABLE("TODO (gc): ref.test");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RefCastId: {
+ DELEGATE_START(RefCast);
+ WASM_UNREACHABLE("TODO (gc): ref.cast");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::BrOnCastId: {
+ DELEGATE_START(BrOnCast);
+ WASM_UNREACHABLE("TODO (gc): br_on_cast");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RttCanonId: {
+ DELEGATE_START(RttCanon);
+ WASM_UNREACHABLE("TODO (gc): rtt.canon");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::RttSubId: {
+ DELEGATE_START(RttSub);
+ WASM_UNREACHABLE("TODO (gc): rtt.sub");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::StructNewId: {
+ DELEGATE_START(StructNew);
+ WASM_UNREACHABLE("TODO (gc): struct.new");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::StructGetId: {
+ DELEGATE_START(StructGet);
+ WASM_UNREACHABLE("TODO (gc): struct.get");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::StructSetId: {
+ DELEGATE_START(StructSet);
+ WASM_UNREACHABLE("TODO (gc): struct.set");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ArrayNewId: {
+ DELEGATE_START(ArrayNew);
+ WASM_UNREACHABLE("TODO (gc): array.new");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ArrayGetId: {
+ DELEGATE_START(ArrayGet);
+ WASM_UNREACHABLE("TODO (gc): array.get");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ArraySetId: {
+ DELEGATE_START(ArraySet);
+ WASM_UNREACHABLE("TODO (gc): array.set");
+ DELEGATE_END();
+ break;
+ }
+ case Expression::Id::ArrayLenId: {
+ DELEGATE_START(ArrayLen);
+ WASM_UNREACHABLE("TODO (gc): array.len");
+ DELEGATE_END();
+ break;
+ }
+}
+
+#undef DELEGATE_ID
+#undef DELEGATE_START
+#undef DELEGATE_END
+#undef DELEGATE_FIELD_CHILD
+#undef DELEGATE_FIELD_OPTIONAL_CHILD
+#undef DELEGATE_FIELD_CHILD_VECTOR
+#undef DELEGATE_FIELD_INT
+#undef DELEGATE_FIELD_INT_ARRAY
+#undef DELEGATE_FIELD_NAME
+#undef DELEGATE_FIELD_SCOPE_NAME
+#undef DELEGATE_FIELD_SCOPE_NAME_VECTOR
+#undef DELEGATE_FIELD_SIGNATURE
+#undef DELEGATE_FIELD_TYPE
+#undef DELEGATE_FIELD_ADDRESS