X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Flto%2FLTOModule.cpp;h=c28c972c484226cb884caaa34944eb03b6bb739a;hb=672b93a3324cc1da6d374eed4c75c050a9cad7be;hp=c4980d6bf79bee615978cc390921ae007875ba9f;hpb=1ca29d318a6632c115b9f62c791077b575494e42;p=oota-llvm.git diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index c4980d6bf79..c28c972c484 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -1,13 +1,13 @@ -//===-LTOModule.cpp - LLVM Link Time Optimizer ----------------------------===// +//===-- LTOModule.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 +// This file implements the Link Time Optimization library. This library is // intended to be used by linker to optimize code at link time. // //===----------------------------------------------------------------------===// @@ -17,529 +17,712 @@ #include "llvm/Constants.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" -#include "llvm/ModuleProvider.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/SystemUtils.h" -#include "llvm/Support/Mangler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/Path.h" -#include "llvm/System/Process.h" -#include "llvm/Target/SubtargetFeature.h" +#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/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/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetMachineRegistry.h" -#include "llvm/Target/TargetAsmInfo.h" - -#include +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" using namespace llvm; -bool LTOModule::isBitcodeFile(const void* mem, size_t length) -{ - return ( llvm::sys::IdentifyFileType((char*)mem, length) - == llvm::sys::Bitcode_FileType ); +bool LTOModule::isBitcodeFile(const void *mem, size_t length) { + return llvm::sys::IdentifyFileType((char*)mem, length) + == llvm::sys::Bitcode_FileType; } -bool LTOModule::isBitcodeFile(const char* path) -{ - return llvm::sys::Path(path).isBitcodeFile(); +bool LTOModule::isBitcodeFile(const char *path) { + return llvm::sys::Path(path).isBitcodeFile(); } -bool LTOModule::isBitcodeFileForTarget(const void* mem, size_t length, - const char* triplePrefix) -{ - MemoryBuffer* buffer = makeBuffer(mem, length); - if ( buffer == NULL ) - return false; - return isTargetMatch(buffer, triplePrefix); +bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, + const char *triplePrefix) { + MemoryBuffer *buffer = makeBuffer(mem, length); + if (!buffer) + return false; + return isTargetMatch(buffer, triplePrefix); } -bool LTOModule::isBitcodeFileForTarget(const char* path, - const char* triplePrefix) -{ - MemoryBuffer *buffer = MemoryBuffer::getFile(path); - if (buffer == NULL) - return false; - return isTargetMatch(buffer, triplePrefix); +bool LTOModule::isBitcodeFileForTarget(const char *path, + const char *triplePrefix) { + OwningPtr buffer; + if (MemoryBuffer::getFile(path, buffer)) + return false; + return isTargetMatch(buffer.take(), triplePrefix); } -// takes ownership of buffer -bool LTOModule::isTargetMatch(MemoryBuffer* buffer, const char* triplePrefix) -{ - OwningPtr mp(getBitcodeModuleProvider(buffer, - getGlobalContext())); - // on success, mp owns buffer and both are deleted at end of this method - if ( !mp ) { - delete buffer; - return false; - } - std::string actualTarget = mp->getModule()->getTargetTriple(); - return ( strncmp(actualTarget.c_str(), triplePrefix, - strlen(triplePrefix)) == 0); +// Takes ownership of buffer. +bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { + std::string Triple = getBitcodeTargetTriple(buffer, getGlobalContext()); + delete buffer; + return (strncmp(Triple.c_str(), triplePrefix, + strlen(triplePrefix)) == 0); } -LTOModule::LTOModule(Module* m, TargetMachine* t) - : _module(m), _target(t), _symbolsParsed(false) +LTOModule::LTOModule(Module *m, TargetMachine *t) + : _module(m), _target(t) { } -LTOModule* LTOModule::makeLTOModule(const char* path, - std::string& errMsg) -{ - OwningPtr buffer(MemoryBuffer::getFile(path, &errMsg)); - if ( !buffer ) - return NULL; - return makeLTOModule(buffer.get(), errMsg); +LTOModule *LTOModule::makeLTOModule(const char *path, + std::string &errMsg) { + OwningPtr buffer; + if (error_code ec = MemoryBuffer::getFile(path, buffer)) { + errMsg = ec.message(); + return NULL; + } + 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. -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(startPtr, endPtr); - else - return MemoryBuffer::getMemBuffer(startPtr, endPtr); +LTOModule *LTOModule::makeLTOModule(int fd, const char *path, + 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 buffer; + if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size, + map_size, offset, false)) { + errMsg = ec.message(); + return NULL; + } + return makeLTOModule(buffer.take(), errMsg); +} -LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, - std::string& errMsg) -{ - OwningPtr buffer(makeBuffer(mem, length)); - if ( !buffer ) - return NULL; - return makeLTOModule(buffer.get(), errMsg); -} - -/// 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. See . -std::string getFeatureString(const char *TargetTriple) { - SubtargetFeatures Features; +/// makeBuffer - Create a MemoryBuffer from a memory range. +MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { + const char *startPtr = (char*)mem; + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); +} - 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(); +LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, + std::string &errMsg) { + OwningPtr buffer(makeBuffer(mem, length)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.take(), errMsg); } -LTOModule* LTOModule::makeLTOModule(MemoryBuffer* buffer, - std::string& errMsg) -{ - // parse bitcode buffer - OwningPtr m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); - if ( !m ) - return NULL; - // find machine architecture for this module - const TargetMachineRegistry::entry* march = - TargetMachineRegistry::getClosestStaticTargetForModule(*m, errMsg); +LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, + std::string &errMsg) { + static bool Initialized = false; + if (!Initialized) { + InitializeAllTargets(); + InitializeAllMCSubtargetInfos(); + InitializeAllAsmParsers(); + Initialized = true; + } - if ( march == NULL ) - return NULL; + // parse bitcode buffer + OwningPtr m(getLazyBitcodeModule(buffer, getGlobalContext(), + &errMsg)); + if (!m) { + delete buffer; + return NULL; + } + + std::string Triple = m->getTargetTriple(); + if (Triple.empty()) + Triple = sys::getHostTriple(); - // construct LTModule, hand over ownership of module and target - std::string FeatureStr = getFeatureString(m->getTargetTriple().c_str()); - TargetMachine* target = march->CtorFn(*m, FeatureStr); - return new LTOModule(m.take(), target); + // find machine architecture for this module + const Target *march = TargetRegistry::lookupTarget(Triple, errMsg); + if (!march) + return NULL; + + // construct LTOModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures(llvm::Triple(Triple)); + std::string FeatureStr = Features.getString(); + std::string CPU; + TargetMachine *target = march->createTargetMachine(Triple, CPU, FeatureStr); + LTOModule *Ret = new LTOModule(m.take(), target); + bool Err = Ret->ParseSymbols(); + if (Err) { + delete Ret; + return NULL; + } + return Ret; } -const char* LTOModule::getTargetTriple() -{ - return _module->getTargetTriple().c_str(); +const char *LTOModule::getTargetTriple() { + return _module->getTargetTriple().c_str(); } -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); - } - } - } +void LTOModule::setTargetTriple(const char *triple) { + _module->setTargetTriple(triple); } -// get string that data pointer points to -bool LTOModule::objcClassNameFromExpression(Constant* c, std::string& name) -{ - if (ConstantExpr* ce = dyn_cast(c)) { - Constant* op = ce->getOperand(0); - if (GlobalVariable* gvn = dyn_cast(op)) { - Constant* cn = gvn->getInitializer(); - if (ConstantArray* ca = dyn_cast(cn)) { - if ( ca->isCString() ) { - name = ".objc_class_name_" + ca->getAsString(); - return true; - } - } - } - } - return false; +void LTOModule::addDefinedFunctionSymbol(Function *f, Mangler &mangler) { + // add to list of defined symbols + addDefinedSymbol(f, mangler, true); } -// parse i386/ppc ObjC class data structure -void LTOModule::addObjCClass(GlobalVariable* clgv) -{ - if (ConstantStruct* c = dyn_cast(clgv->getInitializer())) { - // second slot in __OBJC,__class is pointer to superclass name - std::string superclassName; - if ( objcClassNameFromExpression(c->getOperand(1), superclassName) ) { - NameAndAttributes info; - if ( _undefines.find(superclassName.c_str()) == _undefines.end() ) { - const char* symbolName = ::strdup(superclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } +// Get string that data pointer points to. +bool LTOModule::objcClassNameFromExpression(Constant *c, std::string &name) { + if (ConstantExpr *ce = dyn_cast(c)) { + Constant *op = ce->getOperand(0); + if (GlobalVariable *gvn = dyn_cast(op)) { + Constant *cn = gvn->getInitializer(); + if (ConstantArray *ca = dyn_cast(cn)) { + if (ca->isCString()) { + name = ".objc_class_name_" + ca->getAsCString(); + return true; } - // third slot in __OBJC,__class is pointer to class name - std::string className; - if ( objcClassNameFromExpression(c->getOperand(2), className) ) { - const char* symbolName = ::strdup(className.c_str()); - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes) - (LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | - LTO_SYMBOL_SCOPE_DEFAULT); - _symbols.push_back(info); - _defines[info.name] = 1; - } + } } + } + return false; } - -// parse i386/ppc ObjC category data structure -void LTOModule::addObjCCategory(GlobalVariable* clgv) -{ - if (ConstantStruct* c = dyn_cast(clgv->getInitializer())) { - // second slot in __OBJC,__category is pointer to target class name - std::string targetclassName; - if ( objcClassNameFromExpression(c->getOperand(1), targetclassName) ) { - NameAndAttributes info; - if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ){ - const char* symbolName = ::strdup(targetclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } - } +// Parse i386/ppc ObjC class data structure. +void LTOModule::addObjCClass(GlobalVariable *clgv) { + if (ConstantStruct *c = dyn_cast(clgv->getInitializer())) { + // second slot in __OBJC,__class is pointer to superclass name + std::string superclassName; + if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { + NameAndAttributes info; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(superclassName); + if (!entry.getValue().name) { + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + entry.setValue(info); + } + } + // third slot in __OBJC,__class is pointer to class name + std::string className; + if (objcClassNameFromExpression(c->getOperand(2), className)) { + StringSet::value_type &entry = + _defines.GetOrCreateValue(className); + entry.setValue(1); + NameAndAttributes info; + info.name = entry.getKey().data(); + info.attributes = (lto_symbol_attributes) + (LTO_SYMBOL_PERMISSIONS_DATA | + LTO_SYMBOL_DEFINITION_REGULAR | + LTO_SYMBOL_SCOPE_DEFAULT); + _symbols.push_back(info); } + } } -// parse i386/ppc ObjC class list data structure -void LTOModule::addObjCClassRef(GlobalVariable* clgv) -{ +// Parse i386/ppc ObjC category data structure. +void LTOModule::addObjCCategory(GlobalVariable *clgv) { + if (ConstantStruct *c = dyn_cast(clgv->getInitializer())) { + // second slot in __OBJC,__category is pointer to target class name std::string targetclassName; - if ( objcClassNameFromExpression(clgv->getInitializer(), targetclassName) ){ - NameAndAttributes info; - if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ) { - const char* symbolName = ::strdup(targetclassName.c_str()); - info.name = ::strdup(symbolName); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - // string is owned by _undefines - _undefines[info.name] = info; - } - } -} + if (objcClassNameFromExpression(c->getOperand(1), targetclassName)) { + NameAndAttributes info; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(targetclassName); -void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler) -{ - // add to list of defined symbols - addDefinedSymbol(v, mangler, false); - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - if ( v->hasSection() /* && isTargetDarwin */ ) { - // special case if this data blob is an ObjC class definition - if ( v->getSection().compare(0, 15, "__OBJC,__class,") == 0 ) { - if (GlobalVariable* gv = dyn_cast(v)) { - addObjCClass(gv); - } - } - - // special case if this data blob is an ObjC category definition - else if ( v->getSection().compare(0, 18, "__OBJC,__category,") == 0 ) { - if (GlobalVariable* gv = dyn_cast(v)) { - addObjCCategory(gv); - } - } - - // special case if this data blob is the list of referenced classes - else if ( v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0 ) { - if (GlobalVariable* gv = dyn_cast(v)) { - addObjCClassRef(gv); - } - } - } + if (entry.getValue().name) + return; - // add external symbols referenced by this data. - for (unsigned count = 0, total = v->getNumOperands(); - count != total; ++count) { - findExternalRefs(v->getOperand(count), mangler); + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + entry.setValue(info); } + } } -void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, - bool isFunction) -{ - // ignore all llvm.* symbols - if ( strncmp(def->getNameStart(), "llvm.", 5) == 0 ) - return; +// Parse i386/ppc ObjC class list data structure. +void LTOModule::addObjCClassRef(GlobalVariable *clgv) { + std::string targetclassName; + if (objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) { + NameAndAttributes info; - // string is owned by _defines - const char* symbolName = ::strdup(mangler.getValueName(def).c_str()); - - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; - - // set permissions part - if ( isFunction ) - attr |= LTO_SYMBOL_PERMISSIONS_CODE; - else { - GlobalVariable* gv = dyn_cast(def); - if ( (gv != NULL) && gv->isConstant() ) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; - else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; - } - - // set definition part - if ( def->hasWeakLinkage() || def->hasLinkOnceLinkage() ) { - attr |= LTO_SYMBOL_DEFINITION_WEAK; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(targetclassName); + if (entry.getValue().name) + return; + + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + entry.setValue(info); + } +} + + +void LTOModule::addDefinedDataSymbol(GlobalValue *v, Mangler &mangler) { + // Add to list of defined symbols. + addDefinedSymbol(v, mangler, false); + + // Special case i386/ppc ObjC data structures in magic sections: + // The issue is that the old ObjC object format did some strange + // contortions to avoid real linker symbols. For instance, the + // ObjC class data structure is allocated statically in the executable + // that defines that class. That data structures contains a pointer to + // its superclass. But instead of just initializing that part of the + // struct to the address of its superclass, and letting the static and + // dynamic linkers do the rest, the runtime works by having that field + // instead point to a C-string that is the name of the superclass. + // At runtime the objc initialization updates that pointer and sets + // it to point to the actual super class. As far as the linker + // knows it is just a pointer to a string. But then someone wanted the + // linker to issue errors at build time if the superclass was not found. + // So they figured out a way in mach-o object format to use an absolute + // symbols (.objc_class_name_Foo = 0) and a floating reference + // (.reference .objc_class_name_Bar) to cause the linker into erroring when + // a class was missing. + // The following synthesizes the implicit .objc_* symbols for the linker + // from the ObjC data structures generated by the front end. + if (v->hasSection() /* && isTargetDarwin */) { + // special case if this data blob is an ObjC class definition + if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { + if (GlobalVariable *gv = dyn_cast(v)) { + addObjCClass(gv); + } } - else if ( def->hasCommonLinkage()) { - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; + + // special case if this data blob is an ObjC category definition + else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { + if (GlobalVariable *gv = dyn_cast(v)) { + addObjCCategory(gv); + } } - else { - attr |= LTO_SYMBOL_DEFINITION_REGULAR; + + // special case if this data blob is the list of referenced classes + else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { + if (GlobalVariable *gv = dyn_cast(v)) { + addObjCClassRef(gv); + } } - - // set scope part - if ( def->hasHiddenVisibility() ) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if ( def->hasProtectedVisibility() ) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if ( def->hasExternalLinkage() || def->hasWeakLinkage() - || def->hasLinkOnceLinkage() || def->hasCommonLinkage() ) - attr |= LTO_SYMBOL_SCOPE_DEFAULT; + } +} + + +void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, + bool isFunction) { + // ignore all llvm.* symbols + if (def->getName().startswith("llvm.")) + return; + + // string is owned by _defines + SmallString<64> Buffer; + mangler.getNameWithPrefix(Buffer, def, false); + + // set alignment part log2() can have rounding errors + uint32_t align = def->getAlignment(); + uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; + + // set permissions part + if (isFunction) + attr |= LTO_SYMBOL_PERMISSIONS_CODE; + else { + GlobalVariable *gv = dyn_cast(def); + if (gv && gv->isConstant()) + attr |= LTO_SYMBOL_PERMISSIONS_RODATA; else - attr |= LTO_SYMBOL_SCOPE_INTERNAL; + attr |= LTO_SYMBOL_PERMISSIONS_DATA; + } - // add to table of symbols - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes)attr; - _symbols.push_back(info); - _defines[info.name] = 1; + // set definition part + if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || + def->hasLinkerPrivateWeakLinkage() || + def->hasLinkerPrivateWeakDefAutoLinkage()) + attr |= LTO_SYMBOL_DEFINITION_WEAK; + else if (def->hasCommonLinkage()) + attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; + else + attr |= LTO_SYMBOL_DEFINITION_REGULAR; + + // set scope part + if (def->hasHiddenVisibility()) + attr |= LTO_SYMBOL_SCOPE_HIDDEN; + else if (def->hasProtectedVisibility()) + attr |= LTO_SYMBOL_SCOPE_PROTECTED; + else if (def->hasExternalLinkage() || def->hasWeakLinkage() || + def->hasLinkOnceLinkage() || def->hasCommonLinkage() || + def->hasLinkerPrivateWeakLinkage()) + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + else if (def->hasLinkerPrivateWeakDefAutoLinkage()) + attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; + else + attr |= LTO_SYMBOL_SCOPE_INTERNAL; + + // add to table of symbols + NameAndAttributes info; + StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); + entry.setValue(1); + + StringRef Name = entry.getKey(); + info.name = Name.data(); + assert(info.name[Name.size()] == '\0'); + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); } -void LTOModule::addAsmGlobalSymbol(const char *name) { - // only add new define if not already defined - if ( _defines.count(name, &name[strlen(name)+1]) == 0 ) - return; - - // string is owned by _defines - const char *symbolName = ::strdup(name); - uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes info; - info.name = symbolName; - info.attributes = (lto_symbol_attributes)attr; - _symbols.push_back(info); - _defines[info.name] = 1; +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 + if (entry.getValue()) + return; + + entry.setValue(1); + const char *symbolName = entry.getKey().data(); + uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; + attr |= scope; + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); } -void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) -{ - // ignore all llvm.* symbols - if ( strncmp(decl->getNameStart(), "llvm.", 5) == 0 ) - return; +void LTOModule::addAsmGlobalSymbolUndef(const char *name) { + StringMap::value_type &entry = + _undefines.GetOrCreateValue(name); - // ignore all aliases - if (isa(decl)) - return; + _asm_undefines.push_back(entry.getKey().data()); - const char* name = mangler.getValueName(decl).c_str(); + // we already have the symbol + if (entry.getValue().name) + return; - // we already have the symbol - if (_undefines.find(name) != _undefines.end()) - 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; - NameAndAttributes info; - // string is owned by _undefines - info.name = ::strdup(name); - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; - else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - _undefines[name] = info; + entry.setValue(info); } +void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, + Mangler &mangler) { + // ignore all llvm.* symbols + if (decl->getName().startswith("llvm.")) + return; + // ignore all aliases + if (isa(decl)) + return; -// Find exeternal symbols referenced by VALUE. This is a recursive function. -void LTOModule::findExternalRefs(Value* value, Mangler &mangler) { + SmallString<64> name; + mangler.getNameWithPrefix(name, decl, false); - if (GlobalValue* gv = dyn_cast(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; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(name); + + // we already have the symbol + if (entry.getValue().name) + return; + + NameAndAttributes info; + + info.name = entry.getKey().data(); + if (decl->hasExternalWeakLinkage()) + info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; + else + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + + entry.setValue(info); +} + + +namespace { + class RecordStreamer : public MCStreamer { + public: + enum State { NeverSeen, Global, Defined, DefinedGlobal, Used}; + + private: + StringMap 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; + } } - - // GlobalValue, even with InternalLinkage type, may have operands with - // ExternalLinkage type. Do not ignore these operands. - if (Constant* c = dyn_cast(value)) { - // Handle ConstantExpr, ConstantStruct, ConstantArry etc.. - for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) - findExternalRefs(c->getOperand(i), mangler); + 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; + + case NeverSeen: + case Used: + S = Used; + break; + } } -} -void LTOModule::lazyParseSymbols() -{ - if ( !_symbolsParsed ) { - _symbolsParsed = true; - - // Use mangler to add GlobalPrefix to names to match linker names. - Mangler mangler(*_module, _target->getTargetAsmInfo()->getGlobalPrefix()); - // add chars used in ObjC method names so method names aren't mangled - mangler.markCharAcceptable('['); - mangler.markCharAcceptable(']'); - mangler.markCharAcceptable('('); - mangler.markCharAcceptable(')'); - mangler.markCharAcceptable('-'); - mangler.markCharAcceptable('+'); - mangler.markCharAcceptable(' '); - - // add functions - for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { - if ( f->isDeclaration() ) - addPotentialUndefinedSymbol(f, mangler); - else - addDefinedFunctionSymbol(f, mangler); - } - - // add data - for (Module::global_iterator v = _module->global_begin(), - e = _module->global_end(); v != e; ++v) { - if ( v->isDeclaration() ) - addPotentialUndefinedSymbol(v, mangler); - else - addDefinedDataSymbol(v, mangler); - } + // 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(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + markUsed(cast(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast(Value)->getSubExpr()); + break; + } + } - // 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); - } + public: + typedef StringMap::const_iterator const_iterator; - // make symbols for all undefines - for (StringMap::iterator it=_undefines.begin(); - it != _undefines.end(); ++it) { - // if this symbol also has a definition, then don't make an undefine - // because it is a tentative definition - if ( _defines.count(it->getKeyData(), it->getKeyData()+ - it->getKeyLength()) == 0 ) { - NameAndAttributes info = it->getValue(); - _symbols.push_back(info); - } - } - } + 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, + unsigned PointerSize) {} + + 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 Streamer(new RecordStreamer(Context)); + MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); + SourceMgr SrcMgr; + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + OwningPtr Parser(createMCAsmParser(_target->getTarget(), SrcMgr, + Context, *Streamer, + *_target->getMCAsmInfo())); + OwningPtr STI(_target->getTarget(). + createMCSubtargetInfo(_target->getTargetTriple(), + _target->getTargetCPU(), + _target->getTargetFeatureString())); + OwningPtr + TAP(_target->getTarget().createAsmParser(*STI, *Parser.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; +} -uint32_t LTOModule::getSymbolCount() -{ - lazyParseSymbols(); - return _symbols.size(); +static bool isDeclaration(const GlobalValue &V) { + if (V.hasAvailableExternallyLinkage()) + return true; + if (V.isMaterializable()) + return false; + return V.isDeclaration(); +} + +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()); -lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) -{ - lazyParseSymbols(); - if ( index < _symbols.size() ) - return _symbols[index].attributes; + // add functions + for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { + if (isDeclaration(*f)) + addPotentialUndefinedSymbol(f, mangler); else - return lto_symbol_attributes(0); -} + addDefinedFunctionSymbol(f, mangler); + } -const char* LTOModule::getSymbolName(uint32_t index) -{ - lazyParseSymbols(); - if ( index < _symbols.size() ) - return _symbols[index].name; + // add data + for (Module::global_iterator v = _module->global_begin(), + e = _module->global_end(); v != e; ++v) { + if (isDeclaration(*v)) + addPotentialUndefinedSymbol(v, mangler); + else + addDefinedDataSymbol(v, mangler); + } + + // add asm globals + if (addAsmGlobalSymbols(Context)) + return true; + + // add aliases + for (Module::alias_iterator i = _module->alias_begin(), + e = _module->alias_end(); i != e; ++i) { + if (isAliasToDeclaration(*i)) + addPotentialUndefinedSymbol(i, mangler); else - return NULL; + addDefinedDataSymbol(i, mangler); + } + + // make symbols for all undefines + for (StringMap::iterator it=_undefines.begin(); + it != _undefines.end(); ++it) { + // if this symbol also has a definition, then don't make an undefine + // because it is a tentative definition + if (_defines.count(it->getKey()) == 0) { + NameAndAttributes info = it->getValue(); + _symbols.push_back(info); + } + } + return false; +} + + +uint32_t LTOModule::getSymbolCount() { + return _symbols.size(); +} + + +lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { + if (index < _symbols.size()) + return _symbols[index].attributes; + else + return lto_symbol_attributes(0); +} + +const char *LTOModule::getSymbolName(uint32_t index) { + if (index < _symbols.size()) + return _symbols[index].name; + else + return NULL; }