[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