mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 15:10:59 +03:00
Add pragma(LDC_extern_weak) for symbols with (ELF-style) weak linkage.
For now, this is only an internal feature to be used in the implementation of rt.sections_linux.
This commit is contained in:
parent
36e9465b7a
commit
fc7acc48fc
7 changed files with 78 additions and 5 deletions
|
@ -24,6 +24,10 @@
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
#include "utf.h"
|
#include "utf.h"
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
#include "gen/pragma.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LOG 0
|
#define LOG 0
|
||||||
|
|
||||||
int RealEquals(real_t x1, real_t x2);
|
int RealEquals(real_t x1, real_t x2);
|
||||||
|
@ -68,6 +72,13 @@ int NullExp::isConst()
|
||||||
|
|
||||||
int SymOffExp::isConst()
|
int SymOffExp::isConst()
|
||||||
{
|
{
|
||||||
|
#if IN_LLVM
|
||||||
|
// We don't statically know anything about the address of a weak symbol
|
||||||
|
// if there is no offset. With an offset, we can at least say that it is
|
||||||
|
// non-zero.
|
||||||
|
if (var->llvmInternal == LLVMextern_weak && !offset)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@
|
||||||
#include "doc.h"
|
#include "doc.h"
|
||||||
#include "aav.h"
|
#include "aav.h"
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
#include "gen/pragma.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
bool isArrayOpValid(Expression *e);
|
bool isArrayOpValid(Expression *e);
|
||||||
#if IN_DMD
|
#if IN_DMD
|
||||||
Expression *createTypeInfoArray(Scope *sc, Expression *args[], size_t dim);
|
Expression *createTypeInfoArray(Scope *sc, Expression *args[], size_t dim);
|
||||||
|
@ -5608,6 +5612,14 @@ Expression *SymOffExp::semantic(Scope *sc)
|
||||||
|
|
||||||
int SymOffExp::isBool(int result)
|
int SymOffExp::isBool(int result)
|
||||||
{
|
{
|
||||||
|
#if IN_LLVM
|
||||||
|
// For a weak symbol, we only statically know that it is non-null if the
|
||||||
|
// offset is non-zero.
|
||||||
|
if (var->llvmInternal == LLVMextern_weak)
|
||||||
|
{
|
||||||
|
return result && offset != 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return result ? true : false;
|
return result ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,7 @@ Msgtable msgtable[] =
|
||||||
{ "LDC_atomic_rmw" },
|
{ "LDC_atomic_rmw" },
|
||||||
{ "LDC_global_crt_ctor" },
|
{ "LDC_global_crt_ctor" },
|
||||||
{ "LDC_global_crt_dtor" },
|
{ "LDC_global_crt_dtor" },
|
||||||
|
{ "LDC_extern_weak" },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For special functions
|
// For special functions
|
||||||
|
|
|
@ -1055,12 +1055,17 @@ void DtoResolveVariable(VarDeclaration* vd)
|
||||||
// vd->ir.irGlobal->value!), and in case we also do an initializer
|
// vd->ir.irGlobal->value!), and in case we also do an initializer
|
||||||
// with a different type later, swap it out and replace any existing
|
// with a different type later, swap it out and replace any existing
|
||||||
// uses with bitcasts to the previous type.
|
// uses with bitcasts to the previous type.
|
||||||
//
|
|
||||||
// We always start out with external linkage; any other type is set
|
// We always start out with external linkage; any other type is set
|
||||||
// when actually defining it in VarDeclaration::codegen.
|
// when actually defining it in VarDeclaration::codegen.
|
||||||
|
llvm::GlobalValue::LinkageTypes linkage = llvm::GlobalValue::ExternalLinkage;
|
||||||
|
if (vd->llvmInternal == LLVMextern_weak) {
|
||||||
|
linkage = llvm::GlobalValue::ExternalWeakLinkage;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::GlobalVariable* gvar = getOrCreateGlobal(vd->loc, *gIR->module,
|
llvm::GlobalVariable* gvar = getOrCreateGlobal(vd->loc, *gIR->module,
|
||||||
i1ToI8(DtoType(vd->type)), isLLConst, llvm::GlobalValue::ExternalLinkage,
|
i1ToI8(DtoType(vd->type)), isLLConst, linkage, 0, llName,
|
||||||
0, llName, vd->isThreadlocal());
|
vd->isThreadlocal());
|
||||||
vd->ir.irGlobal->value = gvar;
|
vd->ir.irGlobal->value = gvar;
|
||||||
|
|
||||||
// Set the alignment (it is important not to use type->alignsize because
|
// Set the alignment (it is important not to use type->alignsize because
|
||||||
|
|
|
@ -287,6 +287,17 @@ Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str)
|
||||||
return LLVMinline_ir;
|
return LLVMinline_ir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pragma(LDC_extern_weak) { vardecl(s) }
|
||||||
|
else if (ident == Id::LDC_extern_weak)
|
||||||
|
{
|
||||||
|
if (args && args->dim > 0)
|
||||||
|
{
|
||||||
|
error(Loc(), "takes no parameters");
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
return LLVMextern_weak;
|
||||||
|
}
|
||||||
|
|
||||||
return LLVMnone;
|
return LLVMnone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,6 +522,38 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LLVMextern_weak:
|
||||||
|
if (VarDeclaration* vd = s->isVarDeclaration())
|
||||||
|
{
|
||||||
|
if (!vd->isDataseg() || !(vd->storage_class & STCextern)) {
|
||||||
|
error(s->loc, "'%s' requires storage class 'extern'",
|
||||||
|
ident->toChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// It seems like the interaction between weak symbols and thread-local
|
||||||
|
// storage is not well-defined (the address of an undefined weak TLS
|
||||||
|
// symbol is non-zero on the ELF static TLS model on Linux x86_64).
|
||||||
|
// Thus, just disallow this altogether.
|
||||||
|
if (vd->isThreadlocal()) {
|
||||||
|
error(s->loc, "'%s' cannot be applied to thread-local variable '%s'",
|
||||||
|
ident->toChars(), vd->toPrettyChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
vd->llvmInternal = llvm_internal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Currently, things like "pragma(LDC_extern_weak) extern int foo;"
|
||||||
|
// fail because 'extern' creates an intermediate
|
||||||
|
// StorageClassDeclaration. This might eventually be fixed by making
|
||||||
|
// extern_weak a proper storage class.
|
||||||
|
error(s->loc, "the '%s' pragma can only be specified directly on "
|
||||||
|
"variable declarations for now", ident->toChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
warning(s->loc,
|
warning(s->loc,
|
||||||
"the LDC specific pragma '%s' is not yet implemented, ignoring",
|
"the LDC specific pragma '%s' is not yet implemented, ignoring",
|
||||||
|
|
|
@ -44,7 +44,8 @@ enum Pragma
|
||||||
LLVMbitop_bt,
|
LLVMbitop_bt,
|
||||||
LLVMbitop_btc,
|
LLVMbitop_btc,
|
||||||
LLVMbitop_btr,
|
LLVMbitop_btr,
|
||||||
LLVMbitop_bts
|
LLVMbitop_bts,
|
||||||
|
LLVMextern_weak
|
||||||
};
|
};
|
||||||
|
|
||||||
Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str);
|
Pragma DtoGetPragma(Scope *sc, PragmaDeclaration *decl, std::string &arg1str);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c81979c297785fd53735300767f22e95312b0d80
|
Subproject commit d19b2ef57b27cc8b430d940e1beda0eb9ba8153d
|
Loading…
Add table
Add a link
Reference in a new issue