From 89ed31d3f9eeb8ec77c284a5cf404a74bf5e7acf Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 8 Aug 2009 23:24:23 +0000 Subject: [PATCH] Add support for global initializers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78515 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 35 +++++++++++++++++++++++++++++++++ lib/CodeGen/CGCall.cpp | 2 +- lib/CodeGen/CodeGenFunction.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 6 ++++++ lib/CodeGen/CodeGenModule.cpp | 13 ++++++++++-- lib/CodeGen/CodeGenModule.h | 7 +++++++ test/CodeGenCXX/global-init.cpp | 10 ++++++++++ 7 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 test/CodeGenCXX/global-init.cpp diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index bed6785ef1..bcae8298e6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -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) { diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 31ed8a6390..12d4d9ca25 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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(CurFuncDecl)) { + if (const FunctionDecl* FD = dyn_cast_or_null(CurFuncDecl)) { if (FD->hasImplicitReturnZero()) { QualType RetTy = FD->getResultType().getUnqualifiedType(); const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index eae6161e8e..0b012592e4 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -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(D)) { + if (const FunctionDecl *FD = dyn_cast_or_null(D)) { DI->EmitFunctionStart(CGM.getMangledName(FD), RetTy, CurFn, Builder); } else { // Just use LLVM function name. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index da88b53352..d18217fcc9 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 503bcda8e7..df9b341ac9 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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)); + } } } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 3aa015a99f..923b6d204c 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -173,6 +173,10 @@ class CodeGenModule : public BlockModule { llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; + /// CXXGlobalInits - Variables with global initializers that need to run + /// before main. + std::vector 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 index 0000000000..ecca8ff1d6 --- /dev/null +++ b/test/CodeGenCXX/global-init.cpp @@ -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; -- 2.40.0