summaryrefslogtreecommitdiff
path: root/src/ast/branch-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast/branch-utils.h')
-rw-r--r--src/ast/branch-utils.h75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/ast/branch-utils.h b/src/ast/branch-utils.h
index 853b998af..77ec70753 100644
--- a/src/ast/branch-utils.h
+++ b/src/ast/branch-utils.h
@@ -100,6 +100,81 @@ inline std::set<Name> getBranchTargets(Expression* ast) {
return scanner.targets;
}
+// Finds if there are branches targeting a name. Note that since names are
+// unique in our IR, we just need to look for the name, and do not need
+// to analyze scoping.
+// By default we ignore untaken branches. You can set named to
+// note those as well, then any named branch is noted, even if untaken
+struct BranchSeeker : public PostWalker<BranchSeeker> {
+ Name target;
+ bool named = false;
+
+ Index found;
+ WasmType valueType;
+
+ BranchSeeker(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 (!named) {
+ // ignore an unreachable break
+ if (curr->condition && curr->condition->type == unreachable) return;
+ if (curr->value && curr->value->type == unreachable) return;
+ }
+ // check the break
+ if (curr->name == target) noteFound(curr->value);
+ }
+
+ void visitSwitch(Switch *curr) {
+ if (!named) {
+ // ignore an unreachable switch
+ if (curr->condition->type == unreachable) return;
+ if (curr->value && curr->value->type == unreachable) return;
+ }
+ // check the switch
+ for (auto name : curr->targets) {
+ if (name == target) noteFound(curr->value);
+ }
+ if (curr->default_ == target) noteFound(curr->value);
+ }
+
+ static bool has(Expression* tree, Name target) {
+ if (!target.is()) return false;
+ BranchSeeker seeker(target);
+ seeker.walk(tree);
+ return seeker.found > 0;
+ }
+
+ static Index count(Expression* tree, Name target) {
+ if (!target.is()) return 0;
+ BranchSeeker seeker(target);
+ seeker.walk(tree);
+ return seeker.found;
+ }
+
+ static bool hasNamed(Expression* tree, Name target) {
+ if (!target.is()) return false;
+ BranchSeeker seeker(target);
+ seeker.named = true;
+ seeker.walk(tree);
+ return seeker.found > 0;
+ }
+
+ static Index countNamed(Expression* tree, Name target) {
+ if (!target.is()) return 0;
+ BranchSeeker seeker(target);
+ seeker.named = true;
+ seeker.walk(tree);
+ return seeker.found;
+ }
+};
+
} // namespace BranchUtils
} // namespace wasm