blob: 9bcd7ad79672765870f4b072a5212ad65cfea5c9 [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"
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"
Devang Patel05976672008-07-18 23:46:41 +000026#include "llvm/Support/SystemUtils.h"
Devang Patel6e7775f2008-07-21 23:04:39 +000027#include "llvm/Support/MemoryBuffer.h"
28#include "llvm/Bitcode/ReaderWriter.h"
Devang Patel05976672008-07-18 23:46:41 +000029#include "llvm/System/Path.h"
Devang Patel6e7775f2008-07-21 23:04:39 +000030#include "llvm/Config/config.h"
31#include <fstream>
Devang Patel05976672008-07-18 23:46:41 +000032#include <iostream>
Devang Patel8e450f02008-07-18 22:59:45 +000033
Devang Patel6e7775f2008-07-21 23:04:39 +000034using namespace llvm;
35using namespace Reloc;
Devang Patel05976672008-07-18 23:46:41 +000036/// LTOBugPoint -- Constructor. Popuate list of linker options and
37/// list of linker input files.
Devang Patel8e450f02008-07-18 22:59:45 +000038LTOBugPoint::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}
Devang Patel05976672008-07-18 23:46:41 +000050
51/// findTroubleMakers - Find minimum set of input files that causes error
52/// identified by the script.
53bool
Devang Patel6e7775f2008-07-21 23:04:39 +000054LTOBugPoint::findTroubleMakers(SmallVector<std::string, 4> &TroubleMakers,
Bill Wendlingb6f08eb2008-07-22 09:08:05 +000055 std::string &Script) {
Devang Patel05976672008-07-18 23:46:41 +000056
57 // First, build native object files set.
58 bool bitcodeFileSeen = false;
Devang Patel6e7775f2008-07-21 23:04:39 +000059 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()) {
Devang Patel05976672008-07-18 23:46:41 +000069 bitcodeFileSeen = true;
Devang Patel6e7775f2008-07-21 23:04:39 +000070 if (getNativeObjectFile(FileName) == false)
Bill Wendlingb6f08eb2008-07-22 09:08:05 +000071 return false;
Devang Patel6e7775f2008-07-21 23:04:39 +000072 }
73 else
74 NativeInputFiles.push_back(FileName);
Devang Patel05976672008-07-18 23:46:41 +000075 }
76
77 if (!bitcodeFileSeen) {
Devang Patel6e7775f2008-07-21 23:04:39 +000078 ErrMsg = "Unable to help!";
79 ErrMsg += " Need at least one input file that contains llvm bitcode";
Devang Patel05976672008-07-18 23:46:41 +000080 return false;
81 }
82
83 return true;
84}
Devang Patel6e7775f2008-07-21 23:04:39 +000085
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.
92std::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.
107bool 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,
Bill Wendlingb6f08eb2008-07-22 09:08:05 +0000136 TargetMachine::AssemblyFile, true)) {
Devang Patel6e7775f2008-07-21 23:04:39 +0000137 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
Bill Wendlingb6f08eb2008-07-22 09:08:05 +0000158 it = M->begin(), e = M->end(); it != e; ++it)
Devang Patel6e7775f2008-07-21 23:04:39 +0000159 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.
168bool 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}