diff options
author | Alon Zakai <azakai@google.com> | 2023-05-04 10:24:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-04 10:24:49 -0700 |
commit | 09fe432c0d3cb7562767a8e06d4e918beb5990c2 (patch) | |
tree | e7d1357f4678e76f2d22290ea4debc21b03a2414 /src | |
parent | e9b8e53812610e43260f6db4a05fd12d96a3f449 (diff) | |
download | binaryen-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.cpp | 29 |
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); } } |