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
This commit is contained in:
Daniel Dunbar 2008-08-01 00:01:51 +00:00
parent 032db47f0f
commit 74aa7e1eae
4 changed files with 90 additions and 47 deletions

View File

@ -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; }

View File

@ -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<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));
}
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<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());
}
}
}

View File

@ -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<llvm::Constant*, int> > CtorList;
ASTContext &Context;
const LangOptions &Features;
llvm::Module &TheModule;
@ -80,7 +82,16 @@ class CodeGenModule {
/// 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 @@ 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);

View File

@ -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 <stdio.h>
void A() __attribute__((constructor));
void B() __attribute__((destructor));
void A() {
printf("A\n");
}
void B() {
printf("B\n");
}
int main() {
return 0;
}