1 //===- OptimizerDriver.cpp - Allow BugPoint to run passes safely ----------===// 2 // 3 // This file defines an interface that allows bugpoint to run various passes 4 // without the threat of a buggy pass corrupting bugpoint (of course bugpoint 5 // may have it's own bugs, but that's another story...). It acheives this by 6 // forking a copy of itself and having the child process do the optimizations. 7 // If this client dies, we can always fork a new one. :) 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "BugDriver.h" 12 #include "SystemUtils.h" 13 #include "llvm/PassManager.h" 14 #include "llvm/Analysis/Verifier.h" 15 #include "llvm/Bytecode/WriteBytecodePass.h" 16 #include "llvm/Target/TargetData.h" 17 #include <sys/types.h> 18 #include <sys/wait.h> 19 #include <unistd.h> 20 #include <stdlib.h> 21 #include <fstream> 22 23 /// writeProgramToFile - This writes the current "Program" to the named bytecode 24 /// file. If an error occurs, true is returned. 25 /// 26 bool BugDriver::writeProgramToFile(const std::string &Filename, 27 Module *M) const { 28 std::ofstream Out(Filename.c_str()); 29 if (!Out.good()) return true; 30 WriteBytecodeToFile(M ? M : Program, Out); 31 return false; 32 } 33 34 35 /// EmitProgressBytecode - This function is used to output the current Program 36 /// to a file named "bugpoing-ID.bc". 37 /// 38 void BugDriver::EmitProgressBytecode(const PassInfo *Pass, 39 const std::string &ID) { 40 // Output the input to the current pass to a bytecode file, emit a message 41 // telling the user how to reproduce it: opt -foo blah.bc 42 // 43 std::string Filename = "bugpoint-" + ID + ".bc"; 44 if (writeProgramToFile(Filename)) { 45 std::cerr << "Error opening file '" << Filename << "' for writing!\n"; 46 return; 47 } 48 49 std::cout << "Emitted bytecode to '" << Filename << "'\n"; 50 std::cout << "\n*** You can reproduce the problem with: "; 51 52 unsigned PassType = Pass->getPassType(); 53 if (PassType & PassInfo::Analysis) 54 std::cout << "analyze"; 55 else if (PassType & PassInfo::Optimization) 56 std::cout << "opt"; 57 else if (PassType & PassInfo::LLC) 58 std::cout << "llc"; 59 else 60 std::cout << "bugpoint"; 61 std::cout << " " << Filename << " -" << Pass->getPassArgument() << "\n"; 62 } 63 64 /// FIXME: This should be parameterizable!! 65 static TargetData TD("bugpoint target"); 66 67 static void RunChild(Module *Program,const std::vector<const PassInfo*> &Passes, 68 const std::string &OutFilename) { 69 std::ofstream OutFile(OutFilename.c_str()); 70 if (!OutFile.good()) { 71 std::cerr << "Error opening bytecode file: " << OutFilename << "\n"; 72 exit(1); 73 } 74 75 PassManager PM; 76 for (unsigned i = 0, e = Passes.size(); i != e; ++i) { 77 if (Passes[i]->getNormalCtor()) 78 PM.add(Passes[i]->getNormalCtor()()); 79 else if (Passes[i]->getDataCtor()) 80 PM.add(Passes[i]->getDataCtor()(TD)); // Provide dummy target data... 81 else 82 std::cerr << "Cannot create pass yet: " << Passes[i]->getPassName() 83 << "\n"; 84 } 85 // Check that the module is well formed on completion of optimization 86 PM.add(createVerifierPass()); 87 88 // Write bytecode out to disk as the last step... 89 PM.add(new WriteBytecodePass(&OutFile)); 90 91 // Run all queued passes. 92 PM.run(*Program); 93 } 94 95 /// runPasses - Run the specified passes on Program, outputting a bytecode file 96 /// and writting the filename into OutputFile if successful. If the 97 /// optimizations fail for some reason (optimizer crashes), return true, 98 /// otherwise return false. If DeleteOutput is set to true, the bytecode is 99 /// deleted on success, and the filename string is undefined. This prints to 100 /// cout a single line message indicating whether compilation was successful or 101 /// failed. 102 /// 103 bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, 104 std::string &OutputFilename, bool DeleteOutput, 105 bool Quiet) const{ 106 std::cout << std::flush; 107 OutputFilename = getUniqueFilename("bugpoint-output.bc"); 108 109 pid_t child_pid; 110 switch (child_pid = fork()) { 111 case -1: // Error occurred 112 std::cerr << ToolName << ": Error forking!\n"; 113 exit(1); 114 case 0: // Child process runs passes. 115 RunChild(Program, Passes, OutputFilename); 116 exit(0); // If we finish successfully, return 0! 117 default: // Parent continues... 118 break; 119 } 120 121 // Wait for the child process to get done. 122 int Status; 123 if (wait(&Status) != child_pid) { 124 std::cerr << "Error waiting for child process!\n"; 125 exit(1); 126 } 127 128 // If we are supposed to delete the bytecode file, remove it now 129 // unconditionally... this may fail if the file was never created, but that's 130 // ok. 131 if (DeleteOutput) 132 removeFile(OutputFilename); 133 134 if (!Quiet) std::cout << (Status ? "Crashed!\n" : "Success!\n"); 135 136 // Was the child successful? 137 return Status != 0; 138 } 139