blob: 7b01407465af3bdeb64f720e1973588ca46e995c [file] [log] [blame]
Devang Patel8e450f02008-07-18 22:59:45 +00001//===- 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 Patel6e7775f2008-07-21 23:04:39 +000016#include "llvm/PassManager.h"
Devang Patel6e7775f2008-07-21 23:04:39 +000017#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 Patel05976672008-07-18 23:46:41 +000025#include "llvm/Support/SystemUtils.h"
Devang Patel6e7775f2008-07-21 23:04:39 +000026#include "llvm/Support/MemoryBuffer.h"
27#include "llvm/Bitcode/ReaderWriter.h"
Devang Patel6e7775f2008-07-21 23:04:39 +000028#include "llvm/Config/config.h"
29#include <fstream>
Devang Patel05976672008-07-18 23:46:41 +000030#include <iostream>
Devang Patel8e450f02008-07-18 22:59:45 +000031
Devang Patel6e7775f2008-07-21 23:04:39 +000032using namespace llvm;
33using namespace Reloc;
Devang Patel05976672008-07-18 23:46:41 +000034/// LTOBugPoint -- Constructor. Popuate list of linker options and
35/// list of linker input files.
Devang Patel8e450f02008-07-18 22:59:45 +000036LTOBugPoint::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 Patel85021122008-07-22 20:03:45 +000047
48 TempDir = sys::Path::GetTemporaryDirectory();
49}
50
51LTOBugPoint::~LTOBugPoint() {
52 TempDir.eraseFromDisk(true);
Devang Patel8e450f02008-07-18 22:59:45 +000053}
Devang Patel05976672008-07-18 23:46:41 +000054
55/// findTroubleMakers - Find minimum set of input files that causes error
56/// identified by the script.
57bool
Devang Patel6e7775f2008-07-21 23:04:39 +000058LTOBugPoint::findTroubleMakers(SmallVector<std::string, 4> &TroubleMakers,
Bill Wendlingb6f08eb2008-07-22 09:08:05 +000059 std::string &Script) {
Devang Patel05976672008-07-18 23:46:41 +000060
61 // First, build native object files set.
62 bool bitcodeFileSeen = false;
Devang Patel6e7775f2008-07-21 23:04:39 +000063 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 Patel05976672008-07-18 23:46:41 +000073 bitcodeFileSeen = true;
Devang Patel6e7775f2008-07-21 23:04:39 +000074 if (getNativeObjectFile(FileName) == false)
Bill Wendlingb6f08eb2008-07-22 09:08:05 +000075 return false;
Devang Patel6e7775f2008-07-21 23:04:39 +000076 }
77 else
78 NativeInputFiles.push_back(FileName);
Devang Patel05976672008-07-18 23:46:41 +000079 }
80
81 if (!bitcodeFileSeen) {
Devang Patel6e7775f2008-07-21 23:04:39 +000082 ErrMsg = "Unable to help!";
83 ErrMsg += " Need at least one input file that contains llvm bitcode";
Devang Patel05976672008-07-18 23:46:41 +000084 return false;
85 }
86
87 return true;
88}
Devang Patel6e7775f2008-07-21 23:04:39 +000089
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.
96std::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.
111bool 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 Wendlingb6f08eb2008-07-22 09:08:05 +0000140 TargetMachine::AssemblyFile, true)) {
Devang Patel6e7775f2008-07-21 23:04:39 +0000141 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 Wendlingb6f08eb2008-07-22 09:08:05 +0000162 it = M->begin(), e = M->end(); it != e; ++it)
Devang Patel6e7775f2008-07-21 23:04:39 +0000163 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.
172bool 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 Patel85021122008-07-22 20:03:45 +0000185 sys::Path AsmFile(TempDir);
Devang Patel6e7775f2008-07-21 23:04:39 +0000186 if(AsmFile.createTemporaryFileOnDisk(false, &ErrMsg))
187 return false;
188
Devang Patel85021122008-07-22 20:03:45 +0000189 if (assembleBitcode(M.get(), AsmFile.c_str()) == false) {
190 AsmFile.eraseFromDisk();
Devang Patel6e7775f2008-07-21 23:04:39 +0000191 return false;
Devang Patel85021122008-07-22 20:03:45 +0000192 }
Devang Patel6e7775f2008-07-21 23:04:39 +0000193
Devang Patel85021122008-07-22 20:03:45 +0000194 sys::Path NativeFile(TempDir);
195 if(NativeFile.createTemporaryFileOnDisk(false, &ErrMsg)) {
196 AsmFile.eraseFromDisk();
Devang Patel6e7775f2008-07-21 23:04:39 +0000197 return false;
Devang Patel85021122008-07-22 20:03:45 +0000198 }
Devang Patel6e7775f2008-07-21 23:04:39 +0000199
200 // find compiler driver
201 const sys::Path gcc = sys::Program::FindProgramByName("gcc");
202 if ( gcc.isEmpty() ) {
203 ErrMsg = "can't locate gcc";
Devang Patel85021122008-07-22 20:03:45 +0000204 AsmFile.eraseFromDisk();
205 NativeFile.eraseFromDisk();
Devang Patel6e7775f2008-07-21 23:04:39 +0000206 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 Patel85021122008-07-22 20:03:45 +0000240 ErrMsg = "error in assembly";
241 AsmFile.eraseFromDisk();
242 NativeFile.eraseFromDisk();
Devang Patel6e7775f2008-07-21 23:04:39 +0000243 return false;
244 }
Devang Patel85021122008-07-22 20:03:45 +0000245
246 AsmFile.eraseFromDisk();
Devang Patel6e7775f2008-07-21 23:04:39 +0000247 return true;
248}