summaryrefslogtreecommitdiff
path: root/src/ast_utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast_utils.h')
-rw-r--r--src/ast_utils.h103
1 files changed, 94 insertions, 9 deletions
diff --git a/src/ast_utils.h b/src/ast_utils.h
index 9b2ff10cd..4664f22ae 100644
--- a/src/ast_utils.h
+++ b/src/ast_utils.h
@@ -27,19 +27,27 @@ namespace wasm {
struct BreakSeeker : public PostWalker<BreakSeeker, Visitor<BreakSeeker>> {
Name target; // look for this one XXX looking by name may fall prey to duplicate names
- size_t found;
+ Index found;
+ WasmType valueType;
- BreakSeeker(Name target) : target(target), found(false) {}
+ BreakSeeker(Name target) : target(target), found(0) {}
+
+ void noteFound(Expression* value) {
+ found++;
+ if (found == 1) valueType = unreachable;
+ if (!value) valueType = none;
+ else if (value->type != unreachable) valueType = value->type;
+ }
void visitBreak(Break *curr) {
- if (curr->name == target) found++;
+ if (curr->name == target) noteFound(curr->value);
}
void visitSwitch(Switch *curr) {
for (auto name : curr->targets) {
- if (name == target) found++;
+ if (name == target) noteFound(curr->value);
}
- if (curr->default_ == target) found++;
+ if (curr->default_ == target) noteFound(curr->value);
}
static bool has(Expression* tree, Name target) {
@@ -47,6 +55,12 @@ struct BreakSeeker : public PostWalker<BreakSeeker, Visitor<BreakSeeker>> {
breakSeeker.walk(tree);
return breakSeeker.found > 0;
}
+
+ static Index count(Expression* tree, Name target) {
+ BreakSeeker breakSeeker(target);
+ breakSeeker.walk(tree);
+ return breakSeeker.found;
+ }
};
// Finds all functions that are reachable via direct calls.
@@ -92,13 +106,16 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer
bool calls = false;
std::set<Index> localsRead;
std::set<Index> localsWritten;
+ std::set<Name> globalsRead;
+ std::set<Name> globalsWritten;
bool readsMemory = false;
bool writesMemory = false;
bool accessesLocal() { return localsRead.size() + localsWritten.size() > 0; }
+ bool accessesGlobal() { return globalsRead.size() + globalsWritten.size() > 0; }
bool accessesMemory() { return calls || readsMemory || writesMemory; }
- bool hasSideEffects() { return calls || localsWritten.size() > 0 || writesMemory || branches; }
- bool hasAnything() { return branches || calls || accessesLocal() || readsMemory || writesMemory; }
+ bool hasSideEffects() { return calls || localsWritten.size() > 0 || writesMemory || branches || globalsWritten.size() > 0; }
+ bool hasAnything() { return branches || calls || accessesLocal() || readsMemory || writesMemory || accessesGlobal(); }
// checks if these effects would invalidate another set (e.g., if we write, we invalidate someone that reads, they can't be moved past us)
bool invalidates(EffectAnalyzer& other) {
@@ -115,6 +132,17 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer
for (auto local : localsRead) {
if (other.localsWritten.count(local)) return true;
}
+ if ((accessesGlobal() && other.calls) || (other.accessesGlobal() && calls)) {
+ return true;
+ }
+ for (auto global : globalsWritten) {
+ if (other.globalsWritten.count(global) || other.globalsRead.count(global)) {
+ return true;
+ }
+ }
+ for (auto global : globalsRead) {
+ if (other.globalsWritten.count(global)) return true;
+ }
return false;
}
@@ -163,8 +191,12 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer
void visitSetLocal(SetLocal *curr) {
localsWritten.insert(curr->index);
}
- void visitGetGlobal(GetGlobal *curr) { readsMemory = true; } // TODO: global-specific
- void visitSetGlobal(SetGlobal *curr) { writesMemory = true; } // stuff?
+ void visitGetGlobal(GetGlobal *curr) {
+ globalsRead.insert(curr->name);
+ }
+ void visitSetGlobal(SetGlobal *curr) {
+ globalsWritten.insert(curr->name);
+ }
void visitLoad(Load *curr) { readsMemory = true; }
void visitStore(Store *curr) { writesMemory = true; }
void visitReturn(Return *curr) { branches = true; }
@@ -340,6 +372,21 @@ struct ExpressionManipulator {
} copier;
return flexibleCopy(original, wasm, copier);
}
+
+ // Splice an item into the middle of a block's list
+ static void spliceIntoBlock(Block* block, Index index, Expression* add) {
+ auto& list = block->list;
+ if (index == list.size()) {
+ list.push_back(add); // simple append
+ } else {
+ // we need to make room
+ list.push_back(nullptr);
+ for (Index i = list.size() - 1; i > index; i--) {
+ list[i] = list[i - 1];
+ }
+ list[index] = add;
+ }
+ }
};
struct ExpressionAnalyzer {
@@ -373,6 +420,25 @@ struct ExpressionAnalyzer {
return func->result != none;
}
+ // Checks if a break is a simple - no condition, no value, just a plain branching
+ static bool isSimple(Break* curr) {
+ return !curr->condition && !curr->value;
+ }
+
+ // Checks if an expression ends with a simple break,
+ // and returns a pointer to it if so.
+ // (It might also have other internal branches.)
+ static Expression* getEndingSimpleBreak(Expression* curr) {
+ if (auto* br = curr->dynCast<Break>()) {
+ if (isSimple(br)) return br;
+ return nullptr;
+ }
+ if (auto* block = curr->dynCast<Block>()) {
+ if (block->list.size() > 0) return getEndingSimpleBreak(block->list.back());
+ }
+ return nullptr;
+ }
+
template<typename T>
static bool flexibleEqual(Expression* left, Expression* right, T& comparer) {
std::vector<Name> nameStack;
@@ -814,6 +880,25 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop, Visitor<Auto
curr->finalize(); // we may have changed our type
}
+ void visitIf(If* curr) {
+ if (curr->ifFalse) {
+ if (!isConcreteWasmType(curr->type)) {
+ // if either side of an if-else not returning a value is concrete, drop it
+ if (isConcreteWasmType(curr->ifTrue->type)) {
+ curr->ifTrue = Builder(*getModule()).makeDrop(curr->ifTrue);
+ }
+ if (isConcreteWasmType(curr->ifFalse->type)) {
+ curr->ifFalse = Builder(*getModule()).makeDrop(curr->ifFalse);
+ }
+ }
+ } else {
+ // if without else does not return a value, so the body must be dropped if it is concrete
+ if (isConcreteWasmType(curr->ifTrue->type)) {
+ curr->ifTrue = Builder(*getModule()).makeDrop(curr->ifTrue);
+ }
+ }
+ }
+
void visitFunction(Function* curr) {
if (curr->result == none && isConcreteWasmType(curr->body->type)) {
curr->body = Builder(*getModule()).makeDrop(curr->body);