blob: 587e360bc62f0bb568b6b26b1b1375e827e3f5a4 [file] [log] [blame]
Devang Patele330f2d2008-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 Patel4f574f52008-07-21 23:04:39 +000016#include "llvm/PassManager.h"
Devang Patel4f574f52008-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 Patel5dd66a02008-07-18 23:46:41 +000025#include "llvm/Support/SystemUtils.h"
Devang Patel4f574f52008-07-21 23:04:39 +000026#include "llvm/Support/MemoryBuffer.h"
27#include "llvm/Bitcode/ReaderWriter.h"
Devang Patel4f574f52008-07-21 23:04:39 +000028#include "llvm/Config/config.h"
29#include <fstream>
Devang Patel5dd66a02008-07-18 23:46:41 +000030#include <iostream>
Devang Patele330f2d2008-07-18 22:59:45 +000031
Devang Patel4f574f52008-07-21 23:04:39 +000032using namespace llvm;
33using namespace Reloc;
Devang Patelcfb54102008-07-24 00:34:11 +000034
35/// printBitVector - Helper function.
36static void printBitVector(BitVector &BV, const char *Title) {
37 std::cerr << Title;
38 for (unsigned i = 0, e = BV.size(); i < e; i++) {
39 if (BV[i])
40 std::cerr << " " << i;
41 }
42 std::cerr << "\n";
43}
44
45/// printBitVector - Helper function.
46static void printBitVectorFiles(BitVector &BV, const char *Title,
47 SmallVector<std::string, 16> &InFiles) {
48 std::cerr << Title << "\n";
49 for (unsigned i = 0, e = BV.size(); i < e; i++) {
50 if (BV[i])
51 std::cerr << "\t" << InFiles[i] << "\n";
52 }
53}
54
Devang Patel5dd66a02008-07-18 23:46:41 +000055/// LTOBugPoint -- Constructor. Popuate list of linker options and
56/// list of linker input files.
Devang Patele330f2d2008-07-18 22:59:45 +000057LTOBugPoint::LTOBugPoint(std::istream &args, std::istream &ins) {
58
59 // Read linker options. Order is important here.
60 std::string option;
61 while (getline(args, option))
62 LinkerOptions.push_back(option);
63
64 // Read linker input files. Order is important here.
65 std::string inFile;
66 while(getline(ins, inFile))
67 LinkerInputFiles.push_back(inFile);
Devang Patel35b39b4f2008-07-22 20:03:45 +000068
69 TempDir = sys::Path::GetTemporaryDirectory();
Devang Patelcfb54102008-07-24 00:34:11 +000070
71 // FIXME - Use command line option to set this.
72 findLinkingFailure = true;
Devang Patel35b39b4f2008-07-22 20:03:45 +000073}
74
75LTOBugPoint::~LTOBugPoint() {
76 TempDir.eraseFromDisk(true);
Devang Patele330f2d2008-07-18 22:59:45 +000077}
Devang Patel5dd66a02008-07-18 23:46:41 +000078
79/// findTroubleMakers - Find minimum set of input files that causes error
80/// identified by the script.
81bool
Devang Patel4f574f52008-07-21 23:04:39 +000082LTOBugPoint::findTroubleMakers(SmallVector<std::string, 4> &TroubleMakers,
Bill Wendling80fb2782008-07-22 09:08:05 +000083 std::string &Script) {
Devang Patel5dd66a02008-07-18 23:46:41 +000084
Devang Patela11ec252008-07-22 22:20:18 +000085 // Reproduce original error.
Devang Patelcfb54102008-07-24 00:34:11 +000086 if (!relinkProgram(LinkerInputFiles) && !findLinkingFailure) {
87 ErrMsg = " Unable to reproduce original error!";
88 return false;
89 }
90
91 if (!findLinkingFailure && !reproduceProgramError(Script)) {
92 ErrMsg = " Unable to reproduce original error!";
Devang Patela11ec252008-07-22 22:20:18 +000093 return false;
94 }
95
96 // Build native object files set.
Devang Patel4f574f52008-07-21 23:04:39 +000097 unsigned Size = LinkerInputFiles.size();
Devang Patelcfb54102008-07-24 00:34:11 +000098 BCFiles.resize(Size);
99 ConfirmedClean.resize(Size);
100 ConfirmedGuilty.resize(Size);
Devang Patel4f574f52008-07-21 23:04:39 +0000101 for (unsigned I = 0; I < Size; ++I) {
102 std::string &FileName = LinkerInputFiles[I];
103 sys::Path InputFile(FileName.c_str());
104 if (InputFile.isDynamicLibrary() || InputFile.isArchive()) {
Devang Patelcfb54102008-07-24 00:34:11 +0000105 ErrMsg = "Unable to handle input file " + FileName;
Devang Patel4f574f52008-07-21 23:04:39 +0000106 return false;
107 }
108 else if (InputFile.isBitcodeFile()) {
Devang Patelcfb54102008-07-24 00:34:11 +0000109 BCFiles.set(I);
Devang Patel4f574f52008-07-21 23:04:39 +0000110 if (getNativeObjectFile(FileName) == false)
Bill Wendling80fb2782008-07-22 09:08:05 +0000111 return false;
Devang Patel4f574f52008-07-21 23:04:39 +0000112 }
Devang Patelcfb54102008-07-24 00:34:11 +0000113 else {
114 // Original native object input files are always clean.
115 ConfirmedClean.set(I);
Devang Patel4f574f52008-07-21 23:04:39 +0000116 NativeInputFiles.push_back(FileName);
Devang Patelcfb54102008-07-24 00:34:11 +0000117 }
Devang Patel5dd66a02008-07-18 23:46:41 +0000118 }
119
Devang Patelcfb54102008-07-24 00:34:11 +0000120 if (BCFiles.none()) {
Devang Patel4f574f52008-07-21 23:04:39 +0000121 ErrMsg = "Unable to help!";
Devang Patelcfb54102008-07-24 00:34:11 +0000122 ErrMsg = " Need at least one input file that contains llvm bitcode";
Devang Patel5dd66a02008-07-18 23:46:41 +0000123 return false;
124 }
125
Devang Patela11ec252008-07-22 22:20:18 +0000126 // Try to reproduce error using native object files first. If the error
127 // occurs then this is not a LTO error.
128 if (!relinkProgram(NativeInputFiles)) {
Devang Patelcfb54102008-07-24 00:34:11 +0000129 ErrMsg = " Unable to link the program using all native object files!";
Devang Patela11ec252008-07-22 22:20:18 +0000130 return false;
131 }
Devang Patelcfb54102008-07-24 00:34:11 +0000132 if (!findLinkingFailure && reproduceProgramError(Script) == true) {
133 ErrMsg = " Unable to fix program error using all native object files!";
Devang Patela11ec252008-07-22 22:20:18 +0000134 return false;
135 }
136
Devang Patelcfb54102008-07-24 00:34:11 +0000137 printBitVector(BCFiles, "Initial set of llvm bitcode files");
138 identifyTroubleMakers(BCFiles);
139 printBitVectorFiles(ConfirmedGuilty,
140 "Identified minimal set of bitcode files!",
141 LinkerInputFiles);
Devang Patel5dd66a02008-07-18 23:46:41 +0000142 return true;
143}
Devang Patel4f574f52008-07-21 23:04:39 +0000144
145/// getFeatureString - Return a string listing the features associated with the
146/// target triple.
147///
148/// FIXME: This is an inelegant way of specifying the features of a
149/// subtarget. It would be better if we could encode this information into the
150/// IR.
151std::string LTOBugPoint::getFeatureString(const char *TargetTriple) {
152 SubtargetFeatures Features;
153
154 if (strncmp(TargetTriple, "powerpc-apple-", 14) == 0) {
155 Features.AddFeature("altivec", true);
156 } else if (strncmp(TargetTriple, "powerpc64-apple-", 16) == 0) {
157 Features.AddFeature("64bit", true);
158 Features.AddFeature("altivec", true);
159 }
160
161 return Features.getString();
162}
163
164/// assembleBitcode - Generate assembly code from the module. Return false
165/// in case of an error.
166bool LTOBugPoint::assembleBitcode(llvm::Module *M, const char *AsmFileName) {
167 std::string TargetTriple = M->getTargetTriple();
168 std::string FeatureStr =
169 getFeatureString(TargetTriple.c_str());
170
171 const TargetMachineRegistry::entry* Registry =
172 TargetMachineRegistry::getClosestStaticTargetForModule(
173 *M, ErrMsg);
174 if ( Registry == NULL )
175 return false;
176
177 TargetMachine *Target = Registry->CtorFn(*M, FeatureStr.c_str());
178
179 // If target supports exception handling then enable it now.
180 if (Target->getTargetAsmInfo()->doesSupportExceptionHandling())
181 ExceptionHandling = true;
182
183 // FIXME
184 Target->setRelocationModel(Reloc::PIC_);
185
186 FunctionPassManager* CGPasses =
187 new FunctionPassManager(new ExistingModuleProvider(M));
188
189 CGPasses->add(new TargetData(*Target->getTargetData()));
190 MachineCodeEmitter* mce = NULL;
191
192 std::ofstream *Out = new std::ofstream(AsmFileName, std::ios::out);
193
194 switch (Target->addPassesToEmitFile(*CGPasses, *Out,
Bill Wendling80fb2782008-07-22 09:08:05 +0000195 TargetMachine::AssemblyFile, true)) {
Devang Patel4f574f52008-07-21 23:04:39 +0000196 case FileModel::MachOFile:
197 mce = AddMachOWriter(*CGPasses, *Out, *Target);
198 break;
199 case FileModel::ElfFile:
200 mce = AddELFWriter(*CGPasses, *Out, *Target);
201 break;
202 case FileModel::AsmFile:
203 break;
204 case FileModel::Error:
205 case FileModel::None:
206 ErrMsg = "target file type not supported";
207 return false;
208 }
209
210 if (Target->addPassesToEmitFileFinish(*CGPasses, mce, true)) {
211 ErrMsg = "target does not support generation of this file type";
212 return false;
213 }
214
215 CGPasses->doInitialization();
216 for (Module::iterator
Bill Wendling80fb2782008-07-22 09:08:05 +0000217 it = M->begin(), e = M->end(); it != e; ++it)
Devang Patel4f574f52008-07-21 23:04:39 +0000218 if (!it->isDeclaration())
219 CGPasses->run(*it);
220 CGPasses->doFinalization();
221 delete Out;
222 return true;
223}
224
225/// getNativeObjectFile - Generate native object file based from llvm
226/// bitcode file. Return false in case of an error.
227bool LTOBugPoint::getNativeObjectFile(std::string &FileName) {
228
229 std::auto_ptr<Module> M;
230 MemoryBuffer *Buffer
231 = MemoryBuffer::getFile(FileName.c_str(), &ErrMsg);
232 if (!Buffer) {
Devang Patelcfb54102008-07-24 00:34:11 +0000233 ErrMsg = "Unable to read " + FileName;
Devang Patel4f574f52008-07-21 23:04:39 +0000234 return false;
235 }
236 M.reset(ParseBitcodeFile(Buffer, &ErrMsg));
237 std::string TargetTriple = M->getTargetTriple();
238
Devang Patel35b39b4f2008-07-22 20:03:45 +0000239 sys::Path AsmFile(TempDir);
Devang Patel4f574f52008-07-21 23:04:39 +0000240 if(AsmFile.createTemporaryFileOnDisk(false, &ErrMsg))
241 return false;
242
Devang Patel35b39b4f2008-07-22 20:03:45 +0000243 if (assembleBitcode(M.get(), AsmFile.c_str()) == false) {
244 AsmFile.eraseFromDisk();
Devang Patel4f574f52008-07-21 23:04:39 +0000245 return false;
Devang Patel35b39b4f2008-07-22 20:03:45 +0000246 }
Devang Patel4f574f52008-07-21 23:04:39 +0000247
Devang Patel35b39b4f2008-07-22 20:03:45 +0000248 sys::Path NativeFile(TempDir);
249 if(NativeFile.createTemporaryFileOnDisk(false, &ErrMsg)) {
250 AsmFile.eraseFromDisk();
Devang Patel4f574f52008-07-21 23:04:39 +0000251 return false;
Devang Patel35b39b4f2008-07-22 20:03:45 +0000252 }
Devang Patel4f574f52008-07-21 23:04:39 +0000253
254 // find compiler driver
255 const sys::Path gcc = sys::Program::FindProgramByName("gcc");
256 if ( gcc.isEmpty() ) {
257 ErrMsg = "can't locate gcc";
Devang Patel35b39b4f2008-07-22 20:03:45 +0000258 AsmFile.eraseFromDisk();
259 NativeFile.eraseFromDisk();
Devang Patel4f574f52008-07-21 23:04:39 +0000260 return false;
261 }
262
263 // build argument list
264 std::vector<const char*> args;
265 args.push_back(gcc.c_str());
266 if ( TargetTriple.find("darwin") != TargetTriple.size() ) {
267 if (strncmp(TargetTriple.c_str(), "i686-apple-", 11) == 0) {
268 args.push_back("-arch");
269 args.push_back("i386");
270 }
271 else if (strncmp(TargetTriple.c_str(), "x86_64-apple-", 13) == 0) {
272 args.push_back("-arch");
273 args.push_back("x86_64");
274 }
275 else if (strncmp(TargetTriple.c_str(), "powerpc-apple-", 14) == 0) {
276 args.push_back("-arch");
277 args.push_back("ppc");
278 }
279 else if (strncmp(TargetTriple.c_str(), "powerpc64-apple-", 16) == 0) {
280 args.push_back("-arch");
281 args.push_back("ppc64");
282 }
283 }
284 args.push_back("-c");
285 args.push_back("-x");
286 args.push_back("assembler");
287 args.push_back("-o");
288 args.push_back(NativeFile.c_str());
289 args.push_back(AsmFile.c_str());
290 args.push_back(0);
291
292 // invoke assembler
293 if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) {
Devang Patel35b39b4f2008-07-22 20:03:45 +0000294 ErrMsg = "error in assembly";
295 AsmFile.eraseFromDisk();
296 NativeFile.eraseFromDisk();
Devang Patel4f574f52008-07-21 23:04:39 +0000297 return false;
298 }
Devang Patel35b39b4f2008-07-22 20:03:45 +0000299
300 AsmFile.eraseFromDisk();
Devang Patelcfb54102008-07-24 00:34:11 +0000301 NativeInputFiles.push_back(NativeFile.c_str());
Devang Patel4f574f52008-07-21 23:04:39 +0000302 return true;
303}
Devang Patela11ec252008-07-22 22:20:18 +0000304
305/// relinkProgram - Relink program. Return false if linking fails.
306bool LTOBugPoint::relinkProgram(llvm::SmallVector<std::string, 16> &InFiles) {
307 if (InFiles.empty())
308 return false;
309
310 // Atleast three options: linker path, -o and output file name.
311 if (LinkerOptions.size() < 3)
312 return false;
313
314 const sys::Path linker = sys::Program::FindProgramByName(LinkerOptions[0]);
315 if (linker.isEmpty()) {
316 ErrMsg = "can't locate linker";
317 return false;
318 }
319
320 std::vector<const char*> Args;
321 for (unsigned i = 0, e = LinkerOptions.size(); i < e; ++i)
322 Args.push_back(LinkerOptions[i].c_str());
323
324 for (unsigned i = 0, e = InFiles.size(); i < e; ++i)
325 Args.push_back(InFiles[i].c_str());
326
327 Args.push_back(0);
328
329 if (sys::Program::ExecuteAndWait(linker, &Args[0], 0, 0, 0, 0, &ErrMsg)) {
Devang Patelcfb54102008-07-24 00:34:11 +0000330 ErrMsg = "error while linking program";
331 return false;
Devang Patela11ec252008-07-22 22:20:18 +0000332 }
Devang Patela11ec252008-07-22 22:20:18 +0000333 return true;
334}
335
336/// reproduceProgramError - Validate program using user provided script.
337/// Return true if program error is reproduced.
338bool LTOBugPoint::reproduceProgramError(std::string &Script) {
339
340 const sys::Path validator = sys::Program::FindProgramByName(Script);
341 if (validator.isEmpty()) {
342 ErrMsg = "can't locate validation script";
343 return false;
344 }
345
346 std::vector<const char*> Args;
347 Args.push_back(Script.c_str());
348 Args.push_back(0);
349
350 int result =
351 sys::Program::ExecuteAndWait(validator, &Args[0], 0, 0, 0, 0, &ErrMsg);
352
353 // Validation scrip returns non-zero if the error is reproduced.
354 if (result > 0)
355 // Able to reproduce program error.
356 return true;
357
358 else if (result < 0)
359 // error occured while running validation script. ErrMsg contains error
360 // description.
361 return false;
362
363 return false;
364}
Devang Patelcfb54102008-07-24 00:34:11 +0000365
366/// identifyTroubleMakers - Identify set of bit code files that are causing
367/// the error. This is a recursive function.
368void LTOBugPoint::identifyTroubleMakers(llvm::BitVector &In) {
369
370 assert (In.size() == LinkerInputFiles.size()
371 && "Invalid identifyTroubleMakers input!\n");
372
373 printBitVector(In, "Processing files ");
374 BitVector CandidateVector;
375 CandidateVector.resize(LinkerInputFiles.size());
376
377 // Process first half
378 unsigned count = 0;
379 for (unsigned i = 0, e = In.size(); i < e; ++i) {
380 if (!ConfirmedClean[i]) {
381 count++;
382 CandidateVector.set(i);
383 }
384 if (count >= In.count()/2)
385 break;
386 }
387
388 if (CandidateVector.none())
389 return;
390
391 printBitVector(CandidateVector, "Candidate vector ");
392
393 // Reproduce the error using native object files for candidate files.
394 SmallVector<std::string, 16> CandidateFiles;
395 for (unsigned i = 0, e = CandidateVector.size(); i < e; ++i) {
396 if (CandidateVector[i] || ConfirmedClean[i])
397 CandidateFiles.push_back(NativeInputFiles[i]);
398 else
399 CandidateFiles.push_back(LinkerInputFiles[i]);
400 }
401
402 bool result = relinkProgram(CandidateFiles);
403 if (findLinkingFailure) {
404 if (result == true) {
405 // Candidate files are suspected.
406 if (CandidateVector.count() == 1) {
407 ConfirmedGuilty.set(CandidateVector.find_first());
408 return;
409 }
410 else
411 identifyTroubleMakers(CandidateVector);
412 } else {
413 // Candidate files are not causing this error.
414 for (unsigned i = 0, e = CandidateVector.size(); i < e; ++i) {
415 if (CandidateVector[i])
416 ConfirmedClean.set(i);
417 }
418 }
419 } else {
420 std::cerr << "FIXME : Not yet implemented!\n";
421 }
422
423 // Process remaining cadidates
424 CandidateVector.clear();
425 CandidateVector.resize(LinkerInputFiles.size());
426 for (unsigned i = 0, e = LinkerInputFiles.size(); i < e; ++i) {
427 if (!ConfirmedClean[i] && !ConfirmedGuilty[i])
428 CandidateVector.set(i);
429 }
430 identifyTroubleMakers(CandidateVector);
431}