| 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" | 
| Chris Lattner | 126840f | 2003-04-24 20:16:29 +0000 | [diff] [blame] | 9 | #include "ListReducer.h" | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 10 | #include "llvm/Pass.h" | 
|  | 11 | #include "llvm/Module.h" | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 12 | #include "llvm/Transforms/Utils/Cloning.h" | 
|  | 13 | #include "llvm/Transforms/Utils/Linker.h" | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 14 |  | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 15 | class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> { | 
|  | 16 | BugDriver &BD; | 
|  | 17 | public: | 
|  | 18 | ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} | 
|  | 19 |  | 
| Chris Lattner | 39aebca | 2003-04-24 22:24:22 +0000 | [diff] [blame] | 20 | virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 21 | std::vector<const PassInfo*> &Suffix); | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 22 | }; | 
|  | 23 |  | 
|  | 24 | ReduceMiscompilingPasses::TestResult | 
| Chris Lattner | 39aebca | 2003-04-24 22:24:22 +0000 | [diff] [blame] | 25 | ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 26 | std::vector<const PassInfo*> &Suffix) { | 
|  | 27 | // First, run the program with just the Suffix passes.  If it is still broken | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 28 | // with JUST the kept passes, discard the prefix passes. | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 29 | std::cout << "Checking to see if '" << getPassesString(Suffix) | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 30 | << "' compile correctly: "; | 
|  | 31 |  | 
|  | 32 | std::string BytecodeResult; | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 33 | if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) { | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 34 | std::cerr << BD.getToolName() << ": Error running this sequence of passes" | 
|  | 35 | << " on the input program!\n"; | 
|  | 36 | exit(1); | 
|  | 37 | } | 
|  | 38 |  | 
|  | 39 | // Check to see if the finished program matches the reference output... | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 40 | if (BD.diffProgram(BytecodeResult, "", true /*delete bytecode*/)) { | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 41 | std::cout << "nope.\n"; | 
|  | 42 | return KeepSuffix;        // Miscompilation detected! | 
|  | 43 | } | 
|  | 44 | std::cout << "yup.\n";      // No miscompilation! | 
|  | 45 |  | 
|  | 46 | if (Prefix.empty()) return NoFailure; | 
|  | 47 |  | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 48 | // Next, see if the program is broken if we run the "prefix" passes first, | 
| Misha Brukman | bc0e998 | 2003-07-14 17:20:40 +0000 | [diff] [blame] | 49 | // then separately run the "kept" passes. | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 50 | std::cout << "Checking to see if '" << getPassesString(Prefix) | 
|  | 51 | << "' compile correctly: "; | 
|  | 52 |  | 
|  | 53 | // If it is not broken with the kept passes, it's possible that the prefix | 
|  | 54 | // passes must be run before the kept passes to break it.  If the program | 
|  | 55 | // WORKS after the prefix passes, but then fails if running the prefix AND | 
|  | 56 | // kept passes, we can update our bytecode file to include the result of the | 
|  | 57 | // prefix passes, then discard the prefix passes. | 
|  | 58 | // | 
|  | 59 | if (BD.runPasses(Prefix, BytecodeResult, false/*delete*/, true/*quiet*/)) { | 
|  | 60 | std::cerr << BD.getToolName() << ": Error running this sequence of passes" | 
|  | 61 | << " on the input program!\n"; | 
|  | 62 | exit(1); | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | // If the prefix maintains the predicate by itself, only keep the prefix! | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 66 | if (BD.diffProgram(BytecodeResult)) { | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 67 | std::cout << "nope.\n"; | 
|  | 68 | removeFile(BytecodeResult); | 
|  | 69 | return KeepPrefix; | 
|  | 70 | } | 
|  | 71 | std::cout << "yup.\n";      // No miscompilation! | 
|  | 72 |  | 
|  | 73 | // Ok, so now we know that the prefix passes work, try running the suffix | 
|  | 74 | // passes on the result of the prefix passes. | 
|  | 75 | // | 
|  | 76 | Module *PrefixOutput = BD.ParseInputFile(BytecodeResult); | 
|  | 77 | if (PrefixOutput == 0) { | 
|  | 78 | std::cerr << BD.getToolName() << ": Error reading bytecode file '" | 
|  | 79 | << BytecodeResult << "'!\n"; | 
|  | 80 | exit(1); | 
|  | 81 | } | 
|  | 82 | removeFile(BytecodeResult);  // No longer need the file on disk | 
|  | 83 |  | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 84 | std::cout << "Checking to see if '" << getPassesString(Suffix) | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 85 | << "' passes compile correctly after the '" | 
|  | 86 | << getPassesString(Prefix) << "' passes: "; | 
|  | 87 |  | 
|  | 88 | Module *OriginalInput = BD.Program; | 
|  | 89 | BD.Program = PrefixOutput; | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 90 | if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) { | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 91 | std::cerr << BD.getToolName() << ": Error running this sequence of passes" | 
|  | 92 | << " on the input program!\n"; | 
|  | 93 | exit(1); | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | // Run the result... | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 97 | if (BD.diffProgram(BytecodeResult, "", true/*delete bytecode*/)) { | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 98 | std::cout << "nope.\n"; | 
|  | 99 | delete OriginalInput;     // We pruned down the original input... | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 100 | return KeepSuffix; | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 101 | } | 
|  | 102 |  | 
|  | 103 | // Otherwise, we must not be running the bad pass anymore. | 
|  | 104 | std::cout << "yup.\n";      // No miscompilation! | 
|  | 105 | BD.Program = OriginalInput; // Restore original program | 
|  | 106 | delete PrefixOutput;        // Free experiment | 
|  | 107 | return NoFailure; | 
|  | 108 | } | 
|  | 109 |  | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 110 | class ReduceMiscompilingFunctions : public ListReducer<Function*> { | 
|  | 111 | BugDriver &BD; | 
|  | 112 | public: | 
|  | 113 | ReduceMiscompilingFunctions(BugDriver &bd) : BD(bd) {} | 
|  | 114 |  | 
| Chris Lattner | 39aebca | 2003-04-24 22:24:22 +0000 | [diff] [blame] | 115 | virtual TestResult doTest(std::vector<Function*> &Prefix, | 
| Chris Lattner | 06943ad | 2003-04-25 03:16:05 +0000 | [diff] [blame] | 116 | std::vector<Function*> &Suffix) { | 
| Misha Brukman | 5d3f1f0 | 2003-08-04 19:03:42 +0000 | [diff] [blame^] | 117 | if (!Suffix.empty() && TestFuncs(Suffix, false)) | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 118 | return KeepSuffix; | 
| Chris Lattner | a148ccb | 2003-04-24 19:32:42 +0000 | [diff] [blame] | 119 | if (!Prefix.empty() && TestFuncs(Prefix, false)) | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 120 | return KeepPrefix; | 
|  | 121 | return NoFailure; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | bool TestFuncs(const std::vector<Function*> &Prefix, bool EmitBytecode); | 
|  | 125 | }; | 
|  | 126 |  | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 127 | bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, | 
|  | 128 | bool EmitBytecode) { | 
|  | 129 | // Test to see if the function is misoptimized if we ONLY run it on the | 
|  | 130 | // functions listed in Funcs. | 
|  | 131 | if (!EmitBytecode) { | 
|  | 132 | std::cout << "Checking to see if the program is misoptimized when these " | 
|  | 133 | << "functions are run\nthrough the passes: "; | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 134 | BD.PrintFunctionList(Funcs); | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 135 | std::cout << "\n"; | 
|  | 136 | } else { | 
|  | 137 | std::cout <<"Outputting reduced bytecode files which expose the problem:\n"; | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | // First step: clone the module for the two halves of the program we want. | 
|  | 141 | Module *ToOptimize = CloneModule(BD.Program); | 
|  | 142 |  | 
|  | 143 | // Second step: Make sure functions & globals are all external so that linkage | 
|  | 144 | // between the two modules will work. | 
|  | 145 | for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I) | 
|  | 146 | I->setLinkage(GlobalValue::ExternalLinkage); | 
|  | 147 | for (Module::giterator I = ToOptimize->gbegin(), E = ToOptimize->gend(); | 
|  | 148 | I != E; ++I) | 
|  | 149 | I->setLinkage(GlobalValue::ExternalLinkage); | 
|  | 150 |  | 
|  | 151 | // Third step: make a clone of the externalized program for the non-optimized | 
|  | 152 | // part. | 
|  | 153 | Module *ToNotOptimize = CloneModule(ToOptimize); | 
|  | 154 |  | 
|  | 155 | // Fourth step: Remove the test functions from the ToNotOptimize module, and | 
|  | 156 | // all of the global variables. | 
|  | 157 | for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { | 
|  | 158 | Function *TNOF = ToNotOptimize->getFunction(Funcs[i]->getName(), | 
|  | 159 | Funcs[i]->getFunctionType()); | 
|  | 160 | assert(TNOF && "Function doesn't exist in module!"); | 
|  | 161 | DeleteFunctionBody(TNOF);       // Function is now external in this module! | 
|  | 162 | } | 
|  | 163 | for (Module::giterator I = ToNotOptimize->gbegin(), E = ToNotOptimize->gend(); | 
|  | 164 | I != E; ++I) | 
|  | 165 | I->setInitializer(0);  // Delete the initializer to make it external | 
|  | 166 |  | 
|  | 167 | if (EmitBytecode) { | 
|  | 168 | std::cout << "  Non-optimized portion: "; | 
|  | 169 | std::swap(BD.Program, ToNotOptimize); | 
|  | 170 | BD.EmitProgressBytecode("tonotoptimize", true); | 
|  | 171 | std::swap(BD.Program, ToNotOptimize); | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | // Fifth step: Remove all functions from the ToOptimize module EXCEPT for the | 
|  | 175 | // ones specified in Funcs.  We know which ones these are because they are | 
|  | 176 | // non-external in ToOptimize, but external in ToNotOptimize. | 
|  | 177 | // | 
|  | 178 | for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I) | 
|  | 179 | if (!I->isExternal()) { | 
|  | 180 | Function *TNOF = ToNotOptimize->getFunction(I->getName(), | 
|  | 181 | I->getFunctionType()); | 
|  | 182 | assert(TNOF && "Function doesn't exist in ToNotOptimize module??"); | 
|  | 183 | if (!TNOF->isExternal()) | 
|  | 184 | DeleteFunctionBody(I); | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | if (EmitBytecode) { | 
|  | 188 | std::cout << "  Portion that is input to optimizer: "; | 
|  | 189 | std::swap(BD.Program, ToOptimize); | 
|  | 190 | BD.EmitProgressBytecode("tooptimize"); | 
|  | 191 | std::swap(BD.Program, ToOptimize); | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | // Sixth step: Run the optimization passes on ToOptimize, producing a | 
|  | 195 | // transformed version of the functions being tested. | 
|  | 196 | Module *OldProgram = BD.Program; | 
|  | 197 | BD.Program = ToOptimize; | 
|  | 198 |  | 
|  | 199 | if (!EmitBytecode) | 
|  | 200 | std::cout << "  Optimizing functions being tested: "; | 
|  | 201 | std::string BytecodeResult; | 
|  | 202 | if (BD.runPasses(BD.PassesToRun, BytecodeResult, false/*delete*/, | 
|  | 203 | true/*quiet*/)) { | 
|  | 204 | std::cerr << BD.getToolName() << ": Error running this sequence of passes" | 
|  | 205 | << " on the input program!\n"; | 
|  | 206 | exit(1); | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | if (!EmitBytecode) | 
|  | 210 | std::cout << "done.\n"; | 
|  | 211 |  | 
|  | 212 | delete BD.Program;   // Delete the old "ToOptimize" module | 
|  | 213 | BD.Program = BD.ParseInputFile(BytecodeResult); | 
|  | 214 |  | 
|  | 215 | if (EmitBytecode) { | 
|  | 216 | std::cout << "  'tooptimize' after being optimized: "; | 
|  | 217 | BD.EmitProgressBytecode("optimized", true); | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | if (BD.Program == 0) { | 
|  | 221 | std::cerr << BD.getToolName() << ": Error reading bytecode file '" | 
|  | 222 | << BytecodeResult << "'!\n"; | 
|  | 223 | exit(1); | 
|  | 224 | } | 
|  | 225 | removeFile(BytecodeResult);  // No longer need the file on disk | 
|  | 226 |  | 
|  | 227 | // Seventh step: Link the optimized part of the program back to the | 
|  | 228 | // unoptimized part of the program. | 
|  | 229 | // | 
|  | 230 | if (LinkModules(BD.Program, ToNotOptimize, &BytecodeResult)) { | 
|  | 231 | std::cerr << BD.getToolName() << ": Error linking modules together:" | 
|  | 232 | << BytecodeResult << "\n"; | 
|  | 233 | exit(1); | 
|  | 234 | } | 
|  | 235 | delete ToNotOptimize;  // We are done with this module... | 
|  | 236 |  | 
|  | 237 | if (EmitBytecode) { | 
|  | 238 | std::cout << "  Program as tested: "; | 
|  | 239 | BD.EmitProgressBytecode("linked", true); | 
|  | 240 | delete BD.Program; | 
|  | 241 | BD.Program = OldProgram; | 
|  | 242 | return false;   // We don't need to actually execute the program here. | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | std::cout << "  Checking to see if the merged program executes correctly: "; | 
|  | 246 |  | 
|  | 247 | // Eighth step: Execute the program.  If it does not match the expected | 
|  | 248 | // output, then 'Funcs' are being misoptimized! | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 249 | bool Broken = BD.diffProgram(); | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 250 |  | 
|  | 251 | delete BD.Program;  // Delete the hacked up program | 
|  | 252 | BD.Program = OldProgram;   // Restore the original | 
|  | 253 |  | 
|  | 254 | std::cout << (Broken ? "nope.\n" : "yup.\n"); | 
|  | 255 | return Broken; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 |  | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 259 | /// debugMiscompilation - This method is used when the passes selected are not | 
|  | 260 | /// crashing, but the generated output is semantically different from the | 
|  | 261 | /// input. | 
|  | 262 | /// | 
|  | 263 | bool BugDriver::debugMiscompilation() { | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 264 |  | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 265 | if (diffProgram()) { | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 266 | std::cout << "\n*** Input program does not match reference diff!\n" | 
| Misha Brukman | 5073336 | 2003-07-24 18:17:43 +0000 | [diff] [blame] | 267 | << "    Must be problem with input source!\n"; | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 268 | return false;  // Problem found | 
|  | 269 | } | 
|  | 270 |  | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 271 | // Make sure something was miscompiled... | 
| Misha Brukman | be6bf56 | 2003-07-30 20:15:56 +0000 | [diff] [blame] | 272 | if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 273 | std::cerr << "*** Optimized program matches reference output!  No problem " | 
|  | 274 | << "detected...\nbugpoint can't help you with your problem!\n"; | 
|  | 275 | return false; | 
|  | 276 | } | 
|  | 277 |  | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 278 | std::cout << "\n*** Found miscompiling pass" | 
|  | 279 | << (PassesToRun.size() == 1 ? "" : "es") << ": " | 
|  | 280 | << getPassesString(PassesToRun) << "\n"; | 
|  | 281 | EmitProgressBytecode("passinput"); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 282 |  | 
| Chris Lattner | 640f22e | 2003-04-24 17:02:17 +0000 | [diff] [blame] | 283 | // Okay, now that we have reduced the list of passes which are causing the | 
|  | 284 | // failure, see if we can pin down which functions are being | 
|  | 285 | // miscompiled... first build a list of all of the non-external functions in | 
|  | 286 | // the program. | 
|  | 287 | std::vector<Function*> MiscompiledFunctions; | 
|  | 288 | for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I) | 
|  | 289 | if (!I->isExternal()) | 
|  | 290 | MiscompiledFunctions.push_back(I); | 
|  | 291 |  | 
|  | 292 | // Do the reduction... | 
|  | 293 | ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions); | 
|  | 294 |  | 
|  | 295 | std::cout << "\n*** The following functions are being miscompiled: "; | 
|  | 296 | PrintFunctionList(MiscompiledFunctions); | 
|  | 297 | std::cout << "\n"; | 
|  | 298 |  | 
|  | 299 | // Output a bunch of bytecode files for the user... | 
|  | 300 | ReduceMiscompilingFunctions(*this).TestFuncs(MiscompiledFunctions, true); | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 301 |  | 
| Chris Lattner | 4a10645 | 2002-12-23 23:50:16 +0000 | [diff] [blame] | 302 | return false; | 
|  | 303 | } |