3535#include " support/colors.h"
3636#include " support/command-line.h"
3737#include " support/file.h"
38+ #include " support/hash.h"
3839#include " support/path.h"
3940#include " support/timing.h"
4041#include " tool-options.h"
@@ -397,10 +398,21 @@ struct Reducer
397398 return out == expected;
398399 }
399400
401+ size_t decisionCounter = 0 ;
402+
400403 bool shouldTryToReduce (size_t bonus = 1 ) {
401- static size_t counter = 0 ;
402- counter += bonus;
403- return (counter % factor) <= bonus;
404+ assert (bonus > 0 );
405+ // Increment to avoid returning the same result each time.
406+ decisionCounter += bonus;
407+ return (decisionCounter % factor) <= bonus;
408+ }
409+
410+ // Returns a random number in the range [0, max). This is deterministic given
411+ // all the previous work done in the reducer.
412+ size_t deterministicRandom (size_t max) {
413+ assert (max > 0 );
414+ hash_combine (decisionCounter, max);
415+ return decisionCounter % max;
404416 }
405417
406418 bool isOkReplacement (Expression* with) {
@@ -869,17 +881,26 @@ struct Reducer
869881 // amount of reduction that justifies doing even more.
870882 bool reduceFunctions () {
871883 // try to remove functions
872- std::cerr << " | try to remove functions\n " ;
873884 std::vector<Name> functionNames;
874885 for (auto & func : module ->functions ) {
875886 functionNames.push_back (func->name );
876887 }
888+ auto numFuncs = functionNames.size ();
889+ if (numFuncs == 0 ) {
890+ return false ;
891+ }
877892 size_t skip = 1 ;
878893 size_t maxSkip = 1 ;
879894 // If we just removed some functions in the previous iteration, keep trying
880895 // to remove more as this is one of the most efficient ways to reduce.
881896 bool justReduced = true ;
882- for (size_t i = 0 ; i < functionNames.size (); i++) {
897+ // Start from a new place each time.
898+ size_t base = deterministicRandom (numFuncs);
899+ std::cerr << " | try to remove functions (base: " << base
900+ << " , decisionCounter: " << decisionCounter << " , numFuncs "
901+ << numFuncs << " )\n " ;
902+ for (size_t x = 0 ; x < functionNames.size (); x++) {
903+ size_t i = (base + x) % numFuncs;
883904 if (!justReduced &&
884905 functionsWeTriedToRemove.count (functionNames[i]) == 1 &&
885906 !shouldTryToReduce (std::max ((factor / 5 ) + 1 , 20000 ))) {
@@ -897,18 +918,22 @@ struct Reducer
897918 if (names.size () == 0 ) {
898919 continue ;
899920 }
921+ std::cerr << " | trying at i=" << i << " of size " << names.size ()
922+ << " \n " ;
900923 // Try to remove functions and/or empty them. Note that
901924 // tryToRemoveFunctions() will reload the module if it fails, which means
902925 // function names may change - for that reason, run it second.
903926 justReduced = tryToEmptyFunctions (names) || tryToRemoveFunctions (names);
904927 if (justReduced) {
905928 noteReduction (names.size ());
906- i += skip;
929+ // Subtract 1 since the loop increments us anyhow by one: we want to
930+ // skip over the skipped functions, and not any more.
931+ x += skip - 1 ;
907932 skip = std::min (size_t (factor), 2 * skip);
908933 maxSkip = std::max (skip, maxSkip);
909934 } else {
910935 skip = std::max (skip / 2 , size_t (1 )); // or 1?
911- i += factor / 100 ;
936+ x += factor / 100 ;
912937 }
913938 }
914939 // If maxSkip is 1 then we never reduced at all. If it is 2 then we did
0 commit comments