From 67d135ae40b121a138e334a175d0e02dbb54eeca Mon Sep 17 00:00:00 2001 From: Shuxin Yang Date: Mon, 12 Aug 2013 18:29:43 +0000 Subject: Misc enhancements to LTO: 1. Add some helper classes for partitions. They are designed in a way such that the top-level LTO driver will not see much difference with or without partitioning. 2. Introduce work-dir. Now all intermediate files generated during LTO phases will be saved under work-dir. User can specify the workdir via -lto-workdir=/path/to/dir. By default the work-dir will be erased before linker exit. To keep the workdir, do -lto-keep, or -lto-keep=1. TODO: Erase the workdir, if the linker exit prematurely. We are currently not able to remove directory on signal. The support routines simply ignore directory. 3. Add one new API lto_codegen_get_files_need_remove(). Linker and LTO plugin will communicate via this API about which files (including directories) need to removed before linker exit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188188 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/lto/LTOPartition.cpp | 205 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 tools/lto/LTOPartition.cpp (limited to 'tools/lto/LTOPartition.cpp') diff --git a/tools/lto/LTOPartition.cpp b/tools/lto/LTOPartition.cpp new file mode 100644 index 0000000000..a056b718f1 --- /dev/null +++ b/tools/lto/LTOPartition.cpp @@ -0,0 +1,205 @@ +//===-- LTOPartition.cpp - Parition Merged Module --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTOPartition.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include "llvm/Transforms/Utils/Cloning.h" + +using namespace llvm; +using namespace lto; + +// ///////////////////////////////////////////////////////////////////////////// +// +// Implementation of IPOPartition and IPOPartMgr +// +// ///////////////////////////////////////////////////////////////////////////// +// +IPOPartition::IPOPartition(Module *M, const char *NameWoExt, IPOFileMgr &FM) : + Mod(0), Ctx(0), IRFile(0), ObjFile(0), FileNameWoExt(NameWoExt), FileMgr(FM) { +} + +IPOFile &IPOPartition::getIRFile() const { + if (IRFile) + return *IRFile; + else { + std::string FN(FileNameWoExt + ".bc"); + return *(IRFile = FileMgr.createIRFile(FN.c_str())); + } +} + +IPOFile &IPOPartition::getObjFile() const { + if (ObjFile) + return *ObjFile; + else { + std::string FN(FileNameWoExt + ".o"); + return *(ObjFile = FileMgr.createObjFile(FN.c_str())); + } +} + +bool IPOPartition::saveBitCode() { + if (!Mod) { + // The bit-code have already saved in disk. + return true; + } + + IPOFile &F = getIRFile(); + if (F.errOccur()) + return false; + + raw_fd_ostream OF(F.getPath().c_str(), F.getLastErrStr(), + sys::fs::F_Binary); + WriteBitcodeToFile(Mod, OF); + OF.close(); + + Mod = 0; + delete Ctx; + Ctx = 0; + + return !F.errOccur(); +} + +bool IPOPartition::loadBitCode() { + if (Mod) + return true; + + IPOFile &F = getIRFile(); + if (F.errOccur()) + return false; + + Ctx = new LLVMContext; + + error_code &EC = F.getLastErrCode(); + std::string &ErrMsg = F.getLastErrStr(); + + OwningPtr Buf; + if (error_code ec = MemoryBuffer::getFile(F.getPath(), Buf, -1, false)) { + EC = ec; + ErrMsg += ec.message(); + return false; + } + + Mod = ParseBitcodeFile(Buf.get(), *Ctx, &ErrMsg); + + return Mod != 0; +} + +IPOPartition *IPOPartMgr::createIPOPart(Module *M) { + std::string PartName; + raw_string_ostream OS(PartName); + OS << "part" << NextPartId++; + + IPOPartition *P = new IPOPartition(M, OS.str().c_str(), FileMgr); + P->Mod = M; + IPOParts.push_back(P); + return P; +} + +// /////////////////////////////////////////////////////////////////////////// +// +// Implementation of IPOFile and IPOFileMgr +// +// /////////////////////////////////////////////////////////////////////////// +// +IPOFile::IPOFile(const char *DirName, const char *BaseName, bool KeepFile) + : Fname(BaseName), Keep(KeepFile) { + // Concatenate dirname and basename + StringRef D(DirName); + SmallVector Path(D.begin(), D.end()); + sys::path::append(Path, Twine(BaseName)); + Fpath = StringRef(Path.data(), Path.size()); +} + +IPOFileMgr::IPOFileMgr() { + IRFiles.reserve(20); + ObjFiles.reserve(20); + OtherFiles.reserve(8); + KeepWorkDir = false; + WorkDirCreated = false; +} + +bool IPOFileMgr::createWorkDir(std::string &ErrorInfo) { + if (WorkDirCreated) + return true; + + error_code EC; + if (WorkDir.empty()) { + // If the workdir is not specified, then create workdir under current + // directory. + // + SmallString<128> D; + if (sys::fs::current_path(D) != error_code::success()) { + ErrorInfo += "fail to get current directory"; + return false; + } + sys::path::append(D, "llvmipo"); + sys::fs::make_absolute(D); + + SmallVector ResPath; + EC = sys::fs::createUniqueDirectory(Twine(StringRef(D.data(), D.size())), + ResPath); + WorkDir = StringRef(ResPath.data(), ResPath.size()); + } else { + bool Exist; + EC = sys::fs::create_directory(Twine(WorkDir), Exist); + } + + if (EC == error_code::success()) { + WorkDirCreated = true; + return true; + } + + return false; +} + +IPOFile *IPOFileMgr::createIRFile(const char *Name) { + IPOFile *F = CreateFile(Name); + IRFiles.push_back(F); + return F; +} + +IPOFile *IPOFileMgr::createObjFile(const char *Name) { + IPOFile *F = CreateFile(Name); + ObjFiles.push_back(F); + return F; +} + +IPOFile *IPOFileMgr::createMakefile(const char *Name) { + IPOFile *F = CreateFile(Name); + OtherFiles.push_back(F); + return F; +} + +void IPOFileMgr::removeAllUnneededFiles() { + FileNameVect ToRm; + getFilesNeedToRemove(ToRm); + + for (SmallVector::iterator I = ToRm.begin(), E = ToRm.end(); + I != E; I++) { + const char *FN = *I; + sys::fs::file_status Stat; + if (sys::fs::status(Twine(FN), Stat) != error_code::success()) + continue; + + uint32_t Dummy; + if (sys::fs::is_directory(FN)) + sys::fs::remove_all(Twine(FN), Dummy); + else + sys::fs::remove(Twine(FN)); + } +} -- cgit v1.2.3