[cfe-commits] r69231 - in /cfe/trunk: lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h test/CodeGen/tentative-array.c test/CodeGen/tentative-decls.c test/PCH/external-defs.c

Daniel Dunbar daniel at zuster.org
Wed Apr 15 15:08:45 PDT 2009


Author: ddunbar
Date: Wed Apr 15 17:08:45 2009
New Revision: 69231

URL: http://llvm.org/viewvc/llvm-project?rev=69231&view=rev
Log:
Defer generation of tentative definitions.
 - PR3980.

 - <rdar://problem/6762287> [irgen] crash when generating tentative
   definition of incomplete structure

 - This also avoids creating common definitions for things which are
   later overwritten.

 - XFAIL'ed external-defs.c, it isn't completing types properly yet.

Added:
    cfe/trunk/test/CodeGen/tentative-decls.c
      - copied, changed from r69222, cfe/trunk/test/CodeGen/tentative-array.c
Removed:
    cfe/trunk/test/CodeGen/tentative-array.c
Modified:
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/test/PCH/external-defs.c

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=69231&r1=69230&r2=69231&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Wed Apr 15 17:08:45 2009
@@ -423,6 +423,11 @@
     // Otherwise, emit the definition and move on to the next one.
     EmitGlobalDefinition(D);
   }
+
+  // Emit any tentative definitions.
+  for (std::vector<const VarDecl*>::iterator it = TentativeDefinitions.begin(),
+         ie = TentativeDefinitions.end(); it != ie; ++it)
+    EmitTentativeDefinition(*it);
 }
 
 /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the 
@@ -512,9 +517,16 @@
     const VarDecl *VD = cast<VarDecl>(Global);
     assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
 
-    // Forward declarations are emitted lazily on first use.
-    if (!VD->getInit() && VD->hasExternalStorage())
+    // If this isn't a definition, defer code generation.
+    if (!VD->getInit()) {
+      // If this is a tentative definition, remember it so that we can
+      // emit the common definition if needed. It is important to
+      // defer tentative definitions, since they may have incomplete
+      // type.
+      if (!VD->hasExternalStorage())
+        TentativeDefinitions.push_back(VD);
       return;
+    }
   }
 
   // Defer code generation when possible if this is a static definition, inline
@@ -708,21 +720,35 @@
   return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0);
 }
 
+void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
+  assert(!D->getInit() && "Cannot emit definite definitions here!");
+
+  // See if we have already defined this (as a variable), if so we do
+  // not need to do anything.
+  llvm::GlobalValue *GV = GlobalDeclMap[getMangledName(D)];
+  if (llvm::GlobalVariable *Var = dyn_cast_or_null<llvm::GlobalVariable>(GV))
+    if (Var->hasInitializer())
+      return;
+  
+  EmitGlobalVarDefinition(D);
+}
+
 void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
   llvm::Constant *Init = 0;
   QualType ASTTy = D->getType();
   
   if (D->getInit() == 0) {
     // This is a tentative definition; tentative definitions are
-    // implicitly initialized with { 0 }
-    const llvm::Type *InitTy = getTypes().ConvertTypeForMem(ASTTy);
-    if (ASTTy->isIncompleteArrayType()) {
-      // An incomplete array is normally [ TYPE x 0 ], but we need
-      // to fix it to [ TYPE x 1 ].
-      const llvm::ArrayType* ATy = cast<llvm::ArrayType>(InitTy);
-      InitTy = llvm::ArrayType::get(ATy->getElementType(), 1);
-    }
-    Init = llvm::Constant::getNullValue(InitTy);
+    // implicitly initialized with { 0 }.
+    //
+    // Note that tentative definitions are only emitted at the end of
+    // a translation unit, so they should never have incomplete
+    // type. In addition, EmitTentativeDefinition makes sure that we
+    // never attempt to emit a tentative definition if a real one
+    // exists. A use may still exists, however, so we still may need
+    // to do a RAUW.
+    assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
+    Init = llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(ASTTy));
   } else {
     Init = EmitConstantExpr(D->getInit(), D->getType());
     if (!Init) {
@@ -744,26 +770,6 @@
   // Entry is now either a Function or GlobalVariable.
   llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Entry);
   
-  // If we already have this global and it has an initializer, then
-  // we are in the rare situation where we emitted the defining
-  // declaration of the global and are now being asked to emit a
-  // definition which would be common. This occurs, for example, in
-  // the following situation because statics can be emitted out of
-  // order:
-  //
-  //  static int x;
-  //  static int *y = &x;
-  //  static int x = 10;
-  //  int **z = &y;
-  //
-  // Bail here so we don't blow away the definition. Note that if we
-  // can't distinguish here if we emitted a definition with a null
-  // initializer, but this case is safe.
-  if (GV && GV->hasInitializer() && !GV->getInitializer()->isNullValue()) {
-    assert(!D->getInit() && "Emitting multiple definitions of a decl!");
-    return;
-  }
-  
   // We have a definition after a declaration 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*

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=69231&r1=69230&r2=69231&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Wed Apr 15 17:08:45 2009
@@ -117,6 +117,14 @@
   /// that *are* actually referenced.  These get code generated when the module
   /// is done.
   std::vector<const ValueDecl*> DeferredDeclsToEmit;
+
+  /// TentativeDefinitions - A list of declarations which are
+  /// tentative definitions. Code generation for these must be
+  /// deferred because they are allowed to have incomplete type when
+  /// they are seen. This also allows us to avoid generating an extra
+  /// common definiton in situations where the tentative definition is
+  /// followed by an actual definition.
+  std::vector<const VarDecl*> TentativeDefinitions;
   
   /// LLVMUsed - List of global values which are required to be
   /// present in the object file; bitcast to i8*. This is used for
@@ -357,6 +365,7 @@
   void EmitGlobalDefinition(const ValueDecl *D);
 
   void EmitGlobalFunctionDefinition(const FunctionDecl *D);
+  void EmitTentativeDefinition(const VarDecl *D);
   void EmitGlobalVarDefinition(const VarDecl *D);
   void EmitAliasDefinition(const ValueDecl *D);
   void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);

