1 //===- OptimizerDriver.cpp - Allow BugPoint to run passes safely ----------===// 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 file defines an interface that allows bugpoint to run various passes 11 // without the threat of a buggy pass corrupting bugpoint (of course, bugpoint 12 // may have its own bugs, but that's another story...). It achieves this by 13 // forking a copy of itself and having the child process do the optimizations. 14 // If this client dies, we can always fork a new one. :) 15 // 16 //===----------------------------------------------------------------------===// 17 18 // Note: as a short term hack, the old Unix-specific code and platform- 19 // independent code co-exist via conditional compilation until it is verified 20 // that the new code works correctly on Unix. 21 22 #ifdef _MSC_VER 23 #define PLATFORMINDEPENDENT 24 #endif 25 26 #include "BugDriver.h" 27 #include "llvm/Module.h" 28 #include "llvm/PassManager.h" 29 #include "llvm/Analysis/Verifier.h" 30 #include "llvm/Bytecode/WriteBytecodePass.h" 31 #include "llvm/Target/TargetData.h" 32 #include "llvm/Support/FileUtilities.h" 33 #include "llvm/System/Path.h" 34 #include <fstream> 35 #ifndef PLATFORMINDEPENDENT 36 #include <unistd.h> 37 #include <sys/types.h> 38 #include <sys/wait.h> 39 #endif 40 using namespace llvm; 41 42 /// writeProgramToFile - This writes the current "Program" to the named bytecode 43 /// file. If an error occurs, true is returned. 44 /// 45 bool BugDriver::writeProgramToFile(const std::string &Filename, 46 Module *M) const { 47 std::ios::openmode io_mode = std::ios::out | std::ios::trunc | 48 std::ios::binary; 49 std::ofstream Out(Filename.c_str(), io_mode); 50 if (!Out.good()) return true; 51 WriteBytecodeToFile(M ? M : Program, Out, /*compression=*/true); 52 return false; 53 } 54 55 56 /// EmitProgressBytecode - This function is used to output the current Program 57 /// to a file named "bugpoint-ID.bc". 58 /// 59 void BugDriver::EmitProgressBytecode(const std::string &ID, bool NoFlyer) { 60 // Output the input to the current pass to a bytecode file, emit a message 61 // telling the user how to reproduce it: opt -foo blah.bc 62 // 63 std::string Filename = "bugpoint-" + ID + ".bc"; 64 if (writeProgramToFile(Filename)) { 65 std::cerr << "Error opening file '" << Filename << "' for writing!\n"; 66 return; 67 } 68 69 std::cout << "Emitted bytecode to '" << Filename << "'\n"; 70 if (NoFlyer || PassesToRun.empty()) return; 71 std::cout << "\n*** You can reproduce the problem with: "; 72 73 unsigned PassType = PassesToRun[0]->getPassType(); 74 for (unsigned i = 1, e = PassesToRun.size(); i != e; ++i) 75 PassType &= PassesToRun[i]->getPassType(); 76 77 if (PassType & PassInfo::Analysis) 78 std::cout << "analyze"; 79 else if (PassType & PassInfo::Optimization) 80 std::cout << "opt"; 81 else if (PassType & PassInfo::LLC) 82 std::cout << "llc"; 83 else 84 std::cout << "bugpoint"; 85 std::cout << " " << Filename << " "; 86 std::cout << getPassesString(PassesToRun) << "\n"; 87 } 88 89 static void RunChild(Module *Program,const std::vector<const PassInfo*> &Passes, 90 const std::string &OutFilename) { 91 std::ios::openmode io_mode = std::ios::out | std::ios::trunc | 92 std::ios::binary; 93 std::ofstream OutFile(OutFilename.c_str(), io_mode); 94 if (!OutFile.good()) { 95 std::cerr << "Error opening bytecode file: " << OutFilename << "\n"; 96 exit(1); 97 } 98 99 PassManager PM; 100 // Make sure that the appropriate target data is always used... 101 PM.add(new TargetData("bugpoint", Program)); 102 103 for (unsigned i = 0, e = Passes.size(); i != e; ++i) { 104 if (Passes[i]->getNormalCtor()) 105 PM.add(Passes[i]->getNormalCtor()()); 106 else 107 std::cerr << "Cannot create pass yet: " << Passes[i]->getPassName() 108 << "\n"; 109 } 110 // Check that the module is well formed on completion of optimization 111 PM.add(createVerifierPass()); 112 113 // Write bytecode out to disk as the last step... 114 PM.add(new WriteBytecodePass(&OutFile)); 115 116 // Run all queued passes. 117 PM.run(*Program); 118 } 119 120 /// runPasses - Run the specified passes on Program, outputting a bytecode file 121 /// and writing the filename into OutputFile if successful. If the 122 /// optimizations fail for some reason (optimizer crashes), return true, 123 /// otherwise return false. If DeleteOutput is set to true, the bytecode is 124 /// deleted on success, and the filename string is undefined. This prints to 125 /// cout a single line message indicating whether compilation was successful or 126 /// failed. 127 /// 128 bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, 129 std::string &OutputFilename, bool DeleteOutput, 130 bool Quiet) const{ 131 std::cout << std::flush; 132 sys::Path uniqueFilename("bugpoint-output.bc"); 133 uniqueFilename.makeUnique(); 134 OutputFilename = uniqueFilename.toString(); 135 136 #ifndef PLATFORMINDEPENDENT 137 pid_t child_pid; 138 switch (child_pid = fork()) { 139 case -1: // Error occurred 140 std::cerr << ToolName << ": Error forking!\n"; 141 exit(1); 142 case 0: // Child process runs passes. 143 RunChild(Program, Passes, OutputFilename); 144 exit(0); // If we finish successfully, return 0! 145 default: // Parent continues... 146 break; 147 } 148 149 // Wait for the child process to get done. 150 int Status; 151 if (wait(&Status) != child_pid) { 152 std::cerr << "Error waiting for child process!\n"; 153 exit(1); 154 } 155 156 bool ExitedOK = WIFEXITED(Status) && WEXITSTATUS(Status) == 0; 157 #else 158 bool ExitedOK = false; 159 #endif 160 161 // If we are supposed to delete the bytecode file or if the passes crashed, 162 // remove it now. This may fail if the file was never created, but that's ok. 163 if (DeleteOutput || !ExitedOK) 164 sys::Path(OutputFilename).eraseFromDisk(); 165 166 #ifndef PLATFORMINDEPENDENT 167 if (!Quiet) { 168 if (ExitedOK) 169 std::cout << "Success!\n"; 170 else if (WIFEXITED(Status)) 171 std::cout << "Exited with error code '" << WEXITSTATUS(Status) << "'\n"; 172 else if (WIFSIGNALED(Status)) 173 std::cout << "Crashed with signal #" << WTERMSIG(Status) << "\n"; 174 #ifdef WCOREDUMP 175 else if (WCOREDUMP(Status)) 176 std::cout << "Dumped core\n"; 177 #endif 178 else 179 std::cout << "Failed for unknown reason!\n"; 180 } 181 #endif 182 183 // Was the child successful? 184 return !ExitedOK; 185 } 186 187 188 /// runPassesOn - Carefully run the specified set of pass on the specified 189 /// module, returning the transformed module on success, or a null pointer on 190 /// failure. 191 Module *BugDriver::runPassesOn(Module *M, 192 const std::vector<const PassInfo*> &Passes, 193 bool AutoDebugCrashes) { 194 Module *OldProgram = swapProgramIn(M); 195 std::string BytecodeResult; 196 if (runPasses(Passes, BytecodeResult, false/*delete*/, true/*quiet*/)) { 197 if (AutoDebugCrashes) { 198 std::cerr << " Error running this sequence of passes" 199 << " on the input program!\n"; 200 delete OldProgram; 201 EmitProgressBytecode("pass-error", false); 202 exit(debugOptimizerCrash()); 203 } 204 swapProgramIn(OldProgram); 205 return 0; 206 } 207 208 // Restore the current program. 209 swapProgramIn(OldProgram); 210 211 Module *Ret = ParseInputFile(BytecodeResult); 212 if (Ret == 0) { 213 std::cerr << getToolName() << ": Error reading bytecode file '" 214 << BytecodeResult << "'!\n"; 215 exit(1); 216 } 217 sys::Path(BytecodeResult).eraseFromDisk(); // No longer need the file on disk 218 return Ret; 219 } 220