diff options
Diffstat (limited to 'src/wasm/wasm.cpp')
-rw-r--r-- | src/wasm/wasm.cpp | 134 |
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); } } |