Newer
Older
//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===//
//
// This file implements the Link Time Optimization library. This library is
// intended to be used by linker to optimize code at link time.
//
//===----------------------------------------------------------------------===//
#include "LTOModule.h"
#include "LTOPartition.h"
#include "LTOPostIPODriver.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
Evan Cheng
committed
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.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/Target/Mangler.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/ObjCARC.h"
using namespace llvm;
// /////////////////////////////////////////////////////////////////////////////
//
// Internal options. To avoid collision, most options start with "lto-".
//
// /////////////////////////////////////////////////////////////////////////////
//
static cl::opt<bool>
DisableOpt("disable-opt", cl::init(false),
cl::desc("Do not run any optimization passes"));
static cl::opt<bool>
DisableInline("disable-inlining", cl::init(false),
Nick Kledzik
committed
cl::desc("Do not run the inliner pass"));
static cl::opt<bool>
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<bool>
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<std::string>
TmpWorkDir("lto-workdir", cl::init(""), cl::desc("Specify working directory"));
static cl::opt<bool>
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;
return PACKAGE_NAME " version " PACKAGE_VERSION;
#endif
}
_linker(new Module("ld-temp.o", _context)), _target(NULL),
_emitDwarfDebugInfo(false), _scopeRestrictionsDone(false),
_nativeObjectFile(NULL), PartitionMgr(FileMgr),
OptionsParsed(false) {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
initializeLTOPasses();
LTOCodeGenerator::~LTOCodeGenerator() {
delete _target;
delete _nativeObjectFile;
delete _linker.getModule();
for (std::vector<char*>::iterator I = _codegenOptions.begin(),
E = _codegenOptions.end(); I != E; ++I)
free(*I);
}
// Initialize LTO passes. Please keep this funciton in sync with
// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO
// passes are initialized.
//
void LTOCodeGenerator::initializeLTOPasses() {
PassRegistry &R = *PassRegistry::getPassRegistry();
initializeInternalizePassPass(R);
initializeIPSCCPPass(R);
initializeGlobalOptPass(R);
initializeConstantMergePass(R);
initializeDAHPass(R);
initializeInstCombinerPass(R);
initializeSimpleInlinerPass(R);
initializePruneEHPass(R);
initializeGlobalDCEPass(R);
initializeArgPromotionPass(R);
initializeJumpThreadingPass(R);
initializeSROAPass(R);
initializeSROA_DTPass(R);
initializeSROA_SSAUpPass(R);
initializeFunctionAttrsPass(R);
initializeGlobalsModRefPass(R);
initializeLICMPass(R);
initializeGVNPass(R);
initializeMemCpyOptPass(R);
initializeDCEPass(R);
}
bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) {
bool ret = _linker.linkInModule(mod->getLLVVMModule(), &errMsg);
Rafael Espindola
committed
const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs();
for (int i = 0, e = undefs.size(); i != e; ++i)
_asmUndefinedRefs[undefs[i]] = 1;
Shuxin Yang
committed
return !ret;
Shuxin Yang
committed
void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) {
switch (debug) {
case LTO_DEBUG_MODEL_NONE:
_emitDwarfDebugInfo = false;
Shuxin Yang
committed
return;
case LTO_DEBUG_MODEL_DWARF:
_emitDwarfDebugInfo = true;
Shuxin Yang
committed
return;
}
llvm_unreachable("Unknown debug format!");
Shuxin Yang
committed
void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) {
switch (model) {
case LTO_CODEGEN_PIC_MODEL_STATIC:
case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
_codeModel = model;
Shuxin Yang
committed
return;
}
llvm_unreachable("Unknown PIC model!");
bool LTOCodeGenerator::writeMergedModules(const char *path,
std::string &errMsg) {
Shuxin Yang
committed
if (!determineTarget(errMsg))
Shuxin Yang
committed
return false;
Bill Wendling
committed
// mark which symbols can not be internalized
applyScopeRestrictions();
// create output file
std::string ErrInfo;
tool_output_file Out(path, ErrInfo, sys::fs::F_Binary);
if (!ErrInfo.empty()) {
errMsg = "could not open bitcode file for writing: ";
errMsg += path;
Shuxin Yang
committed
return false;
// write bitcode to it
WriteBitcodeToFile(_linker.getModule(), Out.os());
Out.os().close();
if (Out.os().has_error()) {
errMsg = "could not write bitcode file: ";
errMsg += path;
Out.os().clear_error();
Shuxin Yang
committed
return false;
Shuxin Yang
committed
return true;
// 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<char **>(&_codegenOptions[0]));
OptionsParsed = true;
}
// Do some prepartion right before compilation starts.
bool LTOCodeGenerator::prepareBeforeCompile(std::string &ErrMsg) {
parseOptions();
if (!determineTarget(ErrMsg))
Shuxin Yang
committed
return false;
Rafael Espindola
committed
FileMgr.setWorkDir(TmpWorkDir.c_str());
FileMgr.setKeepWorkDir(KeepWorkDir);
return FileMgr.createWorkDir(ErrMsg);
}
bool LTOCodeGenerator::compile_to_file(const char** Name, std::string& ErrMsg) {
if (!prepareBeforeCompile(ErrMsg))
Shuxin Yang
committed
return false;
performIPO(EnablePartition, ErrMsg);
if (!performPostIPO(ErrMsg))
Shuxin Yang
committed
return false;
Rafael Espindola
committed
*Name = PartitionMgr.getSinglePartition()->getObjFilePath().c_str();
Shuxin Yang
committed
return true;
Rafael Espindola
committed
}
Rafael Espindola
committed
const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
Rafael Espindola
committed
const char *name;
Shuxin Yang
committed
if (!compile_to_file(&name, errMsg))
Rafael Espindola
committed
return NULL;
// remove old buffer if compile() called twice
delete _nativeObjectFile;
// read .o file into memory buffer
OwningPtr<MemoryBuffer> BuffPtr;
Rafael Espindola
committed
if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) {
errMsg = ec.message();
_nativeObjectFile = 0;
} else {
if ((_nativeObjectFile = BuffPtr.take())) {
*length = _nativeObjectFile->getBufferSize();
BufStart = _nativeObjectFile->getBufferStart();
}
Rafael Espindola
committed
}
// 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 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();
Bill Wendling
committed
bool LTOCodeGenerator::determineTarget(std::string &errMsg) {
if (_target != NULL)
Shuxin Yang
committed
return true;
Bill Wendling
committed
// if options were requested, set them
Bill Wendling
committed
std::string TripleStr = _linker.getModule()->getTargetTriple();
if (TripleStr.empty())
TripleStr = sys::getDefaultTargetTriple();
llvm::Triple Triple(TripleStr);
// create target machine from info for merged modules
const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
if (march == NULL)
Shuxin Yang
committed
return false;
// The relocation model is actually a static member of TargetMachine and
// needs to be set before the TargetMachine is instantiated.
Reloc::Model RelocModel = Reloc::Default;
switch (_codeModel) {
case LTO_CODEGEN_PIC_MODEL_STATIC:
RelocModel = Reloc::Static;
break;
case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
RelocModel = Reloc::PIC_;
break;
case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
RelocModel = Reloc::DynamicNoPIC;
break;
// construct LTOModule, hand over ownership of module and target
SubtargetFeatures Features;
Features.getDefaultSubtargetFeatures(Triple);
std::string FeatureStr = Features.getString();
// Set a default CPU for Darwin triples.
if (_mCpu.empty() && Triple.isOSDarwin()) {
if (Triple.getArch() == llvm::Triple::x86_64)
_mCpu = "core2";
else if (Triple.getArch() == llvm::Triple::x86)
_mCpu = "yonah";
}
TargetOptions Options;
LTOModule::getTargetOptions(Options);
_target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options,
RelocModel, CodeModel::Default,
CodeGenOpt::Aggressive);
Shuxin Yang
committed
return true;
void LTOCodeGenerator::
applyRestriction(GlobalValue &GV,
std::vector<const char*> &mustPreserveList,
SmallPtrSet<GlobalValue*, 8> &asmUsed,
Mangler &mangler) {
Rafael Espindola
committed
SmallString<64> Buffer;
mangler.getNameWithPrefix(Buffer, &GV, false);
if (GV.isDeclaration())
return;
if (_mustPreserveSymbols.count(Buffer))
mustPreserveList.push_back(GV.getName().data());
if (_asmUndefinedRefs.count(Buffer))
asmUsed.insert(&GV);
}
static void findUsedValues(GlobalVariable *LLVMUsed,
SmallPtrSet<GlobalValue*, 8> &UsedValues) {
if (LLVMUsed == 0) return;
ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
Rafael Espindola
committed
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))
Rafael Espindola
committed
UsedValues.insert(GV);
}
void LTOCodeGenerator::applyScopeRestrictions() {
if (_scopeRestrictionsDone) return;
Module *mergedModule = _linker.getModule();
// Start off with a verification pass.
PassManager passes;
passes.add(createVerifierPass());
MCContext Context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL);
Mangler mangler(Context, _target);
Rafael Espindola
committed
std::vector<const char*> mustPreserveList;
SmallPtrSet<GlobalValue*, 8> asmUsed;
for (Module::iterator f = mergedModule->begin(),
e = mergedModule->end(); f != e; ++f)
applyRestriction(*f, mustPreserveList, asmUsed, mangler);
for (Module::global_iterator v = mergedModule->global_begin(),
Rafael Espindola
committed
e = mergedModule->global_end(); v != e; ++v)
applyRestriction(*v, mustPreserveList, asmUsed, mangler);
for (Module::alias_iterator a = mergedModule->alias_begin(),
e = mergedModule->alias_end(); a != e; ++a)
applyRestriction(*a, mustPreserveList, asmUsed, mangler);
GlobalVariable *LLVMCompilerUsed =
mergedModule->getGlobalVariable("llvm.compiler.used");
findUsedValues(LLVMCompilerUsed, asmUsed);
if (LLVMCompilerUsed)
LLVMCompilerUsed->eraseFromParent();
if (!asmUsed.empty()) {
llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context);
std::vector<Constant*> asmUsed2;
for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(),
e = asmUsed.end(); i !=e; ++i) {
GlobalValue *GV = *i;
Constant *c = ConstantExpr::getBitCast(GV, i8PTy);
asmUsed2.push_back(c);
}
llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size());
LLVMCompilerUsed =
new llvm::GlobalVariable(*mergedModule, ATy, false,
llvm::GlobalValue::AppendingLinkage,
llvm::ConstantArray::get(ATy, asmUsed2),
"llvm.compiler.used");
LLVMCompilerUsed->setSection("llvm.metadata");
Rafael Espindola
committed
Rafael Espindola
committed
// apply scope restrictions
passes.run(*mergedModule);
_scopeRestrictionsDone = true;
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
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) {
Shuxin Yang
committed
if (!this->determineTarget(errMsg))
return false;
Module* mergedModule = _linker.getModule();
Bill Wendling
committed
// Mark which symbols can not be internalized
Bill Wendling
committed
this->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);
Rafael Espindola
committed
// 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.
Bill Wendling
committed
if (!DisableOpt)
PassManagerBuilder().populateLTOPassManager(passes,
!DisableInline,
DisableGVNLoadPRE);
// Make sure everything is still good.
passes.add(createVerifierPass());
PassManager codeGenPasses;
codeGenPasses.add(new DataLayout(*_target->getDataLayout()));
_target->addAnalysisPasses(codeGenPasses);
// If the bitcode files contain ARC code and were compiled with optimization,
// the ObjCARCContractPass must be run, so do it unconditionally here.
codeGenPasses.add(createObjCARCContractPass());
if (_target->addPassesToEmitFile(codeGenPasses, Out,
errMsg = "target file type not supported";
Shuxin Yang
committed
return false;
// Run our queue of passes all at once now, efficiently.
passes.run(*mergedModule);
// Run the code generator, and write assembly file
codeGenPasses.run(*mergedModule);
Shuxin Yang
committed
return true;
/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging
/// LTO problems.
void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) {
for (std::pair<StringRef, StringRef> o = getToken(options);
!o.first.empty(); o = getToken(o.second)) {
// ParseCommandLineOptions() expects argv[0] to be program name. Lazily add
// that.
if (_codegenOptions.empty())
_codegenOptions.push_back(strdup("libLTO"));
_codegenOptions.push_back(strdup(o.first.str().c_str()));
}