diff options
-rw-r--r-- | src/passes/DeadArgumentElimination.cpp | 29 | ||||
-rw-r--r-- | test/lit/passes/dae_all-features.wast | 34 |
2 files changed, 50 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); } } diff --git a/test/lit/passes/dae_all-features.wast b/test/lit/passes/dae_all-features.wast index 8bfd3c9d0..3952747f7 100644 --- a/test/lit/passes/dae_all-features.wast +++ b/test/lit/passes/dae_all-features.wast @@ -658,3 +658,37 @@ ) ) ) + +(module + ;; CHECK: (type $i32_=>_none (func (param i32))) + + ;; CHECK: (func $0 (type $i32_=>_none) (param $0 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $0 + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + (func $0 (param $0 i32) (result i32) + ;; The result of this function can be removed, which makes us modify the + ;; returns (we should not return a value any more) and also the calls (the + ;; calls must be dropped). The returns here are nested in each other, and one + ;; is a recursive call to this function itself, which makes this a corner case + ;; we might emit invalid code for. + (return + (drop + (call $0 + (return + (i32.const 1) + ) + ) + ) + ) + ) +) |