1*9880d681SAndroid Build Coastguard Worker //===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===// 2*9880d681SAndroid Build Coastguard Worker // 3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure 4*9880d681SAndroid Build Coastguard Worker // 5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source 6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details. 7*9880d681SAndroid Build Coastguard Worker // 8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 9*9880d681SAndroid Build Coastguard Worker // 10*9880d681SAndroid Build Coastguard Worker // This class is to be used as a base class for operations that want to zero in 11*9880d681SAndroid Build Coastguard Worker // on a subset of the input which still causes the bug we are tracking. 12*9880d681SAndroid Build Coastguard Worker // 13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 14*9880d681SAndroid Build Coastguard Worker 15*9880d681SAndroid Build Coastguard Worker #ifndef LLVM_TOOLS_BUGPOINT_LISTREDUCER_H 16*9880d681SAndroid Build Coastguard Worker #define LLVM_TOOLS_BUGPOINT_LISTREDUCER_H 17*9880d681SAndroid Build Coastguard Worker 18*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ErrorHandling.h" 19*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h" 20*9880d681SAndroid Build Coastguard Worker #include <algorithm> 21*9880d681SAndroid Build Coastguard Worker #include <cstdlib> 22*9880d681SAndroid Build Coastguard Worker #include <vector> 23*9880d681SAndroid Build Coastguard Worker 24*9880d681SAndroid Build Coastguard Worker namespace llvm { 25*9880d681SAndroid Build Coastguard Worker 26*9880d681SAndroid Build Coastguard Worker extern bool BugpointIsInterrupted; 27*9880d681SAndroid Build Coastguard Worker 28*9880d681SAndroid Build Coastguard Worker template<typename ElTy> 29*9880d681SAndroid Build Coastguard Worker struct ListReducer { 30*9880d681SAndroid Build Coastguard Worker enum TestResult { 31*9880d681SAndroid Build Coastguard Worker NoFailure, // No failure of the predicate was detected 32*9880d681SAndroid Build Coastguard Worker KeepSuffix, // The suffix alone satisfies the predicate 33*9880d681SAndroid Build Coastguard Worker KeepPrefix, // The prefix alone satisfies the predicate 34*9880d681SAndroid Build Coastguard Worker InternalError // Encountered an error trying to run the predicate 35*9880d681SAndroid Build Coastguard Worker }; 36*9880d681SAndroid Build Coastguard Worker ~ListReducerListReducer37*9880d681SAndroid Build Coastguard Worker virtual ~ListReducer() {} 38*9880d681SAndroid Build Coastguard Worker 39*9880d681SAndroid Build Coastguard Worker // doTest - This virtual function should be overriden by subclasses to 40*9880d681SAndroid Build Coastguard Worker // implement the test desired. The testcase is only required to test to see 41*9880d681SAndroid Build Coastguard Worker // if the Kept list still satisfies the property, but if it is going to check 42*9880d681SAndroid Build Coastguard Worker // the prefix anyway, it can. 43*9880d681SAndroid Build Coastguard Worker // 44*9880d681SAndroid Build Coastguard Worker virtual TestResult doTest(std::vector<ElTy> &Prefix, 45*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> &Kept, 46*9880d681SAndroid Build Coastguard Worker std::string &Error) = 0; 47*9880d681SAndroid Build Coastguard Worker 48*9880d681SAndroid Build Coastguard Worker // reduceList - This function attempts to reduce the length of the specified 49*9880d681SAndroid Build Coastguard Worker // list while still maintaining the "test" property. This is the core of the 50*9880d681SAndroid Build Coastguard Worker // "work" that bugpoint does. 51*9880d681SAndroid Build Coastguard Worker // reduceListListReducer52*9880d681SAndroid Build Coastguard Worker bool reduceList(std::vector<ElTy> &TheList, std::string &Error) { 53*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> empty; 54*9880d681SAndroid Build Coastguard Worker std::srand(0x6e5ea738); // Seed the random number generator 55*9880d681SAndroid Build Coastguard Worker switch (doTest(TheList, empty, Error)) { 56*9880d681SAndroid Build Coastguard Worker case KeepPrefix: 57*9880d681SAndroid Build Coastguard Worker if (TheList.size() == 1) // we are done, it's the base case and it fails 58*9880d681SAndroid Build Coastguard Worker return true; 59*9880d681SAndroid Build Coastguard Worker else 60*9880d681SAndroid Build Coastguard Worker break; // there's definitely an error, but we need to narrow it down 61*9880d681SAndroid Build Coastguard Worker 62*9880d681SAndroid Build Coastguard Worker case KeepSuffix: 63*9880d681SAndroid Build Coastguard Worker // cannot be reached! 64*9880d681SAndroid Build Coastguard Worker llvm_unreachable("bugpoint ListReducer internal error: " 65*9880d681SAndroid Build Coastguard Worker "selected empty set."); 66*9880d681SAndroid Build Coastguard Worker 67*9880d681SAndroid Build Coastguard Worker case NoFailure: 68*9880d681SAndroid Build Coastguard Worker return false; // there is no failure with the full set of passes/funcs! 69*9880d681SAndroid Build Coastguard Worker 70*9880d681SAndroid Build Coastguard Worker case InternalError: 71*9880d681SAndroid Build Coastguard Worker assert(!Error.empty()); 72*9880d681SAndroid Build Coastguard Worker return true; 73*9880d681SAndroid Build Coastguard Worker } 74*9880d681SAndroid Build Coastguard Worker 75*9880d681SAndroid Build Coastguard Worker // Maximal number of allowed splitting iterations, 76*9880d681SAndroid Build Coastguard Worker // before the elements are randomly shuffled. 77*9880d681SAndroid Build Coastguard Worker const unsigned MaxIterationsWithoutProgress = 3; 78*9880d681SAndroid Build Coastguard Worker 79*9880d681SAndroid Build Coastguard Worker // Maximal number of allowed single-element trim iterations. We add a 80*9880d681SAndroid Build Coastguard Worker // threshhold here as single-element reductions may otherwise take a 81*9880d681SAndroid Build Coastguard Worker // very long time to complete. 82*9880d681SAndroid Build Coastguard Worker const unsigned MaxTrimIterationsWithoutBackJump = 3; 83*9880d681SAndroid Build Coastguard Worker bool ShufflingEnabled = true; 84*9880d681SAndroid Build Coastguard Worker 85*9880d681SAndroid Build Coastguard Worker Backjump: 86*9880d681SAndroid Build Coastguard Worker unsigned MidTop = TheList.size(); 87*9880d681SAndroid Build Coastguard Worker unsigned MaxIterations = MaxIterationsWithoutProgress; 88*9880d681SAndroid Build Coastguard Worker unsigned NumOfIterationsWithoutProgress = 0; 89*9880d681SAndroid Build Coastguard Worker while (MidTop > 1) { // Binary split reduction loop 90*9880d681SAndroid Build Coastguard Worker // Halt if the user presses ctrl-c. 91*9880d681SAndroid Build Coastguard Worker if (BugpointIsInterrupted) { 92*9880d681SAndroid Build Coastguard Worker errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; 93*9880d681SAndroid Build Coastguard Worker return true; 94*9880d681SAndroid Build Coastguard Worker } 95*9880d681SAndroid Build Coastguard Worker 96*9880d681SAndroid Build Coastguard Worker // If the loop doesn't make satisfying progress, try shuffling. 97*9880d681SAndroid Build Coastguard Worker // The purpose of shuffling is to avoid the heavy tails of the 98*9880d681SAndroid Build Coastguard Worker // distribution (improving the speed of convergence). 99*9880d681SAndroid Build Coastguard Worker if (ShufflingEnabled && 100*9880d681SAndroid Build Coastguard Worker NumOfIterationsWithoutProgress > MaxIterations) { 101*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> ShuffledList(TheList); 102*9880d681SAndroid Build Coastguard Worker std::random_shuffle(ShuffledList.begin(), ShuffledList.end()); 103*9880d681SAndroid Build Coastguard Worker errs() << "\n\n*** Testing shuffled set...\n\n"; 104*9880d681SAndroid Build Coastguard Worker // Check that random shuffle doesn't loose the bug 105*9880d681SAndroid Build Coastguard Worker if (doTest(ShuffledList, empty, Error) == KeepPrefix) { 106*9880d681SAndroid Build Coastguard Worker // If the bug is still here, use the shuffled list. 107*9880d681SAndroid Build Coastguard Worker TheList.swap(ShuffledList); 108*9880d681SAndroid Build Coastguard Worker MidTop = TheList.size(); 109*9880d681SAndroid Build Coastguard Worker // Must increase the shuffling treshold to avoid the small 110*9880d681SAndroid Build Coastguard Worker // probability of inifinite looping without making progress. 111*9880d681SAndroid Build Coastguard Worker MaxIterations += 2; 112*9880d681SAndroid Build Coastguard Worker errs() << "\n\n*** Shuffling does not hide the bug...\n\n"; 113*9880d681SAndroid Build Coastguard Worker } else { 114*9880d681SAndroid Build Coastguard Worker ShufflingEnabled = false; // Disable shuffling further on 115*9880d681SAndroid Build Coastguard Worker errs() << "\n\n*** Shuffling hides the bug...\n\n"; 116*9880d681SAndroid Build Coastguard Worker } 117*9880d681SAndroid Build Coastguard Worker NumOfIterationsWithoutProgress = 0; 118*9880d681SAndroid Build Coastguard Worker } 119*9880d681SAndroid Build Coastguard Worker 120*9880d681SAndroid Build Coastguard Worker unsigned Mid = MidTop / 2; 121*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> Prefix(TheList.begin(), TheList.begin()+Mid); 122*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> Suffix(TheList.begin()+Mid, TheList.end()); 123*9880d681SAndroid Build Coastguard Worker 124*9880d681SAndroid Build Coastguard Worker switch (doTest(Prefix, Suffix, Error)) { 125*9880d681SAndroid Build Coastguard Worker case KeepSuffix: 126*9880d681SAndroid Build Coastguard Worker // The property still holds. We can just drop the prefix elements, and 127*9880d681SAndroid Build Coastguard Worker // shorten the list to the "kept" elements. 128*9880d681SAndroid Build Coastguard Worker TheList.swap(Suffix); 129*9880d681SAndroid Build Coastguard Worker MidTop = TheList.size(); 130*9880d681SAndroid Build Coastguard Worker // Reset progress treshold and progress counter 131*9880d681SAndroid Build Coastguard Worker MaxIterations = MaxIterationsWithoutProgress; 132*9880d681SAndroid Build Coastguard Worker NumOfIterationsWithoutProgress = 0; 133*9880d681SAndroid Build Coastguard Worker break; 134*9880d681SAndroid Build Coastguard Worker case KeepPrefix: 135*9880d681SAndroid Build Coastguard Worker // The predicate still holds, shorten the list to the prefix elements. 136*9880d681SAndroid Build Coastguard Worker TheList.swap(Prefix); 137*9880d681SAndroid Build Coastguard Worker MidTop = TheList.size(); 138*9880d681SAndroid Build Coastguard Worker // Reset progress treshold and progress counter 139*9880d681SAndroid Build Coastguard Worker MaxIterations = MaxIterationsWithoutProgress; 140*9880d681SAndroid Build Coastguard Worker NumOfIterationsWithoutProgress = 0; 141*9880d681SAndroid Build Coastguard Worker break; 142*9880d681SAndroid Build Coastguard Worker case NoFailure: 143*9880d681SAndroid Build Coastguard Worker // Otherwise the property doesn't hold. Some of the elements we removed 144*9880d681SAndroid Build Coastguard Worker // must be necessary to maintain the property. 145*9880d681SAndroid Build Coastguard Worker MidTop = Mid; 146*9880d681SAndroid Build Coastguard Worker NumOfIterationsWithoutProgress++; 147*9880d681SAndroid Build Coastguard Worker break; 148*9880d681SAndroid Build Coastguard Worker case InternalError: 149*9880d681SAndroid Build Coastguard Worker return true; // Error was set by doTest. 150*9880d681SAndroid Build Coastguard Worker } 151*9880d681SAndroid Build Coastguard Worker assert(Error.empty() && "doTest did not return InternalError for error"); 152*9880d681SAndroid Build Coastguard Worker } 153*9880d681SAndroid Build Coastguard Worker 154*9880d681SAndroid Build Coastguard Worker // Probability of backjumping from the trimming loop back to the binary 155*9880d681SAndroid Build Coastguard Worker // split reduction loop. 156*9880d681SAndroid Build Coastguard Worker const int BackjumpProbability = 10; 157*9880d681SAndroid Build Coastguard Worker 158*9880d681SAndroid Build Coastguard Worker // Okay, we trimmed as much off the top and the bottom of the list as we 159*9880d681SAndroid Build Coastguard Worker // could. If there is more than two elements in the list, try deleting 160*9880d681SAndroid Build Coastguard Worker // interior elements and testing that. 161*9880d681SAndroid Build Coastguard Worker // 162*9880d681SAndroid Build Coastguard Worker if (TheList.size() > 2) { 163*9880d681SAndroid Build Coastguard Worker bool Changed = true; 164*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> EmptyList; 165*9880d681SAndroid Build Coastguard Worker unsigned TrimIterations = 0; 166*9880d681SAndroid Build Coastguard Worker while (Changed) { // Trimming loop. 167*9880d681SAndroid Build Coastguard Worker Changed = false; 168*9880d681SAndroid Build Coastguard Worker 169*9880d681SAndroid Build Coastguard Worker // If the binary split reduction loop made an unfortunate sequence of 170*9880d681SAndroid Build Coastguard Worker // splits, the trimming loop might be left off with a huge number of 171*9880d681SAndroid Build Coastguard Worker // remaining elements (large search space). Backjumping out of that 172*9880d681SAndroid Build Coastguard Worker // search space and attempting a different split can significantly 173*9880d681SAndroid Build Coastguard Worker // improve the convergence speed. 174*9880d681SAndroid Build Coastguard Worker if (std::rand() % 100 < BackjumpProbability) 175*9880d681SAndroid Build Coastguard Worker goto Backjump; 176*9880d681SAndroid Build Coastguard Worker 177*9880d681SAndroid Build Coastguard Worker for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts 178*9880d681SAndroid Build Coastguard Worker if (BugpointIsInterrupted) { 179*9880d681SAndroid Build Coastguard Worker errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; 180*9880d681SAndroid Build Coastguard Worker return true; 181*9880d681SAndroid Build Coastguard Worker } 182*9880d681SAndroid Build Coastguard Worker 183*9880d681SAndroid Build Coastguard Worker std::vector<ElTy> TestList(TheList); 184*9880d681SAndroid Build Coastguard Worker TestList.erase(TestList.begin()+i); 185*9880d681SAndroid Build Coastguard Worker 186*9880d681SAndroid Build Coastguard Worker if (doTest(EmptyList, TestList, Error) == KeepSuffix) { 187*9880d681SAndroid Build Coastguard Worker // We can trim down the list! 188*9880d681SAndroid Build Coastguard Worker TheList.swap(TestList); 189*9880d681SAndroid Build Coastguard Worker --i; // Don't skip an element of the list 190*9880d681SAndroid Build Coastguard Worker Changed = true; 191*9880d681SAndroid Build Coastguard Worker } 192*9880d681SAndroid Build Coastguard Worker if (!Error.empty()) 193*9880d681SAndroid Build Coastguard Worker return true; 194*9880d681SAndroid Build Coastguard Worker } 195*9880d681SAndroid Build Coastguard Worker if (TrimIterations >= MaxTrimIterationsWithoutBackJump) 196*9880d681SAndroid Build Coastguard Worker break; 197*9880d681SAndroid Build Coastguard Worker TrimIterations++; 198*9880d681SAndroid Build Coastguard Worker } 199*9880d681SAndroid Build Coastguard Worker } 200*9880d681SAndroid Build Coastguard Worker 201*9880d681SAndroid Build Coastguard Worker return true; // there are some failure and we've narrowed them down 202*9880d681SAndroid Build Coastguard Worker } 203*9880d681SAndroid Build Coastguard Worker }; 204*9880d681SAndroid Build Coastguard Worker 205*9880d681SAndroid Build Coastguard Worker } // End llvm namespace 206*9880d681SAndroid Build Coastguard Worker 207*9880d681SAndroid Build Coastguard Worker #endif 208