Handle global variable definitions which change the type of a definition, such as:
extern int x[];
void foo() { x[0] = 1; }
int x[10];
void bar() { x[0] = 1; }
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp
index 7ef4fe1..727d9fb 100644
--- a/CodeGen/CodeGenModule.cpp
+++ b/CodeGen/CodeGenModule.cpp
@@ -43,41 +43,123 @@
}
-llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) {
- // See if it is already in the map.
+llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D,
+ bool isDefinition) {
+ // See if it is already in the map. If so, just return it.
llvm::Constant *&Entry = GlobalDeclMap[D];
if (Entry) return Entry;
- QualType ASTTy = cast<ValueDecl>(D)->getType();
- const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
- if (isa<FunctionDecl>(D)) {
- // Check to see if the function already exists.
- if (llvm::Function *F = getModule().getFunction(D->getName())) {
- // If so, make sure it is the correct type.
- return Entry = llvm::ConstantExpr::getBitCast(F,
- llvm::PointerType::get(Ty));
- }
-
+ const llvm::Type *Ty = getTypes().ConvertType(D->getType());
+
+ // Check to see if the function already exists.
+ llvm::Function *F = getModule().getFunction(D->getName());
+ const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
+
+ // If it doesn't already exist, just create and return an entry.
+ if (F == 0) {
// FIXME: param attributes for sext/zext etc.
- const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
D->getName(), &getModule());
}
- assert(isa<FileVarDecl>(D) && "Unknown global decl!");
-
- if (llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName())) {
- // If so, make sure it is the correct type.
- return Entry = llvm::ConstantExpr::getBitCast(GV,
- llvm::PointerType::get(Ty));
+ // If the pointer type matches, just return it.
+ llvm::Type *PFTy = llvm::PointerType::get(Ty);
+ if (PFTy == F->getType()) return Entry = F;
+ // If this isn't a definition, just return it casted to the right type.
+ if (!isDefinition)
+ return Entry = llvm::ConstantExpr::getBitCast(F, PFTy);
+
+ // Otherwise, we have a definition after a prototype with the wrong type.
+ // F is the Function* for the one with the wrong type, we must make a new
+ // Function* and update everything that used F (a declaration) with the new
+ // Function* (which will be a definition).
+ //
+ // This happens if there is a prototype for a function (e.g. "int f()") and
+ // then a definition of a different type (e.g. "int f(int x)"). Start by
+ // making a new function of the correct type, RAUW, then steal the name.
+ llvm::Function *NewFn = new llvm::Function(FTy,
+ llvm::Function::ExternalLinkage,
+ "", &getModule());
+ NewFn->takeName(F);
+
+ // Replace uses of F with the Function we will endow with a body.
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(NewFn, F->getType());
+ F->replaceAllUsesWith(NewPtrForOldDecl);
+
+ // FIXME: Update the globaldeclmap for the previous decl of this name. We
+ // really want a way to walk all of these, but we don't have it yet. This
+ // is incredibly slow!
+ ReplaceMapValuesWith(F, NewPtrForOldDecl);
+
+ // Ok, delete the old function now, which is dead.
+ assert(F->isDeclaration() && "Shouldn't replace non-declaration");
+ F->eraseFromParent();
+
+ // Return the new function which has the right type.
+ return Entry = NewFn;
+}
+
+llvm::Constant *CodeGenModule::GetAddrOfFileVarDecl(const FileVarDecl *D,
+ bool isDefinition) {
+ // See if it is already in the map.
+ llvm::Constant *&Entry = GlobalDeclMap[D];
+ if (Entry) return Entry;
+
+ const llvm::Type *Ty = getTypes().ConvertType(D->getType());
+
+ // Check to see if the global already exists.
+ llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName());
+
+ // If it doesn't already exist, just create and return an entry.
+ if (GV == 0) {
+ return Entry = new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, D->getName(), &getModule());
}
- return Entry = new llvm::GlobalVariable(Ty, false,
- llvm::GlobalValue::ExternalLinkage,
- 0, D->getName(), &getModule());
+ // If the pointer type matches, just return it.
+ llvm::Type *PTy = llvm::PointerType::get(Ty);
+ if (PTy == GV->getType()) return Entry = GV;
+
+ // If this isn't a definition, just return it casted to the right type.
+ if (!isDefinition)
+ return Entry = llvm::ConstantExpr::getBitCast(GV, PTy);
+
+
+ // Otherwise, we have a definition after a prototype with the wrong type.
+ // GV is the GlobalVariable* for the one with the wrong type, we must make a
+ /// new GlobalVariable* and update everything that used GV (a declaration)
+ // with the new GlobalVariable* (which will be a definition).
+ //
+ // This happens if there is a prototype for a global (e.g. "extern int x[];")
+ // and then a definition of a different type (e.g. "int x[10];"). Start by
+ // making a new global of the correct type, RAUW, then steal the name.
+ llvm::GlobalVariable *NewGV =
+ new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage,
+ 0, D->getName(), &getModule());
+ NewGV->takeName(GV);
+
+ // Replace uses of GV with the globalvalue we will endow with a body.
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(NewGV, GV->getType());
+ GV->replaceAllUsesWith(NewPtrForOldDecl);
+
+ // FIXME: Update the globaldeclmap for the previous decl of this name. We
+ // really want a way to walk all of these, but we don't have it yet. This
+ // is incredibly slow!
+ ReplaceMapValuesWith(GV, NewPtrForOldDecl);
+
+ // Ok, delete the old global now, which is dead.
+ assert(GV->isDeclaration() && "Shouldn't replace non-declaration");
+ GV->eraseFromParent();
+
+ // Return the new global which has the right type.
+ return Entry = NewGV;
}
+
void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
// If this is not a prototype, emit the body.
if (FD->getBody())
@@ -307,14 +389,16 @@
}
void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
- llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalDecl(D));
-
- // If the storage class is external and there is no initializer, just leave it
- // as a declaration.
+ // If this is just a forward declaration of the variable, don't emit it now,
+ // allow it to be emitted lazily on its first use.
if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
return;
-
- // Otherwise, convert the initializer, or use zero if appropriate.
+
+ // Get the global, forcing it to be a direct reference.
+ llvm::GlobalVariable *GV =
+ cast<llvm::GlobalVariable>(GetAddrOfFileVarDecl(D, true));
+
+ // Convert the initializer, or use zero if appropriate.
llvm::Constant *Init = 0;
if (D->getInit() == 0) {
Init = llvm::Constant::getNullValue(GV->getType()->getElementType());