//===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class is to be used as a base class for operations that want to zero in // on a subset of the input which still causes the bug we are tracking. // //===----------------------------------------------------------------------===// #ifndef BUGPOINT_LIST_REDUCER_H #define BUGPOINT_LIST_REDUCER_H #include #include namespace llvm { template struct ListReducer { enum TestResult { NoFailure, // No failure of the predicate was detected KeepSuffix, // The suffix alone satisfies the predicate KeepPrefix, // The prefix alone satisfies the predicate }; virtual ~ListReducer() {} // doTest - This virtual function should be overriden by subclasses to // implement the test desired. The testcase is only required to test to see // if the Kept list still satisfies the property, but if it is going to check // the prefix anyway, it can. // virtual TestResult doTest(std::vector &Prefix, std::vector &Kept) = 0; // reduceList - This function attempts to reduce the length of the specified // list while still maintaining the "test" property. This is the core of the // "work" that bugpoint does. // bool reduceList(std::vector &TheList) { std::vector empty; switch (doTest(TheList, empty)) { case KeepPrefix: if (TheList.size() == 1) // we are done, it's the base case and it fails return true; else break; // there's definitely an error, but we need to narrow it down case KeepSuffix: // cannot be reached! std::cerr << "bugpoint ListReducer internal error: selected empty set.\n"; abort(); case NoFailure: return false; // there is no failure with the full set of passes/funcs! } unsigned MidTop = TheList.size(); while (MidTop > 1) { unsigned Mid = MidTop / 2; std::vector Prefix(TheList.begin(), TheList.begin()+Mid); std::vector Suffix(TheList.begin()+Mid, TheList.end()); switch (doTest(Prefix, Suffix)) { case KeepSuffix: // The property still holds. We can just drop the prefix elements, and // shorten the list to the "kept" elements. TheList.swap(Suffix); MidTop = TheList.size(); break; case KeepPrefix: // The predicate still holds, shorten the list to the prefix elements. TheList.swap(Prefix); MidTop = TheList.size(); break; case NoFailure: // Otherwise the property doesn't hold. Some of the elements we removed // must be necessary to maintain the property. MidTop = Mid; break; } } // Okay, we trimmed as much off the top and the bottom of the list as we // could. If there is more two elements in the list, try deleting interior // elements and testing that. // if (TheList.size() > 2) { bool Changed = true; std::vector EmptyList; while (Changed) { Changed = false; std::vector TrimmedList; for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts std::vector TestList(TheList); TestList.erase(TestList.begin()+i); if (doTest(EmptyList, TestList) == KeepSuffix) { // We can trim down the list! TheList.swap(TestList); --i; // Don't skip an element of the list Changed = true; } } } } return true; // there are some failure and we've narrowed them down } }; } // End llvm namespace #endif