diff options
author | Chris Lattner <sabre@nondot.org> | 2009-03-21 09:44:56 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-03-21 09:44:56 +0000 |
commit | 67b00520c8f5b48fad722b790d87fea6be764efe (patch) | |
tree | 6db98ab33ad7562387aca122863bd73f381c092a /lib/CodeGen/CodeGenModule.cpp | |
parent | 0558e79840bfdbbd38c6e2b4f6765bf0158e85f4 (diff) |
now that all the decl reference and creation stuff is going through two
very simple places, reimplement the deferred decl emission logic to not be O(N^2),
fixing PR3810.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67447 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenModule.cpp')
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 109344b9c6..93bf6dd8f0 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -441,38 +441,26 @@ void CodeGenModule::EmitLLVMUsed() { } void CodeGenModule::EmitDeferred() { - // Emit code for any deferred decl which was used. Since a - // previously unused static decl may become used during the - // generation of code for a static function, iterate until no - // changes are made. - bool Changed; - do { - Changed = false; + // Emit code for any potentially referenced deferred decls. Since a + // previously unused static decl may become used during the generation of code + // for a static function, iterate until no changes are made. + while (!DeferredDeclsToEmit.empty()) { + const ValueDecl *D = DeferredDeclsToEmit.back(); + DeferredDeclsToEmit.pop_back(); + + // The mangled name for the decl must have been emitted in GlobalDeclMap. + // Look it up to see if it was defined with a stronger definition (e.g. an + // extern inline function with a strong function redefinition). If so, + // just ignore the deferred decl. + llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)]; + assert(CGRef && "Deferred decl wasn't referenced?"); - for (std::list<const ValueDecl*>::iterator i = DeferredDecls.begin(), - e = DeferredDecls.end(); i != e; ) { - const ValueDecl *D = *i; - - // Check if we have used a decl with the same name - // FIXME: The AST should have some sort of aggregate decls or - // global symbol map. - // FIXME: This is missing some important cases. For example, we - // need to check for uses in an alias. - if (!GlobalDeclMap.count(getMangledName(D))) { - ++i; - continue; - } - - // Emit the definition. - EmitGlobalDefinition(D); - - // Erase the used decl from the list. - i = DeferredDecls.erase(i); - - // Remember that we made a change. - Changed = true; - } - } while (Changed); + if (!CGRef->isDeclaration()) + continue; + + // Otherwise, emit the definition and move on to the next one. + EmitGlobalDefinition(D); + } } /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the @@ -552,6 +540,7 @@ void CodeGenModule::EmitGlobal(const ValueDecl *Global) { return; } + // Ignore declarations, they will be emitted on their first use. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) { // Forward declarations are emitted lazily on first use. if (!FD->isThisDeclarationADefinition()) @@ -565,9 +554,20 @@ void CodeGenModule::EmitGlobal(const ValueDecl *Global) { return; } - // Defer code generation when possible. + // Defer code generation when possible if this is a static definition, inline + // function etc. These we only want to emit if they are used. if (MayDeferGeneration(Global)) { - DeferredDecls.push_back(Global); + // If the value has already been used, add it directly to the + // DeferredDeclsToEmit list. + const char *MangledName = getMangledName(Global); + if (GlobalDeclMap.count(MangledName)) + DeferredDeclsToEmit.push_back(Global); + else { + // Otherwise, remember that we saw a deferred decl with this name. The + // first use of the mangled name will cause it to move into + // DeferredDeclsToEmit. + DeferredDecls[MangledName] = Global; + } return; } @@ -606,6 +606,19 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(const FunctionDecl *D, return llvm::ConstantExpr::getBitCast(Entry, PTy); } + // This is the first use or definition of a mangled name. If there is a + // deferred decl with this name, remember that we need to emit it at the end + // of the file. + llvm::DenseMap<const char*, const ValueDecl*>::iterator DDI = + DeferredDecls.find(MangledName); + if (DDI != DeferredDecls.end()) { + // Move the potentially referenced deferred decl to the DeferredDeclsToEmit + // list, and remove it from DeferredDecls (since we don't need it anymore). + DeferredDeclsToEmit.push_back(DDI->second); + DeferredDecls.erase(DDI); + } + + // This function doesn't have a complete type (for example, the return // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. @@ -648,7 +661,19 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, const llvm::Type *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); return llvm::ConstantExpr::getBitCast(Entry, PTy); } - + + // This is the first use or definition of a mangled name. If there is a + // deferred decl with this name, remember that we need to emit it at the end + // of the file. + llvm::DenseMap<const char*, const ValueDecl*>::iterator DDI = + DeferredDecls.find(MangledName); + if (DDI != DeferredDecls.end()) { + // Move the potentially referenced deferred decl to the DeferredDeclsToEmit + // list, and remove it from DeferredDecls (since we don't need it anymore). + DeferredDeclsToEmit.push_back(DDI->second); + DeferredDecls.erase(DDI); + } + llvm::GlobalVariable *GV = new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, |