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:
parent
032db47f0f
commit
74aa7e1eae
|
@ -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; }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue