diff options
Diffstat (limited to 'tools/lto/LTOModule.cpp')
| -rw-r--r-- | tools/lto/LTOModule.cpp | 356 |
1 files changed, 262 insertions, 94 deletions
diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 1eac22cfaf1c..8f2b1f48406d 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -26,11 +26,18 @@ #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/system_error.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" @@ -73,7 +80,7 @@ bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { LTOModule::LTOModule(Module *m, TargetMachine *t) - : _module(m), _target(t), _symbolsParsed(false) + : _module(m), _target(t) { } @@ -84,32 +91,33 @@ LTOModule *LTOModule::makeLTOModule(const char *path, errMsg = ec.message(); return NULL; } - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), errMsg); } LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - off_t size, + size_t size, + std::string &errMsg) { + return makeLTOModule(fd, path, size, size, 0, errMsg); +} + +LTOModule *LTOModule::makeLTOModule(int fd, const char *path, + size_t file_size, + size_t map_size, + off_t offset, std::string &errMsg) { OwningPtr<MemoryBuffer> buffer; - if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, size)) { + if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size, + map_size, offset, false)) { errMsg = ec.message(); return NULL; } - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), errMsg); } -/// makeBuffer - Create a MemoryBuffer from a memory range. MemoryBuffer -/// requires the byte past end of the buffer to be a zero. We might get lucky -/// and already be that way, otherwise make a copy. Also if next byte is on a -/// different page, don't assume it is readable. +/// makeBuffer - Create a MemoryBuffer from a memory range. MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { const char *startPtr = (char*)mem; - const char *endPtr = startPtr+length; - if (((uintptr_t)endPtr & (sys::Process::GetPageSize()-1)) == 0 || - *endPtr != 0) - return MemoryBuffer::getMemBufferCopy(StringRef(startPtr, length)); - - return MemoryBuffer::getMemBuffer(StringRef(startPtr, length)); + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); } @@ -118,17 +126,25 @@ LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); if (!buffer) return NULL; - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), errMsg); } LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, std::string &errMsg) { - InitializeAllTargets(); + static bool Initialized = false; + if (!Initialized) { + InitializeAllTargets(); + InitializeAllAsmParsers(); + Initialized = true; + } // parse bitcode buffer - OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); - if (!m) + OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(), + &errMsg)); + if (!m) { + delete buffer; return NULL; + } std::string Triple = m->getTargetTriple(); if (Triple.empty()) @@ -139,12 +155,18 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, if (!march) return NULL; - // construct LTModule, hand over ownership of module and target + // construct LTOModule, hand over ownership of module and target SubtargetFeatures Features; Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); std::string FeatureStr = Features.getString(); TargetMachine *target = march->createTargetMachine(Triple, FeatureStr); - return new LTOModule(m.take(), target); + LTOModule *Ret = new LTOModule(m.take(), target); + bool Err = Ret->ParseSymbols(); + if (Err) { + delete Ret; + return NULL; + } + return Ret; } @@ -159,16 +181,6 @@ void LTOModule::setTargetTriple(const char *triple) { void LTOModule::addDefinedFunctionSymbol(Function *f, Mangler &mangler) { // add to list of defined symbols addDefinedSymbol(f, mangler, true); - - // add external symbols referenced by this function. - for (Function::iterator b = f->begin(); b != f->end(); ++b) { - for (BasicBlock::iterator i = b->begin(); i != b->end(); ++i) { - for (unsigned count = 0, total = i->getNumOperands(); - count != total; ++count) { - findExternalRefs(i->getOperand(count), mangler); - } - } - } } // Get string that data pointer points to. @@ -309,12 +321,6 @@ void LTOModule::addDefinedDataSymbol(GlobalValue *v, Mangler &mangler) { } } } - - // add external symbols referenced by this data. - for (unsigned count = 0, total = v->getNumOperands(); - count != total; ++count) { - findExternalRefs(v->getOperand(count), mangler); - } } @@ -324,10 +330,6 @@ void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, if (def->getName().startswith("llvm.")) return; - // ignore available_externally - if (def->hasAvailableExternallyLinkage()) - return; - // string is owned by _defines SmallString<64> Buffer; mangler.getNameWithPrefix(Buffer, def, false); @@ -383,7 +385,8 @@ void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, _symbols.push_back(info); } -void LTOModule::addAsmGlobalSymbol(const char *name) { +void LTOModule::addAsmGlobalSymbol(const char *name, + lto_symbol_attributes scope) { StringSet::value_type &entry = _defines.GetOrCreateValue(name); // only add new define if not already defined @@ -393,13 +396,32 @@ void LTOModule::addAsmGlobalSymbol(const char *name) { entry.setValue(1); const char *symbolName = entry.getKey().data(); uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; + attr |= scope; NameAndAttributes info; info.name = symbolName; info.attributes = (lto_symbol_attributes)attr; _symbols.push_back(info); } +void LTOModule::addAsmGlobalSymbolUndef(const char *name) { + StringMap<NameAndAttributes>::value_type &entry = + _undefines.GetOrCreateValue(name); + + _asm_undefines.push_back(entry.getKey().data()); + + // we already have the symbol + if (entry.getValue().name) + return; + + uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + NameAndAttributes info; + info.name = entry.getKey().data(); + info.attributes = (lto_symbol_attributes)attr; + + entry.setValue(info); +} + void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, Mangler &mangler) { // ignore all llvm.* symbols @@ -432,41 +454,211 @@ void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, } +namespace { + class RecordStreamer : public MCStreamer { + public: + enum State { NeverSeen, Global, Defined, DefinedGlobal, Used}; -// Find external symbols referenced by VALUE. This is a recursive function. -void LTOModule::findExternalRefs(Value *value, Mangler &mangler) { - if (GlobalValue *gv = dyn_cast<GlobalValue>(value)) { - if (!gv->hasExternalLinkage()) - addPotentialUndefinedSymbol(gv, mangler); - // If this is a variable definition, do not recursively process - // initializer. It might contain a reference to this variable - // and cause an infinite loop. The initializer will be - // processed in addDefinedDataSymbol(). - return; - } + private: + StringMap<State> Symbols; + + void markDefined(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Global: + S = DefinedGlobal; + break; + case NeverSeen: + case Defined: + case Used: + S = Defined; + break; + } + } + void markGlobal(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + S = DefinedGlobal; + break; + + case NeverSeen: + case Global: + case Used: + S = Global; + break; + } + } + void markUsed(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + case Global: + break; - // GlobalValue, even with InternalLinkage type, may have operands with - // ExternalLinkage type. Do not ignore these operands. - if (Constant *c = dyn_cast<Constant>(value)) { - // Handle ConstantExpr, ConstantStruct, ConstantArry etc. - for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) - findExternalRefs(c->getOperand(i), mangler); + case NeverSeen: + case Used: + S = Used; + break; + } + } + + // FIXME: mostly copied for the obj streamer. + void AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: + // FIXME: What should we do in here? + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + markUsed(cast<MCSymbolRefExpr>(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); + break; + } + } + + public: + typedef StringMap<State>::const_iterator const_iterator; + + const_iterator begin() { + return Symbols.begin(); + } + + const_iterator end() { + return Symbols.end(); + } + + RecordStreamer(MCContext &Context) : MCStreamer(Context) {} + + virtual void ChangeSection(const MCSection *Section) {} + virtual void InitSections() {} + virtual void EmitLabel(MCSymbol *Symbol) { + Symbol->setSection(*getCurrentSection()); + markDefined(*Symbol); + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // FIXME: should we handle aliases? + markDefined(*Symbol); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + if (Attribute == MCSA_Global) + markGlobal(*Symbol); + } + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} + virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + unsigned Size , unsigned ByteAlignment) { + markDefined(*Symbol); + } + virtual void EmitCOFFSymbolType(int Type) {} + virtual void EndCOFFSymbolDef() {} + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + markDefined(*Symbol); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) {} + virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) {} + virtual void EmitULEB128Value(const MCExpr *Value) {} + virtual void EmitSLEB128Value(const MCExpr *Value) {} + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) {} + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) {} + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value ) {} + virtual void EmitFileDirective(StringRef Filename) {} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) {} + + virtual void EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + } + virtual void Finish() {} + }; +} + +bool LTOModule::addAsmGlobalSymbols(MCContext &Context) { + const std::string &inlineAsm = _module->getModuleInlineAsm(); + + OwningPtr<RecordStreamer> Streamer(new RecordStreamer(Context)); + MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); + SourceMgr SrcMgr; + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + OwningPtr<MCAsmParser> Parser(createMCAsmParser(_target->getTarget(), SrcMgr, + Context, *Streamer, + *_target->getMCAsmInfo())); + OwningPtr<TargetAsmParser> + TAP(_target->getTarget().createAsmParser(*Parser.get(), *_target.get())); + Parser->setTargetParser(*TAP); + int Res = Parser->Run(false); + if (Res) + return true; + + for (RecordStreamer::const_iterator i = Streamer->begin(), + e = Streamer->end(); i != e; ++i) { + StringRef Key = i->first(); + RecordStreamer::State Value = i->second; + if (Value == RecordStreamer::DefinedGlobal) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); + else if (Value == RecordStreamer::Defined) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); + else if (Value == RecordStreamer::Global || + Value == RecordStreamer::Used) + addAsmGlobalSymbolUndef(Key.data()); } + return false; } -void LTOModule::lazyParseSymbols() { - if (_symbolsParsed) - return; +static bool isDeclaration(const GlobalValue &V) { + if (V.hasAvailableExternallyLinkage()) + return true; + if (V.isMaterializable()) + return false; + return V.isDeclaration(); +} - _symbolsParsed = true; +static bool isAliasToDeclaration(const GlobalAlias &V) { + return isDeclaration(*V.getAliasedGlobal()); +} +bool LTOModule::ParseSymbols() { // Use mangler to add GlobalPrefix to names to match linker names. MCContext Context(*_target->getMCAsmInfo(), NULL); Mangler mangler(Context, *_target->getTargetData()); // add functions for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { - if (f->isDeclaration()) + if (isDeclaration(*f)) addPotentialUndefinedSymbol(f, mangler); else addDefinedFunctionSymbol(f, mangler); @@ -475,42 +667,20 @@ void LTOModule::lazyParseSymbols() { // add data for (Module::global_iterator v = _module->global_begin(), e = _module->global_end(); v != e; ++v) { - if (v->isDeclaration()) + if (isDeclaration(*v)) addPotentialUndefinedSymbol(v, mangler); else addDefinedDataSymbol(v, mangler); } // add asm globals - const std::string &inlineAsm = _module->getModuleInlineAsm(); - const std::string glbl = ".globl"; - std::string asmSymbolName; - std::string::size_type pos = inlineAsm.find(glbl, 0); - while (pos != std::string::npos) { - // eat .globl - pos = pos + 6; - - // skip white space between .globl and symbol name - std::string::size_type pbegin = inlineAsm.find_first_not_of(' ', pos); - if (pbegin == std::string::npos) - break; - - // find end-of-line - std::string::size_type pend = inlineAsm.find_first_of('\n', pbegin); - if (pend == std::string::npos) - break; - - asmSymbolName.assign(inlineAsm, pbegin, pend - pbegin); - addAsmGlobalSymbol(asmSymbolName.c_str()); - - // search next .globl - pos = inlineAsm.find(glbl, pend); - } + if (addAsmGlobalSymbols(Context)) + return true; // add aliases for (Module::alias_iterator i = _module->alias_begin(), e = _module->alias_end(); i != e; ++i) { - if (i->isDeclaration()) + if (isAliasToDeclaration(*i)) addPotentialUndefinedSymbol(i, mangler); else addDefinedDataSymbol(i, mangler); @@ -526,17 +696,16 @@ void LTOModule::lazyParseSymbols() { _symbols.push_back(info); } } + return false; } uint32_t LTOModule::getSymbolCount() { - lazyParseSymbols(); return _symbols.size(); } lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { - lazyParseSymbols(); if (index < _symbols.size()) return _symbols[index].attributes; else @@ -544,7 +713,6 @@ lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { } const char *LTOModule::getSymbolName(uint32_t index) { - lazyParseSymbols(); if (index < _symbols.size()) return _symbols[index].name; else |
