Devang Patel | 8e450f0 | 2008-07-18 22:59:45 +0000 | [diff] [blame] | 1 | //===- LTOBugPoint.cpp - Top-Level LTO BugPoint class ---------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This class contains all of the shared state and information that is used by |
| 11 | // the LTO BugPoint tool to track down bit code files that cause errors. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "LTOBugPoint.h" |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 16 | #include "llvm/PassManager.h" |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 17 | #include "llvm/ModuleProvider.h" |
| 18 | #include "llvm/CodeGen/FileWriters.h" |
| 19 | #include "llvm/Target/SubtargetFeature.h" |
| 20 | #include "llvm/Target/TargetOptions.h" |
| 21 | #include "llvm/Target/TargetMachine.h" |
| 22 | #include "llvm/Target/TargetData.h" |
| 23 | #include "llvm/Target/TargetAsmInfo.h" |
| 24 | #include "llvm/Target/TargetMachineRegistry.h" |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 25 | #include "llvm/Support/SystemUtils.h" |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 26 | #include "llvm/Support/MemoryBuffer.h" |
| 27 | #include "llvm/Bitcode/ReaderWriter.h" |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 28 | #include "llvm/Config/config.h" |
| 29 | #include <fstream> |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 30 | #include <iostream> |
Devang Patel | 8e450f0 | 2008-07-18 22:59:45 +0000 | [diff] [blame] | 31 | |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 32 | using namespace llvm; |
| 33 | using namespace Reloc; |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 34 | /// LTOBugPoint -- Constructor. Popuate list of linker options and |
| 35 | /// list of linker input files. |
Devang Patel | 8e450f0 | 2008-07-18 22:59:45 +0000 | [diff] [blame] | 36 | LTOBugPoint::LTOBugPoint(std::istream &args, std::istream &ins) { |
| 37 | |
| 38 | // Read linker options. Order is important here. |
| 39 | std::string option; |
| 40 | while (getline(args, option)) |
| 41 | LinkerOptions.push_back(option); |
| 42 | |
| 43 | // Read linker input files. Order is important here. |
| 44 | std::string inFile; |
| 45 | while(getline(ins, inFile)) |
| 46 | LinkerInputFiles.push_back(inFile); |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 47 | |
| 48 | TempDir = sys::Path::GetTemporaryDirectory(); |
| 49 | } |
| 50 | |
| 51 | LTOBugPoint::~LTOBugPoint() { |
| 52 | TempDir.eraseFromDisk(true); |
Devang Patel | 8e450f0 | 2008-07-18 22:59:45 +0000 | [diff] [blame] | 53 | } |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 54 | |
| 55 | /// findTroubleMakers - Find minimum set of input files that causes error |
| 56 | /// identified by the script. |
| 57 | bool |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 58 | LTOBugPoint::findTroubleMakers(SmallVector<std::string, 4> &TroubleMakers, |
Bill Wendling | b6f08eb | 2008-07-22 09:08:05 +0000 | [diff] [blame] | 59 | std::string &Script) { |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 60 | |
| 61 | // First, build native object files set. |
| 62 | bool bitcodeFileSeen = false; |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 63 | unsigned Size = LinkerInputFiles.size(); |
| 64 | for (unsigned I = 0; I < Size; ++I) { |
| 65 | std::string &FileName = LinkerInputFiles[I]; |
| 66 | sys::Path InputFile(FileName.c_str()); |
| 67 | if (InputFile.isDynamicLibrary() || InputFile.isArchive()) { |
| 68 | ErrMsg = "Unable to handle input file "; |
| 69 | ErrMsg += FileName; |
| 70 | return false; |
| 71 | } |
| 72 | else if (InputFile.isBitcodeFile()) { |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 73 | bitcodeFileSeen = true; |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 74 | if (getNativeObjectFile(FileName) == false) |
Bill Wendling | b6f08eb | 2008-07-22 09:08:05 +0000 | [diff] [blame] | 75 | return false; |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 76 | } |
| 77 | else |
| 78 | NativeInputFiles.push_back(FileName); |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | if (!bitcodeFileSeen) { |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 82 | ErrMsg = "Unable to help!"; |
| 83 | ErrMsg += " Need at least one input file that contains llvm bitcode"; |
Devang Patel | 0597667 | 2008-07-18 23:46:41 +0000 | [diff] [blame] | 84 | return false; |
| 85 | } |
| 86 | |
| 87 | return true; |
| 88 | } |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 89 | |
| 90 | /// getFeatureString - Return a string listing the features associated with the |
| 91 | /// target triple. |
| 92 | /// |
| 93 | /// FIXME: This is an inelegant way of specifying the features of a |
| 94 | /// subtarget. It would be better if we could encode this information into the |
| 95 | /// IR. |
| 96 | std::string LTOBugPoint::getFeatureString(const char *TargetTriple) { |
| 97 | SubtargetFeatures Features; |
| 98 | |
| 99 | if (strncmp(TargetTriple, "powerpc-apple-", 14) == 0) { |
| 100 | Features.AddFeature("altivec", true); |
| 101 | } else if (strncmp(TargetTriple, "powerpc64-apple-", 16) == 0) { |
| 102 | Features.AddFeature("64bit", true); |
| 103 | Features.AddFeature("altivec", true); |
| 104 | } |
| 105 | |
| 106 | return Features.getString(); |
| 107 | } |
| 108 | |
| 109 | /// assembleBitcode - Generate assembly code from the module. Return false |
| 110 | /// in case of an error. |
| 111 | bool LTOBugPoint::assembleBitcode(llvm::Module *M, const char *AsmFileName) { |
| 112 | std::string TargetTriple = M->getTargetTriple(); |
| 113 | std::string FeatureStr = |
| 114 | getFeatureString(TargetTriple.c_str()); |
| 115 | |
| 116 | const TargetMachineRegistry::entry* Registry = |
| 117 | TargetMachineRegistry::getClosestStaticTargetForModule( |
| 118 | *M, ErrMsg); |
| 119 | if ( Registry == NULL ) |
| 120 | return false; |
| 121 | |
| 122 | TargetMachine *Target = Registry->CtorFn(*M, FeatureStr.c_str()); |
| 123 | |
| 124 | // If target supports exception handling then enable it now. |
| 125 | if (Target->getTargetAsmInfo()->doesSupportExceptionHandling()) |
| 126 | ExceptionHandling = true; |
| 127 | |
| 128 | // FIXME |
| 129 | Target->setRelocationModel(Reloc::PIC_); |
| 130 | |
| 131 | FunctionPassManager* CGPasses = |
| 132 | new FunctionPassManager(new ExistingModuleProvider(M)); |
| 133 | |
| 134 | CGPasses->add(new TargetData(*Target->getTargetData())); |
| 135 | MachineCodeEmitter* mce = NULL; |
| 136 | |
| 137 | std::ofstream *Out = new std::ofstream(AsmFileName, std::ios::out); |
| 138 | |
| 139 | switch (Target->addPassesToEmitFile(*CGPasses, *Out, |
Bill Wendling | b6f08eb | 2008-07-22 09:08:05 +0000 | [diff] [blame] | 140 | TargetMachine::AssemblyFile, true)) { |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 141 | case FileModel::MachOFile: |
| 142 | mce = AddMachOWriter(*CGPasses, *Out, *Target); |
| 143 | break; |
| 144 | case FileModel::ElfFile: |
| 145 | mce = AddELFWriter(*CGPasses, *Out, *Target); |
| 146 | break; |
| 147 | case FileModel::AsmFile: |
| 148 | break; |
| 149 | case FileModel::Error: |
| 150 | case FileModel::None: |
| 151 | ErrMsg = "target file type not supported"; |
| 152 | return false; |
| 153 | } |
| 154 | |
| 155 | if (Target->addPassesToEmitFileFinish(*CGPasses, mce, true)) { |
| 156 | ErrMsg = "target does not support generation of this file type"; |
| 157 | return false; |
| 158 | } |
| 159 | |
| 160 | CGPasses->doInitialization(); |
| 161 | for (Module::iterator |
Bill Wendling | b6f08eb | 2008-07-22 09:08:05 +0000 | [diff] [blame] | 162 | it = M->begin(), e = M->end(); it != e; ++it) |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 163 | if (!it->isDeclaration()) |
| 164 | CGPasses->run(*it); |
| 165 | CGPasses->doFinalization(); |
| 166 | delete Out; |
| 167 | return true; |
| 168 | } |
| 169 | |
| 170 | /// getNativeObjectFile - Generate native object file based from llvm |
| 171 | /// bitcode file. Return false in case of an error. |
| 172 | bool LTOBugPoint::getNativeObjectFile(std::string &FileName) { |
| 173 | |
| 174 | std::auto_ptr<Module> M; |
| 175 | MemoryBuffer *Buffer |
| 176 | = MemoryBuffer::getFile(FileName.c_str(), &ErrMsg); |
| 177 | if (!Buffer) { |
| 178 | ErrMsg = "Unable to read "; |
| 179 | ErrMsg += FileName; |
| 180 | return false; |
| 181 | } |
| 182 | M.reset(ParseBitcodeFile(Buffer, &ErrMsg)); |
| 183 | std::string TargetTriple = M->getTargetTriple(); |
| 184 | |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 185 | sys::Path AsmFile(TempDir); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 186 | if(AsmFile.createTemporaryFileOnDisk(false, &ErrMsg)) |
| 187 | return false; |
| 188 | |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 189 | if (assembleBitcode(M.get(), AsmFile.c_str()) == false) { |
| 190 | AsmFile.eraseFromDisk(); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 191 | return false; |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 192 | } |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 193 | |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 194 | sys::Path NativeFile(TempDir); |
| 195 | if(NativeFile.createTemporaryFileOnDisk(false, &ErrMsg)) { |
| 196 | AsmFile.eraseFromDisk(); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 197 | return false; |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 198 | } |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 199 | |
| 200 | // find compiler driver |
| 201 | const sys::Path gcc = sys::Program::FindProgramByName("gcc"); |
| 202 | if ( gcc.isEmpty() ) { |
| 203 | ErrMsg = "can't locate gcc"; |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 204 | AsmFile.eraseFromDisk(); |
| 205 | NativeFile.eraseFromDisk(); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 206 | return false; |
| 207 | } |
| 208 | |
| 209 | // build argument list |
| 210 | std::vector<const char*> args; |
| 211 | args.push_back(gcc.c_str()); |
| 212 | if ( TargetTriple.find("darwin") != TargetTriple.size() ) { |
| 213 | if (strncmp(TargetTriple.c_str(), "i686-apple-", 11) == 0) { |
| 214 | args.push_back("-arch"); |
| 215 | args.push_back("i386"); |
| 216 | } |
| 217 | else if (strncmp(TargetTriple.c_str(), "x86_64-apple-", 13) == 0) { |
| 218 | args.push_back("-arch"); |
| 219 | args.push_back("x86_64"); |
| 220 | } |
| 221 | else if (strncmp(TargetTriple.c_str(), "powerpc-apple-", 14) == 0) { |
| 222 | args.push_back("-arch"); |
| 223 | args.push_back("ppc"); |
| 224 | } |
| 225 | else if (strncmp(TargetTriple.c_str(), "powerpc64-apple-", 16) == 0) { |
| 226 | args.push_back("-arch"); |
| 227 | args.push_back("ppc64"); |
| 228 | } |
| 229 | } |
| 230 | args.push_back("-c"); |
| 231 | args.push_back("-x"); |
| 232 | args.push_back("assembler"); |
| 233 | args.push_back("-o"); |
| 234 | args.push_back(NativeFile.c_str()); |
| 235 | args.push_back(AsmFile.c_str()); |
| 236 | args.push_back(0); |
| 237 | |
| 238 | // invoke assembler |
| 239 | if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) { |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 240 | ErrMsg = "error in assembly"; |
| 241 | AsmFile.eraseFromDisk(); |
| 242 | NativeFile.eraseFromDisk(); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 243 | return false; |
| 244 | } |
Devang Patel | 8502112 | 2008-07-22 20:03:45 +0000 | [diff] [blame^] | 245 | |
| 246 | AsmFile.eraseFromDisk(); |
Devang Patel | 6e7775f | 2008-07-21 23:04:39 +0000 | [diff] [blame] | 247 | return true; |
| 248 | } |