X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Flto%2FLTOCodeGenerator.cpp;h=bcbd01752a4cba4b5b075831a9162750f4f5158b;hb=67d135ae40b121a138e334a175d0e02dbb54eeca;hp=3fe7af25afd4f87a7280e6a123354962f848481f;hpb=353476cbbb80881a754a90abc13851a884a4e26c;p=oota-llvm.git diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 3fe7af25afd..bcbd01752a4 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -14,6 +14,8 @@ #include "LTOCodeGenerator.h" #include "LTOModule.h" +#include "LTOPartition.h" +#include "LTOPostIPODriver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Verifier.h" @@ -35,11 +37,13 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -47,8 +51,16 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/ObjCARC.h" + using namespace llvm; +using namespace lto; +// ///////////////////////////////////////////////////////////////////////////// +// +// Internal options. To avoid collision, most options start with "lto-". +// +// ///////////////////////////////////////////////////////////////////////////// +// static cl::opt DisableOpt("disable-opt", cl::init(false), cl::desc("Do not run any optimization passes")); @@ -61,6 +73,28 @@ static cl::opt DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), cl::desc("Do not run the GVN load PRE pass")); +// To break merged module into partitions, and compile them independently. +static cl::opt +EnablePartition("lto-partition", cl::init(false), + cl::desc("Partition program and compile each piece in parallel")); + +// Specify the work-directory for the LTO compilation. All intermeidate +// files will be created immediately under this dir. If it is not +// specified, compiler will create an unique directory under current-dir. +// +static cl::opt +TmpWorkDir("lto-workdir", cl::init(""), cl::desc("Specify working directory")); + +static cl::opt +KeepWorkDir("lto-keep", cl::init(false), cl::desc("Keep working directory")); + + +// ///////////////////////////////////////////////////////////////////////////// +// +// Implementation of LTOCodeGenerator +// +// ///////////////////////////////////////////////////////////////////////////// +// const char* LTOCodeGenerator::getVersionString() { #ifdef LLVM_VERSION_INFO return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; @@ -74,7 +108,8 @@ LTOCodeGenerator::LTOCodeGenerator() _linker(new Module("ld-temp.o", _context)), _target(NULL), _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), - _nativeObjectFile(NULL) { + _nativeObjectFile(NULL), PartitionMgr(FileMgr), + OptionsParsed(false) { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); @@ -187,35 +222,41 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, return true; } -bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { - // make unique temp .o file to put generated object file - SmallString<128> Filename; - int FD; - error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); - if (EC) { - errMsg = EC.message(); +// This function is to ensure cl::ParseCommandLineOptions() is called no more +// than once. It would otherwise complain and exit the compilation prematurely. +// +void LTOCodeGenerator::parseOptions() { + if (OptionsParsed) + return; + + if (!_codegenOptions.empty()) + cl::ParseCommandLineOptions(_codegenOptions.size(), + const_cast(&_codegenOptions[0])); + + OptionsParsed = true; +} + +// Do some prepartion right before compilation starts. +bool LTOCodeGenerator::prepareBeforeCompile(std::string &ErrMsg) { + parseOptions(); + + if (!determineTarget(ErrMsg)) return false; - } - // generate object file - tool_output_file objFile(Filename.c_str(), FD); + FileMgr.setWorkDir(TmpWorkDir.c_str()); + FileMgr.setKeepWorkDir(KeepWorkDir); + return FileMgr.createWorkDir(ErrMsg); +} - bool genResult = generateObjectFile(objFile.os(), errMsg); - objFile.os().close(); - if (objFile.os().has_error()) { - objFile.os().clear_error(); - sys::fs::remove(Twine(Filename)); +bool LTOCodeGenerator::compile_to_file(const char** Name, std::string& ErrMsg) { + if (!prepareBeforeCompile(ErrMsg)) return false; - } - objFile.keep(); - if (!genResult) { - sys::fs::remove(Twine(Filename)); + performIPO(EnablePartition, ErrMsg); + if (!performPostIPO(ErrMsg)) return false; - } - _nativeObjectPath = Filename.c_str(); - *name = _nativeObjectPath.c_str(); + *Name = PartitionMgr.getSinglePartition()->getObjFilePath().c_str(); return true; } @@ -229,21 +270,41 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { // read .o file into memory buffer OwningPtr BuffPtr; + const char *BufStart = 0; + if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { errMsg = ec.message(); - sys::fs::remove(_nativeObjectPath); - return NULL; + _nativeObjectFile = 0; + } else { + if ((_nativeObjectFile = BuffPtr.take())) { + *length = _nativeObjectFile->getBufferSize(); + BufStart = _nativeObjectFile->getBufferStart(); + } } - _nativeObjectFile = BuffPtr.take(); - // remove temp files - sys::fs::remove(_nativeObjectPath); + // Now that the resulting single object file is handed to linker via memory + // buffer, it is safe to remove all intermediate files now. + // + FileMgr.removeAllUnneededFiles(); - // return buffer, unless error - if (_nativeObjectFile == NULL) - return NULL; - *length = _nativeObjectFile->getBufferSize(); - return _nativeObjectFile->getBufferStart(); + return BufStart; +} + +const char *LTOCodeGenerator::getFilesNeedToRemove() { + IPOFileMgr::FileNameVect ToRm; + FileMgr.getFilesNeedToRemove(ToRm); + + ConcatStrings.clear(); + for (IPOFileMgr::FileNameVect::iterator I = ToRm.begin(), E = ToRm.end(); + I != E; I++) { + StringRef S(*I); + ConcatStrings.append(S.begin(), S.end()); + ConcatStrings.push_back('\0'); + } + ConcatStrings.push_back('\0'); + ConcatStrings.push_back('\0'); + + return ConcatStrings.data(); } bool LTOCodeGenerator::determineTarget(std::string &errMsg) { @@ -251,9 +312,7 @@ bool LTOCodeGenerator::determineTarget(std::string &errMsg) { return true; // if options were requested, set them - if (!_codegenOptions.empty()) - cl::ParseCommandLineOptions(_codegenOptions.size(), - const_cast(&_codegenOptions[0])); + parseOptions(); std::string TripleStr = _linker.getModule()->getTargetTriple(); if (TripleStr.empty()) @@ -384,6 +443,70 @@ void LTOCodeGenerator::applyScopeRestrictions() { _scopeRestrictionsDone = true; } +void LTOCodeGenerator::performIPO(bool ToPartition, std::string &errMsg) { + // Mark which symbols can not be internalized + applyScopeRestrictions(); + + // Instantiate the pass manager to organize the passes. + PassManager Passes; + + // Start off with a verification pass. + Passes.add(createVerifierPass()); + + // Add an appropriate DataLayout instance for this module... + Passes.add(new DataLayout(*_target->getDataLayout())); + _target->addAnalysisPasses(Passes); + + // Enabling internalize here would use its AllButMain variant. It + // keeps only main if it exists and does nothing for libraries. Instead + // we create the pass ourselves with the symbol list provided by the linker. + if (!DisableOpt) + PassManagerBuilder().populateLTOPassManager(Passes, + /*Internalize=*/false, + !DisableInline, + DisableGVNLoadPRE); + // Make sure everything is still good. + Passes.add(createVerifierPass()); + + Module* M = _linker.getModule(); + if (ToPartition) + assert(false && "TBD"); + else { + Passes.run(*M); + + // Create a partition for the merged module. + PartitionMgr.createIPOPart(M); + } +} + +// Perform Post-IPO compilation. If the partition is enabled, there may +// be multiple partitions, and therefore there may be multiple objects. +// In this case, "MergeObjs" indicates to merge all object together (via ld -r) +// and return the path to the merged object via "MergObjPath". +// +bool LTOCodeGenerator::performPostIPO(std::string &ErrMsg, + bool MergeObjs, + const char **MergObjPath) { + // Determine the variant of post-ipo driver + PostIPODriver::VariantTy DrvTy; + if (!EnablePartition) { + assert(!MergeObjs && !MergObjPath && "Invalid parameter"); + DrvTy = PostIPODriver::PIDV_SERIAL; + } else { + DrvTy = PostIPODriver::PIDV_Invalid; + assert(false && "TBD"); + } + + PostIPODriver D(DrvTy, _target, PartitionMgr, FileMgr, MergeObjs); + if (D.Compile(ErrMsg)) { + if (MergeObjs) + *MergObjPath = D.getSingleObjFile()->getPath().c_str(); + return true; + } + + return false; +} + /// Optimize merged modules using various IPO passes bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, std::string &errMsg) {