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/CGExpr.cpp b/CodeGen/CGExpr.cpp
index 93f3d71..e7bd712 100644
--- a/CodeGen/CGExpr.cpp
+++ b/CodeGen/CGExpr.cpp
@@ -268,8 +268,10 @@
llvm::Value *V = LocalDeclMap[D];
assert(V && "BlockVarDecl not entered in LocalDeclMap?");
return LValue::MakeAddr(V);
- } else if (isa<FunctionDecl>(D) || isa<FileVarDecl>(D)) {
- return LValue::MakeAddr(CGM.GetAddrOfGlobalDecl(D));
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false));
+ } else if (const FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
+ return LValue::MakeAddr(CGM.GetAddrOfFileVarDecl(FVD, false));
}
assert(0 && "Unimp declref");
//an invalid LValue, but the assert will
diff --git a/CodeGen/CodeGenFunction.cpp b/CodeGen/CodeGenFunction.cpp
index aa9d2c6..3ee7d1f 100644
--- a/CodeGen/CodeGenFunction.cpp
+++ b/CodeGen/CodeGenFunction.cpp
@@ -59,42 +59,7 @@
SourceLocation()));
CurFuncDecl = FD;
- llvm::Constant *CurFnC = CGM.GetAddrOfGlobalDecl(FD);
- if (!(CurFn = dyn_cast<llvm::Function>(CurFnC))) {
- // If CurFnC is not a constant, it must be a bitcast of another function.
- llvm::ConstantExpr *CurFnCE = cast<llvm::ConstantExpr>(CurFnC);
- assert(CurFnCE->getOpcode() == llvm::Instruction::BitCast &&
- "Unexpected name collision");
- llvm::Function *OtherFunc = cast<llvm::Function>(CurFnCE->getOperand(0));
-
- // 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.
- const llvm::PointerType *PTy = cast<llvm::PointerType>(CurFnC->getType());
- const llvm::FunctionType *FTy =
- cast<llvm::FunctionType>(PTy->getElementType());
- CurFn = new llvm::Function(FTy, llvm::Function::ExternalLinkage, "",
- &CGM.getModule());
- CurFn->takeName(OtherFunc);
-
- // Replace uses of OtherFunc with the Function we will endow with a body.
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(CurFn, OtherFunc->getType());
- OtherFunc->replaceAllUsesWith(NewPtrForOldDecl);
-
- // Make sure the GlobalDecl map for FD is up-to-date.
- CGM.ChangeGlobalDeclMap(FD, CurFn);
-
- // 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!
- CGM.ReplaceMapValuesWith(OtherFunc, NewPtrForOldDecl);
-
- // Ok, delete the old function now, which is dead.
- assert(OtherFunc->isDeclaration() && "Shouldn't replace non-declaration");
- OtherFunc->eraseFromParent();
- }
-
+ CurFn = cast<llvm::Function>(CGM.GetAddrOfFunctionDecl(FD, true));
assert(CurFn->isDeclaration() && "Function already has body?");
// TODO: Set up linkage and many other things. Note, this is a simple
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());
diff --git a/CodeGen/CodeGenModule.h b/CodeGen/CodeGenModule.h
index dd4c006..027c830 100644
--- a/CodeGen/CodeGenModule.h
+++ b/CodeGen/CodeGenModule.h
@@ -66,16 +66,11 @@
CodeGenTypes &getTypes() { return Types; }
Diagnostic &getDiags() const { return Diags; }
- llvm::Constant *GetAddrOfGlobalDecl(const ValueDecl *D);
+ llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D,
+ bool isDefinition);
+ llvm::Constant *GetAddrOfFileVarDecl(const FileVarDecl *D,
+ bool isDefinition);
- void ChangeGlobalDeclMap(const Decl *Decl, llvm::Constant *NewVal) {
- GlobalDeclMap[Decl] = NewVal;
- }
-
- /// ReplaceMapValuesWith - This is a really slow and bad function that
- /// searches for any entries in GlobalDeclMap that point to OldVal, changing
- /// them to point to NewVal. This is badbadbad, FIXME!
- void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal);
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
@@ -92,6 +87,13 @@
llvm::Constant *EmitGlobalInit(const Expr *Expression);
void PrintStats() {}
+
+private:
+ /// ReplaceMapValuesWith - This is a really slow and bad function that
+ /// searches for any entries in GlobalDeclMap that point to OldVal, changing
+ /// them to point to NewVal. This is badbadbad, FIXME!
+ void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal);
+
};
} // end namespace CodeGen
} // end namespace clang
diff --git a/test/CodeGen/globalinit.c b/test/CodeGen/globalinit.c
index 7087669..e94027c 100644
--- a/test/CodeGen/globalinit.c
+++ b/test/CodeGen/globalinit.c
@@ -2,3 +2,9 @@
int A[10] = { 1,2,3,4,5 };
+
+extern int x[];
+void foo() { x[0] = 1; }
+int x[10];
+void bar() { x[0] = 1; }
+