summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-ir-builder.cpp
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-09-22 10:37:33 -0700
committerGitHub <noreply@github.com>2023-09-22 10:37:33 -0700
commit7d4d502500bfd22a0a4e9c1762b1bddccbe14c1c (patch)
treecc7da749e2c8e816b6da548267430320a3771171 /src/wasm/wasm-ir-builder.cpp
parentc290aadaf6c08a35311fc6fcaee557bbd66968e4 (diff)
downloadbinaryen-7d4d502500bfd22a0a4e9c1762b1bddccbe14c1c.tar.gz
binaryen-7d4d502500bfd22a0a4e9c1762b1bddccbe14c1c.tar.bz2
binaryen-7d4d502500bfd22a0a4e9c1762b1bddccbe14c1c.zip
Support function contexts in IRBuilder (#5967)
Add a `visitFunctionStart` function to IRBuilder and make it responsible for setting the function's body when the context is closed. This will simplify outlining, will be necessary to support branches to function scope properly, and removes an extra block around function bodies in the new wat parser.
Diffstat (limited to 'src/wasm/wasm-ir-builder.cpp')
-rw-r--r--src/wasm/wasm-ir-builder.cpp66
1 files changed, 35 insertions, 31 deletions
diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp
index 585f9be49..4312fefe3 100644
--- a/src/wasm/wasm-ir-builder.cpp
+++ b/src/wasm/wasm-ir-builder.cpp
@@ -281,6 +281,15 @@ Result<> IRBuilder::visitArrayNew(ArrayNew* curr) {
return Ok{};
}
+Result<> IRBuilder::visitFunctionStart(Function* func) {
+ if (!scopeStack.empty()) {
+ return Err{"unexpected start of function"};
+ }
+ scopeStack.push_back(ScopeCtx::makeFunc(func));
+ this->func = func;
+ return Ok{};
+}
+
Result<> IRBuilder::visitBlockStart(Block* curr) {
scopeStack.push_back(ScopeCtx::makeBlock(curr));
return Ok{};
@@ -327,12 +336,12 @@ Result<Expression*> IRBuilder::finishScope(Block* block) {
auto hoisted = hoistLastValue();
CHECK_ERR(hoisted);
auto hoistedType = scope.exprStack.back()->type;
- if (hoistedType.size() != block->type.size()) {
+ if (hoistedType.size() != type.size()) {
// We cannot propagate the hoisted value directly because it does not
// have the correct number of elements. Break it up if necessary and
// construct our returned tuple from parts.
CHECK_ERR(packageHoistedValue(*hoisted));
- std::vector<Expression*> elems(block->type.size());
+ std::vector<Expression*> elems(type.size());
for (size_t i = 0; i < elems.size(); ++i) {
auto elem = pop();
CHECK_ERR(elem);
@@ -369,11 +378,11 @@ Result<Expression*> IRBuilder::finishScope(Block* block) {
} else {
// More than one expression, so we need a block. Allocate one if we weren't
// already given one.
- if (!block) {
- block = wasm.allocator.alloc<Block>();
- block->type = type;
+ if (block) {
+ block->list.set(scope.exprStack);
+ } else {
+ block = builder.makeBlock(scope.exprStack, type);
}
- block->list.set(scope.exprStack);
ret = block;
}
scopeStack.pop_back();
@@ -395,50 +404,45 @@ Result<> IRBuilder::visitElse() {
}
Result<> IRBuilder::visitEnd() {
- auto& scope = getScope();
+ auto scope = getScope();
if (scope.isNone()) {
return Err{"unexpected end"};
}
- if (auto* block = scope.getBlock()) {
- auto expr = finishScope(block);
- CHECK_ERR(expr);
+ auto expr = finishScope(scope.getBlock());
+ CHECK_ERR(expr);
+
+ // If the scope expression cannot be directly labeled, we may need to wrap it
+ // in a block.
+ auto maybeWrapForLabel = [&](Expression* curr) -> Expression* {
+ if (auto label = scope.getLabel()) {
+ return builder.makeBlock(label, {curr}, curr->type);
+ }
+ return curr;
+ };
+
+ if (auto* func = scope.getFunction()) {
+ func->body = *expr;
+ } else if (auto* block = scope.getBlock()) {
assert(*expr == block);
// TODO: Track branches so we can know whether this block is a target and
// finalize more efficiently.
block->finalize(block->type);
push(block);
- return Ok{};
} else if (auto* loop = scope.getLoop()) {
- auto expr = finishScope();
- CHECK_ERR(expr);
loop->body = *expr;
loop->finalize(loop->type);
push(loop);
- return Ok{};
- }
- auto label = scope.getLabel();
- Expression* scopeExpr = nullptr;
- if (auto* iff = scope.getIf()) {
- auto expr = finishScope();
- CHECK_ERR(expr);
+ } else if (auto* iff = scope.getIf()) {
iff->ifTrue = *expr;
iff->ifFalse = nullptr;
iff->finalize(iff->type);
- scopeExpr = iff;
+ push(maybeWrapForLabel(iff));
} else if (auto* iff = scope.getElse()) {
- auto expr = finishScope();
- CHECK_ERR(expr);
iff->ifFalse = *expr;
iff->finalize(iff->type);
- scopeExpr = iff;
- }
- assert(scopeExpr && "unexpected scope kind");
- if (label) {
- // We cannot directly name an If in Binaryen IR, so we need to wrap it in
- // a block.
- push(builder.makeBlock(label, {scopeExpr}, scopeExpr->type));
+ push(maybeWrapForLabel(iff));
} else {
- push(scopeExpr);
+ WASM_UNREACHABLE("unexpected scope kind");
}
return Ok{};
}