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