diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index ff6972072c9..37ccc04d147 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -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 &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(I)) { - // Nothing to analyse. + GS.isCompared = true; } else if (isa(I)) { const MemTransferInst *MTI = cast(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 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 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 &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; } 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 cfc9f302ff0..5b06fea5d92 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 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" diff --git a/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll b/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll index e024fc27ecb..d645ce49438 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 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 ; [#uses=2] diff --git a/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll b/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll index c43565af635..b73f62ba148 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 ; [#uses=2] -; CHECK: @TOP = internal global i64* null +; CHECK: @TOP = internal unnamed_addr global i64* null @channelColumns = internal global i64 0 ; [#uses=2] ; Derived from @DescribeChannel() in yacr2 diff --git a/test/Transforms/GlobalOpt/globalsra-unknown-index.ll b/test/Transforms/GlobalOpt/globalsra-unknown-index.ll index 9397a123655..1e0db6a998b 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 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 diff --git a/test/Transforms/GlobalOpt/memcpy.ll b/test/Transforms/GlobalOpt/memcpy.ll index 335f5ec3a36..8f063a2fe42 100644 --- a/test/Transforms/GlobalOpt/memcpy.ll +++ b/test/Transforms/GlobalOpt/memcpy.ll @@ -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 index 00000000000..be028212277 --- /dev/null +++ b/test/Transforms/GlobalOpt/unnamed-addr.ll @@ -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 +}