#ifndef wasm_ir_local_utils_h
#define wasm_ir_local_utils_h
#include <ir/effects.h>
#include <ir/manipulation.h>
#include <ir/utils.h>
namespace wasm {
struct LocalGetCounter : public PostWalker<LocalGetCounter> {
std::vector<Index> num;
LocalGetCounter() = default;
LocalGetCounter(Function* func) { analyze(func, func->body); }
LocalGetCounter(Function* func, Expression* ast) { analyze(func, ast); }
void analyze(Function* func) { analyze(func, func->body); }
void analyze(Function* func, Expression* ast) {
num.clear();
num.resize(func->getNumLocals());
walk(ast);
}
void visitLocalGet(LocalGet* curr) { num[curr->index]++; }
};
struct UnneededSetRemover : public PostWalker<UnneededSetRemover> {
PassOptions& passOptions;
LocalGetCounter* localGetCounter = nullptr;
Module& module;
UnneededSetRemover(Function* func, PassOptions& passOptions, Module& module)
: passOptions(passOptions), module(module) {
LocalGetCounter counter(func);
UnneededSetRemover inner(counter, func, passOptions, module);
removed = inner.removed;
}
UnneededSetRemover(LocalGetCounter& localGetCounter,
Function* func,
PassOptions& passOptions,
Module& module)
: passOptions(passOptions), localGetCounter(&localGetCounter),
module(module) {
walk(func->body);
if (refinalize) {
ReFinalize().walkFunctionInModule(func, &module);
}
}
bool removed = false;
bool refinalize = false;
void visitLocalSet(LocalSet* curr) {
if (localGetCounter->num[curr->index] == 0) {
remove(curr);
}
auto* value = curr->value;
while (true) {
if (auto* set = value->dynCast<LocalSet>()) {
if (set->index == curr->index) {
remove(curr);
} else {
value = set->value;
continue;
}
} else if (auto* get = value->dynCast<LocalGet>()) {
if (get->index == curr->index) {
remove(curr);
}
}
break;
}
}
void remove(LocalSet* set) {
auto* value = set->value;
if (set->isTee()) {
replaceCurrent(value);
if (value->type != set->type) {
refinalize = true;
}
} else if (EffectAnalyzer(passOptions, module, set->value)
.hasSideEffects()) {
Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set);
drop->value = value;
drop->finalize();
} else {
ExpressionManipulator::nop(set);
}
removed = true;
}
};
}
#endif