Hi all. Please find update patch for pr11480.

I made all as it was proposed by Anton in bug description:
http://llvm.org/bugs/show_bug.cgi?id=11480#c0

So, main changes are in EmitCXXGlobalInitFunc and EmitCXXGlobalDtorFunc.
For ctors/dtors with init_priority attribute I just generate separated init functions instead of single one. The exception is case when there are some ctors/dtors with same priority. In that case I put its invokation into a single init/dtor function, in order determined by its order in code.

I also changed CGCXXABI::registerGlobalDtor. I added VarDecl parameter here, since we need to now additional attributes of variable for which it is registered (init_priority for example).

The test-case was also included into the patch.

-Stepan.
Index: test/CodeGenCXX/init_priority.cpp
===================================================================
--- test/CodeGenCXX/init_priority.cpp	(revision 0)
+++ test/CodeGenCXX/init_priority.cpp	(revision 0)
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fno-use-cxa-atexit -fapple-kext %s -o - | FileCheck %s --check-prefix=CHECK_GDTORS
+// RUN: %clang -x c++ -DENABLE_MAIN %s -o %t
+// RUN: chmod u+x %t
+// RUN: %t | FileCheck %s -check-prefix=CHECK_OUTPUT
+// RUN: rm %t
+
+
+// PR11480
+
+extern "C" int printf(...);
+
+class A {
+public:
+  A() { printf("a ctor "); }
+  ~A() { printf("a dtor "); }
+};
+
+class A1 {
+public:
+  A1() { printf("a1 ctor "); }
+  ~A1() { printf("a1 dtor "); }
+};
+
+class B {
+public:
+  B() { printf("b ctor "); }
+  ~B() { printf("b dtor "); }
+};
+
+class C {
+public:
+  C() { printf("c ctor "); }
+  ~C() { printf("c dtor "); }
+};
+
+C arrC;  
+A1 arrA1 __attribute__((init_priority (300) ));
+A arrA __attribute__((init_priority (300) ));
+B arrB __attribute__((init_priority (200) ));
+
+//CHECK: @llvm.global_ctors = appending global [3 x { i32, void ()* }] [{ i32, void ()* } { i32 300, void ()* @_SAME_PRIO__I_a }, { i32, void ()* } { i32 200, void ()* @__cxx_global_var_init3 }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
+
+//CHECK_GDTORS: @llvm.global_dtors = appending global [3 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__D_a }, { i32, void ()* } { i32 300, void ()* @_SAME_PRIO__D_a }, { i32, void ()* } { i32 200, void ()* @__cxx_global_var_dtor }]
+
+#ifdef ENABLE_MAIN
+int main() { return 0; }
+#endif
+
+//CHECK_OUTPUT: b ctor a1 ctor a ctor c ctor c dtor a dtor a1 dtor b dtor
+
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp	(revision 161663)
+++ lib/CodeGen/ItaniumCXXABI.cpp	(working copy)
@@ -122,7 +122,9 @@
 
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr, bool PerformInit);
-  void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
+  void registerGlobalDtor(CodeGenFunction &CGF,
+                          const VarDecl &D,
+                          llvm::Constant *dtor,
                           llvm::Constant *addr);
 
   void EmitVTables(const CXXRecordDecl *Class);
