Add unnamed_addr when we can show that address of a global is not used.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 19 Jan 2011 16:32:21 +0000 (16:32 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 19 Jan 2011 16:32:21 +0000 (16:32 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123834 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/GlobalOpt.cpp
test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll
test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll
test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll
test/Transforms/GlobalOpt/globalsra-unknown-index.ll
test/Transforms/GlobalOpt/memcpy.ll
test/Transforms/GlobalOpt/unnamed-addr.ll [new file with mode: 0644]

index ff6972072c9f358913a96bd95f9b1dd9673d2222..37ccc04d1470477bca7b810a19a34e39bfdbb5e7 100644 (file)
@@ -40,6 +40,7 @@
 using namespace llvm;
 
 STATISTIC(NumMarked    , "Number of globals marked constant");
+STATISTIC(NumUnnamed   , "Number of globals marked unnamed_addr");
 STATISTIC(NumSRA       , "Number of aggregate globals broken into scalars");
 STATISTIC(NumHeapSRA   , "Number of heap objects SRA'd");
 STATISTIC(NumSubstitute,"Number of globals with initializers stored into them");
@@ -55,6 +56,7 @@ STATISTIC(NumAliasesResolved, "Number of global aliases resolved");
 STATISTIC(NumAliasesRemoved, "Number of global aliases eliminated");
 
 namespace {
+  struct GlobalStatus;
   struct GlobalOpt : public ModulePass {
     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
     }
@@ -71,7 +73,10 @@ namespace {
     bool OptimizeGlobalVars(Module &M);
     bool OptimizeGlobalAliases(Module &M);
     bool OptimizeGlobalCtorsList(GlobalVariable *&GCL);
-    bool ProcessInternalGlobal(GlobalVariable *GV,Module::global_iterator &GVI);
+    bool ProcessGlobal(GlobalVariable *GV,Module::global_iterator &GVI);
+    bool ProcessInternalGlobal(GlobalVariable *GV,Module::global_iterator &GVI,
+                               const SmallPtrSet<const PHINode*, 16> &PHIUsers,
+                               const GlobalStatus &GS);
   };
 }
 
@@ -87,6 +92,9 @@ namespace {
 /// about it.  If we find out that the address of the global is taken, none of
 /// this info will be accurate.
 struct GlobalStatus {
+  /// isCompared - True if the global's address is used in a comparison.
+  bool isCompared;
+
   /// isLoaded - True if the global is ever loaded.  If the global isn't ever
   /// loaded it can be deleted.
   bool isLoaded;
@@ -132,9 +140,10 @@ struct GlobalStatus {
   /// HasPHIUser - Set to true if this global has a user that is a PHI node.
   bool HasPHIUser;
 
-  GlobalStatus() : isLoaded(false), StoredType(NotStored), StoredOnceValue(0),
-                   AccessingFunction(0), HasMultipleAccessingFunctions(false),
-                   HasNonInstructionUser(false), HasPHIUser(false) {}
+  GlobalStatus() : isCompared(false), isLoaded(false), StoredType(NotStored),
+                   StoredOnceValue(0), AccessingFunction(0),
+                   HasMultipleAccessingFunctions(false), HasNonInstructionUser(false),
+                   HasPHIUser(false) {}
 };
 
 }
@@ -228,7 +237,7 @@ static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS,
           if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
         GS.HasPHIUser = true;
       } else if (isa<CmpInst>(I)) {
-        // Nothing to analyse.
+        GS.isCompared = true;
       } else if (isa<MemTransferInst>(I)) {
         const MemTransferInst *MTI = cast<MemTransferInst>(I);
         if (MTI->getArgOperand(0) == V)
@@ -1691,10 +1700,12 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
 
 /// ProcessInternalGlobal - Analyze the specified global variable and optimize
 /// it if possible.  If we make a change, return true.
-bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
-                                      Module::global_iterator &GVI) {
-  SmallPtrSet<const PHINode*, 16> PHIUsers;
-  GlobalStatus GS;
+bool GlobalOpt::ProcessGlobal(GlobalVariable *GV,
+                              Module::global_iterator &GVI) {
+  if (!GV->hasLocalLinkage())
+    return false;
+
+  // Do more involved optimizations if the global is internal.
   GV->removeDeadConstantUsers();
 
   if (GV->use_empty()) {
@@ -1704,9 +1715,29 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
     return true;
   }
 
+  SmallPtrSet<const PHINode*, 16> PHIUsers;
+  GlobalStatus GS;
+
   if (AnalyzeGlobal(GV, GS, PHIUsers))
     return false;
 
+  if (!GS.isCompared && !GV->hasUnnamedAddr()) {
+    GV->setUnnamedAddr(true);
+    NumUnnamed++;
+  }
+
+  if (GV->isConstant() || !GV->hasInitializer())
+    return false;
+
+  return ProcessInternalGlobal(GV, GVI, PHIUsers, GS);
+}
+
+/// ProcessInternalGlobal - Analyze the specified global variable and optimize
+/// it if possible.  If we make a change, return true.
+bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
+                                      Module::global_iterator &GVI,
+                                      const SmallPtrSet<const PHINode*, 16> &PHIUsers,
+                                      const GlobalStatus &GS) {
   // If this is a first class global and has only one accessing function
   // and this function is main (which we know is not recursive we can make
   // this global a local variable) we replace the global with a local alloca
@@ -1903,10 +1934,8 @@ bool GlobalOpt::OptimizeGlobalVars(Module &M) {
         if (New && New != CE)
           GV->setInitializer(New);
       }
-    // Do more involved optimizations if the global is internal.
-    if (!GV->isConstant() && GV->hasLocalLinkage() &&
-        GV->hasInitializer())
-      Changed |= ProcessInternalGlobal(GV, GVI);
+
+    Changed |= ProcessGlobal(GV, GVI);
   }
   return Changed;
 }
index cfc9f302ff007ec042daeb9dd124aedafb680f2e..5b06fea5d92c5bc8bf7debf0cf4cb9d6468586df 100644 (file)
@@ -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 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}
+; 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}
 ; 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"
