diff options
Diffstat (limited to 'src/ir/iteration.h')
-rw-r--r-- | src/ir/iteration.h | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/ir/iteration.h b/src/ir/iteration.h new file mode 100644 index 000000000..6cf149894 --- /dev/null +++ b/src/ir/iteration.h @@ -0,0 +1,213 @@ +/* + * Copyright 2018 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. + */ + +#ifndef wasm_ir_iteration_h +#define wasm_ir_iteration_h + +#include "wasm.h" + +namespace wasm { + +// +// Allows iteration over the children of the expression, in order of execution +// where relevant. +// +// * This skips missing children, e.g. if an if has no else, it is represented +// as having 2 children (and not 3 with the last a nullptr). +// +// In general, it is preferable not to use this class and to directly access +// the children (using e.g. iff->ifTrue etc.), as that is faster. However, in +// cases where speed does not matter, this can be convenient. +// + +class ChildIterator { + struct Iterator { + const ChildIterator& parent; + Index index; + + Iterator(const ChildIterator& parent, Index index) : parent(parent), index(index) {} + + bool operator!=(const Iterator& other) const { + return index != other.index || &parent != &(other.parent); + } + + void operator++() { + index++; + } + + Expression* operator*() { + return parent.children[index]; + } + }; + +public: + std::vector<Expression*> children; + + ChildIterator(Expression* expr) { + switch (expr->_id) { + case Expression::Id::BlockId: { + auto& list = expr->cast<Block>()->list; + for (auto* child : list) { + children.push_back(child); + } + break; + } + case Expression::Id::IfId: { + auto* iff = expr->cast<If>(); + children.push_back(iff->condition); + children.push_back(iff->ifTrue); + if (iff->ifFalse) children.push_back(iff->ifFalse); + break; + } + case Expression::Id::LoopId: { + children.push_back(expr->cast<Loop>()->body); + break; + } + case Expression::Id::BreakId: { + auto* br = expr->cast<Break>(); + if (br->value) children.push_back(br->value); + if (br->condition) children.push_back(br->condition); + break; + } + case Expression::Id::SwitchId: { + auto* br = expr->cast<Switch>(); + if (br->value) children.push_back(br->value); + children.push_back(br->condition); + break; + } + case Expression::Id::CallId: { + auto& operands = expr->cast<Call>()->operands; + for (auto* child : operands) { + children.push_back(child); + } + break; + } + case Expression::Id::CallImportId: { + auto& operands = expr->cast<CallImport>()->operands; + for (auto* child : operands) { + children.push_back(child); + } + break; + } + case Expression::Id::CallIndirectId: { + auto* call = expr->cast<CallIndirect>(); + auto& operands = call->operands; + for (auto* child : operands) { + children.push_back(child); + } + children.push_back(call->target); + break; + } + case Expression::Id::SetLocalId: { + children.push_back(expr->cast<SetLocal>()->value); + break; + } + case Expression::Id::SetGlobalId: { + children.push_back(expr->cast<SetGlobal>()->value); + break; + } + case Expression::Id::LoadId: { + children.push_back(expr->cast<Load>()->ptr); + break; + } + case Expression::Id::StoreId: { + auto* store = expr->cast<Store>(); + children.push_back(store->ptr); + children.push_back(store->value); + break; + } + case Expression::Id::UnaryId: { + children.push_back(expr->cast<Unary>()->value); + break; + } + case Expression::Id::BinaryId: { + auto* binary = expr->cast<Binary>(); + children.push_back(binary->left); + children.push_back(binary->right); + break; + } + case Expression::Id::SelectId: { + auto* select = expr->cast<Select>(); + children.push_back(select->ifTrue); + children.push_back(select->ifFalse); + children.push_back(select->condition); + break; + } + case Expression::Id::DropId: { + children.push_back(expr->cast<Drop>()->value); + break; + } + case Expression::Id::ReturnId: { + auto* ret = expr->dynCast<Return>(); + if (ret->value) children.push_back(ret->value); + break; + } + case Expression::Id::HostId: { + auto& operands = expr->cast<Host>()->operands; + for (auto* child : operands) { + children.push_back(child); + } + break; + } + case Expression::Id::AtomicRMWId: { + auto* atomic = expr->cast<AtomicRMW>(); + children.push_back(atomic->ptr); + children.push_back(atomic->value); + break; + } + case Expression::Id::AtomicCmpxchgId: { + auto* atomic = expr->cast<AtomicCmpxchg>(); + children.push_back(atomic->ptr); + children.push_back(atomic->expected); + children.push_back(atomic->replacement); + break; + } + case Expression::Id::AtomicWaitId: { + auto* atomic = expr->cast<AtomicWait>(); + children.push_back(atomic->ptr); + children.push_back(atomic->expected); + children.push_back(atomic->timeout); + break; + } + case Expression::Id::AtomicWakeId: { + auto* atomic = expr->cast<AtomicWake>(); + children.push_back(atomic->ptr); + children.push_back(atomic->wakeCount); + break; + } + case Expression::Id::GetLocalId: + case Expression::Id::GetGlobalId: + case Expression::Id::ConstId: + case Expression::Id::NopId: + case Expression::Id::UnreachableId: { + break; // no children + } + default: WASM_UNREACHABLE(); + } + } + + Iterator begin() const { + return Iterator(*this, 0); + } + Iterator end() const { + return Iterator(*this, children.size()); + } +}; + +} // wasm + +#endif // wasm_ir_iteration_h + |