@@ -1140,6 +1142,7 @@
 
 /// Register a global destructor as best as we know how.
 void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+                                       const VarDecl &D,
                                        llvm::Constant *dtor,
                                        llvm::Constant *addr) {
   // Use __cxa_atexit if available.
@@ -1151,6 +1154,10 @@
   // FIXME: shouldn't this be guarded by some variable?
   if (CGM.getContext().getLangOpts().AppleKext) {
     // Generate a global destructor entry.
+    if (D.hasAttr<InitPriorityAttr>()) {
+      unsigned int order = D.getAttr<InitPriorityAttr>()->getPriority();
+      return CGM.AddCXXPrioritizedDtorEntry(dtor, order, addr);
+    }     
     return CGM.AddCXXDtorEntry(dtor, addr);
   }
 
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h	(revision 161663)
+++ lib/CodeGen/CodeGenModule.h	(working copy)
@@ -79,25 +79,6 @@
   class CGCUDARuntime;
   class BlockFieldFlags;
   class FunctionArgList;
-  
-  struct OrderGlobalInits {
-    unsigned int priority;
-    unsigned int lex_order;
-    OrderGlobalInits(unsigned int p, unsigned int l) 
-      : priority(p), lex_order(l) {}
-    
-    bool operator==(const OrderGlobalInits &RHS) const {
-      return priority == RHS.priority &&
-             lex_order == RHS.lex_order;
-    }
-    
-    bool operator<(const OrderGlobalInits &RHS) const {
-      if (priority < RHS.priority)
-        return true;
-      
-      return priority == RHS.priority && lex_order < RHS.lex_order;
-    }
-  };
 
   struct CodeGenTypeCache {
     /// void
@@ -299,9 +280,19 @@
   /// - Global variables with initializers whose order of initialization
   /// is set by init_priority attribute.
   
-  SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8> 
-    PrioritizedCXXGlobalInits;
+  typedef llvm::DenseMap<unsigned int, llvm::SmallVector<llvm::Constant*, 4> >
+      GlobalInitsMap;
+  typedef GlobalInitsMap::iterator GlobalInitsMapIt;
 
+
+  typedef llvm::DenseMap<unsigned int,
+      std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > > 
+      GlobalDtorsMap;
+  typedef GlobalDtorsMap::iterator GlobalDtorsMapIt;
+  
+  GlobalInitsMap PrioritizedCXXGlobalInits;
+  GlobalDtorsMap PrioritizedCXXGlobalDtors;
+
   /// CXXGlobalDtors - Global destructor functions and arguments that need to
   /// run on termination.
   std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
@@ -695,6 +686,11 @@
   void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) {
     CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object));
   }
+  void AddCXXPrioritizedDtorEntry(llvm::Constant *DtorFn,
+                                  int Order,
+                                  llvm::Constant *Object) {
+    PrioritizedCXXGlobalDtors[Order].push_back(std::make_pair(DtorFn, Object));
+  }
 
   /// CreateRuntimeFunction - Create a new runtime function with the specified
   /// type and name.
@@ -956,6 +952,8 @@
   // FIXME: Hardcoding priority here is gross.
   void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
   void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
+  void AddGlobalCtorForGroup(llvm::Constant** Ctors, unsigned Size,
+                             const char* Name, int Priority=65535);
 
   /// EmitCtorList - Generates a global array of functions and priorities using
   /// the given list and name. This array will have appending linkage and is
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp	(revision 161663)
+++ lib/CodeGen/CGExpr.cpp	(working copy)
@@ -495,8 +495,9 @@
     if (ReferenceTemporaryDtor) {
       llvm::Constant *DtorFn = 
         CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
-      CGM.getCXXABI().registerGlobalDtor(*this, DtorFn, 
-                                    cast<llvm::Constant>(ReferenceTemporary));
+      CGM.getCXXABI().registerGlobalDtor(
+                          *this, *VD, DtorFn, 
+                          cast<llvm::Constant>(ReferenceTemporary));
     } else {
       assert(!ObjCARCReferenceLifetimeType.isNull());
       // Note: We intentionally do not register a global "destructor" to
Index: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h	(revision 161663)
+++ lib/CodeGen/CGCXXABI.h	(working copy)
@@ -279,9 +279,13 @@
   /// Emit code to force the execution of a destructor during global
   /// teardown.  The default implementation of this uses atexit.
   ///
+  /// \param D    - a declaration of variable for which the destructor should be
+  ///               registered.
   /// \param dtor - a function taking a single pointer argument
   /// \param addr - a pointer to pass to the destructor function.
-  virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
+  virtual void registerGlobalDtor(CodeGenFunction &CGF,
+                                  const VarDecl &D,
+                                  llvm::Constant *dtor,
                                   llvm::Constant *addr);
 
   /***************************** Virtual Tables *******************************/
Index: lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- lib/CodeGen/CGDeclCXX.cpp	(revision 161663)
+++ lib/CodeGen/CGDeclCXX.cpp	(working copy)
@@ -98,7 +98,7 @@
     argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
   }
 
-  CGM.getCXXABI().registerGlobalDtor(CGF, function, argument);
+  CGM.getCXXABI().registerGlobalDtor(CGF, D, function, argument);
 }
 
 /// Emit code to cause the variable at the given address to be considered as
@@ -249,8 +249,7 @@
 
   if (D->hasAttr<InitPriorityAttr>()) {
     unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
-    OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
-    PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
+    PrioritizedCXXGlobalInits[order].push_back(Fn);
     DelayedCXXInitPosition.erase(D);
   }
   else {
@@ -266,6 +265,22 @@
   }
 }
 
