Add pragma to install function as global C runtime ctor or dtor.

DMD has the obscure functionality to install functions starting with
_STI_ as global ctors and funtions starting with _STD_ as global
dtors. IMHO a pragma is a better way to specify the behaviour.

This commit adds pragma(LDC_global_crt_ctor) and
pragma(LDC_global_crt_dtor). If the pragma is specified on a function
or static method then an entry is made in the corresponding list. E.g.
in monitor_.d:

    extern (C) {
        #pragma(LDC_global_crt_ctor)
        void _STI_monitor_staticctor()
        {
            // ...
        }
    }

This works on Linux without problems. On Windows with MS C Runtime
ctors work always but dtors are invoked only if linked against the
static C runtime. Dtors on Windows require at least LLVM 3.2.
This commit is contained in:
kai
2012-09-12 17:59:09 +02:00
parent fd0021c6c2
commit 4ea7e8dbf8
7 changed files with 81 additions and 0 deletions

View File

@@ -853,6 +853,7 @@ struct FuncDeclaration : Declaration
std::set<VarDeclaration*> nestedVars;
std::string intrinsicName;
uint32_t priority;
bool isIntrinsic();
bool isVaIntrinsic();

View File

@@ -241,6 +241,8 @@ Msgtable msgtable[] =
{ "LDC_atomic_store" },
{ "LDC_atomic_cmp_xchg" },
{ "LDC_atomic_rmw" },
{ "LDC_global_crt_ctor" },
{ "LDC_global_crt_dtor" },
// Deprecated LDC pragmas lacking the vendor prefix.
{ "intrinsic" },

View File

@@ -907,6 +907,7 @@ struct FuncDeclaration : Declaration
std::set<VarDeclaration*> nestedVars;
std::string intrinsicName;
uint32_t priority;
bool isIntrinsic();
bool isVaIntrinsic();

View File

@@ -285,6 +285,8 @@ Msgtable msgtable[] =
{ "LDC_atomic_store" },
{ "LDC_atomic_cmp_xchg" },
{ "LDC_atomic_rmw" },
{ "LDC_global_crt_ctor" },
{ "LDC_global_crt_dtor" },
// Deprecated LDC pragmas lacking the vendor prefix.
{ "intrinsic" },

View File

@@ -767,6 +767,11 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
}
}
if (fdecl->llvmInternal == LLVMglobal_crt_ctor || fdecl->llvmInternal == LLVMglobal_crt_dtor)
{
AppendFunctionToLLVMGlobalCtorsDtors(func, fdecl->priority, fdecl->llvmInternal == LLVMglobal_crt_ctor);
}
// we never reference parameters of function prototypes
std::string str;
// if (!declareOnly)

View File

@@ -31,6 +31,19 @@ static bool parseStringExp(Expression* e, std::string& res)
return false;
}
static bool parseIntExp(Expression* e, dinteger_t& res)
{
IntegerExp *i = NULL;
e = e->optimize(WANTvalue);
if (e->op == TOKint64 && (i = static_cast<IntegerExp *>(e)))
{
res = i->value;
return true;
}
return false;
}
static void pragmaDeprecated(Identifier* oldIdent, Identifier* newIdent)
{
#ifndef DMDV1
@@ -104,6 +117,31 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str)
return LLVMintrinsic;
}
// pragma(ctor [, priority]) { funcdecl(s) }
else if (ident == Id::LDC_global_crt_ctor || ident == Id::LDC_global_crt_dtor)
{
dinteger_t priority;
if (args)
{
if (args->dim != 1 || !parseIntExp(expr, priority))
{
error("requires at most 1 integer literal parameter");
fatal();
}
if (priority > 65535)
{
error("priority may not be greater then 65535");
priority = 65535;
}
}
else
priority = 65535;
char buf[8];
sprintf(buf, "%lu", priority);
arg1str = std::string(buf);
return ident == Id::LDC_global_crt_ctor ? LLVMglobal_crt_ctor : LLVMglobal_crt_dtor;
}
// pragma(notypeinfo) { typedecl(s) }
else if (matchPragma(ident, Id::LDC_no_typeinfo, Id::no_typeinfo))
{
@@ -332,6 +370,36 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
fatal();
}
break;
case LLVMglobal_crt_ctor:
case LLVMglobal_crt_dtor:
if (FuncDeclaration* fd = s->isFuncDeclaration())
{
assert(fd->type->ty == Tfunction);
TypeFunction* type = static_cast<TypeFunction*>(fd->type);
Type* retType = type->next;
if (retType->ty != Tvoid || type->parameters->dim > 0 || (
#if DMDV2
fd->isAggregateMember()
#else
fd->isThis()
#endif
&& !fd->isStatic())) {
error(fd->loc, "the '%s' pragma is only allowed on void functions which take no arguments",
ident->toChars());
fd->llvmInternal = LLVMnone;
break;
}
fd->llvmInternal = llvm_internal;
fd->priority = std::atoi(arg1str.c_str());
}
else
{
error(s->loc, "the '%s' pragma is only allowed on function declarations",
ident->toChars());
s->llvmInternal = LLVMnone;
}
break;
case LLVMatomic_rmw:
if (TemplateDeclaration* td = s->isTemplateDeclaration())

View File

@@ -25,6 +25,8 @@ enum Pragma
LLVMnone, // Not an LDC pragma.
LLVMignore, // Pragma has already been processed in DtoGetPragma, ignore.
LLVMintrinsic,
LLVMglobal_crt_ctor,
LLVMglobal_crt_dtor,
LLVMno_typeinfo,
LLVMno_moduleinfo,
LLVMalloca,