summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-05-04 10:24:49 -0700
committerGitHub <noreply@github.com>2023-05-04 10:24:49 -0700
commit09fe432c0d3cb7562767a8e06d4e918beb5990c2 (patch)
treee7d1357f4678e76f2d22290ea4debc21b03a2414 /src
parente9b8e53812610e43260f6db4a05fd12d96a3f449 (diff)
downloadbinaryen-09fe432c0d3cb7562767a8e06d4e918beb5990c2.tar.gz
binaryen-09fe432c0d3cb7562767a8e06d4e918beb5990c2.tar.bz2
binaryen-09fe432c0d3cb7562767a8e06d4e918beb5990c2.zip
Fix DeadArgumentElimination return value opts on nesting+recursion (#5701)
The testcase here has a recursive call that is also nested in itself, something like (return (call $me (return .. This found a bug in our return value removal logic. When we remove a return value we both modify call sites (to add drops) and modify returns (to remove their values). One of those uses pointers into the IR which the other invalidated, so the order of the two matters. This PR just reorders that code to fix the bug.
Diffstat (limited to 'src')
-rw-r--r--src/passes/DeadArgumentElimination.cpp29
1 files changed, 16 insertions, 13 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp
index f739e9263..ab4c8b8eb 100644
--- a/src/passes/DeadArgumentElimination.cpp
+++ b/src/passes/DeadArgumentElimination.cpp
@@ -317,7 +317,21 @@ private:
void
removeReturnValue(Function* func, std::vector<Call*>& calls, Module* module) {
func->setResults(Type::none);
- Builder builder(*module);
+ // Remove the drops on the calls. Note that we must do this before updating
+ // returns in ReturnUpdater, as there may be recursive calls of this
+ // function to itself. So we first use the information in allDroppedCalls
+ // before the ReturnUpdater potentially invalidates that information as it
+ // modifies the function.
+ for (auto* call : calls) {
+ auto iter = allDroppedCalls.find(call);
+ assert(iter != allDroppedCalls.end());
+ Expression** location = iter->second;
+ *location = call;
+ // Update the call's type.
+ if (call->type != Type::unreachable) {
+ call->type = Type::none;
+ }
+ }
// Remove any return values.
struct ReturnUpdater : public PostWalker<ReturnUpdater> {
Module* module;
@@ -334,18 +348,7 @@ private:
} returnUpdater(func, module);
// Remove any value flowing out.
if (func->body->type.isConcrete()) {
- func->body = builder.makeDrop(func->body);
- }
- // Remove the drops on the calls.
- for (auto* call : calls) {
- auto iter = allDroppedCalls.find(call);
- assert(iter != allDroppedCalls.end());
- Expression** location = iter->second;
- *location = call;
- // Update the call's type.
- if (call->type != Type::unreachable) {
- call->type = Type::none;
- }
+ func->body = Builder(*module).makeDrop(func->body);
}
}