+void CodeGenModule::AddGlobalCtorForGroup(
+    llvm::Constant** Ctors,
+    unsigned Size,
+    const char* Name,
+    int Priority) {
+  
+  llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+  
+  // Create our global initialization function.
+  llvm::Function *Fn = 
+    CreateGlobalInitOrDestructFunction(*this, FTy, Name);
+    
+  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, Ctors, Size);
+  AddGlobalCtor(Fn, Priority);
+}
+
 void
 CodeGenModule::EmitCXXGlobalInitFunc() {
   while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@@ -274,46 +289,54 @@
   if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
     return;
 
-  llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
-
-  // Create our global initialization function.
-  llvm::Function *Fn = 
-    CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
-
   if (!PrioritizedCXXGlobalInits.empty()) {
-    SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
-    llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(), 
-                         PrioritizedCXXGlobalInits.end()); 
-    for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) {
-      llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second;
-      LocalCXXGlobalInits.push_back(Fn);
+    for (GlobalInitsMapIt i = PrioritizedCXXGlobalInits.begin(),
+                          e = PrioritizedCXXGlobalInits.end(); i != e; ++i) {
+      llvm::SmallVector<llvm::Constant*, 4> &SamePrioCtors = i->second;
+      
+      if (SamePrioCtors.size() > 1)
+        AddGlobalCtorForGroup(
+            &SamePrioCtors[0], SamePrioCtors.size(), "_SAME_PRIO__I_a", i->first);
+      else {
+        llvm::Function *Fn = cast<llvm::Function>(SamePrioCtors[0]);
+        AddGlobalCtor(Fn, i->first);
+      }
     }
-    LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end());
-    CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
-                                                    &LocalCXXGlobalInits[0],
-                                                    LocalCXXGlobalInits.size());
   }
-  else
-    CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
-                                                     &CXXGlobalInits[0],
-                                                     CXXGlobalInits.size());
-  AddGlobalCtor(Fn);
+  if (!CXXGlobalInits.empty())
+    AddGlobalCtorForGroup(
+        &CXXGlobalInits[0], CXXGlobalInits.size(), "_GLOBAL__I_a");
+
   CXXGlobalInits.clear();
   PrioritizedCXXGlobalInits.clear();
 }
 
 void CodeGenModule::EmitCXXGlobalDtorFunc() {
-  if (CXXGlobalDtors.empty())
-    return;
 
-  llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+  if (!CXXGlobalDtors.empty()) {
 
-  // Create our global destructor function.
-  llvm::Function *Fn =
-    CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
+    llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+  
+    // Create our global destructor function.
+    llvm::Function *Fn =
+      CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
+  
+    CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
+    AddGlobalDtor(Fn);
+  }
 
-  CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
-  AddGlobalDtor(Fn);
+  if (!PrioritizedCXXGlobalDtors.empty()) {
+    for (GlobalDtorsMapIt i = PrioritizedCXXGlobalDtors.begin(),
+                          e = PrioritizedCXXGlobalDtors.end(); i != e; ++i) {
+      llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+      const char* Name = i->second.size() == 1 ?
+          "__cxx_global_var_dtor" : "_SAME_PRIO__D_a";
+      llvm::Function *Fn =
+        CreateGlobalInitOrDestructFunction(*this, FTy, Name);
+      CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, i->second);
+      AddGlobalDtor(Fn, i->first);
+    }
+  }
 }
 
 /// Emit the code necessary to initialize the given global variable.
@@ -374,10 +397,11 @@
                 FunctionArgList(), SourceLocation());
 
   // Emit the dtors, in reverse order from construction.
-  for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
-    llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
+  for (unsigned i = DtorsAndObjects.size(); i != 0;) {
+    --i;
+    llvm::Value *Callee = DtorsAndObjects[i].first;
     llvm::CallInst *CI = Builder.CreateCall(Callee,
-                                            DtorsAndObjects[e - i - 1].second);
+                                            DtorsAndObjects[i].second);
     // Make sure the call and the callee agree on calling convention.
     if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
       CI->setCallingConv(F->getCallingConv());
Index: lib/CodeGen/CGCXXABI.cpp
===================================================================
--- lib/CodeGen/CGCXXABI.cpp	(revision 161663)
+++ lib/CodeGen/CGCXXABI.cpp	(working copy)
@@ -222,6 +222,7 @@
 }
 
 void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+                                  const VarDecl &D,
                                   llvm::Constant *dtor,
                                   llvm::Constant *addr) {
   // The default behavior is to use atexit.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to