patch/idea: set unnamed_addr on linkonce_odr early

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 22 14:37:46 PST 2015


The attached patch changes GlobalOpt to set unnamed_addr on
linkonce_odr GVs. The idea is that it marks that the address of *this*
GV is not relevant. If it is in another module the IR linker will
correctly drop the unnamed_addr.

With that we can simplify LTO since we can depend on unnamed_addr to
decide whether a linkonce_odr can be removed from the symbol table or
not.

I tested the attached patch with a clang bootstrap on linux. There
were only 69 GVs with linkonce_odr left in clang, and they all seem to
have their addresses used.

Cheers,
Rafael
-------------- next part --------------
diff --git a/lib/CodeGen/Analysis.cpp b/lib/CodeGen/Analysis.cpp
index 75579a2..857c813 100644
--- a/lib/CodeGen/Analysis.cpp
+++ b/lib/CodeGen/Analysis.cpp
@@ -624,9 +624,6 @@ bool llvm::canBeOmittedFromSymbolTable(const GlobalValue *GV) {
   if (!GV->hasLinkOnceODRLinkage())
     return false;
 
-  if (GV->hasUnnamedAddr())
-    return true;
-
   // If it is a non constant variable, it needs to be uniqued across shared
   // objects.
   if (const GlobalVariable *Var = dyn_cast<GlobalVariable>(GV)) {
@@ -639,11 +636,7 @@ bool llvm::canBeOmittedFromSymbolTable(const GlobalValue *GV) {
   if (isa<GlobalAlias>(GV))
     return false;
 
-  GlobalStatus GS;
-  if (GlobalStatus::analyzeGlobal(GV, GS))
-    return false;
-
-  return !GS.IsCompared;
+  return GV->hasUnnamedAddr();
 }
 
 static void collectFuncletMembers(
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index fd773690..03acd99 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1706,23 +1706,25 @@ bool GlobalOpt::deleteIfDead(GlobalValue &GV) {
 /// Analyze the specified global variable and optimize it if possible.  If we
 /// make a change, return true.
 bool GlobalOpt::processGlobal(GlobalValue &GV) {
-  // Do more involved optimizations if the global is internal.
-  if (!GV.hasLocalLinkage())
+  if (!GV.hasLocalLinkage() && !GV.hasLinkOnceODRLinkage())
     return false;
 
   GlobalStatus GS;
-
   if (GlobalStatus::analyzeGlobal(&GV, GS))
     return false;
 
+  auto *GVar = dyn_cast<GlobalVariable>(&GV);
   bool Changed = false;
-  if (!GS.IsCompared && !GV.hasUnnamedAddr()) {
+  if (!GS.IsCompared && !GV.hasUnnamedAddr() && (!GVar || GVar->isConstant())) {
     GV.setUnnamedAddr(true);
     NumUnnamed++;
     Changed = true;
   }
 
-  auto *GVar = dyn_cast<GlobalVariable>(&GV);
+  // Do more involved optimizations if the global is internal.
+  if (!GV.hasLocalLinkage())
+    return false;
+
   if (!GVar)
     return Changed;
 
diff --git a/test/CodeGen/PowerPC/weak_def_can_be_hidden.ll b/test/CodeGen/PowerPC/weak_def_can_be_hidden.ll
index 0b87613..45220af 100644
--- a/test/CodeGen/PowerPC/weak_def_can_be_hidden.ll
+++ b/test/CodeGen/PowerPC/weak_def_can_be_hidden.ll
@@ -3,7 +3,7 @@
 ; RUN: llc -mtriple=powerpc-apple-darwin9 -O0 < %s | FileCheck --check-prefix=CHECK-D89 %s
 ; RUN: llc -mtriple=powerpc-apple-darwin8 -O0 < %s | FileCheck --check-prefix=CHECK-D89 %s
 
- at v1 = linkonce_odr constant i32 32
+ at v1 = linkonce_odr unnamed_addr constant i32 32
 ; CHECK: .globl  _v1
 ; CHECK: .weak_def_can_be_hidden _v1
 
@@ -26,7 +26,7 @@ define i32* @f2() {
   ret i32* @v2
 }
 
- at v3 = linkonce_odr unnamed_addr global i32 32
+ at v3 = linkonce_odr unnamed_addr constant i32 32
 ; CHECK: .globl  _v3
 ; CHECK: .weak_def_can_be_hidden _v3
 
diff --git a/test/CodeGen/X86/weak_def_can_be_hidden.ll b/test/CodeGen/X86/weak_def_can_be_hidden.ll
index 8e6d34c..673b814 100644
--- a/test/CodeGen/X86/weak_def_can_be_hidden.ll
+++ b/test/CodeGen/X86/weak_def_can_be_hidden.ll
@@ -4,7 +4,7 @@
 ; RUN: llc -mtriple=i686-apple-darwin9 -O0 < %s | FileCheck --check-prefix=CHECK-D89 %s
 ; RUN: llc -mtriple=i686-apple-darwin8 -O0 < %s | FileCheck --check-prefix=CHECK-D89 %s
 
- at v1 = linkonce_odr constant i32 32
+ at v1 = linkonce_odr unnamed_addr constant i32 32
 ; CHECK: .globl  _v1
 ; CHECK: .weak_def_can_be_hidden _v1
 
@@ -27,7 +27,7 @@ define i32* @f2() {
   ret i32* @v2
 }
 
- at v3 = linkonce_odr unnamed_addr global i32 32
+ at v3 = linkonce_odr unnamed_addr constant i32 32
 ; CHECK: .globl  _v3
 ; CHECK: .weak_def_can_be_hidden _v3
 
diff --git a/test/LTO/X86/cfi_endproc.ll b/test/LTO/X86/cfi_endproc.ll
index 57d822b..7a9ab2b 100644
--- a/test/LTO/X86/cfi_endproc.ll
+++ b/test/LTO/X86/cfi_endproc.ll
@@ -33,8 +33,8 @@ define i32* @get_zed1() {
   ret i32* @zed1
 }
 
-; ZED1_AND_ZED2: d zed2
- at zed2 = linkonce_odr unnamed_addr global i32 42
+; ZED1_AND_ZED2: r zed2
+ at zed2 = linkonce_odr unnamed_addr constant i32 42
 
 define i32 @useZed2() {
   %x = load i32, i32* @zed2
diff --git a/test/LTO/X86/linkonce_odr_func.ll b/test/LTO/X86/linkonce_odr_func.ll
index 671b30a..4821528 100644
--- a/test/LTO/X86/linkonce_odr_func.ll
+++ b/test/LTO/X86/linkonce_odr_func.ll
@@ -7,7 +7,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 target triple = "x86_64-unknown-linux-gnu"
 
 ; CHECK: t foo1
-define linkonce_odr void @foo1() noinline {
+define linkonce_odr void @foo1() unnamed_addr noinline{
   ret void
 }
 
@@ -17,7 +17,7 @@ define linkonce_odr void @foo2() noinline {
 }
 
 ; CHECK: t foo3
-define linkonce_odr void @foo3() noinline {
+define linkonce_odr void @foo3() unnamed_addr noinline {
   ret void
 }
 
@@ -27,7 +27,7 @@ define linkonce_odr void @foo4() noinline {
 }
 
 ; CHECK: r v1
- at v1 = linkonce_odr constant i32 32
+ at v1 = linkonce_odr unnamed_addr constant i32 32
 
 define i32 @useV1() {
   %x = load i32, i32* @v1
diff --git a/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll b/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll
index 934d928..3d7a122 100644
--- a/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll
+++ b/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll
@@ -2,9 +2,9 @@
 ; alignments.  Elements 0 and 2 must be 16-byte aligned, and element 
 ; 1 must be at least 8 byte aligned (but could be more). 
 
-; RUN: opt < %s -globalopt -S | grep "@G.0 = internal unnamed_addr global .*align 16"
-; RUN: opt < %s -globalopt -S | grep "@G.1 = internal unnamed_addr global .*align 8"
-; RUN: opt < %s -globalopt -S | grep "@G.2 = internal unnamed_addr global .*align 16"
+; RUN: opt < %s -globalopt -S | grep "@G.0 = internal global .*align 16"
+; RUN: opt < %s -globalopt -S | grep "@G.1 = internal global .*align 8"
+; RUN: opt < %s -globalopt -S | grep "@G.2 = internal global .*align 16"
 ; rdar://5891920
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
diff --git a/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll b/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll
index 469fa76..2a0cbb4 100644
--- a/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll
+++ b/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -globalopt -S | grep "@X = internal unnamed_addr global i32"
+; RUN: opt < %s -globalopt -S | grep "@X = internal global i32"
 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
 target triple = "i386-apple-darwin7"
 @X = internal global i32* null		; <i32**> [#uses=2]
diff --git a/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll b/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll
index 25bb976..705137c 100644
--- a/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll
+++ b/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll
@@ -8,7 +8,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 target triple = "x86_64-apple-darwin10.0"
 
 @TOP = internal global i64* null                    ; <i64**> [#uses=2]
-; CHECK: @TOP = internal unnamed_addr global i64* null
+; CHECK: @TOP = internal global i64* null
 @channelColumns = internal global i64 0             ; <i64*> [#uses=2]
 
 ; Derived from @DescribeChannel() in yacr2
diff --git a/test/Transforms/GlobalOpt/atomic.ll b/test/Transforms/GlobalOpt/atomic.ll
index 563c1fe..fd0a90f 100644
--- a/test/Transforms/GlobalOpt/atomic.ll
+++ b/test/Transforms/GlobalOpt/atomic.ll
@@ -4,7 +4,7 @@
 @GV2 = internal global i32 0
 
 ; CHECK: @GV1 = internal unnamed_addr constant i64 1
-; CHECK: @GV2 = internal unnamed_addr global i32 0
+; CHECK: @GV2 = internal global i32 0
 
 define void @test1() {
 entry:
diff --git a/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll b/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll
index b446d24..f5e6255 100644
--- a/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll
+++ b/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll
@@ -4,11 +4,11 @@
 ; should keep that flag set on all of the new globals. This will prevent the
 ; store to @a[0] from being constant propagated to the load in @foo, but will not
 ; prevent @a[1] from being removed since it is dead.
-; CHECK: @a.0 = internal unnamed_addr externally_initialized global i32 undef
+; CHECK: @a.0 = internal externally_initialized global i32 undef
 ; CHECK-NOT @a.1
 @a = internal externally_initialized global [2 x i32] undef, align 4
 ; This is the same, but a struct rather than an array.
-; CHECK: @b.0 = internal unnamed_addr externally_initialized global i32 undef
+; CHECK: @b.0 = internal externally_initialized global i32 undef
 ; CHECK-NOT @b.1
 @b = internal externally_initialized global {i32, i32} undef, align 4
 
diff --git a/test/Transforms/GlobalOpt/externally-initialized.ll b/test/Transforms/GlobalOpt/externally-initialized.ll
index c01ba10..7194419 100644
--- a/test/Transforms/GlobalOpt/externally-initialized.ll
+++ b/test/Transforms/GlobalOpt/externally-initialized.ll
@@ -3,13 +3,13 @@
 ; This global is externally_initialized, which may modify the value between
 ; it's static initializer and any code in this module being run, so the only
 ; write to it cannot be merged into the static initialiser.
-; CHECK: @a = internal unnamed_addr externally_initialized global i32 undef
+; CHECK: @a = internal externally_initialized global i32 undef
 @a = internal externally_initialized global i32 undef
 
 ; This global is stored to by the external initialization, so cannot be
 ; constant-propagated and removed, despite the fact that there are no writes
 ; to it.
-; CHECK: @b = internal unnamed_addr externally_initialized global i32 undef
+; CHECK: @b = internal externally_initialized global i32 undef
 @b = internal externally_initialized global i32 undef
 
 
diff --git a/test/Transforms/GlobalOpt/globalsra-unknown-index.ll b/test/Transforms/GlobalOpt/globalsra-unknown-index.ll
index 5194b2c..db13fdc 100644
--- a/test/Transforms/GlobalOpt/globalsra-unknown-index.ll
+++ b/test/Transforms/GlobalOpt/globalsra-unknown-index.ll
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -globalopt -S > %t
-; RUN: grep "@Y = internal unnamed_addr global \[3 x [%]struct.X\] zeroinitializer" %t
+; RUN: grep "@Y = internal global \[3 x [%]struct.X\] zeroinitializer" %t
 ; RUN: grep load %t | count 6
 ; RUN: grep "add i32 [%]a, [%]b" %t | count 3
 
diff --git a/test/Transforms/GlobalOpt/pr21191.ll b/test/Transforms/GlobalOpt/pr21191.ll
index 34e15cb..ad037d2 100644
--- a/test/Transforms/GlobalOpt/pr21191.ll
+++ b/test/Transforms/GlobalOpt/pr21191.ll
@@ -6,12 +6,12 @@ $c = comdat any
 define linkonce_odr void @foo() comdat($c) {
   ret void
 }
-; CHECK: define linkonce_odr void @foo() comdat($c)
+; CHECK: define linkonce_odr void @foo() unnamed_addr comdat($c)
 
 define linkonce_odr void @bar() comdat($c) {
   ret void
 }
-; CHECK: define linkonce_odr void @bar() comdat($c)
+; CHECK: define linkonce_odr void @bar() unnamed_addr comdat($c)
 
 define void @zed()  {
   call void @foo()
diff --git a/test/Transforms/GlobalOpt/unnamed-addr.ll b/test/Transforms/GlobalOpt/unnamed-addr.ll
index de436c6..720b5f3 100644
--- a/test/Transforms/GlobalOpt/unnamed-addr.ll
+++ b/test/Transforms/GlobalOpt/unnamed-addr.ll
@@ -2,13 +2,13 @@
 
 @a = internal global i32 0, align 4
 @b = internal global i32 0, align 4
- at c = internal global i32 0, align 4
+ at c = internal constant i32 0, align 4
 @d = internal constant [4 x i8] c"foo\00", align 1
 @e = linkonce_odr global i32 0
 
 ; CHECK: @a = internal global i32 0, align 4
 ; CHECK: @b = internal global i32 0, align 4
-; CHECK: @c = internal unnamed_addr global i32 0, align 4
+; CHECK: @c = internal unnamed_addr constant i32 0, align 4
 ; CHECK: @d = internal unnamed_addr constant [4 x i8] c"foo\00", align 1
 ; CHECK: @e = linkonce_odr global i32 0
 
diff --git a/test/tools/gold/X86/coff.ll b/test/tools/gold/X86/coff.ll
index 5d8a1c9..f503a9f 100644
--- a/test/tools/gold/X86/coff.ll
+++ b/test/tools/gold/X86/coff.ll
@@ -16,7 +16,7 @@ define hidden void @g() {
   ret void
 }
 
-; CHECK: define internal void @h() {
-define linkonce_odr void @h() {
+; CHECK: define internal void @h() unnamed_addr {
+define linkonce_odr void @h() unnamed_addr {
   ret void
 }
diff --git a/test/tools/gold/X86/emit-llvm.ll b/test/tools/gold/X86/emit-llvm.ll
index 4a6d596..49b6277 100644
--- a/test/tools/gold/X86/emit-llvm.ll
+++ b/test/tools/gold/X86/emit-llvm.ll
@@ -53,7 +53,7 @@ define void @f3() {
 
 ; CHECK-DAG: define internal void @f4()
 ; OPT2-NOT: @f4
-define linkonce_odr void @f4() {
+define linkonce_odr void @f4() unnamed_addr {
   ret void
 }
 
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index b6acea7..e95b8c4 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -595,8 +595,7 @@ getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
 static std::unique_ptr<Module>
 getModuleForFile(LLVMContext &Context, claimed_file &F,
                  ld_plugin_input_file &Info, raw_fd_ostream *ApiFile,
-                 StringSet<> &Internalize, StringSet<> &Maybe,
-                 std::vector<GlobalValue *> &Keep) {
+                 StringSet<> &Internalize, std::vector<GlobalValue *> &Keep) {
 
   if (get_symbols(F.handle, F.syms.size(), F.syms.data()) != LDPS_OK)
     message(LDPL_FATAL, "Failed to get symbol information");
@@ -647,12 +646,16 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
     }
 
     ResolutionInfo &Res = ResInfo[Sym.name];
-    if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP && !Res.IsLinkonceOdr)
-      Resolution = LDPR_PREVAILING_DEF;
-
     GV->setUnnamedAddr(Res.UnnamedAddr);
     GV->setVisibility(Res.Visibility);
 
+    if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) {
+      if (!Res.IsLinkonceOdr)
+        Resolution = LDPR_PREVAILING_DEF;
+      else if (canBeOmittedFromSymbolTable(GV))
+        Resolution = LDPR_PREVAILING_DEF_IRONLY;
+    }
+
     // Override gold's resolution for common symbols. We want the largest
     // one to win.
     if (GV->hasCommonLinkage()) {
@@ -714,16 +717,10 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
       }
       break;
 
-    case LDPR_PREVAILING_DEF_IRONLY_EXP: {
-      // We can only check for address uses after we merge the modules. The
-      // reason is that this GV might have a copy in another module
-      // and in that module the address might be significant, but that
-      // copy will be LDPR_PREEMPTED_IR.
-      Maybe.insert(GV->getName());
+    case LDPR_PREVAILING_DEF_IRONLY_EXP:
       Keep.push_back(GV);
       break;
     }
-    }
 
     freeSymName(Sym);
   }
@@ -896,12 +893,11 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
   std::string DefaultTriple = sys::getDefaultTargetTriple();
 
   StringSet<> Internalize;
-  StringSet<> Maybe;
   for (claimed_file &F : Modules) {
     PluginInputFile InputFile(F.handle);
     std::vector<GlobalValue *> Keep;
-    std::unique_ptr<Module> M = getModuleForFile(
-        Context, F, InputFile.file(), ApiFile, Internalize, Maybe, Keep);
+    std::unique_ptr<Module> M = getModuleForFile(Context, F, InputFile.file(),
+                                                 ApiFile, Internalize, Keep);
     if (!options::triple.empty())
       M->setTargetTriple(options::triple.c_str());
     else if (M->getTargetTriple().empty())
@@ -917,15 +913,6 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
       internalize(*GV);
   }
 
-  for (const auto &Name : Maybe) {
-    GlobalValue *GV = Combined->getNamedValue(Name.first());
-    if (!GV)
-      continue;
-    GV->setLinkage(GlobalValue::LinkOnceODRLinkage);
-    if (canBeOmittedFromSymbolTable(GV))
-      internalize(*GV);
-  }
-
   if (options::TheOutputType == options::OT_DISABLE)
     return LDPS_OK;
 


More information about the llvm-commits mailing list