4141#include " llvm/Support/GraphWriter.h"
4242#include " llvm/Support/ManagedStatic.h"
4343
44+ #include < fstream>
45+
4446using namespace swift ;
4547
4648llvm::cl::opt<bool > SILPrintAll (
@@ -67,6 +69,20 @@ llvm::cl::opt<std::string> SILNumOptPassesToRun(
6769 " sil-opt-pass-count" , llvm::cl::init(" " ),
6870 llvm::cl::desc(" Stop optimizing after <N> passes or <N>.<M> passes/sub-passes" ));
6971
72+ // Read pass counts for each module from a config file.
73+ // Config file format:
74+ // <module-name>:<pass-count>(.<sub-pass-count>)
75+ //
76+ // This is useful for bisecting passes in large projects:
77+ // 1. create a config file from a full build log. E.g. with
78+ // grep -e '-module-name' build.log | sed -e 's/.*-module-name \([^ ]*\) .*/\1:10000000/' | sort | uniq > config.txt
79+ // 2. add the `-Xllvm -sil-pass-count-config-file config.txt` option to the project settings
80+ // 3. bisect by modifying the counts in the config file
81+ // 4. clean-rebuild after each bisecting step
82+ llvm::cl::opt<std::string> SILPassCountConfigFile (
83+ " sil-pass-count-config-file" , llvm::cl::init(" " ),
84+ llvm::cl::desc(" Read optimization counts from file" ));
85+
7086llvm::cl::opt<unsigned > SILOptProfileRepeat (
7187 " sil-opt-profile-repeat" , llvm::cl::init(1 ),
7288 llvm::cl::desc(" repeat passes N times and report the run time" ));
@@ -382,19 +398,25 @@ SILPassManager::SILPassManager(SILModule *M, bool isMandatory,
382398#include " swift/SILOptimizer/Analysis/Analysis.def"
383399
384400 if (!SILNumOptPassesToRun.empty ()) {
385- StringRef countsStr = SILNumOptPassesToRun;
386- bool validFormat = true ;
387- if (countsStr.consumeInteger (10 , maxNumPassesToRun))
388- validFormat = false ;
389- if (countsStr.startswith (" ." )) {
390- countsStr = countsStr.drop_front (1 );
391- if (countsStr.consumeInteger (10 , maxNumSubpassesToRun))
392- validFormat = false ;
393- }
394- if (!validFormat || !countsStr.empty ()) {
395- llvm::errs () << " error: wrong format of -sil-opt-pass-count option\n " ;
401+ parsePassCount (SILNumOptPassesToRun);
402+ } else if (!SILPassCountConfigFile.empty ()) {
403+ StringRef moduleName = M->getSwiftModule ()->getName ().str ();
404+ std::fstream fs (SILPassCountConfigFile);
405+ if (!fs) {
406+ llvm::errs () << " cannot open pass count config file\n " ;
396407 exit (1 );
397408 }
409+ std::string line;
410+ while (std::getline (fs, line)) {
411+ auto pair = StringRef (line).split (" :" );
412+ StringRef modName = pair.first ;
413+ StringRef countsStr = pair.second ;
414+ if (modName == moduleName) {
415+ parsePassCount (countsStr);
416+ break ;
417+ }
418+ }
419+ fs.close ();
398420 }
399421
400422 for (SILAnalysis *A : Analyses) {
@@ -407,6 +429,21 @@ SILPassManager::SILPassManager(SILModule *M, bool isMandatory,
407429 M->registerDeserializationNotificationHandler (std::move (handler));
408430}
409431
432+ void SILPassManager::parsePassCount (StringRef countsStr) {
433+ bool validFormat = true ;
434+ if (countsStr.consumeInteger (10 , maxNumPassesToRun))
435+ validFormat = false ;
436+ if (countsStr.startswith (" ." )) {
437+ countsStr = countsStr.drop_front (1 );
438+ if (countsStr.consumeInteger (10 , maxNumSubpassesToRun))
439+ validFormat = false ;
440+ }
441+ if (!validFormat || !countsStr.empty ()) {
442+ llvm::errs () << " error: wrong format of -sil-opt-pass-count option\n " ;
443+ exit (1 );
444+ }
445+ }
446+
410447bool SILPassManager::continueTransforming () {
411448 if (isMandatory)
412449 return true ;
0 commit comments