summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/iteration.h213
-rw-r--r--src/ir/properties.h193
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