#ifndef wasm_ir_flat_h
#define wasm_ir_flat_h
#include "ir/iteration.h"
#include "ir/properties.h"
#include "pass.h"
#include "wasm-traversal.h"
namespace wasm {
namespace Flat {
inline void verifyFlatness(Function* func) {
struct VerifyFlatness
: public PostWalker<VerifyFlatness,
UnifiedExpressionVisitor<VerifyFlatness>> {
void visitExpression(Expression* curr) {
if (Properties::isControlFlowStructure(curr)) {
verify(!curr->type.isConcrete(),
"control flow structures must not flow values");
} else if (auto* set = curr->dynCast<LocalSet>()) {
verify(!set->isTee() || set->type == Type::unreachable,
"tees are not allowed, only sets");
verify(!Properties::isControlFlowStructure(set->value),
"set values cannot be control flow");
} else {
for (auto* child : ChildIterator(curr)) {
verify(Properties::isConstantExpression(child) ||
child->is<LocalGet>() || child->is<Unreachable>(),
"instructions must only have constant expressions, local.get, "
"or unreachable as children");
}
}
}
void verify(bool condition, const char* message) {
if (!condition) {
Fatal() << "IR must be flat: run --flatten beforehand (" << message
<< ", in " << getFunction()->name << ')';
}
}
};
VerifyFlatness verifier;
verifier.walkFunction(func);
verifier.setFunction(func);
verifier.verify(!func->body->type.isConcrete(),
"function bodies must not flow values");
}
inline void verifyFlatness(Module* module) {
struct VerifyFlatness
: public WalkerPass<
PostWalker<VerifyFlatness, UnifiedExpressionVisitor<VerifyFlatness>>> {
bool isFunctionParallel() override { return true; }
VerifyFlatness* create() override { return new VerifyFlatness(); }
void doVisitFunction(Function* func) { verifyFlatness(func); }
};
PassRunner runner(module);
VerifyFlatness().run(&runner, module);
}
}
}
#endif