diff options
author | arsnyder16 <arsnyder16@gmail.com> | 2022-05-04 12:01:38 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-04 16:01:38 +0000 |
commit | 4bcfba261cb8ee182261d26064453cab787d0df4 (patch) | |
tree | ccba9aa47847d1c0987c3ac4a1e6fb3aa3cca8d7 /src | |
parent | cc192b7ed0d80647c39442227f68b907528bc6de (diff) | |
download | binaryen-4bcfba261cb8ee182261d26064453cab787d0df4.tar.gz binaryen-4bcfba261cb8ee182261d26064453cab787d0df4.tar.bz2 binaryen-4bcfba261cb8ee182261d26064453cab787d0df4.zip |
Reduce iterations required for DeadArgumentElimination convergence (#4629)
If we do not remove a param, we can try to remove the return value. We can do that
on a per-function basis, and not only if we removed no params from anywhere.
Also simplify tail call logic.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/DeadArgumentElimination.cpp | 60 |
1 files changed, 16 insertions, 44 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 784aec31a..5ebca9cf0 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -70,8 +70,7 @@ struct DAEFunctionInfo { // because being in a table inhibits DAE. TODO: Allow the removal of dropped // returns from tail-callers if their tail-callees can have their returns // removed as well. - bool hasTailCalls = false; - std::unordered_set<Name> tailCallees; + std::atomic<bool> hasTailCalls; // Whether the function can be called from places that // affect what we can do. For now, any call we don't // see inhibits our optimizations, but TODO: an export @@ -81,7 +80,10 @@ struct DAEFunctionInfo { // during the parallel analysis phase which is run in DAEScanner. std::atomic<bool> hasUnseenCalls; - DAEFunctionInfo() { hasUnseenCalls = false; } + DAEFunctionInfo() { + hasUnseenCalls = false; + hasTailCalls = false; + } }; typedef std::unordered_map<Name, DAEFunctionInfo> DAEFunctionInfoMap; @@ -105,7 +107,7 @@ struct DAEScanner } if (curr->isReturn) { info->hasTailCalls = true; - info->tailCallees.insert(curr->target); + (*infoMap)[curr->target].hasTailCalls = true; } } @@ -201,15 +203,11 @@ struct DAE : public Pass { scanner.run(runner, module); // Combine all the info. std::map<Name, std::vector<Call*>> allCalls; - std::unordered_set<Name> tailCallees; for (auto& [_, info] : infoMap) { for (auto& [name, calls] : info.calls) { auto& allCallsToName = allCalls[name]; allCallsToName.insert(allCallsToName.end(), calls.begin(), calls.end()); } - for (auto& callee : info.tailCallees) { - tailCallees.insert(callee); - } for (auto& [name, calls] : info.droppedCalls) { allDroppedCalls[name] = calls; } @@ -251,45 +249,19 @@ struct DAE : public Pass { std::unordered_set<Function*> changed; // We now know which parameters are unused, and can potentially remove them. for (auto& [name, calls] : allCalls) { - if (infoMap[name].hasUnseenCalls) { + auto& info = infoMap[name]; + if (info.hasUnseenCalls) { continue; } auto* func = module->getFunction(name); - auto numParams = func->getNumParams(); - if (numParams == 0) { - continue; - } - auto removedIndexes = ParamUtils::removeParameters( - {func}, infoMap[name].unusedParams, calls, {}, module, runner); - if (!removedIndexes.empty()) { + if (func->getNumParams() > 0 && + !ParamUtils::removeParameters( + {func}, info.unusedParams, calls, {}, module, runner) + .empty()) { // Success! changed.insert(func); - } - } - // We can also tell which calls have all their return values dropped. Note - // that we can't do this if we changed anything so far, as we may have - // modified allCalls (we can't modify a call site twice in one iteration, - // once to remove a param, once to drop the return value). - if (changed.empty()) { - for (auto& func : module->functions) { - if (func->getResults() == Type::none) { - continue; - } - auto name = func->name; - if (infoMap[name].hasUnseenCalls) { - continue; - } - if (infoMap[name].hasTailCalls) { - continue; - } - if (tailCallees.count(name)) { - continue; - } - auto iter = allCalls.find(name); - if (iter == allCalls.end()) { - continue; - } - auto& calls = iter->second; + } else if (!info.hasTailCalls && func->getResults() != Type::none) { + // We can also tell which calls have all their return values dropped. bool allDropped = std::all_of(calls.begin(), calls.end(), [&](Call* call) { return allDroppedCalls.count(call); @@ -297,10 +269,10 @@ struct DAE : public Pass { if (!allDropped) { continue; } - removeReturnValue(func.get(), calls, module); + removeReturnValue(func, calls, module); // TODO Removing a drop may also open optimization opportunities in the // callers. - changed.insert(func.get()); + changed.insert(func); } } if (optimize && !changed.empty()) { |