diff options
-rw-r--r-- | src/ir/ExpressionManipulator.cpp | 375 | ||||
-rw-r--r-- | src/wasm-delegations-fields.h | 584 |
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 |