OptimizerDriver.cpp revision a229c5cce75209047db32c6039aa0b0fd481f049
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 40using namespace llvm; 41 42/// writeProgramToFile - This writes the current "Program" to the named bytecode 43/// file. If an error occurs, true is returned. 44/// 45bool 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/// 59void 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 89static 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/// 128bool 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. 191Module *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