#include "BugDriver.h"
#include "SystemUtils.h"
+#include "ListReducer.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Transforms/Utils/Cloning.h"
"(for miscompilation detection)"));
}
-template<typename ElTy>
-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
- };
-
- // 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(const std::vector<ElTy> &Prefix,
- const std::vector<ElTy> &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.
- //
- void reduceList(std::vector<ElTy> &TheList) {
- unsigned MidTop = TheList.size();
- while (MidTop > 1) {
- unsigned Mid = MidTop / 2;
- std::vector<ElTy> Prefix(TheList.begin()+Mid, TheList.end());
- std::vector<ElTy> Kept (TheList.begin(), TheList.begin()+Mid);
-
- switch (doTest(Prefix, Kept)) {
- case KeepSuffix:
- // The property still holds. We can just drop the prefix elements, and
- // shorten the list to the "kept" elements.
- TheList.swap(Kept);
- 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 neccesary to maintain the property.
- MidTop = Mid;
- break;
- }
- }
- }
-};
-
class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> {
BugDriver &BD;
public:
ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {}
- virtual TestResult doTest(const std::vector<const PassInfo*> &Prefix,
- const std::vector<const PassInfo*> &Kept);
+ virtual TestResult doTest(std::vector<const PassInfo*> &Prefix,
+ std::vector<const PassInfo*> &Kept);
};
ReduceMiscompilingPasses::TestResult
-ReduceMiscompilingPasses::doTest(const std::vector<const PassInfo*> &Prefix,
- const std::vector<const PassInfo*> &Kept) {
- // First, run the program with just the Kept passes. If it is still broken
+ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix,
+ std::vector<const PassInfo*> &Suffix) {
+ // First, run the program with just the Suffix passes. If it is still broken
// with JUST the kept passes, discard the prefix passes.
- std::cout << "Checking to see if '" << getPassesString(Kept)
+ std::cout << "Checking to see if '" << getPassesString(Suffix)
<< "' compile correctly: ";
std::string BytecodeResult;
- if (BD.runPasses(Kept, BytecodeResult, false/*delete*/, true/*quiet*/)) {
+ if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
std::cerr << BD.getToolName() << ": Error running this sequence of passes"
<< " on the input program!\n";
exit(1);
if (Prefix.empty()) return NoFailure;
- // First, run the program with just the Kept passes. If it is still broken
- // with JUST the kept passes, discard the prefix passes.
+ // Next, see if the program is broken if we run the "prefix" passes first,
+ // then seperately run the "kept" passes.
std::cout << "Checking to see if '" << getPassesString(Prefix)
<< "' compile correctly: ";
}
removeFile(BytecodeResult); // No longer need the file on disk
- std::cout << "Checking to see if '" << getPassesString(Kept)
+ std::cout << "Checking to see if '" << getPassesString(Suffix)
<< "' passes compile correctly after the '"
<< getPassesString(Prefix) << "' passes: ";
Module *OriginalInput = BD.Program;
BD.Program = PrefixOutput;
- if (BD.runPasses(Kept, BytecodeResult, false/*delete*/, true/*quiet*/)) {
+ if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
std::cerr << BD.getToolName() << ": Error running this sequence of passes"
<< " on the input program!\n";
exit(1);
if (BD.diffProgram(Output, BytecodeResult, true/*delete bytecode*/)) {
std::cout << "nope.\n";
delete OriginalInput; // We pruned down the original input...
- return KeepPrefix;
+ return KeepSuffix;
}
// Otherwise, we must not be running the bad pass anymore.
public:
ReduceMiscompilingFunctions(BugDriver &bd) : BD(bd) {}
- virtual TestResult doTest(const std::vector<Function*> &Prefix,
- const std::vector<Function*> &Kept) {
- if (TestFuncs(Kept, false))
+ virtual TestResult doTest(std::vector<Function*> &Prefix,
+ std::vector<Function*> &Suffix) {
+ if (TestFuncs(Suffix, false))
return KeepSuffix;
- if (TestFuncs(Prefix, false))
+ if (!Prefix.empty() && TestFuncs(Prefix, false))
return KeepPrefix;
return NoFailure;
}
bool TestFuncs(const std::vector<Function*> &Prefix, bool EmitBytecode);
};
-// DeleteFunctionBody - "Remove" the function by deleting all of it's basic
-// blocks, making it external.
-//
-static void DeleteFunctionBody(Function *F) {
- // First, break circular use/def chain references...
- for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I)
- I->dropAllReferences();
-
- // Next, delete all of the basic blocks.
- F->getBasicBlockList().clear();
-
- assert(F->isExternal() && "This didn't make the function external!");
-}
-
-
bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs,
bool EmitBytecode) {
// Test to see if the function is misoptimized if we ONLY run it on the