index e024fc27ecb6cadee30af5c39aed0bd3b7f2a20a..d645ce49438bd81e6f6cc8f7fb5c98ffc936f501 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt < %s -globalopt -S | grep {@X = internal global i32}
+; RUN: opt < %s -globalopt -S | grep {@X = internal unnamed_addr 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]
index c43565af635bc20092fe2d9dfab1f8db6d582586..b73f62ba148b74c4295f7a0080c1a2bb24e5b2b2 100644 (file)
@@ -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 global i64* null
+; CHECK: @TOP = internal unnamed_addr global i64* null
 @channelColumns = internal global i64 0             ; <i64*> [#uses=2]
 
 ; Derived from @DescribeChannel() in yacr2
index 9397a12365511fa9ec494756f4ed2506ef836efb..1e0db6a998bd0f26befb2657bc576befab567902 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -globalopt -S > %t
-; RUN: grep {@Y = internal global \\\[3 x \[%\]struct.X\\\] zeroinitializer} %t
+; RUN: grep {@Y = internal unnamed_addr global \\\[3 x \[%\]struct.X\\\] zeroinitializer} %t
 ; RUN: grep load %t | count 6
 ; RUN: grep {add i32 \[%\]a, \[%\]b} %t | count 3
 
index 335f5ec3a36887391b07dcff7a9d212fab83b91f..8f063a2fe4207e02df6787772bf37d002085860c 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -globalopt -S | \
-; RUN:   grep {G1 = internal constant}
+; RUN:   grep {G1 = internal unnamed_addr constant}
 
 @G1 = internal global [58 x i8] c"asdlfkajsdlfkajsd;lfkajds;lfkjasd;flkajsd;lkfja;sdlkfjasd\00"         ; <[58 x i8]*> [#uses=1]
 
diff --git a/test/Transforms/GlobalOpt/unnamed-addr.ll b/test/Transforms/GlobalOpt/unnamed-addr.ll
new file mode 100644 (file)
index 0000000..be02821
--- /dev/null
@@ -0,0 +1,54 @@
+; RUN: opt %s -globalopt -S | FileCheck %s
+
+@a = internal global i32 0, align 4
+@b = internal global i32 0, align 4
+@c = internal global i32 0, align 4
+@d = internal constant [4 x i8] c"foo\00", align 1
+
+; 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: @d = internal unnamed_addr constant [4 x i8] c"foo\00", align 1
+
+define i1 @bah(i64 %i) nounwind readonly optsize ssp {
+entry:
+  %arrayidx4 = getelementptr inbounds [4 x i8]* @d, i64 0, i64 %i
+  %tmp5 = load i8* %arrayidx4, align 1
+  %cmp = icmp eq i8 %tmp5, 42
+  ret i1 %cmp
+}
+
+define void @baz(i32 %x) {
+entry:
+  store i32 %x, i32* @a, align 4
+  store i32 %x, i32* @b, align 4
+  store i32 %x, i32* @c, align 4
+  ret void
+}
+
+define i32 @foo(i32* %x) nounwind readnone optsize ssp {
+entry:
+  %cmp = icmp eq i32* %x, @a
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
+
+define i32 @bar() {
+entry:
+  switch i64 ptrtoint (i32* @b to i64), label %sw.epilog [
+    i64 1, label %return
+    i64 0, label %return
+  ]
+
+sw.epilog:
+  ret i32 0
+
+return:
+  ret i32 1
+}
+
+define i32 @zed() {
+entry:
+  %tmp1 = load i32* @c, align 4
+  ret i32 %tmp1
+}