#ifndef wasm_dataflow_node_h
#define wasm_dataflow_node_h
#include "ir/utils.h"
#include "wasm.h"
namespace wasm {
namespace DataFlow {
struct Node {
enum Type {
Var, Expr, Phi, Cond, Block, Zext, Bad } type;
Node(Type type) : type(type) {}
bool isVar() { return type == Var; }
bool isExpr() { return type == Expr; }
bool isPhi() { return type == Phi; }
bool isCond() { return type == Cond; }
bool isBlock() { return type == Block; }
bool isZext() { return type == Zext; }
bool isBad() { return type == Bad; }
bool isConst() { return type == Expr && expr->is<Const>(); }
union {
wasm::Type wasmType;
Expression* expr;
Index index;
};
Expression* origin = nullptr;
std::vector<Node*> values;
static Node* makeVar(wasm::Type wasmType) {
Node* ret = new Node(Var);
ret->wasmType = wasmType;
return ret;
}
static Node* makeExpr(Expression* expr, Expression* origin) {
Node* ret = new Node(Expr);
ret->expr = expr;
ret->origin = origin;
return ret;
}
static Node* makePhi(Node* block, Index index) {
Node* ret = new Node(Phi);
ret->addValue(block);
ret->index = index;
return ret;
}
static Node* makeCond(Node* block, Index index, Node* node) {
Node* ret = new Node(Cond);
ret->addValue(block);
ret->index = index;
ret->addValue(node);
return ret;
}
static Node* makeBlock() {
Node* ret = new Node(Block);
return ret;
}
static Node* makeZext(Node* child, Expression* origin) {
Node* ret = new Node(Zext);
ret->addValue(child);
ret->origin = origin;
return ret;
}
static Node* makeBad() {
Node* ret = new Node(Bad);
return ret;
}
void addValue(Node* value) { values.push_back(value); }
Node* getValue(Index i) { return values.at(i); }
wasm::Type getWasmType() {
switch (type) {
case Var:
return wasmType;
case Expr:
return expr->type;
case Phi:
return getValue(1)->getWasmType();
case Zext:
return getValue(0)->getWasmType();
case Bad:
return wasm::Type::unreachable;
default:
WASM_UNREACHABLE("invalid node type");
}
}
bool operator==(const Node& other) {
if (type != other.type) {
return false;
}
switch (type) {
case Var:
case Block:
return this == &other;
case Expr: {
if (!ExpressionAnalyzer::equal(expr, other.expr)) {
return false;
}
break;
}
case Cond:
if (index != other.index) {
return false;
}
default: {}
}
if (values.size() != other.values.size()) {
return false;
}
for (Index i = 0; i < values.size(); i++) {
if (*(values[i]) != *(other.values[i])) {
return false;
}
}
return true;
}
bool operator!=(const Node& other) { return !(*this == other); }
bool returnsI1() {
if (isExpr()) {
if (auto* binary = expr->dynCast<Binary>()) {
return binary->isRelational();
} else if (auto* unary = expr->dynCast<Unary>()) {
return unary->isRelational();
}
}
return false;
}
};
}
}
#endif