Removed: cfe/trunk/test/CodeGen/tentative-array.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/tentative-array.c?rev=69230&view=auto

==============================================================================
--- cfe/trunk/test/CodeGen/tentative-array.c (original)
+++ cfe/trunk/test/CodeGen/tentative-array.c (removed)
@@ -1,4 +0,0 @@
-// RUN: clang-cc -emit-llvm < %s -triple=i686-apple-darwin9 | grep "global \[1 x i32\]"
-
-int r[];
-int (*a)[] = &r;

Copied: cfe/trunk/test/CodeGen/tentative-decls.c (from r69222, cfe/trunk/test/CodeGen/tentative-array.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/tentative-decls.c?p2=cfe/trunk/test/CodeGen/tentative-decls.c&p1=cfe/trunk/test/CodeGen/tentative-array.c&r1=69222&r2=69231&rev=69231&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/tentative-array.c (original)
+++ cfe/trunk/test/CodeGen/tentative-decls.c Wed Apr 15 17:08:45 2009
@@ -1,4 +1,28 @@
-// RUN: clang-cc -emit-llvm < %s -triple=i686-apple-darwin9 | grep "global \[1 x i32\]"
+// RUN: clang-cc -emit-llvm -o %t %s &&
+
+// RUN: grep '@r = common global \[1 x .*\] zeroinitializer' %t &&
 
 int r[];
 int (*a)[] = &r;
+
+struct s0;
+struct s0 x;
+// RUN: grep '@x = common global .struct.s0 zeroinitializer' %t &&
+
+struct s0 y;
+// RUN: grep '@y = common global .struct.s0 zeroinitializer' %t &&
+struct s0 *f0() {
+  return &y;
+}
+
+struct s0 {
+  int x;
+};
+
+// RUN: grep '@b = common global \[1 x .*\] zeroinitializer' %t &&
+int b[];
+int *f1() {
+  return b;
+}
+
+// RUN: true

Modified: cfe/trunk/test/PCH/external-defs.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/external-defs.c?rev=69231&r1=69230&r2=69231&view=diff

==============================================================================
--- cfe/trunk/test/PCH/external-defs.c (original)
+++ cfe/trunk/test/PCH/external-defs.c Wed Apr 15 17:08:45 2009
@@ -19,3 +19,5 @@
 struct S {
   int x, y;
 };
+
+// XFAIL





More information about the cfe-commits mailing list