diff options
Diffstat (limited to 'src/ir')
-rw-r--r-- | src/ir/iteration.h | 213 | ||||
-rw-r--r-- | src/ir/properties.h | 193 |
2 files changed, 316 insertions, 90 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 + diff --git a/src/ir/properties.h b/src/ir/properties.h index cf481218c..7cbbe73f0 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -22,51 +22,62 @@ namespace wasm { -struct Properties { - static bool emitsBoolean(Expression* curr) { - if (auto* unary = curr->dynCast<Unary>()) { - return unary->isRelational(); - } else if (auto* binary = curr->dynCast<Binary>()) { - return binary->isRelational(); - } - return false; - } +namespace Properties { - static bool isSymmetric(Binary* binary) { - switch (binary->op) { - case AddInt32: - case MulInt32: - case AndInt32: - case OrInt32: - case XorInt32: - case EqInt32: - case NeInt32: - - case AddInt64: - case MulInt64: - case AndInt64: - case OrInt64: - case XorInt64: - case EqInt64: - case NeInt64: return true; - - default: return false; - } +inline bool emitsBoolean(Expression* curr) { + if (auto* unary = curr->dynCast<Unary>()) { + return unary->isRelational(); + } else if (auto* binary = curr->dynCast<Binary>()) { + return binary->isRelational(); } - - // Check if an expression is a sign-extend, and if so, returns the value - // that is extended, otherwise nullptr - static Expression* getSignExtValue(Expression* curr) { - if (auto* outer = curr->dynCast<Binary>()) { - if (outer->op == ShrSInt32) { - if (auto* outerConst = outer->right->dynCast<Const>()) { - if (outerConst->value.geti32() != 0) { - if (auto* inner = outer->left->dynCast<Binary>()) { - if (inner->op == ShlInt32) { - if (auto* innerConst = inner->right->dynCast<Const>()) { - if (outerConst->value == innerConst->value) { - return inner->left; - } + return false; +} + +inline bool isSymmetric(Binary* binary) { + switch (binary->op) { + case AddInt32: + case MulInt32: + case AndInt32: + case OrInt32: + case XorInt32: + case EqInt32: + case NeInt32: + + case AddInt64: + case MulInt64: + case AndInt64: + case OrInt64: + case XorInt64: + case EqInt64: + case NeInt64: return true; + + default: return false; + } +} + +// Check if an expression is a control flow construct with a name, +// which implies it may have breaks to it. +inline bool isNamedControlFlow(Expression* curr) { + if (auto* block = curr->dynCast<Block>()) { + return block->name.is(); + } else if (auto* loop = curr->dynCast<Loop>()) { + return loop->name.is(); + } + return false; +} + +// Check if an expression is a sign-extend, and if so, returns the value +// that is extended, otherwise nullptr +inline Expression* getSignExtValue(Expression* curr) { + if (auto* outer = curr->dynCast<Binary>()) { + if (outer->op == ShrSInt32) { + if (auto* outerConst = outer->right->dynCast<Const>()) { + if (outerConst->value.geti32() != 0) { + if (auto* inner = outer->left->dynCast<Binary>()) { + if (inner->op == ShlInt32) { + if (auto* innerConst = inner->right->dynCast<Const>()) { + if (outerConst->value == innerConst->value) { + return inner->left; } } } @@ -74,28 +85,28 @@ struct Properties { } } } - return nullptr; - } - - // gets the size of the sign-extended value - static Index getSignExtBits(Expression* curr) { - return 32 - Bits::getEffectiveShifts(curr->cast<Binary>()->right); } - - // Check if an expression is almost a sign-extend: perhaps the inner shift - // is too large. We can split the shifts in that case, which is sometimes - // useful (e.g. if we can remove the signext) - static Expression* getAlmostSignExt(Expression* curr) { - if (auto* outer = curr->dynCast<Binary>()) { - if (outer->op == ShrSInt32) { - if (auto* outerConst = outer->right->dynCast<Const>()) { - if (outerConst->value.geti32() != 0) { - if (auto* inner = outer->left->dynCast<Binary>()) { - if (inner->op == ShlInt32) { - if (auto* innerConst = inner->right->dynCast<Const>()) { - if (Bits::getEffectiveShifts(outerConst) <= Bits::getEffectiveShifts(innerConst)) { - return inner->left; - } + return nullptr; +} + +// gets the size of the sign-extended value +inline Index getSignExtBits(Expression* curr) { + return 32 - Bits::getEffectiveShifts(curr->cast<Binary>()->right); +} + +// Check if an expression is almost a sign-extend: perhaps the inner shift +// is too large. We can split the shifts in that case, which is sometimes +// useful (e.g. if we can remove the signext) +inline Expression* getAlmostSignExt(Expression* curr) { + if (auto* outer = curr->dynCast<Binary>()) { + if (outer->op == ShrSInt32) { + if (auto* outerConst = outer->right->dynCast<Const>()) { + if (outerConst->value.geti32() != 0) { + if (auto* inner = outer->left->dynCast<Binary>()) { + if (inner->op == ShlInt32) { + if (auto* innerConst = inner->right->dynCast<Const>()) { + if (Bits::getEffectiveShifts(outerConst) <= Bits::getEffectiveShifts(innerConst)) { + return inner->left; } } } @@ -103,39 +114,41 @@ struct Properties { } } } - return nullptr; - } - - // gets the size of the almost sign-extended value, as well as the - // extra shifts, if any - static Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) { - extraShifts = Bits::getEffectiveShifts(curr->cast<Binary>()->left->cast<Binary>()->right) - - Bits::getEffectiveShifts(curr->cast<Binary>()->right); - return getSignExtBits(curr); } - - // Check if an expression is a zero-extend, and if so, returns the value - // that is extended, otherwise nullptr - static Expression* getZeroExtValue(Expression* curr) { - if (auto* binary = curr->dynCast<Binary>()) { - if (binary->op == AndInt32) { - if (auto* c = binary->right->dynCast<Const>()) { - if (Bits::getMaskedBits(c->value.geti32())) { - return binary->right; - } + return nullptr; +} + +// gets the size of the almost sign-extended value, as well as the +// extra shifts, if any +inline Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) { + extraShifts = Bits::getEffectiveShifts(curr->cast<Binary>()->left->cast<Binary>()->right) - + Bits::getEffectiveShifts(curr->cast<Binary>()->right); + return getSignExtBits(curr); +} + +// Check if an expression is a zero-extend, and if so, returns the value +// that is extended, otherwise nullptr +inline Expression* getZeroExtValue(Expression* curr) { + if (auto* binary = curr->dynCast<Binary>()) { + if (binary->op == AndInt32) { + if (auto* c = binary->right->dynCast<Const>()) { + if (Bits::getMaskedBits(c->value.geti32())) { + return binary->right; } } } - return nullptr; } + return nullptr; +} - // gets the size of the sign-extended value - static Index getZeroExtBits(Expression* curr) { - return Bits::getMaskedBits(curr->cast<Binary>()->right->cast<Const>()->value.geti32()); - } -}; +// gets the size of the sign-extended value +inline Index getZeroExtBits(Expression* curr) { + return Bits::getMaskedBits(curr->cast<Binary>()->right->cast<Const>()->value.geti32()); +} + +} // Properties } // wasm -#endif // wams_ir_properties_h +#endif // wasm_ir_properties_h |