From 6a9add5552170ba61d94ca7ac7ae76f700e6bbb1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 14:29:33 -0700 Subject: [PATCH 01/17] go --- src/passes/DeadArgumentElimination.cpp | 49 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 93e6ba44b26..eeaa6d4980f 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -233,34 +233,47 @@ struct DAE : public Pass { Call* call; Function* func; }; - std::map> allCalls; - std::unordered_set tailCallees; - std::unordered_set hasUnseenCalls; + + // Maps function names to indexes. This lets us use indexes below for speed. + std::unordered_map indexes; + // Reverse mapping for convenience. + auto numFunctions = module->functions.size(); + std::vector names(numFunctions); + for (Index i = 0; i < module->functions.size(); i++) { + auto name = module->functions[i]->name; + indexes[name] = i; + names[i] = name; + } + + // TODO: vectors! + std::vector> allCalls(numFunctions); + std::vector tailCallees(numFunctions); + std::vector hasUnseenCalls(numFunctions); // Track the function in which relevant expressions exist. When we modify // those expressions we will need to mark the function's info as stale. std::unordered_map expressionFuncs; for (auto& [func, info] : infoMap) { for (auto& [name, calls] : info.calls) { - auto& allCallsToName = allCalls[name]; + auto& allCallsToName = allCalls[indexes[name]]; allCallsToName.insert(allCallsToName.end(), calls.begin(), calls.end()); for (auto* call : calls) { expressionFuncs[call] = func; } } for (auto& callee : info.tailCallees) { - tailCallees.insert(callee); + tailCallees[indexes[callee]] = true; } for (auto& [call, dropp] : info.droppedCalls) { allDroppedCalls[call] = dropp; } for (auto& name : info.hasUnseenCalls) { - hasUnseenCalls.insert(name); + hasUnseenCalls[indexes[name]] = true; } } // Exports are considered unseen calls. for (auto& curr : module->exports) { if (curr->kind == ExternalKind::Function) { - hasUnseenCalls.insert(*curr->getInternalName()); + hasUnseenCalls[indexes[*curr->getInternalName()]] = true; } } @@ -299,9 +312,11 @@ struct DAE : public Pass { // We now have a mapping of all call sites for each function, and can look // for optimization opportunities. - for (auto& [name, calls] : allCalls) { + for (Index index = 0; index < numFunctions; index++) { + auto& calls = allCalls[index]; // We can only optimize if we see all the calls and can modify them. - if (hasUnseenCalls.count(name)) { + auto name = names[index]; + if (hasUnseenCalls[index]) { continue; } auto* func = module->getFunction(name); @@ -336,8 +351,10 @@ struct DAE : public Pass { ReFinalize().run(getPassRunner(), module); } // We now know which parameters are unused, and can potentially remove them. - for (auto& [name, calls] : allCalls) { - if (hasUnseenCalls.count(name)) { + for (Index index = 0; index < numFunctions; index++) { + auto& calls = allCalls[index]; + auto name = names[index]; + if (hasUnseenCalls[index]) { continue; } auto* func = module->getFunction(name); @@ -367,20 +384,20 @@ struct DAE : public Pass { continue; } auto name = func->name; - if (hasUnseenCalls.count(name)) { + auto index = indexes[name]; + if (hasUnseenCalls[index]) { continue; } if (infoMap[name].hasTailCalls) { continue; } - if (tailCallees.count(name)) { + if (tailCallees[index]) { continue; } - auto iter = allCalls.find(name); - if (iter == allCalls.end()) { + auto& calls = allCalls[index]; + if (calls.empty()) { continue; } - auto& calls = iter->second; bool allDropped = std::all_of(calls.begin(), calls.end(), [&](Call* call) { return allDroppedCalls.count(call); From 9f451c53e01ad9c1b899e1e0ba92cd23462a8010 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 15:48:56 -0700 Subject: [PATCH 02/17] vec --- src/passes/DeadArgumentElimination.cpp | 29 +++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index eeaa6d4980f..300b3afb66b 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -247,8 +247,8 @@ struct DAE : public Pass { // TODO: vectors! std::vector> allCalls(numFunctions); - std::vector tailCallees(numFunctions); - std::vector hasUnseenCalls(numFunctions); + std::unordered_set tailCallees; + std::unordered_set hasUnseenCalls; // Track the function in which relevant expressions exist. When we modify // those expressions we will need to mark the function's info as stale. std::unordered_map expressionFuncs; @@ -261,19 +261,19 @@ struct DAE : public Pass { } } for (auto& callee : info.tailCallees) { - tailCallees[indexes[callee]] = true; + tailCallees.insert(indexes[callee]); } for (auto& [call, dropp] : info.droppedCalls) { allDroppedCalls[call] = dropp; } for (auto& name : info.hasUnseenCalls) { - hasUnseenCalls[indexes[name]] = true; + hasUnseenCalls.insert(indexes[name]); } } // Exports are considered unseen calls. for (auto& curr : module->exports) { if (curr->kind == ExternalKind::Function) { - hasUnseenCalls[indexes[*curr->getInternalName()]] = true; + hasUnseenCalls.insert(indexes[*curr->getInternalName()]); } } @@ -316,10 +316,13 @@ struct DAE : public Pass { auto& calls = allCalls[index]; // We can only optimize if we see all the calls and can modify them. auto name = names[index]; - if (hasUnseenCalls[index]) { + if (hasUnseenCalls.count(index)) { + continue; + } + auto* func = module->getFunction(name); // index! + if (func->imported()) { continue; } - auto* func = module->getFunction(name); // Refine argument types before doing anything else. This does not // affect whether an argument is used or not, it just refines the type // where possible. @@ -354,10 +357,13 @@ struct DAE : public Pass { for (Index index = 0; index < numFunctions; index++) { auto& calls = allCalls[index]; auto name = names[index]; - if (hasUnseenCalls[index]) { + if (hasUnseenCalls.count(index)) { continue; } auto* func = module->getFunction(name); + if (func->imported()) { + continue; + } auto numParams = func->getNumParams(); if (numParams == 0) { continue; @@ -380,18 +386,21 @@ struct DAE : public Pass { // once to remove a param, once to drop the return value). if (worthOptimizing.empty()) { for (auto& func : module->functions) { + if (func->imported()) { // XXX why not before? + continue; + } if (func->getResults() == Type::none) { continue; } auto name = func->name; auto index = indexes[name]; - if (hasUnseenCalls[index]) { + if (hasUnseenCalls.count(index)) { continue; } if (infoMap[name].hasTailCalls) { continue; } - if (tailCallees[index]) { + if (tailCallees.count(index)) { continue; } auto& calls = allCalls[index]; From 3f26c1e4626609653a57b81f24ff6c5961c168de Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 15:52:32 -0700 Subject: [PATCH 03/17] vec --- src/passes/DeadArgumentElimination.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 300b3afb66b..ee1493b05d2 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -247,8 +247,8 @@ struct DAE : public Pass { // TODO: vectors! std::vector> allCalls(numFunctions); - std::unordered_set tailCallees; - std::unordered_set hasUnseenCalls; + std::vector tailCallees(numFunctions); + std::vector hasUnseenCalls(numFunctions); // Track the function in which relevant expressions exist. When we modify // those expressions we will need to mark the function's info as stale. std::unordered_map expressionFuncs; @@ -261,19 +261,19 @@ struct DAE : public Pass { } } for (auto& callee : info.tailCallees) { - tailCallees.insert(indexes[callee]); + tailCallees[indexes[callee]] = true; } for (auto& [call, dropp] : info.droppedCalls) { allDroppedCalls[call] = dropp; } for (auto& name : info.hasUnseenCalls) { - hasUnseenCalls.insert(indexes[name]); + hasUnseenCalls[indexes[name]] = true; } } // Exports are considered unseen calls. for (auto& curr : module->exports) { if (curr->kind == ExternalKind::Function) { - hasUnseenCalls.insert(indexes[*curr->getInternalName()]); + hasUnseenCalls[indexes[*curr->getInternalName()]] = true; } } @@ -316,7 +316,7 @@ struct DAE : public Pass { auto& calls = allCalls[index]; // We can only optimize if we see all the calls and can modify them. auto name = names[index]; - if (hasUnseenCalls.count(index)) { + if (hasUnseenCalls[index]) { continue; } auto* func = module->getFunction(name); // index! @@ -357,7 +357,7 @@ struct DAE : public Pass { for (Index index = 0; index < numFunctions; index++) { auto& calls = allCalls[index]; auto name = names[index]; - if (hasUnseenCalls.count(index)) { + if (hasUnseenCalls[index]) { continue; } auto* func = module->getFunction(name); @@ -394,13 +394,13 @@ struct DAE : public Pass { } auto name = func->name; auto index = indexes[name]; - if (hasUnseenCalls.count(index)) { + if (hasUnseenCalls[index]) { continue; } if (infoMap[name].hasTailCalls) { continue; } - if (tailCallees.count(index)) { + if (tailCallees[index]) { continue; } auto& calls = allCalls[index]; From 295200ef22567d171bd9a89f60e3b6d740e2387e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 15:57:20 -0700 Subject: [PATCH 04/17] vec --- src/passes/DeadArgumentElimination.cpp | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index ee1493b05d2..f276beaa48f 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -313,16 +313,16 @@ struct DAE : public Pass { // We now have a mapping of all call sites for each function, and can look // for optimization opportunities. for (Index index = 0; index < numFunctions; index++) { + auto* func = module->functions[index].get(); + if (func->imported()) { + continue; + } auto& calls = allCalls[index]; // We can only optimize if we see all the calls and can modify them. - auto name = names[index]; + auto name = func->name; if (hasUnseenCalls[index]) { continue; } - auto* func = module->getFunction(name); // index! - if (func->imported()) { - continue; - } // Refine argument types before doing anything else. This does not // affect whether an argument is used or not, it just refines the type // where possible. @@ -333,7 +333,7 @@ struct DAE : public Pass { // Refine return types as well. if (refineReturnTypes(func, calls, module)) { refinedReturnTypes = true; - markStale(func->name); + markStale(name); markCallersStale(calls); } auto optimizedIndexes = @@ -355,13 +355,13 @@ struct DAE : public Pass { } // We now know which parameters are unused, and can potentially remove them. for (Index index = 0; index < numFunctions; index++) { - auto& calls = allCalls[index]; - auto name = names[index]; - if (hasUnseenCalls[index]) { + auto* func = module->functions[index].get(); + if (func->imported()) { continue; } - auto* func = module->getFunction(name); - if (func->imported()) { + auto& calls = allCalls[index]; + auto name = func->name; + if (hasUnseenCalls[index]) { continue; } auto numParams = func->getNumParams(); @@ -373,7 +373,7 @@ struct DAE : public Pass { if (!removedIndexes.empty()) { // Success! worthOptimizing.insert(func); - markStale(func->name); + markStale(name); markCallersStale(calls); } if (outcome == ParamUtils::RemovalOutcome::Failure) { @@ -385,7 +385,8 @@ struct DAE : public Pass { // 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 (worthOptimizing.empty()) { - for (auto& func : module->functions) { + for (Index index = 0; index < numFunctions; index++) { + auto& func = module->functions[index]; if (func->imported()) { // XXX why not before? continue; } @@ -393,7 +394,6 @@ struct DAE : public Pass { continue; } auto name = func->name; - auto index = indexes[name]; if (hasUnseenCalls[index]) { continue; } @@ -423,7 +423,7 @@ struct DAE : public Pass { // TODO Removing a drop may also open optimization opportunities in the // callers. worthOptimizing.insert(func.get()); - markStale(func->name); + markStale(name); markCallersStale(calls); } } From 971499362398cb87febce93691fd9a99563f7056 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 15:58:28 -0700 Subject: [PATCH 05/17] vec --- src/passes/DeadArgumentElimination.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index f276beaa48f..c73c3a0cad1 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -236,13 +236,9 @@ struct DAE : public Pass { // Maps function names to indexes. This lets us use indexes below for speed. std::unordered_map indexes; - // Reverse mapping for convenience. auto numFunctions = module->functions.size(); - std::vector names(numFunctions); for (Index i = 0; i < module->functions.size(); i++) { - auto name = module->functions[i]->name; - indexes[name] = i; - names[i] = name; + indexes[module->functions[i]->name] = i; } // TODO: vectors! From 31c6e8dac6b2e61515a8cd876155e26ea13fe819 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 16:10:34 -0700 Subject: [PATCH 06/17] vec --- src/passes/DeadArgumentElimination.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index c73c3a0cad1..7e4774db663 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -274,7 +274,7 @@ struct DAE : public Pass { } // Track which functions we changed that are worth re-optimizing at the end. - std::unordered_set worthOptimizing; + std::vector worthOptimizing; // If we refine return types then we will need to do more type updating // at the end. @@ -323,7 +323,7 @@ struct DAE : public Pass { // affect whether an argument is used or not, it just refines the type // where possible. if (refineArgumentTypes(func, calls, module, infoMap[name])) { - worthOptimizing.insert(func); + worthOptimizing.push_back(func); markStale(func->name); } // Refine return types as well. @@ -368,7 +368,7 @@ struct DAE : public Pass { {func}, infoMap[name].unusedParams, calls, {}, module, getPassRunner()); if (!removedIndexes.empty()) { // Success! - worthOptimizing.insert(func); + worthOptimizing.push_back(func); markStale(name); markCallersStale(calls); } @@ -413,12 +413,12 @@ struct DAE : public Pass { if (removeReturnValue(func.get(), calls, module)) { // We should optimize the callers. for (auto* call : calls) { - worthOptimizing.insert(module->getFunction(expressionFuncs[call])); + worthOptimizing.push_back(module->getFunction(expressionFuncs[call])); } } // TODO Removing a drop may also open optimization opportunities in the // callers. - worthOptimizing.insert(func.get()); + worthOptimizing.push_back(func.get()); markStale(name); markCallersStale(calls); } @@ -430,7 +430,8 @@ struct DAE : public Pass { }); } if (optimize && !worthOptimizing.empty()) { - OptUtils::optimizeAfterInlining(worthOptimizing, module, getPassRunner()); + std::unordered_set worthOptimizingSet(worthOptimizing.begin(), worthOptimizing.end()); + OptUtils::optimizeAfterInlining(worthOptimizingSet, module, getPassRunner()); } return !worthOptimizing.empty() || refinedReturnTypes || From 2b2fdaa75f5ca79c2f0b870ecb33c92b5659b846 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 16:15:30 -0700 Subject: [PATCH 07/17] form --- src/passes/DeadArgumentElimination.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 7e4774db663..a46bcc28e02 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -413,7 +413,8 @@ struct DAE : public Pass { if (removeReturnValue(func.get(), calls, module)) { // We should optimize the callers. for (auto* call : calls) { - worthOptimizing.push_back(module->getFunction(expressionFuncs[call])); + worthOptimizing.push_back( + module->getFunction(expressionFuncs[call])); } } // TODO Removing a drop may also open optimization opportunities in the @@ -430,8 +431,10 @@ struct DAE : public Pass { }); } if (optimize && !worthOptimizing.empty()) { - std::unordered_set worthOptimizingSet(worthOptimizing.begin(), worthOptimizing.end()); - OptUtils::optimizeAfterInlining(worthOptimizingSet, module, getPassRunner()); + std::unordered_set worthOptimizingSet(worthOptimizing.begin(), + worthOptimizing.end()); + OptUtils::optimizeAfterInlining( + worthOptimizingSet, module, getPassRunner()); } return !worthOptimizing.empty() || refinedReturnTypes || From 4dcb35cd7d4fb48c31c6d500749cf6eb35bb211e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 16:19:04 -0700 Subject: [PATCH 08/17] un --- src/passes/DeadArgumentElimination.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index a46bcc28e02..6a8b66f6020 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -274,7 +274,9 @@ struct DAE : public Pass { } // Track which functions we changed that are worth re-optimizing at the end. - std::vector worthOptimizing; + // For efficiency we use a vector here, which may sometimes contain + // duplicates + std::unordered_set worthOptimizing; // If we refine return types then we will need to do more type updating // at the end. @@ -323,7 +325,7 @@ struct DAE : public Pass { // affect whether an argument is used or not, it just refines the type // where possible. if (refineArgumentTypes(func, calls, module, infoMap[name])) { - worthOptimizing.push_back(func); + worthOptimizing.insert(func); markStale(func->name); } // Refine return types as well. @@ -368,7 +370,7 @@ struct DAE : public Pass { {func}, infoMap[name].unusedParams, calls, {}, module, getPassRunner()); if (!removedIndexes.empty()) { // Success! - worthOptimizing.push_back(func); + worthOptimizing.insert(func); markStale(name); markCallersStale(calls); } @@ -413,13 +415,13 @@ struct DAE : public Pass { if (removeReturnValue(func.get(), calls, module)) { // We should optimize the callers. for (auto* call : calls) { - worthOptimizing.push_back( + worthOptimizing.insert( module->getFunction(expressionFuncs[call])); } } // TODO Removing a drop may also open optimization opportunities in the // callers. - worthOptimizing.push_back(func.get()); + worthOptimizing.insert(func.get()); markStale(name); markCallersStale(calls); } @@ -431,10 +433,7 @@ struct DAE : public Pass { }); } if (optimize && !worthOptimizing.empty()) { - std::unordered_set worthOptimizingSet(worthOptimizing.begin(), - worthOptimizing.end()); - OptUtils::optimizeAfterInlining( - worthOptimizingSet, module, getPassRunner()); + OptUtils::optimizeAfterInlining(worthOptimizing, module, getPassRunner()); } return !worthOptimizing.empty() || refinedReturnTypes || From 0c7491cb253ea08ecd26d905d08413be726c484e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 22 Aug 2025 16:19:10 -0700 Subject: [PATCH 09/17] fix --- src/passes/DeadArgumentElimination.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 6a8b66f6020..ed0414fb281 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -415,8 +415,7 @@ struct DAE : public Pass { if (removeReturnValue(func.get(), calls, module)) { // We should optimize the callers. for (auto* call : calls) { - worthOptimizing.insert( - module->getFunction(expressionFuncs[call])); + worthOptimizing.insert(module->getFunction(expressionFuncs[call])); } } // TODO Removing a drop may also open optimization opportunities in the From 3d5e3a2089cce66745a518bc48e235ec438bc534 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 08:43:03 -0700 Subject: [PATCH 10/17] fastr --- src/passes/DeadArgumentElimination.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index ed0414fb281..e014771fea8 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -188,6 +188,11 @@ struct DAE : public Pass { bool optimize = false; + Index numFunctions; + + // Map of function names to indexes. This lets us use indexes below for speed. + std::unordered_map indexes; + void run(Module* module) override { DAEFunctionInfoMap infoMap; // Ensure all entries exist so the parallel threads don't modify the data @@ -198,6 +203,13 @@ struct DAE : public Pass { // The null name represents module-level code (not in a function). infoMap[Name()]; + numFunctions = module->functions.size(); + + std::unordered_map indexes; + for (Index i = 0; i < numFunctions; i++) { + indexes[module->functions[i]->name] = i; + } + // Iterate to convergence. while (1) { if (!iteration(module, infoMap)) { @@ -234,13 +246,6 @@ struct DAE : public Pass { Function* func; }; - // Maps function names to indexes. This lets us use indexes below for speed. - std::unordered_map indexes; - auto numFunctions = module->functions.size(); - for (Index i = 0; i < module->functions.size(); i++) { - indexes[module->functions[i]->name] = i; - } - // TODO: vectors! std::vector> allCalls(numFunctions); std::vector tailCallees(numFunctions); From 4842d6aa97a197bfe9bc882e9aefe7d8a0315589 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 08:44:04 -0700 Subject: [PATCH 11/17] clean --- src/passes/DeadArgumentElimination.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index e014771fea8..761e39316e1 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -246,10 +246,10 @@ struct DAE : public Pass { Function* func; }; - // TODO: vectors! std::vector> allCalls(numFunctions); std::vector tailCallees(numFunctions); std::vector hasUnseenCalls(numFunctions); + // Track the function in which relevant expressions exist. When we modify // those expressions we will need to mark the function's info as stale. std::unordered_map expressionFuncs; @@ -279,8 +279,6 @@ struct DAE : public Pass { } // Track which functions we changed that are worth re-optimizing at the end. - // For efficiency we use a vector here, which may sometimes contain - // duplicates std::unordered_set worthOptimizing; // If we refine return types then we will need to do more type updating From f87a5a20d5752e7890cb699c28186cbefecd0ba6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:01:42 -0700 Subject: [PATCH 12/17] whoops --- src/passes/DeadArgumentElimination.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 761e39316e1..5a0fdc7d936 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -205,7 +205,6 @@ struct DAE : public Pass { numFunctions = module->functions.size(); - std::unordered_map indexes; for (Index i = 0; i < numFunctions; i++) { indexes[module->functions[i]->name] = i; } From cee0e0b4db034174cb7755e724ba735cb941b833 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:44:29 -0700 Subject: [PATCH 13/17] fix --- src/passes/DeadArgumentElimination.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 5a0fdc7d936..dcaf119a858 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -317,12 +317,16 @@ struct DAE : public Pass { if (func->imported()) { continue; } - auto& calls = allCalls[index]; // We can only optimize if we see all the calls and can modify them. auto name = func->name; if (hasUnseenCalls[index]) { continue; } + auto& calls = allCalls[index]; + if (calls.empty()) { + // Nothing calls this, so it is not worth optimizing. + continue; + } // Refine argument types before doing anything else. This does not // affect whether an argument is used or not, it just refines the type // where possible. @@ -359,7 +363,6 @@ struct DAE : public Pass { if (func->imported()) { continue; } - auto& calls = allCalls[index]; auto name = func->name; if (hasUnseenCalls[index]) { continue; @@ -368,6 +371,10 @@ struct DAE : public Pass { if (numParams == 0) { continue; } + auto& calls = allCalls[index]; + if (calls.empty()) { + continue; + } auto [removedIndexes, outcome] = ParamUtils::removeParameters( {func}, infoMap[name].unusedParams, calls, {}, module, getPassRunner()); if (!removedIndexes.empty()) { @@ -433,7 +440,7 @@ struct DAE : public Pass { markStale(func->name); }); } - if (optimize && !worthOptimizing.empty()) { + if (optimize && !worthOptimizing.empty()) { OptUtils::optimizeAfterInlining(worthOptimizing, module, getPassRunner()); } From ef6b4daf1ed04547601e42e6592f19b1fd976b4a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:44:36 -0700 Subject: [PATCH 14/17] format --- src/passes/DeadArgumentElimination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index dcaf119a858..b202d2e1476 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -440,7 +440,7 @@ struct DAE : public Pass { markStale(func->name); }); } - if (optimize && !worthOptimizing.empty()) { + if (optimize && !worthOptimizing.empty()) { OptUtils::optimizeAfterInlining(worthOptimizing, module, getPassRunner()); } From a41e15815d640a09d97c4317ba9b59a68e93ed20 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:52:22 -0700 Subject: [PATCH 15/17] clean --- src/passes/DeadArgumentElimination.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index b202d2e1476..3943d2b1a32 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -318,7 +318,6 @@ struct DAE : public Pass { continue; } // We can only optimize if we see all the calls and can modify them. - auto name = func->name; if (hasUnseenCalls[index]) { continue; } @@ -330,6 +329,7 @@ struct DAE : public Pass { // Refine argument types before doing anything else. This does not // affect whether an argument is used or not, it just refines the type // where possible. + auto name = func->name; if (refineArgumentTypes(func, calls, module, infoMap[name])) { worthOptimizing.insert(func); markStale(func->name); @@ -363,7 +363,6 @@ struct DAE : public Pass { if (func->imported()) { continue; } - auto name = func->name; if (hasUnseenCalls[index]) { continue; } @@ -375,6 +374,7 @@ struct DAE : public Pass { if (calls.empty()) { continue; } + auto name = func->name; auto [removedIndexes, outcome] = ParamUtils::removeParameters( {func}, infoMap[name].unusedParams, calls, {}, module, getPassRunner()); if (!removedIndexes.empty()) { From ad31f5cf373dc9bcffaccbf3eef89d07cc386fe3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:52:56 -0700 Subject: [PATCH 16/17] clean --- src/passes/DeadArgumentElimination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 3943d2b1a32..ba44c86bea8 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -394,7 +394,7 @@ struct DAE : public Pass { if (worthOptimizing.empty()) { for (Index index = 0; index < numFunctions; index++) { auto& func = module->functions[index]; - if (func->imported()) { // XXX why not before? + if (func->imported()) { continue; } if (func->getResults() == Type::none) { From 4717ae03edd2723dd8cdc6d575f447630898668d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 27 Aug 2025 09:56:50 -0700 Subject: [PATCH 17/17] clean --- src/passes/DeadArgumentElimination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index ba44c86bea8..c1a6689c976 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -400,10 +400,10 @@ struct DAE : public Pass { if (func->getResults() == Type::none) { continue; } - auto name = func->name; if (hasUnseenCalls[index]) { continue; } + auto name = func->name; if (infoMap[name].hasTailCalls) { continue; }