| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame^] | 1 | //===- Miscompilation.cpp - Debug program miscompilations -----------------===// | 
|  | 2 | // | 
|  | 3 | // This file implements program miscompilation debugging support. | 
|  | 4 | // | 
|  | 5 | //===----------------------------------------------------------------------===// | 
|  | 6 |  | 
|  | 7 | #include "BugDriver.h" | 
|  | 8 | #include "SystemUtils.h" | 
|  | 9 | #include "llvm/Pass.h" | 
|  | 10 | #include "llvm/Module.h" | 
|  | 11 | #include "Support/CommandLine.h" | 
|  | 12 |  | 
|  | 13 | // Anonymous namespace to define command line options for miscompilation | 
|  | 14 | // debugging. | 
|  | 15 | // | 
|  | 16 | namespace { | 
|  | 17 | // Output - The user can specify a file containing the expected output of the | 
|  | 18 | // program.  If this filename is set, it is used as the reference diff source, | 
|  | 19 | // otherwise the raw input run through an interpreter is used as the reference | 
|  | 20 | // source. | 
|  | 21 | // | 
|  | 22 | cl::opt<std::string> | 
|  | 23 | Output("output", cl::desc("Specify a reference program output " | 
|  | 24 | "(for miscompilation detection)")); | 
|  | 25 | } | 
|  | 26 |  | 
|  | 27 | /// debugMiscompilation - This method is used when the passes selected are not | 
|  | 28 | /// crashing, but the generated output is semantically different from the | 
|  | 29 | /// input. | 
|  | 30 | /// | 
|  | 31 | bool BugDriver::debugMiscompilation() { | 
|  | 32 | std::cout << "*** Debugging miscompilation!\n"; | 
|  | 33 |  | 
|  | 34 | // Set up the execution environment, selecting a method to run LLVM bytecode. | 
|  | 35 | if (initializeExecutionEnvironment()) return true; | 
|  | 36 |  | 
|  | 37 | // Run the raw input to see where we are coming from.  If a reference output | 
|  | 38 | // was specified, make sure that the raw output matches it.  If not, it's a | 
|  | 39 | // problem in the front-end or whatever produced the input code. | 
|  | 40 | // | 
|  | 41 | bool CreatedOutput = false; | 
|  | 42 | if (Output.empty()) { | 
|  | 43 | std::cout << "Generating reference output from raw program..."; | 
|  | 44 | Output = executeProgram("bugpoint.reference.out"); | 
|  | 45 | CreatedOutput = true; | 
|  | 46 | std::cout << " done!\n"; | 
|  | 47 | } else if (diffProgram(Output)) { | 
|  | 48 | std::cout << "\n*** Input program does not match reference diff!\n" | 
|  | 49 | << "    Must be problem with input source!\n"; | 
|  | 50 | return false;  // Problem found | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | // Figure out which transformation is the first to miscompile the input | 
|  | 54 | // program.  We do a binary search here in case there are a large number of | 
|  | 55 | // passes involved. | 
|  | 56 | // | 
|  | 57 | unsigned LastGood = 0, LastBad = PassesToRun.size(); | 
|  | 58 | while (LastGood != LastBad) { | 
|  | 59 | unsigned Mid = (LastBad+LastGood+1) / 2; | 
|  | 60 | std::vector<const PassInfo*> P(PassesToRun.begin(), | 
|  | 61 | PassesToRun.begin()+Mid); | 
|  | 62 | std::cout << "Checking to see if the first " << Mid << " passes are ok: "; | 
|  | 63 |  | 
|  | 64 | std::string BytecodeResult; | 
|  | 65 | if (runPasses(P, BytecodeResult, false, true)) { | 
|  | 66 | std::cerr << ToolName << ": Error running this sequence of passes" | 
|  | 67 | << " on the input program!\n"; | 
|  | 68 | exit(1); | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | // Check to see if the finished program matches the reference output... | 
|  | 72 | if (diffProgram(Output, BytecodeResult)) { | 
|  | 73 | std::cout << "nope.\n"; | 
|  | 74 | LastBad = Mid-1;    // Miscompilation detected! | 
|  | 75 | } else { | 
|  | 76 | std::cout << "yup.\n"; | 
|  | 77 | LastGood = Mid;     // No miscompilation! | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | // We are now done with the optimized output... so remove it. | 
|  | 81 | removeFile(BytecodeResult); | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | // Make sure something was miscompiled... | 
|  | 85 | if (LastBad >= PassesToRun.size()) { | 
|  | 86 | std::cerr << "*** Optimized program matches reference output!  No problem " | 
|  | 87 | << "detected...\nbugpoint can't help you with your problem!\n"; | 
|  | 88 | return false; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | // Calculate which pass it is that miscompiles... | 
|  | 92 | const PassInfo *ThePass = PassesToRun[LastBad]; | 
|  | 93 |  | 
|  | 94 | std::cout << "\n*** Found miscompiling pass '-" << ThePass->getPassArgument() | 
|  | 95 | << "': " << ThePass->getPassName() << "\n"; | 
|  | 96 |  | 
|  | 97 | if (LastGood != 0) { | 
|  | 98 | std::vector<const PassInfo*> P(PassesToRun.begin(), | 
|  | 99 | PassesToRun.begin()+LastGood); | 
|  | 100 | std::string Filename; | 
|  | 101 | std::cout << "Running good passes to get input for pass:"; | 
|  | 102 | if (runPasses(P, Filename, false, true)) { | 
|  | 103 | std::cerr << "ERROR: Running the first " << LastGood | 
|  | 104 | << " passes crashed!\n"; | 
|  | 105 | return true; | 
|  | 106 | } | 
|  | 107 | std::cout << " done!\n"; | 
|  | 108 |  | 
|  | 109 | // Assuming everything was successful, we now have a valid bytecode file in | 
|  | 110 | // OutputName.  Use it for "Program" Instead. | 
|  | 111 | delete Program; | 
|  | 112 | Program = ParseInputFile(Filename); | 
|  | 113 |  | 
|  | 114 | // Delete the file now. | 
|  | 115 | removeFile(Filename); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | bool Result = debugPassMiscompilation(ThePass, Output); | 
|  | 119 |  | 
|  | 120 | if (CreatedOutput) removeFile(Output); | 
|  | 121 | return Result; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | /// debugPassMiscompilation - This method is called when the specified pass | 
|  | 125 | /// miscompiles Program as input.  It tries to reduce the testcase to something | 
|  | 126 | /// that smaller that still miscompiles the program.  ReferenceOutput contains | 
|  | 127 | /// the filename of the file containing the output we are to match. | 
|  | 128 | /// | 
|  | 129 | bool BugDriver::debugPassMiscompilation(const PassInfo *Pass, | 
|  | 130 | const std::string &ReferenceOutput) { | 
|  | 131 | EmitProgressBytecode(Pass, "passinput"); | 
|  | 132 |  | 
|  | 133 | // Loop over all of the functions in the program, attempting to find one that | 
|  | 134 | // is being miscompiled.  We do this by extracting the function into a module, | 
|  | 135 | // running the "bad" optimization on that module, then linking it back into | 
|  | 136 | // the program.  If the program fails the diff, the function got misoptimized. | 
|  | 137 | // | 
|  | 138 |  | 
|  | 139 |  | 
|  | 140 | return false; | 
|  | 141 | } |