Support constructor and destructor attributes in CodeGen

 - There is an miscompilation issue remaining due to a poor
   interaction between the delayed emission of static functions and
   the emission of constructors, but that already existed prior to
   this change.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54258 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index a65c2b3..b531616 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -53,7 +53,8 @@
   llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction();
   if (ObjCInitFunction)
     AddGlobalCtor(ObjCInitFunction);
-  EmitGlobalCtors();
+  EmitCtorList(GlobalCtors, "llvm.global_ctors");
+  EmitCtorList(GlobalDtors, "llvm.global_dtors");
   EmitAnnotations();
   delete Runtime;
   delete DebugInfo;
@@ -102,55 +103,48 @@
 
 /// AddGlobalCtor - Add a function to the list that will be called before
 /// main() runs.
-void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor) {
+void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) {
   // TODO: Type coercion of void()* types.
-  GlobalCtors.push_back(Ctor);
+  GlobalCtors.push_back(std::make_pair(Ctor, Priority));
 }
 
-/// EmitGlobalCtors - Generates the array of contsturctor functions to be
-/// called on module load, if any have been registered with AddGlobalCtor.
-void CodeGenModule::EmitGlobalCtors() {
-  if (GlobalCtors.empty()) return;
-  
-  // Get the type of @llvm.global_ctors
-  std::vector<const llvm::Type*> CtorFields;
-  CtorFields.push_back(llvm::IntegerType::get(32));
-  // Constructor function type
-  std::vector<const llvm::Type*> VoidArgs;
-  llvm::FunctionType* CtorFuncTy =
-    llvm::FunctionType::get(llvm::Type::VoidTy, VoidArgs, false);
-  
-  // i32, function type pair
-  const llvm::Type *FPType = llvm::PointerType::getUnqual(CtorFuncTy);
+/// AddGlobalDtor - Add a function to the list that will be called
+/// when the module is unloaded.
+void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
+  // TODO: Type coercion of void()* types.
+  GlobalDtors.push_back(std::make_pair(Dtor, Priority));
+}
+
+void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
+  // Ctor function type is void()*.
+  llvm::FunctionType* CtorFTy =
+    llvm::FunctionType::get(llvm::Type::VoidTy, 
+                            std::vector<const llvm::Type*>(),
+                            false);
+  llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
+
+  // Get the type of a ctor entry, { i32, void ()* }.
   llvm::StructType* CtorStructTy = 
-  llvm::StructType::get(llvm::Type::Int32Ty, FPType, NULL);
-  // Array of fields
-  llvm::ArrayType* GlobalCtorsTy = 
-    llvm::ArrayType::get(CtorStructTy, GlobalCtors.size());
-  
-  // Define the global variable
-  llvm::GlobalVariable *GlobalCtorsVal =
-    new llvm::GlobalVariable(GlobalCtorsTy, false,
-                             llvm::GlobalValue::AppendingLinkage,
-                             (llvm::Constant*)0, "llvm.global_ctors",
-                             &TheModule);
+    llvm::StructType::get(llvm::Type::Int32Ty, 
+                          llvm::PointerType::getUnqual(CtorFTy), NULL);
 
-  // Populate the array
-  std::vector<llvm::Constant*> CtorValues;
-  llvm::Constant *MagicNumber = 
-    llvm::ConstantInt::get(llvm::Type::Int32Ty, 65535, false);
-  std::vector<llvm::Constant*> StructValues;
-  for (std::vector<llvm::Constant*>::iterator I = GlobalCtors.begin(), 
-       E = GlobalCtors.end(); I != E; ++I) {
-    StructValues.clear();
-    StructValues.push_back(MagicNumber);
-    StructValues.push_back(*I);
-
-    CtorValues.push_back(llvm::ConstantStruct::get(CtorStructTy, StructValues));
+  // Construct the constructor and destructor arrays.
+  std::vector<llvm::Constant*> Ctors;
+  for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
+    std::vector<llvm::Constant*> S;
+    S.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, I->second, false));
+    S.push_back(llvm::ConstantExpr::getBitCast(I->first, CtorPFTy));
+    Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S));
   }
-  
-  GlobalCtorsVal->setInitializer(llvm::ConstantArray::get(GlobalCtorsTy,
-                                                          CtorValues));
+
+  if (!Ctors.empty()) {
+    llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size());
+    new llvm::GlobalVariable(AT, false,
+                             llvm::GlobalValue::AppendingLinkage,
+                             llvm::ConstantArray::get(AT, Ctors),
+                             GlobalName, 
+                             &TheModule);
+  }
 }
 
 void CodeGenModule::EmitAnnotations() {
@@ -796,6 +790,12 @@
   } else {
     llvm::Function *Fn = cast<llvm::Function>(Entry);    
     CodeGenFunction(*this).GenerateCode(D, Fn);
+
+    if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>()) {
+      AddGlobalCtor(Fn, CA->getPriority());
+    } else if (const DestructorAttr *DA = D->getAttr<DestructorAttr>()) {
+      AddGlobalDtor(Fn, DA->getPriority());
+    }
   }
 }
 
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 3a39eb3..1fb2cf7 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -54,6 +54,8 @@
 /// CodeGenModule - This class organizes the cross-module state that is used
 /// while generating LLVM code.
 class CodeGenModule {
+  typedef std::vector< std::pair<llvm::Constant*, int> > CtorList;
+
   ASTContext &Context;
   const LangOptions &Features;
   llvm::Module &TheModule;
@@ -80,7 +82,16 @@
   /// which actually define something.
   std::vector<const ValueDecl*> StaticDecls;
   
-  std::vector<llvm::Constant*> GlobalCtors;
+  /// GlobalCtors - Store the list of global constructors and their
+  /// respective priorities to be emitted when the translation unit is
+  /// complete.
+  CtorList GlobalCtors;
+
+  /// GlobalDtors - Store the list of global destructors and their
+  /// respective priorities to be emitted when the translation unit is
+  /// complete.
+  CtorList GlobalDtors;
+
   std::vector<llvm::Constant*> Annotations;
     
   llvm::StringMap<llvm::Constant*> CFConstantStringMap;
@@ -173,9 +184,17 @@
   llvm::GlobalValue *EmitForwardFunctionDefinition(const FunctionDecl *D);
   void EmitGlobalFunctionDefinition(const FunctionDecl *D);
   void EmitGlobalVarDefinition(const VarDecl *D);
+  
+  // FIXME: Hardcoding priority here is gross.
+  void AddGlobalCtor(llvm::Function * Ctor, int Priority=65535);
+  void AddGlobalDtor(llvm::Function * Dtor, int Priority=65535);
 
-  void AddGlobalCtor(llvm::Function * Ctor);
-  void EmitGlobalCtors(void);
+  /// EmitCtorList - Generates a global array of functions and
+  /// priorities using the given list and name. This array will have
+  /// appending linkage and is suitable for use as a LLVM constructor
+  /// or destructor array.
+  void EmitCtorList(const CtorList &Fns, const char *GlobalName);
+
   void EmitAnnotations(void);
   void EmitStatics(void);