]> granicus.if.org Git - clang/commitdiff
Add support for global initializers.
authorAnders Carlsson <andersca@mac.com>
Sat, 8 Aug 2009 23:24:23 +0000 (23:24 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 8 Aug 2009 23:24:23 +0000 (23:24 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78515 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/global-init.cpp [new file with mode: 0644]

index bed6785ef18e760b77f05bd4bafa25d781ae127c..bcae8298e6fa803bc0d92343352c1c8c3114811f 100644 (file)
@@ -91,6 +91,41 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
   }
 }
 
+void
+CodeGenModule::EmitCXXGlobalInitFunc() {
+  if (CXXGlobalInits.empty())
+    return;
+  
+  const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::VoidTy,
+                                                          false);
+  
+  // Create our global initialization function.
+  // FIXME: Should this be tweakable by targets?
+  llvm::Function *Fn = 
+    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+                           "__cxx_global_initialization", &TheModule);
+  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+                                                   CXXGlobalInits.data(),
+                                                   CXXGlobalInits.size());
+  AddGlobalCtor(Fn);
+}
+
+void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+                                                const VarDecl **Decls,
+                                                unsigned NumDecls) {
+  StartFunction(0, getContext().VoidTy, Fn, FunctionArgList(), 
+                SourceLocation());
+  
+  for (unsigned i = 0; i != NumDecls; ++i) {
+    const VarDecl *D = Decls[i];
+    
+    llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+    EmitCXXGlobalVarDeclInit(*D, DeclPtr);
+  }
+  FinishFunction();
+}
+
 void 
 CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, 
                                                llvm::GlobalVariable *GV) {
index 31ed8a6390df281e86f2d40cad1e206f17313d2c..12d4d9ca25235ebf69f72a6e89cf60a9095c60d1 100644 (file)
@@ -509,7 +509,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
   // initialize the return value.  TODO: it might be nice to have
   // a more general mechanism for this that didn't require synthesized
   // return statements.
-  if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(CurFuncDecl)) {
+  if (const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
     if (FD->hasImplicitReturnZero()) {
       QualType RetTy = FD->getResultType().getUnqualifiedType();
       const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
index eae6161e8e138be6c7eb430e236e0c515fb31791..0b012592e4f37e3b6c538b34e1ce968243205792 100644 (file)
@@ -173,7 +173,7 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
   // FIXME: The cast here is a huge hack.
   if (CGDebugInfo *DI = getDebugInfo()) {
     DI->setLocation(StartLoc);
-    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
       DI->EmitFunctionStart(CGM.getMangledName(FD), RetTy, CurFn, Builder);
     } else {
       // Just use LLVM function name.
index da88b53352eeae592554be24c4b4c83c4dc5fcc1..d18217fcc9e4ed646ab9ffce5eb461d99c40ee5d 100644 (file)
@@ -901,6 +901,12 @@ public:
   void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
                                      llvm::Constant *DeclPtr);
   
+  /// GenerateCXXGlobalInitFunc - Generates code for initializing global 
+  /// variables.
+  void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+                                 const VarDecl **Decls,
+                                 unsigned NumDecls);
+  
   void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
   
   RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
index 503bcda8e7b33efbca252424431e5b6eac9fd07d..df9b341ac9b55795b9002c762779dc48b6e7e7a2 100644 (file)
@@ -62,6 +62,9 @@ CodeGenModule::~CodeGenModule() {
 }
 
 void CodeGenModule::Release() {
+  // We need to call this first because it can add deferred declarations.
+  EmitCXXGlobalInitFunc();
+
   EmitDeferred();
   if (Runtime)
     if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
@@ -854,10 +857,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
     Init = EmitNullConstant(D->getType());
   } else {
     Init = EmitConstantExpr(D->getInit(), D->getType());
+    
     if (!Init) {
-      ErrorUnsupported(D, "static initializer");
       QualType T = D->getInit()->getType();
-      Init = llvm::UndefValue::get(getTypes().ConvertType(T));
+      if (getLangOptions().CPlusPlus) {
+        CXXGlobalInits.push_back(D);
+        Init = EmitNullConstant(T);
+      } else {
+        ErrorUnsupported(D, "static initializer");
+        Init = llvm::UndefValue::get(getTypes().ConvertType(T));
+      }
     }
   }
 
index 3aa015a99f7475c257aac634a223142b9d4735ab..923b6d204c669d1258a30574902f1653e1b60f23 100644 (file)
@@ -173,6 +173,10 @@ class CodeGenModule : public BlockModule {
   llvm::StringMap<llvm::Constant*> CFConstantStringMap;
   llvm::StringMap<llvm::Constant*> ConstantStringMap;
 
+  /// CXXGlobalInits - Variables with global initializers that need to run
+  /// before main.
+  std::vector<const VarDecl*> CXXGlobalInits;
+  
   /// CFConstantStringClassRef - Cached reference to the class for constant
   /// strings. This value has type int * but is actually an Obj-C class pointer.
   llvm::Constant *CFConstantStringClassRef;
@@ -444,6 +448,9 @@ private:
   /// a C++ destructor Decl.
   void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
   
+  /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
+  void EmitCXXGlobalInitFunc();
+  
   // FIXME: Hardcoding priority here is gross.
   void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
   void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
new file mode 100644 (file)
index 0000000..ecca8ff
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t &&
+// RUN: grep "call void @_ZN1AC1Ev" %t | count 1 &&
+// RUN: grep "call i32 @__cxa_atexit(void (i8\*)\* bitcast (void (%.truct.A\*)\* @_ZN1AD1Ev to void (i8\*)\*), i8\* getelementptr (%.truct.A\* @a, i32 0, i32 0), i8\* bitcast (i8\*\* @__dso_handle to i8\*))" %t | count 1 
+
+struct A {
+  A();
+  ~A();
+};
+
+A a;