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