From 74aa7e1eaeb8a38ee5d97ae85a498d6d46b5635d Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 1 Aug 2008 00:01:51 +0000 Subject: [PATCH] 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. llvm-svn: 54258 --- clang/include/clang/AST/Attr.h | 4 + clang/lib/CodeGen/CodeGenModule.cpp | 88 +++++++++++----------- clang/lib/CodeGen/CodeGenModule.h | 25 +++++- clang/test/CodeGen/constructor-attribute.c | 20 +++++ 4 files changed, 90 insertions(+), 47 deletions(-) create mode 100644 clang/test/CodeGen/constructor-attribute.c diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index ac0042248254..ea052559be52 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -132,6 +132,8 @@ class ConstructorAttr : public Attr { int priority; public: ConstructorAttr(int p) : Attr(Constructor), priority(p) {} + + int getPriority() const { return priority; } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Constructor; } @@ -142,6 +144,8 @@ class DestructorAttr : public Attr { int priority; public: DestructorAttr(int p) : Attr(Destructor), priority(p) {} + + int getPriority() const { return priority; } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Destructor; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a65c2b3807d6..b531616b13c2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -53,7 +53,8 @@ CodeGenModule::~CodeGenModule() { 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 @@ void CodeGenModule::setVisibility(llvm::GlobalValue *GV, /// 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 CtorFields; - CtorFields.push_back(llvm::IntegerType::get(32)); - // Constructor function type - std::vector 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(), + 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 CtorValues; - llvm::Constant *MagicNumber = - llvm::ConstantInt::get(llvm::Type::Int32Ty, 65535, false); - std::vector StructValues; - for (std::vector::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 Ctors; + for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { + std::vector 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)); + } + + 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); } - - GlobalCtorsVal->setInitializer(llvm::ConstantArray::get(GlobalCtorsTy, - CtorValues)); } void CodeGenModule::EmitAnnotations() { @@ -796,6 +790,12 @@ void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) { } else { llvm::Function *Fn = cast(Entry); CodeGenFunction(*this).GenerateCode(D, Fn); + + if (const ConstructorAttr *CA = D->getAttr()) { + AddGlobalCtor(Fn, CA->getPriority()); + } else if (const DestructorAttr *DA = D->getAttr()) { + AddGlobalDtor(Fn, DA->getPriority()); + } } } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 3a39eb3f79d3..1fb2cf7ae024 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -54,6 +54,8 @@ namespace CodeGen { /// CodeGenModule - This class organizes the cross-module state that is used /// while generating LLVM code. class CodeGenModule { + typedef std::vector< std::pair > CtorList; + ASTContext &Context; const LangOptions &Features; llvm::Module &TheModule; @@ -80,7 +82,16 @@ class CodeGenModule { /// which actually define something. std::vector StaticDecls; - std::vector 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 Annotations; llvm::StringMap CFConstantStringMap; @@ -173,9 +184,17 @@ private: 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); + + /// 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 AddGlobalCtor(llvm::Function * Ctor); - void EmitGlobalCtors(void); void EmitAnnotations(void); void EmitStatics(void); diff --git a/clang/test/CodeGen/constructor-attribute.c b/clang/test/CodeGen/constructor-attribute.c new file mode 100644 index 000000000000..0ecc47babfe6 --- /dev/null +++ b/clang/test/CodeGen/constructor-attribute.c @@ -0,0 +1,20 @@ +// RUN: clang -emit-llvm -o %t %s && +// RUN: grep -e "global_ctors.*@A" %t && +// RUN: grep -e "global_dtors.*@B" %t + +#include + +void A() __attribute__((constructor)); +void B() __attribute__((destructor)); + +void A() { + printf("A\n"); +} + +void B() { + printf("B\n"); +} + +int main() { + return 0; +}