1 //===- LTOBugPoint.cpp - Top-Level LTO BugPoint class ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
13 //===----------------------------------------------------------------------===//
15 #include "LTOBugPoint.h"
16 #include "llvm/PassManager.h"
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"
25 #include "llvm/Support/SystemUtils.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include "llvm/Bitcode/ReaderWriter.h"
29 #include "llvm/Config/config.h"
34 using namespace Reloc;
36 /// printBitVector - Helper function.
37 static void printBitVector(BitVector &BV, const char *Title) {
39 for (unsigned i = 0, e = BV.size(); i < e; i++) {
41 std::cerr << " " << i;
46 /// printBitVector - Helper function.
47 static void printBitVectorFiles(BitVector &BV, const char *Title,
48 SmallVector<std::string, 16> &InFiles) {
49 std::cerr << Title << "\n";
50 for (unsigned i = 0, e = BV.size(); i < e; i++) {
52 std::cerr << "\t" << InFiles[i] << "\n";
56 /// LTOBugPoint -- Constructor. Popuate list of linker options and
57 /// list of linker input files.
58 LTOBugPoint::LTOBugPoint(std::istream &args, std::istream &ins) {
60 // Read linker options. Order is important here.
62 while (getline(args, option))
63 LinkerOptions.push_back(option);
65 // Read linker input files. Order is important here.
67 while(getline(ins, inFile))
68 LinkerInputFiles.push_back(inFile);
70 TempDir = sys::Path::GetTemporaryDirectory();
72 // FIXME - Use command line option to set this.
73 findLinkingFailure = true;
76 LTOBugPoint::~LTOBugPoint() {
77 TempDir.eraseFromDisk(true);
80 /// findTroubleMakers - Find minimum set of input files that causes error
81 /// identified by the script.
83 LTOBugPoint::findTroubleMakers(SmallVector<std::string, 4> &TroubleMakers,
84 std::string &Script) {
86 // Reproduce original error.
87 if (!relinkProgram(LinkerInputFiles) && !findLinkingFailure) {
88 ErrMsg = " Unable to reproduce original error!";
92 if (!findLinkingFailure && !reproduceProgramError(Script)) {
93 ErrMsg = " Unable to reproduce original error!";
97 // Build native object files set.
98 unsigned Size = LinkerInputFiles.size();
100 ConfirmedClean.resize(Size);
101 ConfirmedGuilty.resize(Size);
102 for (unsigned I = 0; I < Size; ++I) {
103 std::string &FileName = LinkerInputFiles[I];
104 sys::Path InputFile(FileName.c_str());
105 if (InputFile.isDynamicLibrary() || InputFile.isArchive()) {
106 ErrMsg = "Unable to handle input file " + FileName;
109 else if (InputFile.isBitcodeFile()) {
111 if (getNativeObjectFile(FileName) == false)
115 // Original native object input files are always clean.
116 ConfirmedClean.set(I);
117 NativeInputFiles.push_back(FileName);
121 if (BCFiles.none()) {
122 ErrMsg = "Unable to help!";
123 ErrMsg = " Need at least one input file that contains llvm bitcode";
127 // Try to reproduce error using native object files first. If the error
128 // occurs then this is not a LTO error.
129 if (!relinkProgram(NativeInputFiles)) {
130 ErrMsg = " Unable to link the program using all native object files!";
133 if (!findLinkingFailure && reproduceProgramError(Script) == true) {
134 ErrMsg = " Unable to fix program error using all native object files!";
138 printBitVector(BCFiles, "Initial set of llvm bitcode files");
139 identifyTroubleMakers(BCFiles);
140 printBitVectorFiles(ConfirmedGuilty,
141 "Identified minimal set of bitcode files!",
146 /// getFeatureString - Return a string listing the features associated with the
149 /// FIXME: This is an inelegant way of specifying the features of a
150 /// subtarget. It would be better if we could encode this information into the
152 std::string LTOBugPoint::getFeatureString(const char *TargetTriple) {
153 SubtargetFeatures Features;
155 if (strncmp(TargetTriple, "powerpc-apple-", 14) == 0) {
156 Features.AddFeature("altivec", true);
157 } else if (strncmp(TargetTriple, "powerpc64-apple-", 16) == 0) {
158 Features.AddFeature("64bit", true);
159 Features.AddFeature("altivec", true);
162 return Features.getString();
165 /// assembleBitcode - Generate assembly code from the module. Return false
166 /// in case of an error.
167 bool LTOBugPoint::assembleBitcode(llvm::Module *M, const char *AsmFileName) {
168 std::string TargetTriple = M->getTargetTriple();
169 std::string FeatureStr =
170 getFeatureString(TargetTriple.c_str());
172 const TargetMachineRegistry::entry* Registry =
173 TargetMachineRegistry::getClosestStaticTargetForModule(
175 if ( Registry == NULL )
178 TargetMachine *Target = Registry->CtorFn(*M, FeatureStr.c_str());
180 // If target supports exception handling then enable it now.
181 if (Target->getTargetAsmInfo()->doesSupportExceptionHandling())
182 ExceptionHandling = true;
185 Target->setRelocationModel(Reloc::PIC_);
187 FunctionPassManager* CGPasses =
188 new FunctionPassManager(new ExistingModuleProvider(M));
190 CGPasses->add(new TargetData(*Target->getTargetData()));
191 MachineCodeEmitter* mce = NULL;
194 raw_ostream *Out = new raw_fd_ostream(AsmFileName, error);
195 if (!error.empty()) {
196 std::cerr << error << '\n';
201 switch (Target->addPassesToEmitFile(*CGPasses, *Out,
202 TargetMachine::AssemblyFile, true)) {
203 case FileModel::MachOFile:
204 mce = AddMachOWriter(*CGPasses, *Out, *Target);
206 case FileModel::ElfFile:
207 mce = AddELFWriter(*CGPasses, *Out, *Target);
209 case FileModel::AsmFile:
211 case FileModel::Error:
212 case FileModel::None:
213 ErrMsg = "target file type not supported";
217 if (Target->addPassesToEmitFileFinish(*CGPasses, mce, true)) {
218 ErrMsg = "target does not support generation of this file type";
222 CGPasses->doInitialization();
223 for (Module::iterator
224 it = M->begin(), e = M->end(); it != e; ++it)
225 if (!it->isDeclaration())
227 CGPasses->doFinalization();
232 /// getNativeObjectFile - Generate native object file based from llvm
233 /// bitcode file. Return false in case of an error.
234 bool LTOBugPoint::getNativeObjectFile(std::string &FileName) {
236 std::auto_ptr<Module> M;
238 = MemoryBuffer::getFile(FileName.c_str(), &ErrMsg);
240 ErrMsg = "Unable to read " + FileName;
243 M.reset(ParseBitcodeFile(Buffer, &ErrMsg));
244 std::string TargetTriple = M->getTargetTriple();
246 sys::Path AsmFile(TempDir);
247 if(AsmFile.createTemporaryFileOnDisk(false, &ErrMsg))
250 if (assembleBitcode(M.get(), AsmFile.c_str()) == false) {
251 AsmFile.eraseFromDisk();
255 sys::Path NativeFile(TempDir);
256 if(NativeFile.createTemporaryFileOnDisk(false, &ErrMsg)) {
257 AsmFile.eraseFromDisk();
261 // find compiler driver
262 const sys::Path gcc = sys::Program::FindProgramByName("gcc");
263 if ( gcc.isEmpty() ) {
264 ErrMsg = "can't locate gcc";
265 AsmFile.eraseFromDisk();
266 NativeFile.eraseFromDisk();
270 // build argument list
271 std::vector<const char*> args;
272 args.push_back(gcc.c_str());
273 if ( TargetTriple.find("darwin") != TargetTriple.size() ) {
274 if (strncmp(TargetTriple.c_str(), "i686-apple-", 11) == 0) {
275 args.push_back("-arch");
276 args.push_back("i386");
278 else if (strncmp(TargetTriple.c_str(), "x86_64-apple-", 13) == 0) {
279 args.push_back("-arch");
280 args.push_back("x86_64");
282 else if (strncmp(TargetTriple.c_str(), "powerpc-apple-", 14) == 0) {
283 args.push_back("-arch");
284 args.push_back("ppc");
286 else if (strncmp(TargetTriple.c_str(), "powerpc64-apple-", 16) == 0) {
287 args.push_back("-arch");
288 args.push_back("ppc64");
291 args.push_back("-c");
292 args.push_back("-x");
293 args.push_back("assembler");
294 args.push_back("-o");
295 args.push_back(NativeFile.c_str());
296 args.push_back(AsmFile.c_str());
300 if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) {
301 ErrMsg = "error in assembly";
302 AsmFile.eraseFromDisk();
303 NativeFile.eraseFromDisk();
307 AsmFile.eraseFromDisk();
308 NativeInputFiles.push_back(NativeFile.c_str());
312 /// relinkProgram - Relink program. Return false if linking fails.
313 bool LTOBugPoint::relinkProgram(llvm::SmallVector<std::string, 16> &InFiles) {
317 // Atleast three options: linker path, -o and output file name.
318 if (LinkerOptions.size() < 3)
321 const sys::Path linker = sys::Program::FindProgramByName(LinkerOptions[0]);
322 if (linker.isEmpty()) {
323 ErrMsg = "can't locate linker";
327 std::vector<const char*> Args;
328 for (unsigned i = 0, e = LinkerOptions.size(); i < e; ++i)
329 Args.push_back(LinkerOptions[i].c_str());
331 for (unsigned i = 0, e = InFiles.size(); i < e; ++i)
332 Args.push_back(InFiles[i].c_str());
336 if (sys::Program::ExecuteAndWait(linker, &Args[0], 0, 0, 0, 0, &ErrMsg)) {
337 ErrMsg = "error while linking program";
343 /// reproduceProgramError - Validate program using user provided script.
344 /// Return true if program error is reproduced.
345 bool LTOBugPoint::reproduceProgramError(std::string &Script) {
347 const sys::Path validator = sys::Program::FindProgramByName(Script);
348 if (validator.isEmpty()) {
349 ErrMsg = "can't locate validation script";
353 std::vector<const char*> Args;
354 Args.push_back(Script.c_str());
358 sys::Program::ExecuteAndWait(validator, &Args[0], 0, 0, 0, 0, &ErrMsg);
360 // Validation scrip returns non-zero if the error is reproduced.
362 // Able to reproduce program error.
366 // error occured while running validation script. ErrMsg contains error
373 /// identifyTroubleMakers - Identify set of bit code files that are causing
374 /// the error. This is a recursive function.
375 void LTOBugPoint::identifyTroubleMakers(llvm::BitVector &In) {
377 assert (In.size() == LinkerInputFiles.size()
378 && "Invalid identifyTroubleMakers input!\n");
380 printBitVector(In, "Processing files ");
381 BitVector CandidateVector;
382 CandidateVector.resize(LinkerInputFiles.size());
384 // Process first half
386 for (unsigned i = 0, e = In.size(); i < e; ++i) {
387 if (!ConfirmedClean[i]) {
389 CandidateVector.set(i);
391 if (count >= In.count()/2)
395 if (CandidateVector.none())
398 printBitVector(CandidateVector, "Candidate vector ");
400 // Reproduce the error using native object files for candidate files.
401 SmallVector<std::string, 16> CandidateFiles;
402 for (unsigned i = 0, e = CandidateVector.size(); i < e; ++i) {
403 if (CandidateVector[i] || ConfirmedClean[i])
404 CandidateFiles.push_back(NativeInputFiles[i]);
406 CandidateFiles.push_back(LinkerInputFiles[i]);
409 bool result = relinkProgram(CandidateFiles);
410 if (findLinkingFailure) {
411 if (result == true) {
412 // Candidate files are suspected.
413 if (CandidateVector.count() == 1) {
414 ConfirmedGuilty.set(CandidateVector.find_first());
418 identifyTroubleMakers(CandidateVector);
420 // Candidate files are not causing this error.
421 for (unsigned i = 0, e = CandidateVector.size(); i < e; ++i) {
422 if (CandidateVector[i])
423 ConfirmedClean.set(i);
427 std::cerr << "FIXME : Not yet implemented!\n";
430 // Process remaining cadidates
431 CandidateVector.clear();
432 CandidateVector.resize(LinkerInputFiles.size());
433 for (unsigned i = 0, e = LinkerInputFiles.size(); i < e; ++i) {
434 if (!ConfirmedClean[i] && !ConfirmedGuilty[i])
435 CandidateVector.set(i);
437 identifyTroubleMakers(CandidateVector);