mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 05:26:06 +00:00
Fix PR6473.
Clang's support for weakref is now better than llvm-gcc's :-) We don't introduce a new symbol and we correctly mark undefined references weak only if there is no definition or regular undefined references in the same file. llvm-svn: 97733
This commit is contained in:
parent
334db0ce7f
commit
2e42fec3a0
@ -1062,6 +1062,16 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
|
||||
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
||||
const NamedDecl *ND = E->getDecl();
|
||||
|
||||
if (ND->hasAttr<WeakRefAttr>()) {
|
||||
const ValueDecl* VD = cast<ValueDecl>(ND);
|
||||
llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD);
|
||||
|
||||
Qualifiers Quals = MakeQualifiers(E->getType());
|
||||
LValue LV = LValue::MakeAddr(Aliasee, Quals);
|
||||
|
||||
return LV;
|
||||
}
|
||||
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
|
||||
|
||||
// Check if this is a global variable.
|
||||
|
@ -619,9 +619,41 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
|
||||
const AliasAttr *AA = VD->getAttr<AliasAttr>();
|
||||
assert(AA && "No alias?");
|
||||
|
||||
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType());
|
||||
|
||||
// Unique the name through the identifier table.
|
||||
const char *AliaseeName =
|
||||
getContext().Idents.get(AA->getAliasee()).getNameStart();
|
||||
|
||||
// See if there is already something with the target's name in the module.
|
||||
llvm::GlobalValue *Entry = GlobalDeclMap[AliaseeName];
|
||||
|
||||
llvm::Constant *Aliasee;
|
||||
if (isa<llvm::FunctionType>(DeclTy))
|
||||
Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
|
||||
else
|
||||
Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
|
||||
llvm::PointerType::getUnqual(DeclTy), 0);
|
||||
if (!Entry) {
|
||||
llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
|
||||
F->setLinkage(llvm::Function::ExternalWeakLinkage);
|
||||
WeakRefReferences.insert(F);
|
||||
}
|
||||
|
||||
return Aliasee;
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitGlobal(GlobalDecl GD) {
|
||||
const ValueDecl *Global = cast<ValueDecl>(GD.getDecl());
|
||||
|
||||
// Weak references don't produce any output by themselves.
|
||||
if (Global->hasAttr<WeakRefAttr>())
|
||||
return;
|
||||
|
||||
// If this is an alias definition (which otherwise looks like a declaration)
|
||||
// emit it now.
|
||||
if (Global->hasAttr<AliasAttr>())
|
||||
@ -708,6 +740,14 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
|
||||
// Lookup the entry, lazily creating it if necessary.
|
||||
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
|
||||
if (Entry) {
|
||||
if (WeakRefReferences.count(Entry)) {
|
||||
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
|
||||
if (FD && !FD->hasAttr<WeakAttr>())
|
||||
Entry->setLinkage(llvm::Function::ExternalLinkage);
|
||||
|
||||
WeakRefReferences.erase(Entry);
|
||||
}
|
||||
|
||||
if (Entry->getType()->getElementType() == Ty)
|
||||
return Entry;
|
||||
|
||||
@ -817,6 +857,13 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName,
|
||||
// Lookup the entry, lazily creating it if necessary.
|
||||
llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
|
||||
if (Entry) {
|
||||
if (WeakRefReferences.count(Entry)) {
|
||||
if (D && !D->hasAttr<WeakAttr>())
|
||||
Entry->setLinkage(llvm::Function::ExternalLinkage);
|
||||
|
||||
WeakRefReferences.erase(Entry);
|
||||
}
|
||||
|
||||
if (Entry->getType() == Ty)
|
||||
return Entry;
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include <list>
|
||||
|
||||
@ -117,6 +118,11 @@ class CodeGenModule : public BlockModule {
|
||||
/// pointer lookups instead of full string lookups.
|
||||
llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap;
|
||||
|
||||
// WeakRefReferences - A set of references that have only been seen via
|
||||
// a weakref so far. This is used to remove the weak of the reference if we ever
|
||||
// see a direct reference or a definition.
|
||||
llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences;
|
||||
|
||||
/// \brief Contains the strings used for mangled names.
|
||||
///
|
||||
/// FIXME: Eventually, this should map from the semantic/canonical
|
||||
@ -243,6 +249,9 @@ public:
|
||||
void BuildThunksForVirtual(GlobalDecl GD);
|
||||
void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD);
|
||||
|
||||
/// GetWeakRefReference - Get a reference to the target of VD.
|
||||
llvm::Constant *GetWeakRefReference(const ValueDecl *VD);
|
||||
|
||||
/// BuildThunk - Build a thunk for the given method.
|
||||
llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern,
|
||||
const ThunkAdjustment &ThisAdjustment);
|
||||
|
54
clang/test/CodeGen/attr-weakref.c
Normal file
54
clang/test/CodeGen/attr-weakref.c
Normal file
@ -0,0 +1,54 @@
|
||||
// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu -o %t %s
|
||||
// RUN: FileCheck --input-file=%t %s
|
||||
|
||||
// CHECK: declare extern_weak void @test1_f()
|
||||
void test1_f(void);
|
||||
static void test1_g(void) __attribute__((weakref("test1_f")));
|
||||
void test1_h(void) {
|
||||
test1_g();
|
||||
}
|
||||
|
||||
// CHECK: define void @test2_f()
|
||||
void test2_f(void) {}
|
||||
static void test2_g(void) __attribute__((weakref("test2_f")));
|
||||
void test2_h(void) {
|
||||
test2_g();
|
||||
}
|
||||
|
||||
// CHECK: declare void @test3_f()
|
||||
void test3_f(void);
|
||||
static void test3_g(void) __attribute__((weakref("test3_f")));
|
||||
void test3_foo(void) {
|
||||
test3_f();
|
||||
}
|
||||
void test3_h(void) {
|
||||
test3_g();
|
||||
}
|
||||
|
||||
// CHECK: define void @test4_f()
|
||||
void test4_f(void);
|
||||
static void test4_g(void) __attribute__((weakref("test4_f")));
|
||||
void test4_h(void) {
|
||||
test4_g();
|
||||
}
|
||||
void test4_f(void) {}
|
||||
|
||||
// CHECK: declare void @test5_f()
|
||||
void test5_f(void);
|
||||
static void test5_g(void) __attribute__((weakref("test5_f")));
|
||||
void test5_h(void) {
|
||||
test5_g();
|
||||
}
|
||||
void test5_foo(void) {
|
||||
test5_f();
|
||||
}
|
||||
|
||||
// CHECK: declare extern_weak void @test6_f()
|
||||
void test6_f(void) __attribute__((weak));
|
||||
static void test6_g(void) __attribute__((weakref("test6_f")));
|
||||
void test6_h(void) {
|
||||
test6_g();
|
||||
}
|
||||
void test6_foo(void) {
|
||||
test6_f();
|
||||
}
|
54
clang/test/CodeGen/attr-weakref2.c
Normal file
54
clang/test/CodeGen/attr-weakref2.c
Normal file
@ -0,0 +1,54 @@
|
||||
// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu -o %t %s
|
||||
// RUN: FileCheck --input-file=%t %s
|
||||
|
||||
// CHECK: @test1_f = extern_weak global i32
|
||||
extern int test1_f;
|
||||
static int test1_g __attribute__((weakref("test1_f")));
|
||||
int test1_h(void) {
|
||||
return test1_g;
|
||||
}
|
||||
|
||||
// CHECK: @test2_f = common global i32 0, align 4
|
||||
int test2_f;
|
||||
static int test2_g __attribute__((weakref("test2_f")));
|
||||
int test2_h(void) {
|
||||
return test2_g;
|
||||
}
|
||||
|
||||
// CHECK: @test3_f = external global i32
|
||||
extern int test3_f;
|
||||
static int test3_g __attribute__((weakref("test3_f")));
|
||||
int test3_foo(void) {
|
||||
return test3_f;
|
||||
}
|
||||
int test3_h(void) {
|
||||
return test3_g;
|
||||
}
|
||||
|
||||
// CHECK: @test4_f = common global i32 0, align 4
|
||||
extern int test4_f;
|
||||
static int test4_g __attribute__((weakref("test4_f")));
|
||||
int test4_h(void) {
|
||||
return test4_g;
|
||||
}
|
||||
int test4_f;
|
||||
|
||||
// CHECK: @test5_f = external global i32
|
||||
extern int test5_f;
|
||||
static int test5_g __attribute__((weakref("test5_f")));
|
||||
int test5_h(void) {
|
||||
return test5_g;
|
||||
}
|
||||
int test5_foo(void) {
|
||||
return test5_f;
|
||||
}
|
||||
|
||||
// CHECK: @test6_f = extern_weak global i32
|
||||
extern int test6_f __attribute__((weak));
|
||||
static int test6_g __attribute__((weakref("test6_f")));
|
||||
int test6_h(void) {
|
||||
return test6_g;
|
||||
}
|
||||
int test6_foo(void) {
|
||||
return test6_f;
|
||||
}
|
@ -30,12 +30,6 @@ int t12 __attribute__((section("SECT")));
|
||||
void __t8() {}
|
||||
void t9() __attribute__((weak, alias("__t8")));
|
||||
|
||||
static void t22(void) __attribute__((weakref("t8")));
|
||||
// CHECK: @t22 = alias weak void ()* @t8
|
||||
|
||||
static void t23(void) __attribute__((weakref, alias("t8")));
|
||||
// CHECK: @t23 = alias weak void ()* @t8
|
||||
|
||||
// CHECK: declare extern_weak i32 @t15()
|
||||
int __attribute__((weak_import)) t15(void);
|
||||
int t17() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user