From: Rafael Espindola Date: Thu, 4 Mar 2010 18:17:24 +0000 (+0000) Subject: Fix PR6473. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6a836706c40a31c716952b74785102c90fd6afa7;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97733 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 030d2c9c9f..dc9ecd64f4 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1062,6 +1062,16 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { const NamedDecl *ND = E->getDecl(); + if (ND->hasAttr()) { + const ValueDecl* VD = cast(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(ND)) { // Check if this is a global variable. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index bc2bd6c882..e6e9b1a595 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -619,9 +619,41 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { return false; } +llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { + const AliasAttr *AA = VD->getAttr(); + 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(DeclTy)) + Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl()); + else + Aliasee = GetOrCreateLLVMGlobal(AliaseeName, + llvm::PointerType::getUnqual(DeclTy), 0); + if (!Entry) { + llvm::GlobalValue* F = cast(Aliasee); + F->setLinkage(llvm::Function::ExternalWeakLinkage); + WeakRefReferences.insert(F); + } + + return Aliasee; +} + void CodeGenModule::EmitGlobal(GlobalDecl GD) { const ValueDecl *Global = cast(GD.getDecl()); + // Weak references don't produce any output by themselves. + if (Global->hasAttr()) + return; + // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr()) @@ -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(D.getDecl()); + if (FD && !FD->hasAttr()) + 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()) + Entry->setLinkage(llvm::Function::ExternalLinkage); + + WeakRefReferences.erase(Entry); + } + if (Entry->getType() == Ty) return Entry; diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index ac8332647b..c839b42559 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -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 @@ -117,6 +118,11 @@ class CodeGenModule : public BlockModule { /// pointer lookups instead of full string lookups. llvm::DenseMap 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 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); diff --git a/test/CodeGen/attr-weakref.c b/test/CodeGen/attr-weakref.c new file mode 100644 index 0000000000..06185e8e34 --- /dev/null +++ b/test/CodeGen/attr-weakref.c @@ -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(); +} diff --git a/test/CodeGen/attr-weakref2.c b/test/CodeGen/attr-weakref2.c new file mode 100644 index 0000000000..9976063558 --- /dev/null +++ b/test/CodeGen/attr-weakref2.c @@ -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; +} diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index 4fdf1a5176..770ce766df 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -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() {