From 6e7775f732b4695dd049389238689415bdc99835 Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Mon, 21 Jul 2008 23:04:39 +0000 Subject: [PATCH] Provide llvm bitcode file to native object file interface. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53886 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/lto-bugpoint/LTOBugPoint.cpp | 191 +++++++++++++++++++++++++++- tools/lto-bugpoint/LTOBugPoint.h | 15 +++ tools/lto-bugpoint/Makefile | 7 +- tools/lto-bugpoint/lto-bugpoint.cpp | 4 +- 4 files changed, 208 insertions(+), 9 deletions(-) diff --git a/tools/lto-bugpoint/LTOBugPoint.cpp b/tools/lto-bugpoint/LTOBugPoint.cpp index 925ab9e1acb..a855a0bcda6 100644 --- a/tools/lto-bugpoint/LTOBugPoint.cpp +++ b/tools/lto-bugpoint/LTOBugPoint.cpp @@ -13,10 +13,26 @@ //===----------------------------------------------------------------------===// #include "LTOBugPoint.h" +#include "llvm/PassManager.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/CodeGen/FileWriters.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetMachineRegistry.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/System/Path.h" +#include "llvm/Config/config.h" +#include #include +using namespace llvm; +using namespace Reloc; /// LTOBugPoint -- Constructor. Popuate list of linker options and /// list of linker input files. LTOBugPoint::LTOBugPoint(std::istream &args, std::istream &ins) { @@ -35,23 +51,184 @@ LTOBugPoint::LTOBugPoint(std::istream &args, std::istream &ins) { /// findTroubleMakers - Find minimum set of input files that causes error /// identified by the script. bool -LTOBugPoint::findTroubleMakers(llvm::SmallVector &TroubleMakers, +LTOBugPoint::findTroubleMakers(SmallVector &TroubleMakers, std::string &Script) { // First, build native object files set. bool bitcodeFileSeen = false; - for(llvm::SmallVector::iterator I = LinkerInputFiles.begin(), - E = LinkerInputFiles.end(); I != E; ++I) { - std::string &path = *I; - if (llvm::sys::Path(path.c_str()).isBitcodeFile()) + unsigned Size = LinkerInputFiles.size(); + for (unsigned I = 0; I < Size; ++I) { + std::string &FileName = LinkerInputFiles[I]; + sys::Path InputFile(FileName.c_str()); + if (InputFile.isDynamicLibrary() || InputFile.isArchive()) { + ErrMsg = "Unable to handle input file "; + ErrMsg += FileName; + return false; + } + else if (InputFile.isBitcodeFile()) { bitcodeFileSeen = true; + if (getNativeObjectFile(FileName) == false) + return false; + } + else + NativeInputFiles.push_back(FileName); } if (!bitcodeFileSeen) { - std::cerr << "lto-bugpoint: Error: Unable to help!"; - std::cerr << " Need at least one input file that contains llvm bitcode\n"; + ErrMsg = "Unable to help!"; + ErrMsg += " Need at least one input file that contains llvm bitcode"; return false; } return true; } + +/// getFeatureString - Return a string listing the features associated with the +/// target triple. +/// +/// FIXME: This is an inelegant way of specifying the features of a +/// subtarget. It would be better if we could encode this information into the +/// IR. +std::string LTOBugPoint::getFeatureString(const char *TargetTriple) { + SubtargetFeatures Features; + + if (strncmp(TargetTriple, "powerpc-apple-", 14) == 0) { + Features.AddFeature("altivec", true); + } else if (strncmp(TargetTriple, "powerpc64-apple-", 16) == 0) { + Features.AddFeature("64bit", true); + Features.AddFeature("altivec", true); + } + + return Features.getString(); +} + +/// assembleBitcode - Generate assembly code from the module. Return false +/// in case of an error. +bool LTOBugPoint::assembleBitcode(llvm::Module *M, const char *AsmFileName) { + std::string TargetTriple = M->getTargetTriple(); + std::string FeatureStr = + getFeatureString(TargetTriple.c_str()); + + const TargetMachineRegistry::entry* Registry = + TargetMachineRegistry::getClosestStaticTargetForModule( + *M, ErrMsg); + if ( Registry == NULL ) + return false; + + TargetMachine *Target = Registry->CtorFn(*M, FeatureStr.c_str()); + + // If target supports exception handling then enable it now. + if (Target->getTargetAsmInfo()->doesSupportExceptionHandling()) + ExceptionHandling = true; + + // FIXME + Target->setRelocationModel(Reloc::PIC_); + + FunctionPassManager* CGPasses = + new FunctionPassManager(new ExistingModuleProvider(M)); + + CGPasses->add(new TargetData(*Target->getTargetData())); + MachineCodeEmitter* mce = NULL; + + std::ofstream *Out = new std::ofstream(AsmFileName, std::ios::out); + + switch (Target->addPassesToEmitFile(*CGPasses, *Out, + TargetMachine::AssemblyFile, true)) { + case FileModel::MachOFile: + mce = AddMachOWriter(*CGPasses, *Out, *Target); + break; + case FileModel::ElfFile: + mce = AddELFWriter(*CGPasses, *Out, *Target); + break; + case FileModel::AsmFile: + break; + case FileModel::Error: + case FileModel::None: + ErrMsg = "target file type not supported"; + return false; + } + + if (Target->addPassesToEmitFileFinish(*CGPasses, mce, true)) { + ErrMsg = "target does not support generation of this file type"; + return false; + } + + CGPasses->doInitialization(); + for (Module::iterator + it = M->begin(), e = M->end(); it != e; ++it) + if (!it->isDeclaration()) + CGPasses->run(*it); + CGPasses->doFinalization(); + delete Out; + return true; +} + +/// getNativeObjectFile - Generate native object file based from llvm +/// bitcode file. Return false in case of an error. +bool LTOBugPoint::getNativeObjectFile(std::string &FileName) { + + std::auto_ptr M; + MemoryBuffer *Buffer + = MemoryBuffer::getFile(FileName.c_str(), &ErrMsg); + if (!Buffer) { + ErrMsg = "Unable to read "; + ErrMsg += FileName; + return false; + } + M.reset(ParseBitcodeFile(Buffer, &ErrMsg)); + std::string TargetTriple = M->getTargetTriple(); + + sys::Path AsmFile(sys::Path::GetTemporaryDirectory()); + if(AsmFile.createTemporaryFileOnDisk(false, &ErrMsg)) + return false; + + if (assembleBitcode(M.get(), AsmFile.c_str()) == false) + return false; + + sys::Path NativeFile(sys::Path::GetTemporaryDirectory()); + if(NativeFile.createTemporaryFileOnDisk(false, &ErrMsg)) + return false; + + // find compiler driver + const sys::Path gcc = sys::Program::FindProgramByName("gcc"); + if ( gcc.isEmpty() ) { + ErrMsg = "can't locate gcc"; + return false; + } + + // build argument list + std::vector args; + args.push_back(gcc.c_str()); + if ( TargetTriple.find("darwin") != TargetTriple.size() ) { + if (strncmp(TargetTriple.c_str(), "i686-apple-", 11) == 0) { + args.push_back("-arch"); + args.push_back("i386"); + } + else if (strncmp(TargetTriple.c_str(), "x86_64-apple-", 13) == 0) { + args.push_back("-arch"); + args.push_back("x86_64"); + } + else if (strncmp(TargetTriple.c_str(), "powerpc-apple-", 14) == 0) { + args.push_back("-arch"); + args.push_back("ppc"); + } + else if (strncmp(TargetTriple.c_str(), "powerpc64-apple-", 16) == 0) { + args.push_back("-arch"); + args.push_back("ppc64"); + } + } + args.push_back("-c"); + args.push_back("-x"); + args.push_back("assembler"); + args.push_back("-o"); + args.push_back(NativeFile.c_str()); + args.push_back(AsmFile.c_str()); + args.push_back(0); + + // invoke assembler + if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) { + ErrMsg = "error in assembly"; + return false; + } + return true; +} diff --git a/tools/lto-bugpoint/LTOBugPoint.h b/tools/lto-bugpoint/LTOBugPoint.h index b73b2672d6c..c63a2723b2d 100644 --- a/tools/lto-bugpoint/LTOBugPoint.h +++ b/tools/lto-bugpoint/LTOBugPoint.h @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallVector.h" +#include "llvm/Module.h" #include #include @@ -25,6 +26,13 @@ class LTOBugPoint { /// identified by the script. bool findTroubleMakers(llvm::SmallVector &TroubleMakers, std::string &Script); + + /// getNativeObjectFile - Generate native object file based from llvm + /// bitcode file. Return false in case of an error. + bool getNativeObjectFile(std::string &FileName); + + std::string &getErrMsg() { return ErrMsg; } + private: /// LinkerInputFiles - This is a list of linker input files. Once populated /// this list is not modified. @@ -39,4 +47,11 @@ class LTOBugPoint { /// at index 4 in NativeInputFiles is corresponding native object file. llvm::SmallVector NativeInputFiles; + std::string getFeatureString(const char *TargetTriple); + std::string ErrMsg; + +private: + /// assembleBitcode - Generate assembly code from the module. Return false + /// in case of an error. + bool assembleBitcode(llvm::Module *M, const char *AsmFileName); }; diff --git a/tools/lto-bugpoint/Makefile b/tools/lto-bugpoint/Makefile index c63eb6b6feb..6a08c919c01 100644 --- a/tools/lto-bugpoint/Makefile +++ b/tools/lto-bugpoint/Makefile @@ -10,7 +10,12 @@ LEVEL = ../.. TOOLNAME = lto-bugpoint -LINK_COMPONENTS := system +# Include this here so we can get the configuration of the targets +# that have been configured for construction. We have to do this +# early so we can set up LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader REQUIRES_EH := 1 diff --git a/tools/lto-bugpoint/lto-bugpoint.cpp b/tools/lto-bugpoint/lto-bugpoint.cpp index 01adb5734d3..230d3eb44f1 100644 --- a/tools/lto-bugpoint/lto-bugpoint.cpp +++ b/tools/lto-bugpoint/lto-bugpoint.cpp @@ -51,8 +51,10 @@ int main(int argc, char **argv) { LTOBugPoint bugFinder(*LinkerArgsFile, *LinkerInputsFile); llvm::SmallVector TroubleMakers; - if (!bugFinder.findTroubleMakers(TroubleMakers, ValidationScript)) + if (!bugFinder.findTroubleMakers(TroubleMakers, ValidationScript)) { + std::cerr << "lto-bugpoint:" << bugFinder.getErrMsg() << "\n"; return 1; + } return 0; } catch (const std::string& msg) {