From: Rafael Espindola Date: Fri, 24 Oct 2014 18:13:04 +0000 (+0000) Subject: Don't ever call materializeAllPermanently during LTO. X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=68b02dcd543f7c962dd0c4293044ebb629ab7360 Don't ever call materializeAllPermanently during LTO. To do this, change the representation of lazy loaded functions. The previous representation cannot differentiate between a function whose body has been removed and one whose body hasn't been read from the .bc file. That means that in order to drop a function, the entire body had to be read. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220580 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index ad4b1395f0c..26d893b889e 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -143,6 +143,9 @@ public: /// arguments. bool isVarArg() const; + bool isMaterializable() const; + void setIsMaterializable(bool V); + /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an /// intrinsic, or if the pointer is null. This value is always defined to be diff --git a/include/llvm/IR/GVMaterializer.h b/include/llvm/IR/GVMaterializer.h index 4afdbb05f85..7cc48eb05d0 100644 --- a/include/llvm/IR/GVMaterializer.h +++ b/include/llvm/IR/GVMaterializer.h @@ -32,10 +32,6 @@ protected: public: virtual ~GVMaterializer(); - /// True if GV can be materialized from whatever backing store this - /// GVMaterializer uses and has not been materialized yet. - virtual bool isMaterializable(const GlobalValue *GV) const = 0; - /// True if GV has been materialized and can be dematerialized back to /// whatever backing store this GVMaterializer uses. virtual bool isDematerializable(const GlobalValue *GV) const = 0; diff --git a/include/llvm/IR/GlobalObject.h b/include/llvm/IR/GlobalObject.h index 2e042f48974..581fb966c02 100644 --- a/include/llvm/IR/GlobalObject.h +++ b/include/llvm/IR/GlobalObject.h @@ -35,12 +35,24 @@ protected: std::string Section; // Section to emit this into, empty means default Comdat *ObjComdat; + static const unsigned AlignmentBits = 5; + static const unsigned GlobalObjectSubClassDataBits = + GlobalValueSubClassDataBits - AlignmentBits; + +private: + static const unsigned AlignmentMask = (1 << AlignmentBits) - 1; + public: unsigned getAlignment() const { - return (1u << getGlobalValueSubClassData()) >> 1; + unsigned Data = getGlobalValueSubClassData(); + unsigned AlignmentData = Data & AlignmentMask; + return (1u << AlignmentData) >> 1; } void setAlignment(unsigned Align); + unsigned getGlobalObjectSubClassData() const; + void setGlobalObjectSubClassData(unsigned Val); + bool hasSection() const { return !StringRef(getSection()).empty(); } const char *getSection() const { return Section.c_str(); } void setSection(StringRef S); diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index d42d0a9c392..aaf86c33867 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -84,6 +84,7 @@ private: // (19 + 3 + 2 + 1 + 2 + 5) == 32. unsigned SubClassData : 19; protected: + static const unsigned GlobalValueSubClassDataBits = 19; unsigned getGlobalValueSubClassData() const { return SubClassData; } @@ -326,6 +327,13 @@ public: /// the current translation unit. bool isDeclaration() const; + bool isDeclarationForLinker() const { + if (hasAvailableExternallyLinkage()) + return true; + + return isDeclaration(); + } + /// This method unlinks 'this' from the containing module, but does not delete /// it. virtual void removeFromParent() = 0; diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 76ec1fd1ec8..6c744dd2759 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -469,9 +469,6 @@ public: /// Retrieves the GVMaterializer, if any, for this Module. GVMaterializer *getMaterializer() const { return Materializer.get(); } - /// True if the definition of GV has yet to be materializedfrom the - /// GVMaterializer. - bool isMaterializable(const GlobalValue *GV) const; /// Returns true if this GV was loaded from this Module's GVMaterializer and /// the GVMaterializer knows how to dematerialize the GV. bool isDematerializable(const GlobalValue *GV) const; diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index ca6d73c12ba..507164c8468 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2070,6 +2070,7 @@ std::error_code BitcodeReader::ParseModule(bool Resume) { // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. if (!isProto) { + Func->setIsMaterializable(true); FunctionsWithBodies.push_back(Func); if (LazyStreamer) DeferredFunctionInfo[Func] = 0; @@ -3281,14 +3282,6 @@ std::error_code BitcodeReader::FindFunctionInStream( void BitcodeReader::releaseBuffer() { Buffer.release(); } -bool BitcodeReader::isMaterializable(const GlobalValue *GV) const { - if (const Function *F = dyn_cast(GV)) { - return F->isDeclaration() && - DeferredFunctionInfo.count(const_cast(F)); - } - return false; -} - std::error_code BitcodeReader::Materialize(GlobalValue *GV) { Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. @@ -3308,6 +3301,7 @@ std::error_code BitcodeReader::Materialize(GlobalValue *GV) { if (std::error_code EC = ParseFunctionBody(F)) return EC; + F->setIsMaterializable(false); // Upgrade any old intrinsic calls in the function. for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(), @@ -3349,6 +3343,7 @@ void BitcodeReader::Dematerialize(GlobalValue *GV) { // Just forget the function body, we can remat it later. F->dropAllReferences(); + F->setIsMaterializable(true); } std::error_code BitcodeReader::MaterializeModule(Module *M) { diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index c9525661ec1..9f0f6686121 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -223,7 +223,6 @@ public: void releaseBuffer(); - bool isMaterializable(const GlobalValue *GV) const override; bool isDematerializable(const GlobalValue *GV) const override; std::error_code Materialize(GlobalValue *GV) override; std::error_code MaterializeModule(Module *M) override; diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index 2323c7459fc..8a69e39ee32 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -213,6 +213,12 @@ void Argument::removeAttr(AttributeSet AS) { // Helper Methods in Function //===----------------------------------------------------------------------===// +bool Function::isMaterializable() const { + return getGlobalObjectSubClassData(); +} + +void Function::setIsMaterializable(bool V) { setGlobalObjectSubClassData(V); } + LLVMContext &Function::getContext() const { return getType()->getContext(); } @@ -247,6 +253,7 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name, Linkage, name) { assert(FunctionType::isValidReturnType(getReturnType()) && "invalid return type"); + setIsMaterializable(false); SymTab = new ValueSymbolTable(); // If the function has arguments, mark them as lazily built. @@ -318,6 +325,8 @@ void Function::setParent(Module *parent) { // delete. // void Function::dropAllReferences() { + setIsMaterializable(false); + for (iterator I = begin(), E = end(); I != E; ++I) I->dropAllReferences(); diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp index 244e3e4baee..64bc61c5008 100644 --- a/lib/IR/Globals.cpp +++ b/lib/IR/Globals.cpp @@ -29,7 +29,9 @@ using namespace llvm; //===----------------------------------------------------------------------===// bool GlobalValue::isMaterializable() const { - return getParent() && getParent()->isMaterializable(this); + if (const Function *F = dyn_cast(this)) + return F->isMaterializable(); + return false; } bool GlobalValue::isDematerializable() const { return getParent() && getParent()->isDematerializable(this); @@ -77,10 +79,24 @@ void GlobalObject::setAlignment(unsigned Align) { assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); assert(Align <= MaximumAlignment && "Alignment is greater than MaximumAlignment!"); - setGlobalValueSubClassData(Log2_32(Align) + 1); + unsigned AlignmentData = Log2_32(Align) + 1; + unsigned OldData = getGlobalValueSubClassData(); + setGlobalValueSubClassData((OldData & ~AlignmentMask) | AlignmentData); assert(getAlignment() == Align && "Alignment representation error!"); } +unsigned GlobalObject::getGlobalObjectSubClassData() const { + unsigned ValueData = getGlobalValueSubClassData(); + return ValueData >> AlignmentBits; +} + +void GlobalObject::setGlobalObjectSubClassData(unsigned Val) { + unsigned OldData = getGlobalValueSubClassData(); + setGlobalValueSubClassData((OldData & AlignmentMask) | + (Val << AlignmentBits)); + assert(getGlobalObjectSubClassData() == Val && "representation error"); +} + void GlobalObject::copyAttributesFrom(const GlobalValue *Src) { const auto *GV = cast(Src); GlobalValue::copyAttributesFrom(GV); @@ -117,7 +133,7 @@ bool GlobalValue::isDeclaration() const { // Functions are definitions if they have a body. if (const Function *F = dyn_cast(this)) - return F->empty(); + return F->empty() && !F->isMaterializable(); // Aliases are always definitions. assert(isa(this)); diff --git a/lib/IR/Module.cpp b/lib/IR/Module.cpp index 7f673d07e92..f43080b72ee 100644 --- a/lib/IR/Module.cpp +++ b/lib/IR/Module.cpp @@ -389,12 +389,6 @@ void Module::setMaterializer(GVMaterializer *GVM) { Materializer.reset(GVM); } -bool Module::isMaterializable(const GlobalValue *GV) const { - if (Materializer) - return Materializer->isMaterializable(GV); - return false; -} - bool Module::isDematerializable(const GlobalValue *GV) const { if (Materializer) return Materializer->isDematerializable(GV); diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 3060baa52e2..b7c2ee24111 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -2632,7 +2632,7 @@ bool llvm::verifyModule(const Module &M, raw_ostream *OS) { bool Broken = false; for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (!I->isDeclaration()) + if (!I->isDeclaration() && !I->isMaterializable()) Broken |= !V.verify(*I); // Note that this function's return value is inverted from what you would diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 0313e2b8a7e..510813ad972 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -672,21 +672,10 @@ bool ModuleLinker::getComdatResult(const Comdat *SrcC, LinkFromSrc); } -// FIXME: Duplicated from the gold plugin. This should be refactored somewhere. -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - bool ModuleLinker::shouldLinkFromSource(const GlobalValue &Dest, const GlobalValue &Src) { - bool SrcIsDeclaration = isDeclaration(Src); - bool DestIsDeclaration = isDeclaration(Dest); + bool SrcIsDeclaration = Src.isDeclarationForLinker(); + bool DestIsDeclaration = Dest.isDeclarationForLinker(); // FIXME: Make datalayout mandatory and just use getDataLayout(). DataLayout DL(Dest.getParent()); @@ -1635,14 +1624,16 @@ bool ModuleLinker::run() { SF->getPrefixData(), ValueMap, RF_None, &TypeMap, &ValMaterializer)); } - // Skip if no body (function is external) or materialize. - if (SF->isDeclaration()) { - if (!SF->isMaterializable()) - continue; + // Materialize if needed. + if (SF->isMaterializable()) { if (SF->Materialize(&ErrorMsg)) return true; } + // Skip if no body (function is external). + if (SF->isDeclaration()) + continue; + linkFunctionBody(DF, SF); SF->Dematerialize(); } @@ -1684,14 +1675,16 @@ bool ModuleLinker::run() { &ValMaterializer)); } - // Materialize if necessary. - if (SF->isDeclaration()) { - if (!SF->isMaterializable()) - continue; + // Materialize if needed. + if (SF->isMaterializable()) { if (SF->Materialize(&ErrorMsg)) return true; } + // Skip if no body (function is external). + if (SF->isDeclaration()) + continue; + // Erase from vector *before* the function body is linked - linkFunctionBody could // invalidate I. LazilyLinkFunctions.erase(I); diff --git a/lib/Object/IRObjectFile.cpp b/lib/Object/IRObjectFile.cpp index f3bea51be97..7256a2fc007 100644 --- a/lib/Object/IRObjectFile.cpp +++ b/lib/Object/IRObjectFile.cpp @@ -204,16 +204,6 @@ std::error_code IRObjectFile::printSymbolName(raw_ostream &OS, return object_error::success; } -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - uint32_t IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { const GlobalValue *GV = getGV(Symb); @@ -224,7 +214,7 @@ uint32_t IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { } uint32_t Res = BasicSymbolRef::SF_None; - if (isDeclaration(*GV)) + if (GV->isDeclarationForLinker()) Res |= BasicSymbolRef::SF_Undefined; if (GV->hasPrivateLinkage()) Res |= BasicSymbolRef::SF_FormatSpecific; diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index f65cdf2f0d1..8ebae0e498c 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -418,18 +418,8 @@ static void keepGlobalValue(GlobalValue &GV, assert(!GV.isDiscardableIfUnused()); } -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - static void internalize(GlobalValue &GV) { - if (isDeclaration(GV)) + if (GV.isDeclarationForLinker()) return; // We get here if there is a matching asm definition. if (!GV.hasLocalLinkage()) GV.setLinkage(GlobalValue::InternalLinkage); @@ -492,6 +482,9 @@ static GlobalObject *makeInternalReplacement(GlobalObject *GO) { Module *M = GO->getParent(); GlobalObject *Ret; if (auto *F = dyn_cast(GO)) { + if (F->isMaterializable()) + F->Materialize(); + auto *NewF = Function::Create(F->getFunctionType(), F->getLinkage(), F->getName(), M); @@ -620,7 +613,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: case LDPR_UNDEF: - assert(isDeclaration(*GV)); + assert(GV->isDeclarationForLinker()); break; case LDPR_PREVAILING_DEF_IRONLY: { @@ -667,12 +660,6 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, Sym.comdat_key = nullptr; } - if (!Drop.empty()) - // This is horrible. Given how lazy loading is implemented, dropping - // the body while there is a materializer present doesn't work, the - // linker will just read the body back. - M->materializeAllPermanently(); - ValueToValueMapTy VM; LocalValueMaterializer Materializer(Drop); for (GlobalAlias *GA : KeptAliases) {