[cfe-commits] r51783 - /cfe/trunk/lib/CodeGen/CodeGenModule.cpp
Eli Friedman
eli.friedman at gmail.com
Fri May 30 12:50:47 PDT 2008
Author: efriedma
Date: Fri May 30 14:50:47 2008
New Revision: 51783
URL: http://llvm.org/viewvc/llvm-project?rev=51783&view=rev
Log:
Allow the type of a global to be different from the type of its
associated declaration. This is a prerequisite to handling
general union initializations; for example, an array of unions involving
pointers has to be turned into a struct because the elements can have
incompatible types.
I refactored the code a bit to make it more readable; now, the logic for
definitions is all in EmitGlobalVarInit.
The second parameter for GetAddrOfGlobalVar is now dead; I'll remove it
separately.
By itself, this patch should not cause any visible changes.
Modified:
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=51783&r1=51782&r2=51783&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri May 30 14:50:47 2008
@@ -246,20 +246,15 @@
return Entry = NewFn;
}
-static bool IsZeroElementArray(const llvm::Type *Ty) {
- if (const llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(Ty))
- return ATy->getNumElements() == 0;
- return false;
-}
-
llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
bool isDefinition) {
assert(D->hasGlobalStorage() && "Not a global variable");
-
+ assert(!isDefinition && "This shouldn't be called for definitions!");
+
// See if it is already in the map.
llvm::Constant *&Entry = GlobalDeclMap[D];
if (Entry) return Entry;
-
+
QualType ASTTy = D->getType();
const llvm::Type *Ty = getTypes().ConvertTypeForMem(ASTTy);
@@ -273,53 +268,11 @@
0, D->getName(), &getModule(), 0,
ASTTy.getAddressSpace());
}
-
- // If the pointer type matches, just return it.
- llvm::Type *PTy = llvm::PointerType::getUnqual(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(), 0,
- ASTTy.getAddressSpace());
- 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);
-
- // Verify that GV was a declaration or something like x[] which turns into
- // [0 x type].
- assert((GV->isDeclaration() ||
- IsZeroElementArray(GV->getType()->getElementType())) &&
- "Shouldn't replace non-declaration");
-
- // Ok, delete the old global now, which is dead.
- GV->eraseFromParent();
-
- // Return the new global which has the right type.
- return Entry = NewGV;
-}
+ // Otherwise, it already exists; return the existing version
+ llvm::PointerType *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
+ return Entry = llvm::ConstantExpr::getBitCast(GV, PTy);
+}
void CodeGenModule::EmitObjCMethod(const ObjCMethodDecl *OMD) {
// If this is not a prototype, emit the body.
@@ -449,23 +402,65 @@
}
void CodeGenModule::EmitGlobalVarInit(const VarDecl *D) {
- // Get the global, forcing it to be a direct reference.
- llvm::GlobalVariable *GV =
- cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, true));
-
- // Convert the initializer, or use zero if appropriate.
+ assert(D->hasGlobalStorage() && "Not a global variable");
+
llvm::Constant *Init = 0;
+ QualType ASTTy = D->getType();
+ const llvm::Type *VarTy = getTypes().ConvertTypeForMem(ASTTy);
+ const llvm::Type *VarPtrTy =
+ llvm::PointerType::get(VarTy, ASTTy.getAddressSpace());
+
if (D->getInit() == 0) {
- Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
- } else if (D->getType()->isIntegerType()) {
- llvm::APSInt Value(static_cast<uint32_t>(
- getContext().getTypeSize(D->getInit()->getType())));
- if (D->getInit()->isIntegerConstantExpr(Value, Context))
- Init = llvm::ConstantInt::get(Value);
+ Init = llvm::Constant::getNullValue(VarTy);
+ } else {
+ Init = EmitGlobalInit(D->getInit());
}
+ const llvm::Type* InitType = Init->getType();
- if (!Init)
- Init = EmitGlobalInit(D->getInit());
+ llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName(), true);
+
+ if (!GV) {
+ GV = new llvm::GlobalVariable(InitType, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, D->getName(), &getModule(), 0,
+ ASTTy.getAddressSpace());
+ } else if (GV->getType()->getElementType() != InitType ||
+ GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
+ // We have a definition after a prototype with the wrong type.
+ // We must make a new GlobalVariable* and update everything that used OldGV
+ // (a declaration or tentative definition) 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];"). This also
+ // happens when an initializer has a different type from the type of the
+ // global (this happens with unions).
+
+ // Save the old global
+ llvm::GlobalVariable *OldGV = GV;
+
+ // Make a new global with the correct type
+ GV = new llvm::GlobalVariable(InitType, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, D->getName(), &getModule(), 0,
+ ASTTy.getAddressSpace());
+ // Steal the name of the old global
+ GV->takeName(OldGV);
+
+ // Replace all uses of the old global with the new global
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtrForOldDecl);
+ // Make sure we don't keep around any stale references to globals
+ // FIXME: This is really slow; we need a better way to walk all
+ // the decls with the same name
+ ReplaceMapValuesWith(OldGV, NewPtrForOldDecl);
+
+ // Erase the old global, since it is no longer used.
+ OldGV->eraseFromParent();
+ }
+
+ GlobalDeclMap[D] = llvm::ConstantExpr::getBitCast(GV, VarPtrTy);
if (const AnnotateAttr *AA = D->getAttr<AnnotateAttr>()) {
SourceManager &SM = Context.getSourceManager();
@@ -473,8 +468,6 @@
SM.getLogicalLineNumber(D->getLocation())));
}
- assert(GV->getType()->getElementType() == Init->getType() &&
- "Initializer codegen type mismatch!");
GV->setInitializer(Init);
unsigned Align = Context.getTypeAlign(D->getType());
More information about the cfe-commits
mailing list