summaryrefslogtreecommitdiff
path: root/src/wasm/wasm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm.cpp')
-rw-r--r--src/wasm/wasm.cpp134
1 files changed, 35 insertions, 99 deletions
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 851e6a804..d9ca03185 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -267,72 +267,12 @@ Literals getLiteralsFromConstExpression(Expression* curr) {
}
}
-// core AST type checking
-
-struct TypeSeeker : public PostWalker<TypeSeeker> {
- Expression* target; // look for this one
- Name targetName;
- std::vector<Type> types;
-
- TypeSeeker(Expression* target, Name targetName)
- : target(target), targetName(targetName) {
- Expression* temp = target;
- walk(temp);
- }
-
- void visitBreak(Break* curr) {
- if (curr->name == targetName) {
- types.push_back(curr->value ? curr->value->type : Type::none);
- }
- }
-
- void visitSwitch(Switch* curr) {
- for (auto name : curr->targets) {
- if (name == targetName) {
- types.push_back(curr->value ? curr->value->type : Type::none);
- }
- }
- if (curr->default_ == targetName) {
- types.push_back(curr->value ? curr->value->type : Type::none);
- }
- }
-
- void visitBrOnExn(BrOnExn* curr) {
- if (curr->name == targetName) {
- types.push_back(curr->sent);
- }
- }
-
- void visitBlock(Block* curr) {
- if (curr == target) {
- if (curr->list.size() > 0) {
- types.push_back(curr->list.back()->type);
- } else {
- types.push_back(Type::none);
- }
- } else if (curr->name == targetName) {
- // ignore all breaks til now, they were captured by someone with the same
- // name
- types.clear();
- }
- }
-
- void visitLoop(Loop* curr) {
- if (curr == target) {
- types.push_back(curr->body->type);
- } else if (curr->name == targetName) {
- // ignore all breaks til now, they were captured by someone with the same
- // name
- types.clear();
- }
- }
-};
-
// a block is unreachable if one of its elements is unreachable,
// and there are no branches to it
-static void handleUnreachable(Block* block,
- bool breakabilityKnown = false,
- bool hasBreak = false) {
+
+static void
+handleUnreachable(Block* block,
+ Block::Breakability breakability = Block::Unknown) {
if (block->type == Type::unreachable) {
return; // nothing to do
}
@@ -350,10 +290,12 @@ static void handleUnreachable(Block* block,
if (child->type == Type::unreachable) {
// there is an unreachable child, so we are unreachable, unless we have a
// break
- if (!breakabilityKnown) {
- hasBreak = BranchUtils::BranchSeeker::has(block, block->name);
+ if (breakability == Block::Unknown) {
+ breakability = BranchUtils::BranchSeeker::has(block, block->name)
+ ? Block::HasBreak
+ : Block::NoBreak;
}
- if (!hasBreak) {
+ if (breakability == Block::NoBreak) {
block->type = Type::unreachable;
}
return;
@@ -362,41 +304,35 @@ static void handleUnreachable(Block* block,
}
void Block::finalize() {
+ if (list.size() == 0) {
+ type = Type::none;
+ return;
+ }
+ // The default type is what is at the end. Next we need to see if breaks and/
+ // or unreachabitily change that.
+ type = list.back()->type;
if (!name.is()) {
- if (list.size() > 0) {
- // nothing branches here, so this is easy
- // normally the type is the type of the final child
- type = list.back()->type;
- // and even if we have an unreachable child somewhere,
- // we still mark ourselves as having that type,
- // (block (result i32)
- // (return)
- // (i32.const 10)
- // )
- if (type.isConcrete()) {
- return;
- }
- // if we are unreachable, we are done
- if (type == Type::unreachable) {
- return;
- }
- // we may still be unreachable if we have an unreachable
- // child
- for (auto* child : list) {
- if (child->type == Type::unreachable) {
- type = Type::unreachable;
- return;
- }
- }
+ // Nothing branches here, so this is easy.
+ handleUnreachable(this, NoBreak);
+ return;
+ }
+
+ // The default type is according to the value that flows out.
+ BranchUtils::BranchSeeker seeker(this->name);
+ Expression* temp = this;
+ seeker.walk(temp);
+ if (seeker.found) {
+ // Take the branch values into account.
+ if (seeker.valueType != Type::none) {
+ type = Type::getLeastUpperBound(type, seeker.valueType);
} else {
+ // No value is sent, but as we have a branch we are not unreachable.
type = Type::none;
}
- return;
+ } else {
+ // There are no branches, so this block may be unreachable.
+ handleUnreachable(this, NoBreak);
}
-
- TypeSeeker seeker(this, this->name);
- type = Type::mergeTypes(seeker.types);
- handleUnreachable(this);
}
void Block::finalize(Type type_) {
@@ -406,10 +342,10 @@ void Block::finalize(Type type_) {
}
}
-void Block::finalize(Type type_, bool hasBreak) {
+void Block::finalize(Type type_, Breakability breakability) {
type = type_;
if (type == Type::none && list.size() > 0) {
- handleUnreachable(this, true, hasBreak);
+ handleUnreachable(this, breakability);
}
}