ListReducer.h revision 1c2f68631e7710343bb7ba11b082ac91bdb9374d
1//===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This class is to be used as a base class for operations that want to zero in
11// on a subset of the input which still causes the bug we are tracking.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef BUGPOINT_LIST_REDUCER_H
16#define BUGPOINT_LIST_REDUCER_H
17
18#include <vector>
19#include <iostream>
20
21namespace llvm {
22
23template<typename ElTy>
24struct ListReducer {
25  enum TestResult {
26    NoFailure,         // No failure of the predicate was detected
27    KeepSuffix,        // The suffix alone satisfies the predicate
28    KeepPrefix,        // The prefix alone satisfies the predicate
29  };
30
31  virtual ~ListReducer() {}
32
33  // doTest - This virtual function should be overriden by subclasses to
34  // implement the test desired.  The testcase is only required to test to see
35  // if the Kept list still satisfies the property, but if it is going to check
36  // the prefix anyway, it can.
37  //
38  virtual TestResult doTest(std::vector<ElTy> &Prefix,
39                            std::vector<ElTy> &Kept) = 0;
40
41  // reduceList - This function attempts to reduce the length of the specified
42  // list while still maintaining the "test" property.  This is the core of the
43  // "work" that bugpoint does.
44  //
45  bool reduceList(std::vector<ElTy> &TheList) {
46    std::vector<ElTy> empty;
47    switch (doTest(TheList, empty)) {
48    case KeepPrefix:
49      if (TheList.size() == 1) // we are done, it's the base case and it fails
50        return true;
51      else
52        break; // there's definitely an error, but we need to narrow it down
53
54    case KeepSuffix:
55      // cannot be reached!
56      std::cerr << "bugpoint ListReducer internal error: selected empty set.\n";
57      abort();
58
59    case NoFailure:
60      return false; // there is no failure with the full set of passes/funcs!
61    }
62
63    unsigned MidTop = TheList.size();
64    while (MidTop > 1) {
65      unsigned Mid = MidTop / 2;
66      std::vector<ElTy> Prefix(TheList.begin(), TheList.begin()+Mid);
67      std::vector<ElTy> Suffix(TheList.begin()+Mid, TheList.end());
68
69      switch (doTest(Prefix, Suffix)) {
70      case KeepSuffix:
71        // The property still holds.  We can just drop the prefix elements, and
72        // shorten the list to the "kept" elements.
73        TheList.swap(Suffix);
74        MidTop = TheList.size();
75        break;
76      case KeepPrefix:
77        // The predicate still holds, shorten the list to the prefix elements.
78        TheList.swap(Prefix);
79        MidTop = TheList.size();
80        break;
81      case NoFailure:
82        // Otherwise the property doesn't hold.  Some of the elements we removed
83        // must be necessary to maintain the property.
84        MidTop = Mid;
85        break;
86      }
87    }
88
89    // Okay, we trimmed as much off the top and the bottom of the list as we
90    // could.  If there is more two elements in the list, try deleting interior
91    // elements and testing that.
92    //
93    if (TheList.size() > 2) {
94      bool Changed = true;
95      std::vector<ElTy> EmptyList;
96      while (Changed) {
97        Changed = false;
98        std::vector<ElTy> TrimmedList;
99        for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts
100          std::vector<ElTy> TestList(TheList);
101          TestList.erase(TestList.begin()+i);
102
103          if (doTest(EmptyList, TestList) == KeepSuffix) {
104            // We can trim down the list!
105            TheList.swap(TestList);
106            --i;  // Don't skip an element of the list
107            Changed = true;
108          }
109        }
110      }
111    }
112
113    return true; // there are some failure and we've narrowed them down
114  }
115};
116
117} // End llvm namespace
118
119#endif
120