diff options
Diffstat (limited to 'llvm/test/Transforms/GlobalOpt')
125 files changed, 4516 insertions, 0 deletions
diff --git a/llvm/test/Transforms/GlobalOpt/2004-10-10-CastStoreOnce.ll b/llvm/test/Transforms/GlobalOpt/2004-10-10-CastStoreOnce.ll new file mode 100644 index 00000000000..061b9b0670f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2004-10-10-CastStoreOnce.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -globalopt + +@V = global float 1.200000e+01 ; <float*> [#uses=1] +@G = internal global i32* null ; <i32**> [#uses=2] + +define i32 @user() { + %P = load i32*, i32** @G ; <i32*> [#uses=1] + %Q = load i32, i32* %P ; <i32> [#uses=1] + ret i32 %Q +} + +define void @setter() { + %Vi = bitcast float* @V to i32* ; <i32*> [#uses=1] + store i32* %Vi, i32** @G + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/2005-06-15-LocalizeConstExprCrash.ll b/llvm/test/Transforms/GlobalOpt/2005-06-15-LocalizeConstExprCrash.ll new file mode 100644 index 00000000000..3efbde42341 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2005-06-15-LocalizeConstExprCrash.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -globalopt -disable-output +; PR579 + +@g_40507551 = internal global i16 31038 ; <i16*> [#uses=1] + +define void @main() { + %tmp.4.i.1 = load i8, i8* getelementptr (i8, i8* bitcast (i16* @g_40507551 to i8*), i32 1) ; <i8> [#uses=0] + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/2005-09-27-Crash.ll b/llvm/test/Transforms/GlobalOpt/2005-09-27-Crash.ll new file mode 100644 index 00000000000..061c88159dd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2005-09-27-Crash.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -globalopt -disable-output + %RPyString = type { i32, %arraytype.Char } + %arraytype.Char = type { i32, [0 x i8] } + %arraytype.Signed = type { i32, [0 x i32] } + %functiontype.1 = type { %RPyString* (i32) *} + %structtype.test = type { i32, %arraytype.Signed } +@structinstance.test = internal global { i32, { i32, [2 x i32] } } { i32 41, { i32, [2 x i32] } { i32 2, [2 x i32] [ i32 100, i32 101 ] } } ; <{ i32, { i32, [2 x i32] } }*> [#uses=1] + +define fastcc void @pypy_array_constant() { +block0: + %tmp.9 = getelementptr %structtype.test, %structtype.test* bitcast ({ i32, { i32, [2 x i32] } }* @structinstance.test to %structtype.test*), i32 0, i32 0 ; <i32*> [#uses=0] + ret void +} + +define fastcc void @new.varsizestruct.rpy_string() { + unreachable +} + +define void @__entrypoint__pypy_array_constant() { + call fastcc void @pypy_array_constant( ) + ret void +} + +define void @__entrypoint__raised_LLVMException() { + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/2006-07-07-InlineAsmCrash.ll b/llvm/test/Transforms/GlobalOpt/2006-07-07-InlineAsmCrash.ll new file mode 100644 index 00000000000..419ae101966 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2006-07-07-InlineAsmCrash.ll @@ -0,0 +1,135 @@ +; RUN: opt < %s -globalopt -disable-output +; PR820 +target datalayout = "e-p:32:32" +target triple = "i686-pc-linux-gnu" + %struct..0FileDescriptor = type { i32 } + %"struct.FlagDescription<int32>" = type { i8*, i32*, i1, i1, i32, i8* } + %"struct.FlagRegisterer<bool>" = type { i8 } + %struct.MutexLock = type { %struct..0FileDescriptor* } + %"struct.std::DisabledRangeMap" = type { %"struct.std::_Rb_tree<const char*,std::pair<const char* const, FlagDescription<bool> >,std::_Select1st<std::pair<const char* const, FlagDescription<bool> > >,StringCmp,std::allocator<std::pair<const char* const, FlagDescription<bool> > > >" } + %"struct.std::_Rb_tree<const char*,std::pair<const char* const, FlagDescription<bool> >,std::_Select1st<std::pair<const char* const, FlagDescription<bool> > >,StringCmp,std::allocator<std::pair<const char* const, FlagDescription<bool> > > >" = type { %"struct.std::_Rb_tree<const char*,std::pair<const char* const, FlagDescription<bool> >,std::_Select1st<std::pair<const char* const, FlagDescription<bool> > >,StringCmp,std::allocator<std::pair<const char* const, FlagDescription<bool> > > >::_Rb_tree_impl<StringCmp,false>" } + %"struct.std::_Rb_tree<const char*,std::pair<const char* const, FlagDescription<bool> >,std::_Select1st<std::pair<const char* const, FlagDescription<bool> > >,StringCmp,std::allocator<std::pair<const char* const, FlagDescription<bool> > > >::_Rb_tree_impl<StringCmp,false>" = type { %"struct.FlagRegisterer<bool>", %"struct.std::_Rb_tree_node_base", i32 } + %"struct.std::_Rb_tree_const_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >" = type { %"struct.std::_Rb_tree_node_base"* } + %"struct.std::_Rb_tree_node_base" = type { i32, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"* } + %"struct.std::_Vector_base<int,std::allocator<int> >" = type { %"struct.std::_Vector_base<int,std::allocator<int> >::_Vector_impl" } + %"struct.std::_Vector_base<int,std::allocator<int> >::_Vector_impl" = type { i32*, i32*, i32* } + %"struct.std::vector<int,std::allocator<int> >" = type { %"struct.std::_Vector_base<int,std::allocator<int> >" } +@registry_lock = external global %struct..0FileDescriptor ; <%struct..0FileDescriptor*> [#uses=0] +@_ZN61FLAG__foo_int32_44FLAGS_E = external global %"struct.FlagRegisterer<bool>" ; <%"struct.FlagRegisterer<bool>"*> [#uses=0] +@llvm.global_ctors = appending global [20 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN62FLAG__foo_string_10FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN60FLAG__foo_bool_19FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZNK5Bzh4Enum13is_contiguousEv }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN62FLAG__foo_string_17FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN61FLAG__foo_int32_21FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN7ScannerC2Ev }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__Z11StripStringPSsPKcc }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZNK9__gnu_cxx4hashI11StringPieceEclERKS1_ }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN8Hasher325ResetEj }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__Z25ACLRv }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN61FLAG__foo_int64_25FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN61FLAG__foo_int32_7FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN62FLAG__foo_string_18FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN62FLAG__foo_string_17FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN61FLAG__foo_int32_25FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_eventbuf }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN61FLAG__foo_int32_26FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN62FLAG__foo_string_16FLAGS_E }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__ZN17InitializerC2EPKcS1_PFvvE }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__checker_bcad_variable } ] ; <[20 x { i32, void ()* }]*> [#uses=0] + +declare void @_GLOBAL__I__ZN62FLAG__foo_string_10FLAGS_E() + +declare void @_GLOBAL__I__ZN60FLAG__foo_bool_19FLAGS_E() + +declare void @_GLOBAL__I__ZNK5Bzh4Enum13is_contiguousEv() + +declare void @_GLOBAL__I__ZN62FLAG__foo_string_17FLAGS_E() + +declare void @_GLOBAL__I__ZN61FLAG__foo_int32_21FLAGS_E() + +define void @_ZN14FlagRegistererIiEC1EPKcRK15FlagDescriptionIiE() { +entry: + call void @_Z12RegisterFlagIiEvPKcRK15FlagDescriptionIT_E( ) + ret void +} + +define void @_Z12RegisterFlagIiEvPKcRK15FlagDescriptionIT_E() { +entry: + call void @_ZN9MutexLockC1EP5Mutex( ) + ret void +} + +declare void @_GLOBAL__I__ZN7ScannerC2Ev() + +declare void @_GLOBAL__I__Z11StripStringPSsPKcc() + +define void @_ZNSt6vectorIiSaIiEEC1ERKS0_() { +entry: + unreachable +} + +declare void @_GLOBAL__I__ZNK9__gnu_cxx4hashI11StringPieceEclERKS1_() + +declare void @_GLOBAL__I__ZN8Hasher325ResetEj() + +declare void @_GLOBAL__I__Z25ACLRv() + +define void @_ZN9MutexLockC1EP5Mutex() { +entry: + call void @_ZN5Mutex4LockEv( ) + ret void +} + +define void @_ZN5Mutex4LockEv() { +entry: + call void @_Z22Acquire_CASPViii( ) + ret void +} + +define void @_ZNSt3mapIPKc15FlagDescriptionIiE9StringCmpSaISt4pairIKS1_S3_EEE3endEv(%"struct.std::_Rb_tree_const_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >"* sret %agg.result) { +entry: + unreachable +} + +declare void @_GLOBAL__I__ZN61FLAG__foo_int64_25FLAGS_E() + +define void @_Z14CASPViii() { +entry: + %tmp3 = call i32 asm sideeffect "lock; cmpxchg $1,$2", "={ax},q,m,0,~{dirflag},~{fpsr},~{flags},~{memory}"( i32 0, i32* null, i32 0 ) ; <i32> [#uses=0] + unreachable +} + +declare void @_GLOBAL__I__ZN61FLAG__foo_int32_7FLAGS_E() + +declare void @_GLOBAL__I__ZN62FLAG__foo_string_18FLAGS_E() + +define void @_Z22Acquire_CASPViii() { +entry: + call void @_Z14CASPViii( ) + unreachable +} + +declare void @_GLOBAL__I__ZN61FLAG__foo_int32_25FLAGS_E() + +declare void @_GLOBAL__I_eventbuf() + +define void @_GLOBAL__I__ZN61FLAG__foo_int32_26FLAGS_E() { +entry: + call void @_Z41__static_initialization_and_destruction_0ii1662( i32 1, i32 65535 ) + ret void +} + +define void @_Z41__static_initialization_and_destruction_0ii1662(i32 %__initialize_p, i32 %__priority) { +entry: + %__initialize_p_addr = alloca i32 ; <i32*> [#uses=2] + %__priority_addr = alloca i32 ; <i32*> [#uses=2] + store i32 %__initialize_p, i32* %__initialize_p_addr + store i32 %__priority, i32* %__priority_addr + %tmp = load i32, i32* %__priority_addr ; <i32> [#uses=1] + %tmp.upgrd.1 = icmp eq i32 %tmp, 65535 ; <i1> [#uses=1] + br i1 %tmp.upgrd.1, label %cond_true, label %cond_next14 + +cond_true: ; preds = %entry + %tmp8 = load i32, i32* %__initialize_p_addr ; <i32> [#uses=1] + %tmp9 = icmp eq i32 %tmp8, 1 ; <i1> [#uses=1] + br i1 %tmp9, label %cond_true10, label %cond_next14 + +cond_true10: ; preds = %cond_true + call void @_ZN14FlagRegistererIiEC1EPKcRK15FlagDescriptionIiE( ) + ret void + +cond_next14: ; preds = %cond_true, %entry + ret void +} + +declare void @_GLOBAL__I__ZN62FLAG__foo_string_16FLAGS_E() + +define void @_ZN9__gnu_cxx13new_allocatorIPNS_15_Hashtable_nodeIjEEEC2Ev() { +entry: + unreachable +} + +declare void @_GLOBAL__I__ZN17InitializerC2EPKcS1_PFvvE() + +declare void @_GLOBAL__I__checker_bcad_variable() diff --git a/llvm/test/Transforms/GlobalOpt/2006-11-01-ShrinkGlobalPhiCrash.ll b/llvm/test/Transforms/GlobalOpt/2006-11-01-ShrinkGlobalPhiCrash.ll new file mode 100644 index 00000000000..7b62cf08a4b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2006-11-01-ShrinkGlobalPhiCrash.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -globalopt -disable-output + + %struct._list = type { i32*, %struct._list* } + %struct._play = type { i32, i32*, %struct._list*, %struct._play* } +@nrow = internal global i32 0 ; <i32*> [#uses=2] + +define void @make_play() { +entry: + br label %cond_true16.i + +cond_true16.i: ; preds = %cond_true16.i, %entry + %low.0.in.i.0 = phi i32* [ @nrow, %entry ], [ null, %cond_true16.i ] ; <i32*> [#uses=1] + %low.0.i = load i32, i32* %low.0.in.i.0 ; <i32> [#uses=0] + br label %cond_true16.i +} + +define void @make_wanted() { +entry: + unreachable +} + +define void @get_good_move() { +entry: + ret void +} + +define void @main() { +entry: + store i32 8, i32* @nrow + tail call void @make_play( ) + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/2007-04-05-Crash.ll b/llvm/test/Transforms/GlobalOpt/2007-04-05-Crash.ll new file mode 100644 index 00000000000..f312fbbc9f9 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2007-04-05-Crash.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -globalopt -disable-output + +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32" +target triple = "thumb-apple-darwin8" +@replacementUnichar = internal global i16 -3 ; <i16*> [#uses=2] +@"L_OBJC_IMAGE_INFO" = internal global [2 x i32] zeroinitializer ; <[2 x i32]*> [#uses=1] +@llvm.used = appending global [1 x i8*] [ i8* bitcast ([2 x i32]* @"L_OBJC_IMAGE_INFO" to i8*) ] ; <[1 x i8*]*> [#uses=0] + +define zeroext i16 @__NSCharToUnicharCFWrapper(i8 zeroext %ch) { +entry: + %iftmp.0.0.in.in = select i1 false, i16* @replacementUnichar, i16* null ; <i16*> [#uses=1] + %iftmp.0.0.in = load i16, i16* %iftmp.0.0.in.in ; <i16> [#uses=1] + ret i16 %iftmp.0.0.in +} + +define void @__NSASCIICharToUnichar() { +entry: + ret void +} + +define void @_NSDefaultCStringEncoding() { +entry: + call void @__NSSetCStringCharToUnichar( ) + br i1 false, label %cond_true6, label %cond_next8 + +cond_true6: ; preds = %entry + store i16 -2, i16* @replacementUnichar + ret void + +cond_next8: ; preds = %entry + ret void +} + +declare void @__NSSetCStringCharToUnichar() diff --git a/llvm/test/Transforms/GlobalOpt/2007-05-13-Crash.ll b/llvm/test/Transforms/GlobalOpt/2007-05-13-Crash.ll new file mode 100644 index 00000000000..bed4fec981e --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2007-05-13-Crash.ll @@ -0,0 +1,74 @@ +; RUN: opt < %s -globalopt -disable-output + +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" +target triple = "i686-apple-darwin8" + %struct.SFLMutableListItem = type { i16 } + %struct.__CFDictionary = type opaque + %struct.__CFString = type opaque + %struct.__builtin_CFString = type { i32*, i32, i8*, i32 } +@_ZZ19SFLGetVisibilityKeyvE19_kSFLLVisibilityKey = internal global %struct.__CFString* null ; <%struct.__CFString**> [#uses=2] +@_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey = internal global %struct.__CFString* null ; <%struct.__CFString**> [#uses=7] +@0 = internal constant %struct.__builtin_CFString { + i32* getelementptr ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), + i32 1992, + i8* getelementptr ([14 x i8], [14 x i8]* @.str, i32 0, i32 0), + i32 13 }, section "__DATA,__cfstring" ; <%struct.__builtin_CFString*>:0 [#uses=1] +@__CFConstantStringClassReference = external global [0 x i32] ; <[0 x i32]*> [#uses=1] +@.str = internal constant [14 x i8] c"AlwaysVisible\00" ; <[14 x i8]*> [#uses=1] +@_ZZ21SFLGetNeverVisibleKeyvE21_kSFLLNeverVisibleKey = internal global %struct.__CFString* null ; <%struct.__CFString**> [#uses=2] + +define %struct.__CFString* @_Z19SFLGetVisibilityKeyv() { +entry: + %tmp1 = load %struct.__CFString*, %struct.__CFString** @_ZZ19SFLGetVisibilityKeyvE19_kSFLLVisibilityKey ; <%struct.__CFString*> [#uses=1] + ret %struct.__CFString* %tmp1 +} + +define %struct.__CFString* @_Z22SFLGetAlwaysVisibleKeyv() { +entry: + %tmp1 = load %struct.__CFString*, %struct.__CFString** @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey ; <%struct.__CFString*> [#uses=1] + %tmp2 = icmp eq %struct.__CFString* %tmp1, null ; <i1> [#uses=1] + br i1 %tmp2, label %cond_true, label %cond_next + +cond_true: ; preds = %entry + store %struct.__CFString* bitcast (%struct.__builtin_CFString* @0 to %struct.__CFString*), %struct.__CFString** @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey + br label %cond_next + +cond_next: ; preds = %entry, %cond_true + %tmp4 = load %struct.__CFString*, %struct.__CFString** @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey ; <%struct.__CFString*> [#uses=1] + ret %struct.__CFString* %tmp4 +} + +define %struct.__CFString* @_Z21SFLGetNeverVisibleKeyv() { +entry: + %tmp1 = load %struct.__CFString*, %struct.__CFString** @_ZZ21SFLGetNeverVisibleKeyvE21_kSFLLNeverVisibleKey ; <%struct.__CFString*> [#uses=1] + ret %struct.__CFString* %tmp1 +} + +define %struct.__CFDictionary* @_ZN18SFLMutableListItem18GetPrefsDictionaryEv(%struct.SFLMutableListItem* %this) { +entry: + %tmp4 = getelementptr %struct.SFLMutableListItem, %struct.SFLMutableListItem* %this, i32 0, i32 0 ; <i16*> [#uses=1] + %tmp5 = load i16, i16* %tmp4 ; <i16> [#uses=1] + %tmp6 = icmp eq i16 %tmp5, 0 ; <i1> [#uses=1] + br i1 %tmp6, label %cond_next22, label %cond_true + +cond_true: ; preds = %entry + %tmp9 = load %struct.__CFString*, %struct.__CFString** @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey ; <%struct.__CFString*> [#uses=1] + %tmp10 = icmp eq %struct.__CFString* %tmp9, null ; <i1> [#uses=1] + br i1 %tmp10, label %cond_true13, label %cond_next22 + +cond_true13: ; preds = %cond_true + store %struct.__CFString* bitcast (%struct.__builtin_CFString* @0 to %struct.__CFString*), %struct.__CFString** @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey + br label %cond_next22 + +cond_next22: ; preds = %entry, %cond_true13, %cond_true + %iftmp.1.0.in = phi %struct.__CFString** [ @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey, %cond_true ], [ @_ZZ22SFLGetAlwaysVisibleKeyvE22_kSFLLAlwaysVisibleKey, %cond_true13 ], [ @_ZZ21SFLGetNeverVisibleKeyvE21_kSFLLNeverVisibleKey, %entry ] ; <%struct.__CFString**> [#uses=1] + %iftmp.1.0 = load %struct.__CFString*, %struct.__CFString** %iftmp.1.0.in ; <%struct.__CFString*> [#uses=1] + %tmp24 = load %struct.__CFString*, %struct.__CFString** @_ZZ19SFLGetVisibilityKeyvE19_kSFLLVisibilityKey ; <%struct.__CFString*> [#uses=1] + %tmp2728 = bitcast %struct.__CFString* %tmp24 to i8* ; <i8*> [#uses=1] + %tmp2930 = bitcast %struct.__CFString* %iftmp.1.0 to i8* ; <i8*> [#uses=1] + call void @_Z20CFDictionaryAddValuePKvS0_( i8* %tmp2728, i8* %tmp2930 ) + ret %struct.__CFDictionary* undef +} + +declare void @_Z20CFDictionaryAddValuePKvS0_(i8*, i8*) + diff --git a/llvm/test/Transforms/GlobalOpt/2007-06-04-PackedStruct.ll b/llvm/test/Transforms/GlobalOpt/2007-06-04-PackedStruct.ll new file mode 100644 index 00000000000..f6e0bb70d63 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2007-06-04-PackedStruct.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -globalopt -disable-output +; PR1491 + +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" +target triple = "i686-pc-linux-gnu" + %"struct.__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<const int, int> > >" = type <{ i8 }> + %"struct.std::_Rb_tree<int,std::pair<const int, int>,std::_Select1st<std::pair<const int, int> >,std::less<int>,std::allocator<std::pair<const int, int> > >" = type { %"struct.std::_Rb_tree<int,std::pair<const int, int>,std::_Select1st<std::pair<const int, int> >,std::less<int>,std::allocator<std::pair<const int, int> > >::_Rb_tree_impl<std::less<int>,false>" } + %"struct.std::_Rb_tree<int,std::pair<const int, int>,std::_Select1st<std::pair<const int, int> >,std::less<int>,std::allocator<std::pair<const int, int> > >::_Rb_tree_impl<std::less<int>,false>" = type { %"struct.__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<const int, int> > >", %"struct.std::_Rb_tree_node_base", i32 } + %"struct.std::_Rb_tree_node_base" = type { i32, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"* } + %"struct.std::map<int,int,std::less<int>,std::allocator<std::pair<const int, int> > >" = type { %"struct.std::_Rb_tree<int,std::pair<const int, int>,std::_Select1st<std::pair<const int, int> >,std::less<int>,std::allocator<std::pair<const int, int> > >" } +@someMap = global %"struct.std::map<int,int,std::less<int>,std::allocator<std::pair<const int, int> > >" zeroinitializer ; <%"struct.std::map<int,int,std::less<int>,std::allocator<std::pair<const int, int> > >"*> [#uses=1] +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_someMap } ] ; <[1 x { i32, void ()* }]*> [#uses=0] +@llvm.global_dtors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @_GLOBAL__D_someMap } ] ; <[1 x { i32, void ()* }]*> [#uses=0] + +define void @_GLOBAL__I_someMap() { +entry: + call void @_Z41__static_initialization_and_destruction_0ii( i32 1, i32 65535 ) + ret void +} + +declare void @_GLOBAL__D_someMap() + +define void @_Z41__static_initialization_and_destruction_0ii(i32 %__initialize_p, i32 %__priority) { +entry: + %tmp1 = icmp eq i32 %__priority, 65535 ; <i1> [#uses=1] + %tmp4 = icmp eq i32 %__initialize_p, 1 ; <i1> [#uses=1] + %tmp7 = and i1 %tmp1, %tmp4 ; <i1> [#uses=1] + br i1 %tmp7, label %cond_true, label %cond_next + +cond_true: ; preds = %entry + store i8 0, i8* getelementptr (%"struct.std::map<int,int,std::less<int>,std::allocator<std::pair<const int, int> > >", %"struct.std::map<int,int,std::less<int>,std::allocator<std::pair<const int, int> > >"* @someMap, i32 0, i32 0, i32 0, i32 0, i32 0) + ret void + +cond_next: ; preds = %entry + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/2007-11-09-GEP-GEP-Crash.ll b/llvm/test/Transforms/GlobalOpt/2007-11-09-GEP-GEP-Crash.ll new file mode 100644 index 00000000000..f6225cd3ad0 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2007-11-09-GEP-GEP-Crash.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -globalopt -disable-output +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-f128:64:128" +target triple = "powerpc-unknown-linux-gnu" + %struct.empty0 = type { } + %struct.es = type { %struct.empty0 } + %struct.es1 = type { %struct.empty0 } +@aaui1 = internal global [6 x [2 x i32]] [ [2 x i32] [ i32 1, i32 1 ], [2 x i32] [ i32 1, i32 1 ], [2 x i32] [ i32 1, i32 1 ], [2 x i32] [ i32 1, i32 1 ], [2 x i32] [ i32 1, i32 1 ], [2 x i32] [ i32 1, i32 1 ] ] ; <[6 x [2 x i32]]*> [#uses=1] +@aaui0 = internal global [0 x [2 x i32]] zeroinitializer ; <[0 x [2 x i32]]*> [#uses=1] + +define i8 @func() { +entry: + %tmp10 = getelementptr [2 x i32], [2 x i32]* getelementptr ([6 x [2 x i32]], [6 x [2 x i32]]* @aaui1, i32 0, i32 0), i32 5, i32 1 ; <i32*> [#uses=1] + %tmp11 = load i32, i32* %tmp10, align 4 ; <i32> [#uses=1] + %tmp12 = call i32 (...) @func3( i32* null, i32 0, i32 %tmp11 ) ; <i32> [#uses=0] + ret i8 undef +} + +declare i32 @func3(...) + diff --git a/llvm/test/Transforms/GlobalOpt/2008-01-03-Crash.ll b/llvm/test/Transforms/GlobalOpt/2008-01-03-Crash.ll new file mode 100644 index 00000000000..dc41fdb8de4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-01-03-Crash.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -globalopt | llvm-dis +; PR1896 + +@indirect1 = internal global void (i32)* null ; <void (i32)**> [#uses=2] + +declare void @indirectmarked(i32) + +define i32 @main() { +entry: + br i1 false, label %cond_next20.i, label %cond_true.i9 + +cond_true.i9: ; preds = %entry + ret i32 0 + +cond_next20.i: ; preds = %entry + store void (i32)* @indirectmarked, void (i32)** @indirect1, align 4 + br i1 false, label %cond_next21.i.i23.i, label %stack_restore + +stack_restore: ; preds = %cond_next20.i + ret i32 0 + +cond_next21.i.i23.i: ; preds = %cond_next20.i + %tmp6.i4.i = load i32, i32* bitcast (void (i32)** @indirect1 to i32*), align 4 ; <i32> [#uses=0] + ret i32 0 +} + diff --git a/llvm/test/Transforms/GlobalOpt/2008-01-13-OutOfRangeSROA.ll b/llvm/test/Transforms/GlobalOpt/2008-01-13-OutOfRangeSROA.ll new file mode 100644 index 00000000000..4adc9607c75 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-01-13-OutOfRangeSROA.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; The 'X' indices could be larger than 31. Do not SROA the outer +; indices of this array. +; CHECK: @mm = {{.*}} [16 x [31 x double]] zeroinitializer +@mm = internal global [16 x [31 x double]] zeroinitializer, align 32 + +define void @test(i32 %X) { + %P = getelementptr [16 x [31 x double]], [16 x [31 x double]]* @mm, i32 0, i32 0, i32 %X + store double 1.0, double* %P + ret void +} + +define double @get(i32 %X) { + %P = getelementptr [16 x [31 x double]], [16 x [31 x double]]* @mm, i32 0, i32 0, i32 %X + %V = load double, double* %P + ret double %V +} diff --git a/llvm/test/Transforms/GlobalOpt/2008-01-29-VolatileGlobal.ll b/llvm/test/Transforms/GlobalOpt/2008-01-29-VolatileGlobal.ll new file mode 100644 index 00000000000..7818e5d642c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-01-29-VolatileGlobal.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: load volatile +@t0.1441 = internal global double 0x3FD5555555555555, align 8 ; <double*> [#uses=1] + +define double @foo() nounwind { +entry: + %tmp1 = load volatile double, double* @t0.1441, align 8 ; <double> [#uses=2] + %tmp4 = fmul double %tmp1, %tmp1 ; <double> [#uses=1] + ret double %tmp4 +} diff --git a/llvm/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll b/llvm/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll new file mode 100644 index 00000000000..c3a6d7b5716 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-04-26-SROA-Global-Align.ll @@ -0,0 +1,34 @@ +; Verify that when @G is SROA'd that the new globals have correct +; 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 | FileCheck %s +; CHECK: @G.0 = internal unnamed_addr global {{.*}}align 16 +; CHECK: @G.1 = internal unnamed_addr global {{.*}}align 8 +; CHECK: @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" +target triple = "x86_64-apple-darwin8" + +%T = type { double, double, double } + +@G = internal global %T zeroinitializer, align 16 + + +define void @test() { + store double 1.0, double* getelementptr (%T, %T* @G, i32 0, i32 0), align 16 + store double 2.0, double* getelementptr (%T, %T* @G, i32 0, i32 1), align 8 + store double 3.0, double* getelementptr (%T, %T* @G, i32 0, i32 2), align 16 + ret void +} + +define double @test2() { + %V1 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 0), align 16 + %V2 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 1), align 8 + %V3 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 2), align 16 + %R = fadd double %V1, %V2 + %R2 = fadd double %R, %V3 + ret double %R2 +} diff --git a/llvm/test/Transforms/GlobalOpt/2008-07-17-addrspace.ll b/llvm/test/Transforms/GlobalOpt/2008-07-17-addrspace.ll new file mode 100644 index 00000000000..b9d2d993240 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-07-17-addrspace.ll @@ -0,0 +1,28 @@ +; This test lets globalopt split the global struct and array into different +; values. This used to crash, because globalopt forgot to put the new var in the +; same address space as the old one. + +; RUN: opt < %s -globalopt -S | FileCheck %s + +; Check that the new global values still have their address space +; CHECK: addrspace(1) global +; CHECK: addrspace(1) global + +@struct = internal addrspace(1) global { i32, i32 } zeroinitializer +@array = internal addrspace(1) global [ 2 x i32 ] zeroinitializer + +define i32 @foo() { + %A = load i32, i32 addrspace(1) * getelementptr ({ i32, i32 }, { i32, i32 } addrspace(1) * @struct, i32 0, i32 0) + %B = load i32, i32 addrspace(1) * getelementptr ([ 2 x i32 ], [ 2 x i32 ] addrspace(1) * @array, i32 0, i32 0) + ; Use the loaded values, so they won't get removed completely + %R = add i32 %A, %B + ret i32 %R +} + +; We put stores in a different function, so that the global variables won't get +; optimized away completely. +define void @bar(i32 %R) { + store i32 %R, i32 addrspace(1) * getelementptr ([ 2 x i32 ], [ 2 x i32 ] addrspace(1) * @array, i32 0, i32 0) + store i32 %R, i32 addrspace(1) * getelementptr ({ i32, i32 }, { i32, i32 } addrspace(1) * @struct, i32 0, i32 0) + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash-2.ll b/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash-2.ll new file mode 100644 index 00000000000..bd32163e5f9 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash-2.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -globalopt | llvm-dis +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" + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] + +define void @bar(i32 %Size) nounwind noinline { +entry: + %malloccall = tail call i8* @malloc(i32 trunc (i64 mul (i64 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64), i64 2000000) to i32)) + %tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i32) + + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=2] + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %tmp = phi %struct.foo* [ %tmpLD1, %bb1.thread ], [ %tmpLD1, %bb1 ] ; <%struct.foo*> [#uses=1] + %0 = getelementptr %struct.foo, %struct.foo* %tmp, i32 1 ; <%struct.foo*> [#uses=0] + br label %bb1 +} diff --git a/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash.ll b/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash.ll new file mode 100644 index 00000000000..e9c16785afa --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2008-12-16-HeapSRACrash.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -globalopt | llvm-dis +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" + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] + +define void @bar(i32 %Size) nounwind noinline { +entry: + %malloccall = tail call i8* @malloc(i32 trunc (i64 mul (i64 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64), i64 2000000) to i32)) + %tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i32) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=3] + store %struct.foo* %tmpLD1, %struct.foo** null + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %tmp = phi %struct.foo* [ %tmpLD1, %bb1.thread ], [ %tmpLD1, %bb1 ] ; <%struct.foo*> [#uses=0] + br i1 false, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 0 +} diff --git a/llvm/test/Transforms/GlobalOpt/2009-01-13-phi-user.ll b/llvm/test/Transforms/GlobalOpt/2009-01-13-phi-user.ll new file mode 100644 index 00000000000..7ad24b92a2d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-01-13-phi-user.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: phi{{.*}}@head +; PR3321 +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + %struct.node = type { %struct.node*, i32 } +@head = internal global %struct.node* null ; <%struct.node**> [#uses=2] +@node = internal global %struct.node { %struct.node* null, i32 42 }, align 16 ; <%struct.node*> [#uses=1] + +define i32 @f() nounwind { +entry: + store %struct.node* @node, %struct.node** @head, align 8 + br label %bb1 + +bb: ; preds = %bb1 + %0 = getelementptr %struct.node, %struct.node* %t.0, i64 0, i32 1 ; <i32*> [#uses=1] + %1 = load i32, i32* %0, align 4 ; <i32> [#uses=1] + %2 = getelementptr %struct.node, %struct.node* %t.0, i64 0, i32 0 ; <%struct.node**> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb, %entry + %value.0 = phi i32 [ undef, %entry ], [ %1, %bb ] ; <i32> [#uses=1] + %t.0.in = phi %struct.node** [ @head, %entry ], [ %2, %bb ] ; <%struct.node**> [#uses=1] + %t.0 = load %struct.node*, %struct.node** %t.0.in ; <%struct.node*> [#uses=3] + %3 = icmp eq %struct.node* %t.0, null ; <i1> [#uses=1] + br i1 %3, label %bb2, label %bb + +bb2: ; preds = %bb1 + ret i32 %value.0 +} + +define i32 @main() nounwind { +entry: + %0 = call i32 @f() nounwind ; <i32> [#uses=1] + ret i32 %0 +} diff --git a/llvm/test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll b/llvm/test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll new file mode 100644 index 00000000000..e6337adefa1 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-02-15-BitcastAlias.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -globalopt + +@g = global i32 0 + +@a = alias i8, bitcast (i32* @g to i8*) + +define void @f() { + %tmp = load i8, i8* @a + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll b/llvm/test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll new file mode 100644 index 00000000000..42c243d9d7c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-02-15-ResolveAlias.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +define internal void @f() { +; CHECK-NOT: @f( +; CHECK: define void @a + ret void +} + +@a = alias void (), void ()* @f + +define void @g() { + call void() @a() + ret void +} + +@b = internal alias void (), void ()* @g +; CHECK-NOT: @b + +define void @h() { + call void() @b() +; CHECK: call void @g + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/2009-03-05-dbg.ll b/llvm/test/Transforms/GlobalOpt/2009-03-05-dbg.ll new file mode 100644 index 00000000000..68ea4ffe639 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-03-05-dbg.ll @@ -0,0 +1,80 @@ +; REQUIRES: asserts +; RUN: opt < %s -globalopt -stats -disable-output 2>&1 | FileCheck %s +; CHECK: 1 globalopt - Number of global vars shrunk to booleans + +source_filename = "test/Transforms/GlobalOpt/2009-03-05-dbg.ll" + +@Stop = internal global i32 0, !dbg !0 + +; Function Attrs: nounwind ssp +define i32 @foo(i32 %i) #0 { +entry: + %"alloca point" = bitcast i32 0 to i32 + call void @llvm.dbg.value(metadata i32 %i, metadata !8, metadata !12), !dbg !13 + %0 = icmp eq i32 %i, 1, !dbg !13 + br i1 %0, label %bb, label %bb1, !dbg !13 + +bb: ; preds = %entry + store i32 0, i32* @Stop, align 4, !dbg !15 + %1 = mul nsw i32 %i, 42, !dbg !16 + call void @llvm.dbg.value(metadata i32 %1, metadata !8, metadata !12), !dbg !16 + br label %bb2, !dbg !16 + +bb1: ; preds = %entry + store i32 1, i32* @Stop, align 4, !dbg !17 + br label %bb2, !dbg !17 + +bb2: ; preds = %bb1, %bb + %i_addr.0 = phi i32 [ %1, %bb ], [ %i, %bb1 ] + br label %return, !dbg !18 + +return: ; preds = %bb2 + ret i32 %i_addr.0, !dbg !18 +} + +; Function Attrs: nounwind readnone + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind ssp +define i32 @bar() #0 { +entry: + %"alloca point" = bitcast i32 0 to i32 + %0 = load i32, i32* @Stop, align 4, !dbg !19 + %1 = icmp eq i32 %0, 1, !dbg !19 + br i1 %1, label %bb, label %bb1, !dbg !19 + +bb: ; preds = %entry + + br label %bb2, !dbg !24 + +bb1: ; preds = %entry + br label %bb2, !dbg !25 + +bb2: ; preds = %bb1, %bb + %.0 = phi i32 [ 0, %bb ], [ 1, %bb1 ] + br label %return, !dbg !25 + +return: ; preds = %bb2 + ret i32 %.0, !dbg !25 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind ssp } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!6, !7} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = !DIGlobalVariable(name: "Stop", scope: !2, file: !3, line: 2, type: !5, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C89, file: !3, producer: "4.2.1 (Based on Apple Inc. build 5658) (LLVM build)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4) +!3 = !DIFile(filename: "g.c", directory: "/tmp") +!4 = !{!0} +!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!6 = !{i32 2, !"Dwarf Version", i32 2} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !DILocalVariable(name: "i", arg: 1, scope: !9, file: !3, line: 4, type: !5) +!9 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !2, file: !3, line: 4, type: !10, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2)!10 = !DISubroutineType(types: !11)!11 = !{!5, !5}!12 = !DIExpression()!13 = !DILocation(line: 5, scope: !14)!14 = distinct !DILexicalBlock(scope: !9, file: !3)!15 = !DILocation(line: 6, scope: !14)!16 = !DILocation(line: 7, scope: !14)!17 = !DILocation(line: 9, scope: !14)!18 = !DILocation(line: 11, scope: !14)!19 = !DILocation(line: 14, scope: !20)!20 = distinct !DILexicalBlock(scope: !21, file: !3)!21 = distinct !DISubprogram(name: "bar", linkageName: "bar", scope: !2, file: !3, line: 13, type: !22, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2)!22 = !DISubroutineType(types: !23)!23 = !{!5}!24 = !DILocation(line: 15, scope: !20)!25 = !DILocation(line: 16, scope: !20) diff --git a/llvm/test/Transforms/GlobalOpt/2009-03-06-Anonymous.ll b/llvm/test/Transforms/GlobalOpt/2009-03-06-Anonymous.ll new file mode 100644 index 00000000000..d5836ea9254 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-03-06-Anonymous.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@0 = global i32 0 +; CHECK-DAG: @0 = internal global i32 0 + +@1 = private global i32 0 +; CHECK-DAG: @1 = private global i32 0 + +define i32* @2() { + ret i32* @0 +} +; CHECK-DAG: define internal fastcc i32* @2() + +define i32* @f() { +entry: + call i32* @2() + ret i32* %0 +} + +define i32* @g() { +entry: + ret i32* @1 +} diff --git a/llvm/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll b/llvm/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll new file mode 100644 index 00000000000..bec4891a496 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-03-07-PromotePtrToBool.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +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" + +; CHECK: @X = internal unnamed_addr global i32 +@X = internal global i32* null ; <i32**> [#uses=2] +@Y = internal global i32 0 ; <i32*> [#uses=1] + +define void @foo() nounwind { +entry: + store i32* @Y, i32** @X, align 4 + ret void +} + +define i32* @get() nounwind { +entry: + %0 = load i32*, i32** @X, align 4 ; <i32*> [#uses=1] + ret i32* %0 +} diff --git a/llvm/test/Transforms/GlobalOpt/2009-06-01-RecursivePHI.ll b/llvm/test/Transforms/GlobalOpt/2009-06-01-RecursivePHI.ll new file mode 100644 index 00000000000..30e4d422621 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-06-01-RecursivePHI.ll @@ -0,0 +1,122 @@ +; RUN: opt < %s -globalopt +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.s_annealing_sched = type { i32, float, float, float, float } + %struct.s_bb = type { i32, i32, i32, i32 } + %struct.s_net = type { i8*, i32, i32*, float, float } + %struct.s_placer_opts = type { i32, float, i32, i32, i8*, i32, i32 } +@net = internal global %struct.s_net* null ; <%struct.s_net**> [#uses=4] + +define fastcc void @alloc_and_load_placement_structs(i32 %place_cost_type, i32 %num_regions, float %place_cost_exp, float*** nocapture %old_region_occ_x, float*** nocapture %old_region_occ_y) nounwind ssp { +entry: + br i1 undef, label %bb.i, label %my_malloc.exit + +bb.i: ; preds = %entry + unreachable + +my_malloc.exit: ; preds = %entry + br i1 undef, label %bb.i81, label %my_malloc.exit83 + +bb.i81: ; preds = %my_malloc.exit + unreachable + +my_malloc.exit83: ; preds = %my_malloc.exit + br i1 undef, label %bb.i.i57, label %my_calloc.exit.i + +bb.i.i57: ; preds = %my_malloc.exit83 + unreachable + +my_calloc.exit.i: ; preds = %my_malloc.exit83 + br i1 undef, label %bb.i4.i, label %my_calloc.exit5.i + +bb.i4.i: ; preds = %my_calloc.exit.i + unreachable + +my_calloc.exit5.i: ; preds = %my_calloc.exit.i + %.pre.i58 = load %struct.s_net*, %struct.s_net** @net, align 4 ; <%struct.s_net*> [#uses=1] + br label %bb17.i78 + +bb1.i61: ; preds = %bb4.preheader.i, %bb1.i61 + br i1 undef, label %bb1.i61, label %bb5.i62 + +bb5.i62: ; preds = %bb1.i61 + br i1 undef, label %bb6.i64, label %bb15.preheader.i + +bb15.preheader.i: ; preds = %bb4.preheader.i, %bb5.i62 + br label %bb16.i77 + +bb6.i64: ; preds = %bb5.i62 + br i1 undef, label %bb7.i65, label %bb8.i67 + +bb7.i65: ; preds = %bb6.i64 + unreachable + +bb8.i67: ; preds = %bb6.i64 + br i1 undef, label %bb.i1.i68, label %my_malloc.exit.i70 + +bb.i1.i68: ; preds = %bb8.i67 + unreachable + +my_malloc.exit.i70: ; preds = %bb8.i67 + %0 = load %struct.s_net*, %struct.s_net** @net, align 4 ; <%struct.s_net*> [#uses=1] + br i1 undef, label %bb9.i71, label %bb16.i77 + +bb9.i71: ; preds = %bb9.i71, %my_malloc.exit.i70 + %1 = load %struct.s_net*, %struct.s_net** @net, align 4 ; <%struct.s_net*> [#uses=1] + br i1 undef, label %bb9.i71, label %bb16.i77 + +bb16.i77: ; preds = %bb9.i71, %my_malloc.exit.i70, %bb15.preheader.i + %.pre41.i.rle244 = phi %struct.s_net* [ %.pre41.i, %bb15.preheader.i ], [ %0, %my_malloc.exit.i70 ], [ %1, %bb9.i71 ] ; <%struct.s_net*> [#uses=1] + br label %bb17.i78 + +bb17.i78: ; preds = %bb16.i77, %my_calloc.exit5.i + %.pre41.i = phi %struct.s_net* [ %.pre41.i.rle244, %bb16.i77 ], [ %.pre.i58, %my_calloc.exit5.i ] ; <%struct.s_net*> [#uses=1] + br i1 undef, label %bb4.preheader.i, label %alloc_and_load_unique_pin_list.exit + +bb4.preheader.i: ; preds = %bb17.i78 + br i1 undef, label %bb1.i61, label %bb15.preheader.i + +alloc_and_load_unique_pin_list.exit: ; preds = %bb17.i78 + ret void +} + +define void @read_net(i8* %net_file) nounwind ssp { +entry: + br i1 undef, label %bb3.us.us.i, label %bb6.preheader + +bb6.preheader: ; preds = %entry + br i1 undef, label %bb7, label %bb + +bb3.us.us.i: ; preds = %entry + unreachable + +bb: ; preds = %bb6.preheader + br i1 undef, label %bb.i34, label %bb1.i38 + +bb.i34: ; preds = %bb + unreachable + +bb1.i38: ; preds = %bb + %mallocsize = mul i64 28, undef ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %0 = bitcast i8* %malloccall to %struct.s_net* ; <%struct.s_net*> [#uses=1] + br i1 undef, label %bb.i1.i39, label %my_malloc.exit2.i + +bb.i1.i39: ; preds = %bb1.i38 + unreachable + +my_malloc.exit2.i: ; preds = %bb1.i38 + store %struct.s_net* %0, %struct.s_net** @net, align 4 + br i1 undef, label %bb.i7.i40, label %my_malloc.exit8.i + +bb.i7.i40: ; preds = %my_malloc.exit2.i + unreachable + +my_malloc.exit8.i: ; preds = %my_malloc.exit2.i + unreachable + +bb7: ; preds = %bb6.preheader + unreachable +} + +declare noalias i8* @malloc(i64) diff --git a/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll b/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll new file mode 100644 index 00000000000..461c25316e9 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-apple-darwin10.0" + +%struct.hashheader = type { i16, i16, i16, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, [5 x i8], [13 x i8], i8, i8, i8, [228 x i16], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [128 x i8], [100 x [11 x i8]], [100 x i32], [100 x i32], i16 } +%struct.strchartype = type { i8*, i8*, i8* } + +@hashheader = internal global %struct.hashheader zeroinitializer, align 32 ; <%struct.hashheader*> [#uses=1] +@chartypes = internal global %struct.strchartype* null ; <%struct.strchartype**> [#uses=1] +; CHECK-NOT: @hashheader +; CHECK-NOT: @chartypes + +; based on linit in office-ispell +define void @test() nounwind ssp { + %1 = load i32, i32* getelementptr inbounds (%struct.hashheader, %struct.hashheader* @hashheader, i64 0, i32 13), align 8 ; <i32> [#uses=1] + %2 = sext i32 %1 to i64 ; <i64> [#uses=1] + %3 = mul i64 %2, ptrtoint (%struct.strchartype* getelementptr (%struct.strchartype, %struct.strchartype* null, i64 1) to i64) ; <i64> [#uses=1] + %4 = tail call i8* @malloc(i64 %3) ; <i8*> [#uses=1] +; CHECK-NOT: call i8* @malloc(i64 + %5 = bitcast i8* %4 to %struct.strchartype* ; <%struct.strchartype*> [#uses=1] + store %struct.strchartype* %5, %struct.strchartype** @chartypes, align 8 + ret void +} + +declare noalias i8* @malloc(i64) diff --git a/llvm/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll b/llvm/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll new file mode 100644 index 00000000000..25bb9769f49 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-11-16-MallocSingleStoreToGlobalVar.ll @@ -0,0 +1,30 @@ +; Test ensures that non-optimizable array mallocs are not optimized; specifically +; GlobalOpt was treating a non-optimizable array malloc as a non-array malloc +; and optimizing the global object that the malloc was stored to as a single +; element global. The global object @TOP in this test should not be optimized. +; RUN: opt < %s -globalopt -S | FileCheck %s + +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-apple-darwin10.0" + +@TOP = internal global i64* null ; <i64**> [#uses=2] +; CHECK: @TOP = internal unnamed_addr global i64* null +@channelColumns = internal global i64 0 ; <i64*> [#uses=2] + +; Derived from @DescribeChannel() in yacr2 +define void @test() nounwind ssp { + store i64 2335, i64* @channelColumns, align 8 + %1 = load i64, i64* @channelColumns, align 8 ; <i64> [#uses=1] + %2 = shl i64 %1, 3 ; <i64> [#uses=1] + %3 = add i64 %2, 8 ; <i64> [#uses=1] + %4 = call noalias i8* @malloc(i64 %3) nounwind ; <i8*> [#uses=1] +; CHECK: call noalias i8* @malloc + %5 = bitcast i8* %4 to i64* ; <i64*> [#uses=1] + store i64* %5, i64** @TOP, align 8 + %6 = load i64*, i64** @TOP, align 8 ; <i64*> [#uses=1] + %7 = getelementptr inbounds i64, i64* %6, i64 13 ; <i64*> [#uses=1] + store i64 0, i64* %7, align 8 + ret void +} + +declare noalias i8* @malloc(i64) nounwind diff --git a/llvm/test/Transforms/GlobalOpt/2010-02-25-MallocPromote.ll b/llvm/test/Transforms/GlobalOpt/2010-02-25-MallocPromote.ll new file mode 100644 index 00000000000..9f53ce402fd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2010-02-25-MallocPromote.ll @@ -0,0 +1,18 @@ +; PR6422 +; RUN: opt -globalopt -S < %s +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +@fixLRBT = internal global i32* null ; <i32**> [#uses=2] + +declare noalias i8* @malloc(i32) + +define i32 @parser() nounwind { +bb918: + %malloccall.i10 = call i8* @malloc(i32 16) nounwind ; <i8*> [#uses=1] + %0 = bitcast i8* %malloccall.i10 to i32* ; <i32*> [#uses=1] + store i32* %0, i32** @fixLRBT, align 8 + %1 = load i32*, i32** @fixLRBT, align 8 ; <i32*> [#uses=0] + %A = load i32, i32* %1 + ret i32 %A +} diff --git a/llvm/test/Transforms/GlobalOpt/2010-02-26-MallocSROA.ll b/llvm/test/Transforms/GlobalOpt/2010-02-26-MallocSROA.ll new file mode 100644 index 00000000000..12fa3419192 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2010-02-26-MallocSROA.ll @@ -0,0 +1,27 @@ +; RUN: opt -globalopt -S < %s +; PR6435 +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.xyz = type { double, i32 } + +@Y = internal global %struct.xyz* null ; <%struct.xyz**> [#uses=2] +@numf2s = external global i32 ; <i32*> [#uses=1] + +define fastcc void @init_net() nounwind { +entry: + %0 = load i32, i32* @numf2s, align 4 ; <i32> [#uses=1] + %mallocsize2 = shl i32 %0, 4 ; <i32> [#uses=1] + %malloccall3 = tail call i8* @malloc(i32 %mallocsize2) nounwind ; <i8*> [#uses=1] + %1 = bitcast i8* %malloccall3 to %struct.xyz* ; <%struct.xyz*> [#uses=1] + store %struct.xyz* %1, %struct.xyz** @Y, align 8 + ret void +} + +define fastcc void @load_train(i8* %trainfile, i32 %mode, i32 %objects) nounwind { +entry: + %0 = load %struct.xyz*, %struct.xyz** @Y, align 8 ; <%struct.xyz*> [#uses=0] + ret void +} + +declare noalias i8* @malloc(i32) diff --git a/llvm/test/Transforms/GlobalOpt/2010-10-19-WeakOdr.ll b/llvm/test/Transforms/GlobalOpt/2010-10-19-WeakOdr.ll new file mode 100644 index 00000000000..c88dc1c2d12 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2010-10-19-WeakOdr.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; PR8389: Globals with weak_odr linkage type must not be modified + +; CHECK: weak_odr local_unnamed_addr global i32 0 + +@SomeVar = weak_odr global i32 0 + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @CTOR } ] + +define internal void @CTOR() { + store i32 23, i32* @SomeVar + ret void +} + + diff --git a/llvm/test/Transforms/GlobalOpt/2011-04-09-EmptyGlobalCtors.ll b/llvm/test/Transforms/GlobalOpt/2011-04-09-EmptyGlobalCtors.ll new file mode 100644 index 00000000000..321a487cc82 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2011-04-09-EmptyGlobalCtors.ll @@ -0,0 +1,5 @@ +; RUN: opt < %s -globalopt -disable-output + +%0 = type { i32, void ()* } +@llvm.global_ctors = appending global [0 x %0] zeroinitializer + diff --git a/llvm/test/Transforms/GlobalOpt/2012-05-11-blockaddress.ll b/llvm/test/Transforms/GlobalOpt/2012-05-11-blockaddress.ll new file mode 100644 index 00000000000..24213af024f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2012-05-11-blockaddress.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; Check that the mere presence of a blockaddress doesn't prevent -globalopt +; from promoting @f to fastcc. + +; CHECK-LABEL: define{{.*}}fastcc{{.*}}@f( +define internal i8* @f() { + ret i8* blockaddress(@f, %L1) +L1: + ret i8* null +} + +define void @g() { + ; CHECK: call{{.*}}fastcc{{.*}}@f + %p = call i8* @f() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/GSROA-section.ll b/llvm/test/Transforms/GlobalOpt/GSROA-section.ll new file mode 100644 index 00000000000..a439fa0797d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/GSROA-section.ll @@ -0,0 +1,30 @@ +; This test lets globalopt split the global struct and array into different +; values. The pass needs to preserve section attribute. + +; RUN: opt < %s -globalopt -S | FileCheck %s +; Check that the new global values still have their section assignment. +; CHECK: @struct +; CHECK: section ".foo" +; CHECK: @array +; CHECK-NOT: section ".foo" + +@struct = internal global { i32, i32 } zeroinitializer, section ".foo" +@array = internal global [ 2 x i32 ] zeroinitializer + +define i32 @foo() { + %A = load i32, i32* getelementptr ({ i32, i32 }, { i32, i32 }* @struct, i32 0, i32 0) + %B = load i32, i32* getelementptr ([ 2 x i32 ], [ 2 x i32 ]* @array, i32 0, i32 0) + ; Use the loaded values, so they won't get removed completely + %R = add i32 %A, %B + ret i32 %R +} + +; We put stores in a different function, so that the global variables won't get +; optimized away completely. +define void @bar(i32 %R) { + store i32 %R, i32* getelementptr ([ 2 x i32 ], [ 2 x i32 ]* @array, i32 0, i32 0) + store i32 %R, i32* getelementptr ({ i32, i32 }, { i32, i32 }* @struct, i32 0, i32 0) + ret void +} + + diff --git a/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll new file mode 100644 index 00000000000..c9b3f6fc1cd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/MallocSROA-section-no-null-opt.ll @@ -0,0 +1,34 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +; CHECK: @Y +; CHECK: section ".foo" + +%struct.xyz = type { double, i32 } + +@Y = internal global %struct.xyz* null ,section ".foo" ; <%struct.xyz**> [#uses=2] +@numf2s = external global i32 ; <i32*> [#uses=1] + +define void @init_net() #0 { +; CHECK-LABEL: init_net( +; CHECK: load i32, i32* @numf2s +; CHECK: call i8* @malloc +; CHECK: store %struct.xyz* {{.*}}, %struct.xyz** @Y +entry: + %0 = load i32, i32* @numf2s, align 4 ; <i32> [#uses=1] + %mallocsize2 = shl i32 %0, 4 ; <i32> [#uses=1] + %malloccall3 = tail call i8* @malloc(i32 %mallocsize2) ; <i8*> [#uses=1] + %1 = bitcast i8* %malloccall3 to %struct.xyz* ; <%struct.xyz*> [#uses=1] + store %struct.xyz* %1, %struct.xyz** @Y, align 8 + ret void +} + +define %struct.xyz* @load_train() #0 { +; CHECK-LABEL: load_train( +; CHECK: load %struct.xyz*, %struct.xyz** @Y +entry: + %0 = load %struct.xyz*, %struct.xyz** @Y, align 8 ; <%struct.xyz*> [#uses=0] + ret %struct.xyz* %0 +} + +declare noalias i8* @malloc(i32) + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/MallocSROA-section.ll b/llvm/test/Transforms/GlobalOpt/MallocSROA-section.ll new file mode 100644 index 00000000000..75b3cfec137 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/MallocSROA-section.ll @@ -0,0 +1,28 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +; CHECK: @Y.f0 +; CHECK: section ".foo" +; CHECK: @Y.f1 +; CHECK: section ".foo" + +%struct.xyz = type { double, i32 } + +@Y = internal global %struct.xyz* null ,section ".foo" ; <%struct.xyz**> [#uses=2] +@numf2s = external global i32 ; <i32*> [#uses=1] + +define void @init_net() { +entry: + %0 = load i32, i32* @numf2s, align 4 ; <i32> [#uses=1] + %mallocsize2 = shl i32 %0, 4 ; <i32> [#uses=1] + %malloccall3 = tail call i8* @malloc(i32 %mallocsize2) ; <i8*> [#uses=1] + %1 = bitcast i8* %malloccall3 to %struct.xyz* ; <%struct.xyz*> [#uses=1] + store %struct.xyz* %1, %struct.xyz** @Y, align 8 + ret void +} + +define void @load_train() { +entry: + %0 = load %struct.xyz*, %struct.xyz** @Y, align 8 ; <%struct.xyz*> [#uses=0] + ret void +} + +declare noalias i8* @malloc(i32) diff --git a/llvm/test/Transforms/GlobalOpt/PowerPC/coldcc_coldsites.ll b/llvm/test/Transforms/GlobalOpt/PowerPC/coldcc_coldsites.ll new file mode 100644 index 00000000000..8fedf834f40 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/PowerPC/coldcc_coldsites.ll @@ -0,0 +1,81 @@ +; RUN: opt -globalopt -mtriple=powerpc64le-unknown-linux-gnu -ppc-enable-coldcc -S < %s | FileCheck %s -check-prefix=COLDCC +; RUN: opt -globalopt -S < %s | FileCheck %s -check-prefix=CHECK + +define signext i32 @caller(i32 signext %a, i32 signext %b, i32 signext %lim, i32 signext %i) local_unnamed_addr #0 !prof !30 { +entry: +; COLDCC: call coldcc signext i32 @callee +; CHECK: call fastcc signext i32 @callee + %add = add nsw i32 %b, %a + %sub = add nsw i32 %lim, -1 + %cmp = icmp eq i32 %sub, %i + br i1 %cmp, label %if.then, label %if.end, !prof !31 + +if.then: ; preds = %entry + %call = tail call signext i32 @callee(i32 signext %a, i32 signext %b) + br label %if.end + +if.end: ; preds = %if.then, %entry + %f.0 = phi i32 [ %call, %if.then ], [ %add, %entry ] + ret i32 %f.0 +} + +define internal signext i32 @callee(i32 signext %a, i32 signext %b) unnamed_addr #0 { +entry: + %0 = tail call i32 asm "add $0, $1, $2", "=r,r,r,~{r6},~{r7},~{r8},~{r9}"(i32 %a, i32 %b) #1, !srcloc !32 + %mul = mul nsw i32 %a, 3 + %mul1 = shl i32 %0, 1 + %add = add nsw i32 %mul1, %mul + ret i32 %add +} + +define signext i32 @main() local_unnamed_addr #0 !prof !33 { +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.body + %add.lcssa = phi i32 [ %add, %for.body ] + ret i32 %add.lcssa + +for.body: ; preds = %for.body, %entry + %i.011 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %ret.010 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %call = tail call signext i32 @caller(i32 signext 4, i32 signext 5, i32 signext 10000000, i32 signext %i.011) + %add = add nsw i32 %call, %ret.010 + %inc = add nuw nsw i32 %i.011, 1 + %exitcond = icmp eq i32 %inc, 10000000 + br i1 %exitcond, label %for.cond.cleanup, label %for.body, !prof !34 +} +attributes #0 = { noinline } + +!0 = !{i32 1, !"ProfileSummary", !1} +!1 = !{!2, !3, !4, !5, !6, !7, !8, !9} +!2 = !{!"ProfileFormat", !"InstrProf"} +!3 = !{!"TotalCount", i64 20000003} +!4 = !{!"MaxCount", i64 10000000} +!5 = !{!"MaxInternalCount", i64 10000000} +!6 = !{!"MaxFunctionCount", i64 10000000} +!7 = !{!"NumCounts", i64 5} +!8 = !{!"NumFunctions", i64 3} +!9 = !{!"DetailedSummary", !10} +!10 = !{!11, !12, !13, !14, !15, !16, !16, !17, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26} +!11 = !{i32 10000, i64 10000000, i32 2} +!12 = !{i32 100000, i64 10000000, i32 2} +!13 = !{i32 200000, i64 10000000, i32 2} +!14 = !{i32 300000, i64 10000000, i32 2} +!15 = !{i32 400000, i64 10000000, i32 2} +!16 = !{i32 500000, i64 10000000, i32 2} +!17 = !{i32 600000, i64 10000000, i32 2} +!18 = !{i32 700000, i64 10000000, i32 2} +!19 = !{i32 800000, i64 10000000, i32 2} +!20 = !{i32 900000, i64 10000000, i32 2} +!21 = !{i32 950000, i64 10000000, i32 2} +!22 = !{i32 990000, i64 10000000, i32 2} +!23 = !{i32 999000, i64 10000000, i32 2} +!24 = !{i32 999900, i64 10000000, i32 2} +!25 = !{i32 999990, i64 10000000, i32 2} +!26 = !{i32 999999, i64 10000000, i32 2} +!30 = !{!"function_entry_count", i64 10000000} +!31 = !{!"branch_weights", i32 2, i32 10000000} +!32 = !{i32 59} +!33 = !{!"function_entry_count", i64 1} +!34 = !{!"branch_weights", i32 2, i32 10000001} diff --git a/llvm/test/Transforms/GlobalOpt/PowerPC/lit.local.cfg b/llvm/test/Transforms/GlobalOpt/PowerPC/lit.local.cfg new file mode 100644 index 00000000000..5d33887ff0a --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/PowerPC/lit.local.cfg @@ -0,0 +1,3 @@ +if not 'PowerPC' in config.root.targets: + config.unsupported = True + diff --git a/llvm/test/Transforms/GlobalOpt/SROA-section.ll b/llvm/test/Transforms/GlobalOpt/SROA-section.ll new file mode 100644 index 00000000000..1589608a67a --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/SROA-section.ll @@ -0,0 +1,27 @@ +; Verify that section assignment is copied during SROA +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: @G.0 +; CHECK: section ".foo" +; CHECK: @G.1 +; CHECK: section ".foo" +; CHECK: @G.2 +; CHECK: section ".foo" + +%T = type { double, double, double } +@G = internal global %T zeroinitializer, align 16, section ".foo" + +define void @test() { + store double 1.0, double* getelementptr (%T, %T* @G, i32 0, i32 0), align 16 + store double 2.0, double* getelementptr (%T, %T* @G, i32 0, i32 1), align 8 + store double 3.0, double* getelementptr (%T, %T* @G, i32 0, i32 2), align 16 + ret void +} + +define double @test2() { + %V1 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 0), align 16 + %V2 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 1), align 8 + %V3 = load double, double* getelementptr (%T, %T* @G, i32 0, i32 2), align 16 + %R = fadd double %V1, %V2 + %R2 = fadd double %R, %V3 + ret double %R2 +} diff --git a/llvm/test/Transforms/GlobalOpt/alias-resolve.ll b/llvm/test/Transforms/GlobalOpt/alias-resolve.ll new file mode 100644 index 00000000000..46b90ec29b9 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/alias-resolve.ll @@ -0,0 +1,46 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@foo1 = alias void (), void ()* @foo2 +; CHECK: @foo1 = alias void (), void ()* @bar2 + +@foo2 = alias void(), void()* @bar1 +; CHECK: @foo2 = alias void (), void ()* @bar2 + +@bar1 = alias void (), void ()* @bar2 +; CHECK: @bar1 = alias void (), void ()* @bar2 + +@weak1 = weak alias void (), void ()* @bar2 +; CHECK: @weak1 = weak alias void (), void ()* @bar2 + +@bar4 = private unnamed_addr constant [2 x i8*] zeroinitializer +@foo4 = weak_odr unnamed_addr alias i8*, getelementptr inbounds ([2 x i8*], [2 x i8*]* @bar4, i32 0, i32 1) +; CHECK: @foo4 = weak_odr unnamed_addr alias i8*, getelementptr inbounds ([2 x i8*], [2 x i8*]* @bar4, i32 0, i32 1) + +define void @bar2() { + ret void +} +; CHECK: define void @bar2() + +define void @baz() { +entry: + call void @foo1() +; CHECK: call void @bar2() + + call void @foo2() +; CHECK: call void @bar2() + + call void @bar1() +; CHECK: call void @bar2() + + call void @weak1() +; CHECK: call void @weak1() + ret void +} + +@foo3 = alias void (), void ()* @bar3 +; CHECK-NOT: bar3 + +define internal void @bar3() { + ret void +} +;CHECK: define void @foo3 diff --git a/llvm/test/Transforms/GlobalOpt/alias-used-address-space.ll b/llvm/test/Transforms/GlobalOpt/alias-used-address-space.ll new file mode 100644 index 00000000000..08081b89ac6 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/alias-used-address-space.ll @@ -0,0 +1,26 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +target datalayout = "p:32:32:32-p1:16:16:16" + +@c = addrspace(1) global i8 42 + +@i = internal addrspace(1) global i8 42 + +; CHECK: @ia = internal addrspace(1) global i8 42 +@ia = internal alias i8, i8 addrspace(1)* @i + +@llvm.used = appending global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* @ca to i8*)], section "llvm.metadata" +; CHECK-DAG: @llvm.used = appending global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* @ca to i8*)], section "llvm.metadata" + +@llvm.compiler.used = appending global [2 x i8*] [i8* addrspacecast(i8 addrspace(1)* @ia to i8*), i8* addrspacecast (i8 addrspace(1)* @i to i8*)], section "llvm.metadata" +; CHECK-DAG: @llvm.compiler.used = appending global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* @ia to i8*)], section "llvm.metadata" + +@sameAsUsed = global [1 x i8*] [i8* addrspacecast(i8 addrspace(1)* @ca to i8*)] +; CHECK-DAG: @sameAsUsed = local_unnamed_addr global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* @c to i8*)] + +@ca = internal alias i8, i8 addrspace(1)* @c +; CHECK: @ca = internal alias i8, i8 addrspace(1)* @c + +define i8 addrspace(1)* @h() { + ret i8 addrspace(1)* @ca +} diff --git a/llvm/test/Transforms/GlobalOpt/alias-used-section.ll b/llvm/test/Transforms/GlobalOpt/alias-used-section.ll new file mode 100644 index 00000000000..a3657dfd16b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/alias-used-section.ll @@ -0,0 +1,8 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +@_Z17in_custom_section = internal global i8 42, section "CUSTOM" +@in_custom_section = internal dllexport alias i8, i8* @_Z17in_custom_section + +; CHECK: @in_custom_section = internal dllexport global i8 42, section "CUSTOM" + +@llvm.used = appending global [1 x i8*] [i8* @in_custom_section], section "llvm.metadata" diff --git a/llvm/test/Transforms/GlobalOpt/alias-used.ll b/llvm/test/Transforms/GlobalOpt/alias-used.ll new file mode 100644 index 00000000000..91601fb9927 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/alias-used.ll @@ -0,0 +1,66 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@c = global i8 42 + +@i = internal global i8 42 +; CHECK: @ia = internal global i8 42 +@ia = internal alias i8, i8* @i + +@llvm.used = appending global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca], section "llvm.metadata" +; CHECK-DAG: @llvm.used = appending global [3 x i8*] [i8* @ca, i8* bitcast (void ()* @f to i8*), i8* bitcast (void ()* @fa to i8*)], section "llvm.metadata" + +@llvm.compiler.used = appending global [4 x i8*] [i8* bitcast (void ()* @fa3 to i8*), i8* bitcast (void ()* @fa to i8*), i8* @ia, i8* @i], section "llvm.metadata" +; CHECK-DAG: @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast (void ()* @fa3 to i8*), i8* @ia], section "llvm.metadata" + +@sameAsUsed = global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca] +; CHECK-DAG: @sameAsUsed = local_unnamed_addr global [3 x i8*] [i8* bitcast (void ()* @f to i8*), i8* bitcast (void ()* @f to i8*), i8* @c] + +@other = global i32* bitcast (void ()* @fa to i32*) +; CHECK-DAG: @other = local_unnamed_addr global i32* bitcast (void ()* @f to i32*) + +@fa = internal alias void (), void ()* @f +; CHECK: @fa = internal alias void (), void ()* @f + +@fa2 = internal alias void (), void ()* @f +; CHECK-NOT: @fa2 + +@fa3 = internal alias void (), void ()* @f +; CHECK: @fa3 + +@ca = internal alias i8, i8* @c +; CHECK: @ca = internal alias i8, i8* @c + +define void @f() { + ret void +} + +define i8* @g() { + ret i8* bitcast (void ()* @fa to i8*); +} + +define i8* @g2() { + ret i8* bitcast (void ()* @fa2 to i8*); +} + +define i8* @h() { + ret i8* @ca +} + +; Check that GlobalOpt doesn't try to resolve aliases with GEP operands. + +%struct.S = type { i32, i32, i32 } +@s = global %struct.S { i32 1, i32 2, i32 3 }, align 4 + +@alias1 = alias i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i64 0, i32 1) +@alias2 = alias i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i64 0, i32 2) + +; CHECK: load i32, i32* @alias1, align 4 +; CHECK: load i32, i32* @alias2, align 4 + +define i32 @foo1() { +entry: + %0 = load i32, i32* @alias1, align 4 + %1 = load i32, i32* @alias2, align 4 + %add = add nsw i32 %1, %0 + ret i32 %add +} diff --git a/llvm/test/Transforms/GlobalOpt/amdgcn-ctor-alloca.ll b/llvm/test/Transforms/GlobalOpt/amdgcn-ctor-alloca.ll new file mode 100644 index 00000000000..6bdcf49e95e --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/amdgcn-ctor-alloca.ll @@ -0,0 +1,17 @@ +; RUN: opt -data-layout=A5 -globalopt %s -S -o - | FileCheck %s + +; CHECK-NOT: @g +@g = internal addrspace(1) global i32* zeroinitializer + +; CHECK: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] + [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }] + +; CHECK-NOT: @ctor +define internal void @ctor() { + %addr = alloca i32, align 8, addrspace(5) + %tmp = addrspacecast i32 addrspace(5)* %addr to i32* + store i32* %tmp, i32* addrspace(1)* @g + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/array-elem-refs.ll b/llvm/test/Transforms/GlobalOpt/array-elem-refs.ll new file mode 100644 index 00000000000..c31965b656d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/array-elem-refs.ll @@ -0,0 +1,32 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.S = type { i8, i8 } + +@c = internal global i8** bitcast (i8* getelementptr (i8, i8* bitcast ([8 x i8*]* @b to i8*), i64 48) to i8**), align 8 +@b = internal global [8 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* getelementptr inbounds (%struct.S, %struct.S* @a, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S, %struct.S* @a, i32 0, i32 0), i64 1)], align 16 +@a = internal global %struct.S zeroinitializer, align 1 + +; Function Attrs: nounwind uwtable +define signext i8 @foo() #0 { +entry: + %0 = load i8**, i8*** @c, align 8 + %1 = load i8*, i8** %0, align 8 + %2 = load i8, i8* %1, align 1 + ret i8 %2 + +; CHECK-LABEL: @foo +; CHECK: ret i8 0 +} + +; Function Attrs: nounwind uwtable +define i32 @main() #0 { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + ret i32 0 +} + +attributes #0 = { nounwind uwtable } + diff --git a/llvm/test/Transforms/GlobalOpt/assume.ll b/llvm/test/Transforms/GlobalOpt/assume.ll new file mode 100644 index 00000000000..b15106bc83a --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/assume.ll @@ -0,0 +1,21 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +; CHECK: @tmp = local_unnamed_addr global i32 42 + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] +@tmp = global i32 0 + +define i32 @TheAnswerToLifeTheUniverseAndEverything() { + ret i32 42 +} + +define void @_GLOBAL__I_a() { +enter: + %tmp1 = call i32 @TheAnswerToLifeTheUniverseAndEverything() + store i32 %tmp1, i32* @tmp + %cmp = icmp eq i32 %tmp1, 42 + call void @llvm.assume(i1 %cmp) + ret void +} + +declare void @llvm.assume(i1) diff --git a/llvm/test/Transforms/GlobalOpt/atexit.ll b/llvm/test/Transforms/GlobalOpt/atexit.ll new file mode 100644 index 00000000000..55c2dab1c1d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/atexit.ll @@ -0,0 +1,6 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; CHECK: ModuleID +define internal i32 @__cxa_atexit(void (i8*)* nocapture %func, i8* nocapture %arg, i8* nocapture %dso_handle) nounwind readnone optsize noimplicitfloat { + unreachable +} diff --git a/llvm/test/Transforms/GlobalOpt/atomic.ll b/llvm/test/Transforms/GlobalOpt/atomic.ll new file mode 100644 index 00000000000..563c1fec7d2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/atomic.ll @@ -0,0 +1,25 @@ +; RUN: opt -globalopt < %s -S -o - | FileCheck %s + +@GV1 = internal global i64 1 +@GV2 = internal global i32 0 + +; CHECK: @GV1 = internal unnamed_addr constant i64 1 +; CHECK: @GV2 = internal unnamed_addr global i32 0 + +define void @test1() { +entry: + %0 = load atomic i8, i8* bitcast (i64* @GV1 to i8*) acquire, align 8 + ret void +} + +; PR17163 +define void @test2a() { +entry: + store atomic i32 10, i32* @GV2 seq_cst, align 4 + ret void +} +define i32 @test2b() { +entry: + %atomic-load = load atomic i32, i32* @GV2 seq_cst, align 4 + ret i32 %atomic-load +} diff --git a/llvm/test/Transforms/GlobalOpt/available_externally_global_ctors.ll b/llvm/test/Transforms/GlobalOpt/available_externally_global_ctors.ll new file mode 100644 index 00000000000..7092a5ae222 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/available_externally_global_ctors.ll @@ -0,0 +1,22 @@ +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +; RUN: opt -S -globalopt < %s | FileCheck %s + +; Verify that the initialization of the available_externally global is not eliminated +; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo_static_init, i8* null }] + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @foo_static_init, i8* null }] +@foo_external = available_externally global void ()* null + +define internal void @foo_static_init() { +entry: + store void ()* @foo_impl, void ()** @foo_external + ret void +} + +define internal void @foo_impl() { +entry: + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/basictest.ll b/llvm/test/Transforms/GlobalOpt/basictest.ll new file mode 100644 index 00000000000..d5294820abe --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/basictest.ll @@ -0,0 +1,10 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; RUN: opt < %s -passes=globalopt -S | FileCheck %s + +; CHECK-NOT: global +@X = internal global i32 4 ; <i32*> [#uses=1] + +define i32 @foo() { + %V = load i32, i32* @X ; <i32> [#uses=1] + ret i32 %V +} diff --git a/llvm/test/Transforms/GlobalOpt/blockaddress.ll b/llvm/test/Transforms/GlobalOpt/blockaddress.ll new file mode 100644 index 00000000000..12e09fcd481 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/blockaddress.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@x = internal global i8* zeroinitializer + +define void @f() { +; CHECK-LABEL: @f( + +; Check that we don't hit an assert in Constant::IsThreadDependent() +; when storing this blockaddress into a global. + + store i8* blockaddress(@g, %here), i8** @x, align 8 + ret void +} + +define void @g() { +entry: + br label %here + +; CHECK-LABEL: @g( + +here: + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll new file mode 100644 index 00000000000..16da5315db0 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users.ll @@ -0,0 +1,49 @@ +; RUN: opt -globalopt -S -o - < %s | FileCheck %s + +@glbl = internal global i8* null + +define void @test1a() { +; CHECK-LABEL: @test1a( +; CHECK-NOT: store +; CHECK-NEXT: ret void + store i8* null, i8** @glbl + ret void +} + +define void @test1b(i8* %p) { +; CHECK-LABEL: @test1b( +; CHECK-NEXT: store +; CHECK-NEXT: ret void + store i8* %p, i8** @glbl + ret void +} + +define void @test2() { +; CHECK-LABEL: @test2( +; CHECK: alloca i8 + %txt = alloca i8 + call void @foo2(i8* %txt) + %call2 = call i8* @strdup(i8* %txt) + store i8* %call2, i8** @glbl + ret void +} +declare i8* @strdup(i8*) +declare void @foo2(i8*) + +define void @test3() uwtable personality i32 (i32, i64, i8*, i8*)* @__gxx_personality_v0 { +; CHECK-LABEL: @test3( +; CHECK-NOT: bb1: +; CHECK-NOT: bb2: +; CHECK: invoke + %ptr = invoke i8* @_Znwm(i64 1) + to label %bb1 unwind label %bb2 +bb1: + store i8* %ptr, i8** @glbl + unreachable +bb2: + %tmp1 = landingpad { i8*, i32 } + cleanup + resume { i8*, i32 } %tmp1 +} +declare i32 @__gxx_personality_v0(i32, i64, i8*, i8*) +declare i8* @_Znwm(i64) diff --git a/llvm/test/Transforms/GlobalOpt/coldcc_stress_test.ll b/llvm/test/Transforms/GlobalOpt/coldcc_stress_test.ll new file mode 100644 index 00000000000..80c9366af6f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/coldcc_stress_test.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -globalopt -S -enable-coldcc-stress-test -mtriple=powerpc64le-unknown-linux-gnu | FileCheck %s -check-prefix=COLDCC +; RUN: opt < %s -globalopt -S | FileCheck %s -check-prefix=CHECK + +define internal i32 @callee_default(i32* %m) { +; COLDCC-LABEL: define internal coldcc i32 @callee_default +; CHECK-LABEL: define internal fastcc i32 @callee_default + %v = load i32, i32* %m + ret i32 %v +} + +define internal fastcc i32 @callee_fastcc(i32* %m) { +; COLDCC-LABEL: define internal fastcc i32 @callee_fastcc +; CHECK-LABEL: define internal fastcc i32 @callee_fastcc + %v = load i32, i32* %m + ret i32 %v +} + +define internal coldcc i32 @callee_coldcc(i32* %m) { +; COLDCC-LABEL: define internal coldcc i32 @callee_coldcc +; CHECK-LABEL: define internal coldcc i32 @callee_coldcc + %v = load i32, i32* %m + ret i32 %v +} + +define i32 @callee(i32* %m) { + %v = load i32, i32* %m + ret i32 %v +} + +define void @caller() { + %m = alloca i32 + call i32 @callee_default(i32* %m) + call fastcc i32 @callee_fastcc(i32* %m) + call coldcc i32 @callee_coldcc(i32* %m) + call i32 @callee(i32* %m) + ret void +} + +; COLDCC-LABEL: define void @caller() +; COLDCC: call coldcc i32 @callee_default +; COLDCC: call fastcc i32 @callee_fastcc +; COLDCC: call coldcc i32 @callee_coldcc +; COLDCC: call i32 @callee +; CHECK-LABEL: define void @caller() +; CHECK: call fastcc i32 @callee_default +; CHECK: call fastcc i32 @callee_fastcc +; CHECK: call coldcc i32 @callee_coldcc +; CHECK: call i32 @callee diff --git a/llvm/test/Transforms/GlobalOpt/compiler-used.ll b/llvm/test/Transforms/GlobalOpt/compiler-used.ll new file mode 100644 index 00000000000..a710d272edc --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/compiler-used.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; Test that when all members of llvm.compiler.used are found to be redundant +; we delete it instead of crashing. + +define void @foo() { + ret void +} + +@llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" + +@llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" + +; CHECK-NOT: @llvm.compiler.used +; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" +; CHECK-NOT: @llvm.compiler.used diff --git a/llvm/test/Transforms/GlobalOpt/constantexpr-dangle.ll b/llvm/test/Transforms/GlobalOpt/constantexpr-dangle.ll new file mode 100644 index 00000000000..3917bfff411 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/constantexpr-dangle.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -instcombine -globalopt -S | FileCheck %s +; CHECK: internal fastcc float @foo + +define internal float @foo() { + ret float 0.000000e+00 +} + +define float @bar() { + %tmp1 = call float (...) bitcast (float ()* @foo to float (...)*)( ) + %tmp2 = fmul float %tmp1, 1.000000e+01 ; <float> [#uses=1] + ret float %tmp2 +} diff --git a/llvm/test/Transforms/GlobalOpt/constantfold-initializers.ll b/llvm/test/Transforms/GlobalOpt/constantfold-initializers.ll new file mode 100644 index 00000000000..3c20353d157 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/constantfold-initializers.ll @@ -0,0 +1,103 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" + +@.str91250 = global [3 x i8] zeroinitializer + +; CHECK: @A = local_unnamed_addr global i1 false +@A = global i1 icmp ne (i64 sub nsw (i64 ptrtoint (i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str91250, i64 0, i64 1) to i64), i64 ptrtoint ([3 x i8]* @.str91250 to i64)), i64 1) + +; PR11352 + +@xs = global [2 x i32] zeroinitializer, align 4 +; CHECK: @xs = local_unnamed_addr global [2 x i32] [i32 1, i32 1] + +; PR12642 +%PR12642.struct = type { i8 } +@PR12642.s = global <{}> zeroinitializer, align 1 +@PR12642.p = constant %PR12642.struct* bitcast (i8* getelementptr (i8, i8* bitcast (<{}>* @PR12642.s to i8*), i64 1) to %PR12642.struct*), align 8 + +define internal void @test1() { +entry: + store i32 1, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @xs, i64 0, i64 0) + %0 = load i32, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @xs, i32 0, i64 0), align 4 + store i32 %0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @xs, i64 0, i64 1) + ret void +} + +; PR12060 + +%closure = type { i32 } + +@f = internal global %closure zeroinitializer, align 4 +@m = global i32 0, align 4 +; CHECK-NOT: @f +; CHECK: @m = local_unnamed_addr global i32 13 + +define internal i32 @test2_helper(%closure* %this, i32 %b) { +entry: + %0 = getelementptr inbounds %closure, %closure* %this, i32 0, i32 0 + %1 = load i32, i32* %0, align 4 + %add = add nsw i32 %1, %b + ret i32 %add +} + +define internal void @test2() { +entry: + store i32 4, i32* getelementptr inbounds (%closure, %closure* @f, i32 0, i32 0) + %call = call i32 @test2_helper(%closure* @f, i32 9) + store i32 %call, i32* @m, align 4 + ret void +} + +; PR19955 + +@dllimportptr = global i32* null, align 4 +; CHECK: @dllimportptr = local_unnamed_addr global i32* null, align 4 +@dllimportvar = external dllimport global i32 +define internal void @test3() { +entry: + store i32* @dllimportvar, i32** @dllimportptr, align 4 + ret void +} + +@dllexportptr = global i32* null, align 4 +; CHECK: @dllexportptr = local_unnamed_addr global i32* @dllexportvar, align 4 +@dllexportvar = dllexport global i32 0, align 4 +; CHECK: @dllexportvar = dllexport global i32 20, align 4 +define internal void @test4() { +entry: + store i32 20, i32* @dllexportvar, align 4 + store i32* @dllexportvar, i32** @dllexportptr, align 4 + ret void +} + +@threadlocalptr = global i32* null, align 4 +; CHECK: @threadlocalptr = global i32* null, align 4 +@threadlocalvar = external thread_local global i32 +define internal void @test5() { +entry: + store i32* @threadlocalvar, i32** @threadlocalptr, align 4 + ret void +} + +@test6_v1 = internal global { i32, i32 } { i32 42, i32 0 }, align 8 +@test6_v2 = global i32 0, align 4 +; CHECK: @test6_v2 = local_unnamed_addr global i32 42, align 4 +define internal void @test6() { + %load = load { i32, i32 }, { i32, i32 }* @test6_v1, align 8 + %xv0 = extractvalue { i32, i32 } %load, 0 + %iv = insertvalue { i32, i32 } %load, i32 %xv0, 1 + %xv1 = extractvalue { i32, i32 } %iv, 1 + store i32 %xv1, i32* @test6_v2, align 4 + ret void +} + +@llvm.global_ctors = appending constant + [6 x { i32, void ()* }] + [{ i32, void ()* } { i32 65535, void ()* @test1 }, + { i32, void ()* } { i32 65535, void ()* @test2 }, + { i32, void ()* } { i32 65535, void ()* @test3 }, + { i32, void ()* } { i32 65535, void ()* @test4 }, + { i32, void ()* } { i32 65535, void ()* @test5 }, + { i32, void ()* } { i32 65535, void ()* @test6 }] diff --git a/llvm/test/Transforms/GlobalOpt/crash-2.ll b/llvm/test/Transforms/GlobalOpt/crash-2.ll new file mode 100644 index 00000000000..748fb027c7d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/crash-2.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | opt -globalopt -disable-output +; NOTE: This needs to run through 'llvm-as' first to reproduce the error! +; PR15440 + +%union.U5.0.6.12 = type { i32 } +%struct.S0.1.7.13 = type { i8, i8, i8, i8, i16, [2 x i8] } +%struct.S1.2.8.14 = type { i32, i16, i8, i8 } + +@.str = external unnamed_addr constant [2 x i8], align 1 +@g_25 = external global i8, align 1 +@g_71 = internal global %struct.S0.1.7.13 { i8 1, i8 -93, i8 58, i8 -1, i16 -5, [2 x i8] undef }, align 4 +@g_114 = external global i8, align 1 +@g_30 = external global { i32, i8, i32, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8 }, align 4 +@g_271 = internal global [7 x [6 x [5 x i8*]]] [[6 x [5 x i8*]] [[5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* null], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* null, i8* null], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)]], [6 x [5 x i8*]] [[5 x i8*] [i8* @g_25, i8* null, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* @g_25, i8* @g_114, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25], [5 x i8*] [i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25, i8* @g_25, i8* @g_25], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)]], [6 x [5 x i8*]] [[5 x i8*] [i8* null, i8* @g_25, i8* @g_25, i8* @g_25, i8* null], [5 x i8*] [i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* null, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* null, i8* @g_25], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* null], [5 x i8*] [i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)]], [6 x [5 x i8*]] [[5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* null, i8* @g_25], [5 x i8*] [i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25], [5 x i8*] [i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* @g_114, i8* @g_25, i8* @g_25, i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)]], [6 x [5 x i8*]] [[5 x i8*] [i8* @g_25, i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_114], [5 x i8*] [i8* @g_25, i8* null, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* null], [5 x i8*] [i8* @g_114, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* @g_25]], [6 x [5 x i8*]] [[5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* @g_114, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0)], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25]], [6 x [5 x i8*]] [[5 x i8*] [i8* @g_25, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* null], [5 x i8*] [i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* @g_25, i8* @g_25, i8* @g_114], [5 x i8*] [i8* null, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_25, i8* null, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_114, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* @g_114, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1)], [5 x i8*] [i8* @g_25, i8* @g_25, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25], [5 x i8*] [i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25, i8* @g_25, i8* getelementptr (i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), i64 1), i8* @g_25]]], align 4 + +define i32 @func() { + %tmp = load i8, i8* getelementptr inbounds (%struct.S0.1.7.13, %struct.S0.1.7.13* @g_71, i32 0, i32 0), align 1 + ret i32 0 +} diff --git a/llvm/test/Transforms/GlobalOpt/crash.ll b/llvm/test/Transforms/GlobalOpt/crash.ll new file mode 100644 index 00000000000..8cfe9ea0570 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/crash.ll @@ -0,0 +1,80 @@ +; RUN: opt -globalopt -disable-output < %s +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-n8:16:32" +target triple = "i386-apple-darwin9.8" + +%0 = type { i32, void ()* } +%struct.btSimdScalar = type { %"union.btSimdScalar::$_14" } +%"union.btSimdScalar::$_14" = type { <4 x float> } + +@_ZL6vTwist = global %struct.btSimdScalar zeroinitializer ; <%struct.btSimdScalar*> [#uses=1] +@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I__ZN21btConeTwistConstraintC2Ev }] ; <[12 x %0]*> [#uses=0] + +define internal void @_GLOBAL__I__ZN21btConeTwistConstraintC2Ev() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" { +entry: + store float 1.0, float* getelementptr inbounds (%struct.btSimdScalar, %struct.btSimdScalar* @_ZL6vTwist, i32 0, i32 0, i32 0, i32 3), align 4 + ret void +} + + +; PR6760 +%T = type { [5 x i32] } + +@switch_inf = internal global %T* null + +define void @test(i8* %arch_file, i32 %route_type) { +entry: + %A = sext i32 1 to i64 + %B = mul i64 %A, 20 + %C = call noalias i8* @malloc(i64 %B) nounwind + %D = bitcast i8* %C to %T* + store %T* %D, %T** @switch_inf, align 8 + unreachable + +bb.nph.i: + %scevgep.i539 = getelementptr i8, i8* %C, i64 4 + unreachable + +xx: + %E = load %T*, %T** @switch_inf, align 8 + unreachable +} + +declare noalias i8* @malloc(i64) nounwind + + +; PR8063 +@permute_bitrev.bitrev = internal global i32* null, align 8 +define void @permute_bitrev() nounwind { +entry: + %tmp = load i32*, i32** @permute_bitrev.bitrev, align 8 + %conv = sext i32 0 to i64 + %mul = mul i64 %conv, 4 + %call = call i8* @malloc(i64 %mul) + %0 = bitcast i8* %call to i32* + store i32* %0, i32** @permute_bitrev.bitrev, align 8 + ret void +} + + + + +@data8 = internal global [8000 x i8] zeroinitializer, align 16 +define void @memset_with_strange_user() ssp { + call void @llvm.memset.p0i8.i64(i8* align 16 getelementptr inbounds ([8000 x i8], [8000 x i8]* @data8, i64 0, i64 0), i8 undef, i64 ptrtoint (i8* getelementptr ([8000 x i8], [8000 x i8]* @data8, i64 1, i64 sub (i64 0, i64 ptrtoint ([8000 x i8]* @data8 to i64))) to i64), i1 false) + ret void +} +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) nounwind + + +; PR9856 +@g_52 = internal global i32** null, align 8 +@g_90 = external global i32*, align 8 + +define void @icmp_user_of_stored_once() nounwind ssp { +entry: + %tmp4 = load i32**, i32*** @g_52, align 8 + store i32** @g_90, i32*** @g_52 + %cmp17 = icmp ne i32*** undef, @g_52 + ret void +} + diff --git a/llvm/test/Transforms/GlobalOpt/ctor-list-opt-constexpr.ll b/llvm/test/Transforms/GlobalOpt/ctor-list-opt-constexpr.ll new file mode 100644 index 00000000000..0c3ff68a437 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/ctor-list-opt-constexpr.ll @@ -0,0 +1,34 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-apple-darwin10.0.0" + +%0 = type { i32, void ()* } +%struct.foo = type { i32* } +%struct.bar = type { i128 } + +@G = global i32 0, align 4 +@H = global i32 0, align 4 +@X = global %struct.foo zeroinitializer, align 8 +@X2 = global %struct.bar zeroinitializer, align 8 +@llvm.global_ctors = appending global [2 x %0] [%0 { i32 65535, void ()* @init1 }, %0 { i32 65535, void ()* @init2 }] + +; PR8710 - GlobalOpt shouldn't change the global's initializer to have this +; arbitrary constant expression, the code generator can't handle it. +define internal void @init1() { +entry: + %tmp = getelementptr inbounds %struct.foo, %struct.foo* @X, i32 0, i32 0 + store i32* inttoptr (i64 sdiv (i64 ptrtoint (i32* @G to i64), i64 ptrtoint (i32* @H to i64)) to i32*), i32** %tmp, align 8 + ret void +} +; CHECK-LABEL: @init1( +; CHECK: store i32* + +; PR11705 - ptrtoint isn't safe in general in global initializers. +define internal void @init2() { +entry: + %tmp = getelementptr inbounds %struct.bar, %struct.bar* @X2, i32 0, i32 0 + store i128 ptrtoint (i32* @G to i128), i128* %tmp, align 16 + ret void +} +; CHECK-LABEL: @init2( +; CHECK: store i128 diff --git a/llvm/test/Transforms/GlobalOpt/ctor-list-opt-inbounds.ll b/llvm/test/Transforms/GlobalOpt/ctor-list-opt-inbounds.ll new file mode 100644 index 00000000000..b969345710d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/ctor-list-opt-inbounds.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; Don't get fooled by the inbounds keyword; it doesn't change +; the computed address. + +; CHECK: @H = local_unnamed_addr global i32 2 +; CHECK: @I = local_unnamed_addr global i32 2 + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @CTOR } ] +@addr = external global i32 +@G = internal global [6 x [5 x i32]] zeroinitializer +@H = global i32 80 +@I = global i32 90 + +define internal void @CTOR() { + store i32 1, i32* getelementptr ([6 x [5 x i32]], [6 x [5 x i32]]* @G, i64 0, i64 0, i64 0) + store i32 2, i32* getelementptr inbounds ([6 x [5 x i32]], [6 x [5 x i32]]* @G, i64 0, i64 0, i64 0) + %t = load i32, i32* getelementptr ([6 x [5 x i32]], [6 x [5 x i32]]* @G, i64 0, i64 0, i64 0) + store i32 %t, i32* @H + %s = load i32, i32* getelementptr inbounds ([6 x [5 x i32]], [6 x [5 x i32]]* @G, i64 0, i64 0, i64 0) + store i32 %s, i32* @I + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll b/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll new file mode 100644 index 00000000000..95e7d4d1ab5 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll @@ -0,0 +1,115 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: CTOR +%ini = type { i32, void()*, i8* } +@llvm.global_ctors = appending global [11 x %ini] [ + %ini { i32 65535, void ()* @CTOR1, i8* null }, + %ini { i32 65535, void ()* @CTOR1, i8* null }, + %ini { i32 65535, void ()* @CTOR2, i8* null }, + %ini { i32 65535, void ()* @CTOR3, i8* null }, + %ini { i32 65535, void ()* @CTOR4, i8* null }, + %ini { i32 65535, void ()* @CTOR5, i8* null }, + %ini { i32 65535, void ()* @CTOR6, i8* null }, + %ini { i32 65535, void ()* @CTOR7, i8* null }, + %ini { i32 65535, void ()* @CTOR8, i8* null }, + %ini { i32 65535, void ()* @CTOR9, i8* null }, + %ini { i32 2147483647, void ()* null, i8* null } +] + +@G = global i32 0 ; <i32*> [#uses=1] +@G2 = global i32 0 ; <i32*> [#uses=1] +@G3 = global i32 -123 ; <i32*> [#uses=2] +@X = global { i32, [2 x i32] } { i32 0, [2 x i32] [ i32 17, i32 21 ] } ; <{ i32, [2 x i32] }*> [#uses=2] +@Y = global i32 -1 ; <i32*> [#uses=2] +@Z = global i32 123 ; <i32*> [#uses=1] +@D = global double 0.000000e+00 ; <double*> [#uses=1] +@CTORGV = internal global i1 false ; <i1*> [#uses=2] + +define internal void @CTOR1() { + ret void +} + +define internal void @CTOR2() { + %A = add i32 1, 23 ; <i32> [#uses=1] + store i32 %A, i32* @G + store i1 true, i1* @CTORGV + ret void +} + +define internal void @CTOR3() { + %X = or i1 true, false ; <i1> [#uses=1] + br label %Cont + +Cont: ; preds = %0 + br i1 %X, label %S, label %T + +S: ; preds = %Cont + store i32 24, i32* @G2 + ret void + +T: ; preds = %Cont + ret void +} + +define internal void @CTOR4() { + %X = load i32, i32* @G3 ; <i32> [#uses=1] + %Y = add i32 %X, 123 ; <i32> [#uses=1] + store i32 %Y, i32* @G3 + ret void +} + +define internal void @CTOR5() { + %X.2p = getelementptr inbounds { i32, [2 x i32] }, { i32, [2 x i32] }* @X, i32 0, i32 1, i32 0 ; <i32*> [#uses=2] + %X.2 = load i32, i32* %X.2p ; <i32> [#uses=1] + %X.1p = getelementptr inbounds { i32, [2 x i32] }, { i32, [2 x i32] }* @X, i32 0, i32 0 ; <i32*> [#uses=1] + store i32 %X.2, i32* %X.1p + store i32 42, i32* %X.2p + ret void +} + +define internal void @CTOR6() { + %A = alloca i32 ; <i32*> [#uses=2] + %y = load i32, i32* @Y ; <i32> [#uses=1] + store i32 %y, i32* %A + %Av = load i32, i32* %A ; <i32> [#uses=1] + %Av1 = add i32 %Av, 1 ; <i32> [#uses=1] + store i32 %Av1, i32* @Y + ret void +} + +define internal void @CTOR7() { + call void @setto( i32* @Z, i32 0 ) + ret void +} + +define void @setto(i32* %P, i32 %V) { + store i32 %V, i32* %P + ret void +} + +declare double @cos(double) + +define internal void @CTOR8() { + %X = call double @cos( double 0.000000e+00 ) ; <double> [#uses=1] + store double %X, double* @D + ret void +} + +define i1 @accessor() { + %V = load i1, i1* @CTORGV ; <i1> [#uses=1] + ret i1 %V +} + +%struct.A = type { i32 } +%struct.B = type { i32 (...)**, i8*, [4 x i8] } +@GV1 = global %struct.B zeroinitializer, align 8 +@GV2 = constant [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* null to i8*)] +; CHECK-NOT: CTOR9 +define internal void @CTOR9() { +entry: + %0 = bitcast %struct.B* @GV1 to i8* + %1 = getelementptr inbounds i8, i8* %0, i64 16 + %2 = bitcast i8* %1 to %struct.A* + %3 = bitcast %struct.B* @GV1 to i8*** + store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @GV2, i64 1, i64 0), i8*** %3 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/cxx-dtor.ll b/llvm/test/Transforms/GlobalOpt/cxx-dtor.ll new file mode 100644 index 00000000000..c43a8e2be2e --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/cxx-dtor.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -S -passes='cgscc(inline),function(early-cse),globalopt' | FileCheck %s + +%0 = type { i32, void ()* } +%struct.A = type { i8 } +%struct.B = type { } + +@a = global %struct.A zeroinitializer, align 1 +@__dso_handle = external global i8* +@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I_a }] + +; CHECK-NOT: call i32 @__cxa_atexit + +define internal void @__cxx_global_var_init() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" { + %1 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A, %struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) + ret void +} + +define linkonce_odr void @_ZN1AD1Ev(%struct.A* %this) nounwind align 2 { + %t = bitcast %struct.A* %this to %struct.B* + call void @_ZN1BD1Ev(%struct.B* %t) + ret void +} + +declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) + +define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) nounwind align 2 { + ret void +} + +define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @__cxx_global_var_init() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/deaddeclaration.ll b/llvm/test/Transforms/GlobalOpt/deaddeclaration.ll new file mode 100644 index 00000000000..942f2e1bf6b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/deaddeclaration.ll @@ -0,0 +1,7 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; CHECK-NOT: aa +; CHECK-NOT: bb + +declare void @aa() +@bb = external global i8 diff --git a/llvm/test/Transforms/GlobalOpt/deadfunction.ll b/llvm/test/Transforms/GlobalOpt/deadfunction.ll new file mode 100644 index 00000000000..5771c4ccfb7 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/deadfunction.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; CHECK-NOT: test + +declare void @aa() +declare void @bb() + +; Test that we can erase a function which has a blockaddress referring to it +@test.x = internal unnamed_addr constant [3 x i8*] [i8* blockaddress(@test, %a), i8* blockaddress(@test, %b), i8* blockaddress(@test, %c)], align 16 +define internal void @test(i32 %n) nounwind noinline { +entry: + %idxprom = sext i32 %n to i64 + %arrayidx = getelementptr inbounds [3 x i8*], [3 x i8*]* @test.x, i64 0, i64 %idxprom + %0 = load i8*, i8** %arrayidx, align 8 + indirectbr i8* %0, [label %a, label %b, label %c] + +a: + tail call void @aa() nounwind + br label %b + +b: + tail call void @bb() nounwind + br label %c + +c: + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/deadglobal-2.ll b/llvm/test/Transforms/GlobalOpt/deadglobal-2.ll new file mode 100644 index 00000000000..92c0f994f36 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/deadglobal-2.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; This is a harder case to delete as the GEP has a variable index. + +; CHECK-NOT: internal +@G = internal global [4 x i32] zeroinitializer + +define void @foo(i32 %X) { + %Ptr = getelementptr [4 x i32], [4 x i32]* @G, i32 0, i32 %X + store i32 1, i32* %Ptr + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/deadglobal.ll b/llvm/test/Transforms/GlobalOpt/deadglobal.ll new file mode 100644 index 00000000000..f5eed44cbb6 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/deadglobal.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@G1 = internal global i32 123 ; <i32*> [#uses=1] +@A1 = internal alias i32, i32* @G1 + +; CHECK-NOT: @G1 +; CHECK: @G2 +; CHECK-NOT: @G3 + +; CHECK-NOT: @A1 + +define void @foo1() { +; CHECK: define void @foo +; CHECK-NEXT: ret + store i32 1, i32* @G1 + ret void +} + +@G2 = linkonce_odr constant i32 42 + +define void @foo2() { +; CHECK-LABEL: define void @foo2( +; CHECK-NEXT: store + store i32 1, i32* @G2 + ret void +} + +@G3 = linkonce_odr constant i32 42 diff --git a/llvm/test/Transforms/GlobalOpt/evaluate-bitcast.ll b/llvm/test/Transforms/GlobalOpt/evaluate-bitcast.ll new file mode 100644 index 00000000000..740dba2be66 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/evaluate-bitcast.ll @@ -0,0 +1,28 @@ +; RUN: opt -globalopt -instcombine %s -S -o - | FileCheck %s + +; Static constructor should have been optimized out +; CHECK: i32 @main +; CHECK-NEXT: ret i32 69905 +; CHECK-NOT: _GLOBAL__sub_I_main.cpp + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux-gnu" + +%struct.S = type { %struct.A* } +%struct.A = type { i64, i64 } + +@s = internal local_unnamed_addr global %struct.S zeroinitializer, align 8 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main.cpp, i8* null }] +@gA = available_externally dso_local local_unnamed_addr global %struct.A* inttoptr (i64 69905 to %struct.A*), align 8 + +define dso_local i32 @main() local_unnamed_addr { + %1 = load i64, i64* bitcast (%struct.S* @s to i64*), align 8 + %2 = trunc i64 %1 to i32 + ret i32 %2 +} + +define internal void @_GLOBAL__sub_I_main.cpp() section ".text.startup" { + %1 = load i64, i64* bitcast (%struct.A** @gA to i64*), align 8 + store i64 %1, i64* bitcast (%struct.S* @s to i64*), align 8 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/evaluate-call-errors.ll b/llvm/test/Transforms/GlobalOpt/evaluate-call-errors.ll new file mode 100644 index 00000000000..88f7cbd8df1 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/evaluate-call-errors.ll @@ -0,0 +1,99 @@ +; Checks for few bitcasted call evaluation errors + +; REQUIRES: asserts +; RUN: opt -globalopt -instcombine -S -debug-only=evaluator %s -o %t 2>&1 | FileCheck %s + +; CHECK: Failed to fold bitcast call expr +; CHECK: Can not convert function argument + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + +%struct.S = type { i32 } +%struct.Q = type { i32 } +%struct.Foo = type { i32 } + +@_s = global %struct.S zeroinitializer, align 4 +@_q = global %struct.Q zeroinitializer, align 4 +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main2.cpp, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main3.cpp, i8* null }] + +define internal void @__cxx_global_var_init() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @_ZN1SC1Ev(%struct.S* @_s) + ret void +} + +define linkonce_odr void @_ZN1SC1Ev(%struct.S*) unnamed_addr align 2 { + %2 = alloca %struct.S*, align 8 + store %struct.S* %0, %struct.S** %2, align 8 + %3 = load %struct.S*, %struct.S** %2, align 8 + call void @_ZN1SC2Ev(%struct.S* %3) + ret void +} + +define internal void @__cxx_global_var_init.1() #0 section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @_ZN1QC1Ev(%struct.Q* @_q) + ret void +} + +define linkonce_odr void @_ZN1QC1Ev(%struct.Q*) unnamed_addr align 2 { + %2 = alloca %struct.Q*, align 8 + store %struct.Q* %0, %struct.Q** %2, align 8 + %3 = load %struct.Q*, %struct.Q** %2, align 8 + call void @_ZN1QC2Ev(%struct.Q* %3) + ret void +} + +define i32 @main() { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + ret i32 0 +} + +define linkonce_odr void @_ZN1SC2Ev(%struct.S*) unnamed_addr align 2 { + %2 = alloca %struct.S*, align 8 + %3 = alloca %struct.Foo, align 4 + store %struct.S* %0, %struct.S** %2, align 8 + %4 = load %struct.S*, %struct.S** %2, align 8 + %5 = getelementptr inbounds %struct.S, %struct.S* %4, i32 0, i32 0 + %6 = call i32 bitcast (%struct.Foo* ()* @_ZL3foov to i32 ()*)() + %7 = getelementptr inbounds %struct.Foo, %struct.Foo* %3, i32 0, i32 0 + store i32 %6, i32* %7, align 4 + %8 = getelementptr inbounds %struct.Foo, %struct.Foo* %3, i32 0, i32 0 + %9 = load i32, i32* %8, align 4 + store i32 %9, i32* %5, align 4 + ret void +} + +define internal %struct.Foo* @_ZL3foov() { + ret %struct.Foo* null +} + +define linkonce_odr void @_ZN1QC2Ev(%struct.Q*) unnamed_addr align 2 { + %2 = alloca %struct.Q*, align 8 + store %struct.Q* %0, %struct.Q** %2, align 8 + %3 = load %struct.Q*, %struct.Q** %2, align 8 + %4 = getelementptr inbounds %struct.Q, %struct.Q* %3, i32 0, i32 0 + %5 = call i32 bitcast (i32 (i32)* @_ZL3baz3Foo to i32 (%struct.Foo*)*)(%struct.Foo* null) + store i32 %5, i32* %4, align 4 + ret void +} + +define internal i32 @_ZL3baz3Foo(i32) { + %2 = alloca %struct.Foo, align 4 + %3 = getelementptr inbounds %struct.Foo, %struct.Foo* %2, i32 0, i32 0 + store i32 %0, i32* %3, align 4 + %4 = getelementptr inbounds %struct.Foo, %struct.Foo* %2, i32 0, i32 0 + %5 = load i32, i32* %4, align 4 + ret i32 %5 +} + +; Function Attrs: noinline ssp uwtable +define internal void @_GLOBAL__sub_I_main2.cpp() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @__cxx_global_var_init() + ret void +} + +define internal void @_GLOBAL__sub_I_main3.cpp() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @__cxx_global_var_init.1() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/evaluate-call.ll b/llvm/test/Transforms/GlobalOpt/evaluate-call.ll new file mode 100644 index 00000000000..c0456740da4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/evaluate-call.ll @@ -0,0 +1,87 @@ +; Checks if bitcasted call expression can be evaluated +; Given call expresion: +; %struct.Bar* bitcast (%struct.Foo* (%struct.Foo*)* @_ZL3fooP3Foo to %struct.Bar* (%struct.Bar*)*)(%struct.Bar* @gBar) +; We evaluate call to function @_ZL3fooP3Foo casting both parameter and return value +; Given call expression: +; void bitcast (void (%struct.Foo*)* @_ZL3bazP3Foo to void (%struct.Bar*)*)(%struct.Bar* @gBar) +; We evaluate call to function _ZL3bazP3Foo casting its parameter and check that evaluated value (nullptr) +; is handled correctly + +; RUN: opt -globalopt -instcombine -S %s -o - | FileCheck %s + +; CHECK: @gBar = local_unnamed_addr global %struct.Bar { i32 2 } +; CHECK-NEXT: @_s = local_unnamed_addr global %struct.S { i32 1 }, align 4 +; CHECK-NEXT: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer + +; CHECK: define i32 @main() +; CHECK-NEXT: ret i32 0 + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + +%struct.Bar = type { i32 } +%struct.S = type { i32 } +%struct.Foo = type { i32 } + +@gBar = global %struct.Bar zeroinitializer, align 4 +@_s = global %struct.S zeroinitializer, align 4 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main.cpp, i8* null }] + +define internal void @__cxx_global_var_init() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @_ZN1SC1Ev_alias(%struct.S* @_s) + ret void +} + +@_ZN1SC1Ev_alias = linkonce_odr unnamed_addr alias void (%struct.S*), void (%struct.S*)* @_ZN1SC1Ev + +define linkonce_odr void @_ZN1SC1Ev(%struct.S*) unnamed_addr align 2 { + %2 = alloca %struct.S*, align 8 + store %struct.S* %0, %struct.S** %2, align 8 + %3 = load %struct.S*, %struct.S** %2, align 8 + call void @_ZN1SC2Ev(%struct.S* %3) + ret void +} + +define i32 @main() { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + ret i32 0 +} + +define linkonce_odr void @_ZN1SC2Ev(%struct.S*) unnamed_addr align 2 { + %2 = alloca %struct.S*, align 8 + store %struct.S* %0, %struct.S** %2, align 8 + %3 = load %struct.S*, %struct.S** %2, align 8 + %4 = getelementptr inbounds %struct.S, %struct.S* %3, i32 0, i32 0 + %5 = call %struct.Bar* bitcast (%struct.Foo* (%struct.Foo*)* @_ZL3fooP3Foo to %struct.Bar* (%struct.Bar*)*)(%struct.Bar* @gBar) + %6 = getelementptr inbounds %struct.Bar, %struct.Bar* %5, i32 0, i32 0 + %7 = load i32, i32* %6, align 4 + store i32 %7, i32* %4, align 4 + call void bitcast (void (%struct.Foo*)* @_ZL3bazP3Foo to void (%struct.Bar*)*)(%struct.Bar* @gBar) + ret void +} + +define internal %struct.Foo* @_ZL3fooP3Foo(%struct.Foo*) { + %2 = alloca %struct.Foo*, align 8 + store %struct.Foo* %0, %struct.Foo** %2, align 8 + %3 = load %struct.Foo*, %struct.Foo** %2, align 8 + %4 = getelementptr inbounds %struct.Foo, %struct.Foo* %3, i32 0, i32 0 + store i32 1, i32* %4, align 4 + %5 = load %struct.Foo*, %struct.Foo** %2, align 8 + ret %struct.Foo* %5 +} + +define internal void @_ZL3bazP3Foo(%struct.Foo*) { + %2 = alloca %struct.Foo*, align 8 + store %struct.Foo* %0, %struct.Foo** %2, align 8 + %3 = load %struct.Foo*, %struct.Foo** %2, align 8 + %4 = getelementptr inbounds %struct.Foo, %struct.Foo* %3, i32 0, i32 0 + store i32 2, i32* %4, align 4 + ret void +} + +; Function Attrs: noinline ssp uwtable +define internal void @_GLOBAL__sub_I_main.cpp() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @__cxx_global_var_init() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/evaluate-constfold-call.ll b/llvm/test/Transforms/GlobalOpt/evaluate-constfold-call.ll new file mode 100644 index 00000000000..aeaa5e800c7 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/evaluate-constfold-call.ll @@ -0,0 +1,55 @@ +; Check if we can evaluate a bitcasted call to a function which is constant folded. +; Evaluator folds call to fmodf, replacing it with constant value in case both operands +; are known at compile time. +; RUN: opt -globalopt -instcombine %s -S -o - | FileCheck %s + +; CHECK: @_q = dso_local local_unnamed_addr global %struct.Q { i32 1066527622 } +; CHECK: define dso_local i32 @main +; CHECK-NEXT: %[[V:.+]] = load i32, i32* getelementptr inbounds (%struct.Q, %struct.Q* @_q, i64 0, i32 0) +; CHECK-NEXT: ret i32 %[[V]] + +source_filename = "main.cpp" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-none-linux-gnu" + +%struct.Q = type { i32 } + +$_ZN1QC2Ev = comdat any + +@_q = dso_local global %struct.Q zeroinitializer, align 4 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main.cpp, i8* null }] + +define internal void @__cxx_global_var_init() section ".text.startup" { + call void @_ZN1QC2Ev(%struct.Q* @_q) + ret void +} + +define linkonce_odr dso_local void @_ZN1QC2Ev(%struct.Q*) unnamed_addr #1 comdat align 2 { + %2 = alloca %struct.Q*, align 8 + store %struct.Q* %0, %struct.Q** %2, align 8 + %3 = load %struct.Q*, %struct.Q** %2, align 8 + %4 = getelementptr inbounds %struct.Q, %struct.Q* %3, i32 0, i32 0 + %5 = call i32 bitcast (float (float, float)* @fmodf to i32 (float, float)*)(float 0x40091EB860000000, float 2.000000e+00) + store i32 %5, i32* %4, align 4 + ret void +} + +define dso_local i32 @main(i32, i8**) { + %3 = alloca i32, align 4 + %4 = alloca i32, align 4 + %5 = alloca i8**, align 8 + store i32 0, i32* %3, align 4 + store i32 %0, i32* %4, align 4 + store i8** %1, i8*** %5, align 8 + %6 = load i32, i32* getelementptr inbounds (%struct.Q, %struct.Q* @_q, i32 0, i32 0), align 4 + ret i32 %6 +} + +; Function Attrs: nounwind +declare dso_local float @fmodf(float, float) + +; Function Attrs: noinline uwtable +define internal void @_GLOBAL__sub_I_main.cpp() section ".text.startup" { + call void @__cxx_global_var_init() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll b/llvm/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll new file mode 100644 index 00000000000..2434f20e92b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +; This global is externally_initialized, so if we split it into scalars we +; 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-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-NOT: @b.1 +@b = internal externally_initialized global {i32, i32} undef, align 4 + +define i32 @foo() { +; CHECK-LABEL: define i32 @foo +entry: +; This load uses the split global, but cannot be constant-propagated away. +; CHECK: %0 = load i32, i32* @a.0 + %0 = load i32, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 0), align 4 + ret i32 %0 +} + +define i32 @bar() { +; CHECK-LABEL: define i32 @bar +entry: +; This load uses the split global, but cannot be constant-propagated away. +; CHECK: %0 = load i32, i32* @b.0 + %0 = load i32, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 0), align 4 + ret i32 %0 +} + +define void @init() { +; CHECK-LABEL: define void @init +entry: +; This store uses the split global, but cannot be constant-propagated away. +; CHECK: store i32 1, i32* @a.0 + store i32 1, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 0), align 4 +; This store can be removed, because the second element of @a is never read. +; CHECK-NOT: store i32 2, i32* @a.1 + store i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 1), align 4 + +; This store uses the split global, but cannot be constant-propagated away. +; CHECK: store i32 3, i32* @b.0 + store i32 3, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 0), align 4 +; This store can be removed, because the second element of @b is never read. +; CHECK-NOT: store i32 4, i32* @b.1 + store i32 4, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 1), align 4 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/externally-initialized-global-ctr.ll b/llvm/test/Transforms/GlobalOpt/externally-initialized-global-ctr.ll new file mode 100644 index 00000000000..2e22ff06444 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/externally-initialized-global-ctr.ll @@ -0,0 +1,35 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; rdar://12580965. +; ObjC++ test case. + +%struct.ButtonInitData = type { i8* } + +@_ZL14buttonInitData = internal global [1 x %struct.ButtonInitData] zeroinitializer, align 4 + +@"\01L_OBJC_METH_VAR_NAME_40" = internal global [7 x i8] c"print:\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +@"\01L_OBJC_SELECTOR_REFERENCES_41" = internal externally_initialized global i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_OBJC_METH_VAR_NAME_40", i32 0, i32 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] +@llvm.used = appending global [2 x i8*] [i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_OBJC_METH_VAR_NAME_40", i32 0, i32 0), i8* bitcast (i8** @"\01L_OBJC_SELECTOR_REFERENCES_41" to i8*)] + +define internal void @__cxx_global_var_init() section "__TEXT,__StaticInit,regular,pure_instructions" { + %1 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_41", !invariant.load !2009 + store i8* %1, i8** getelementptr inbounds ([1 x %struct.ButtonInitData], [1 x %struct.ButtonInitData]* @_ZL14buttonInitData, i32 0, i32 0, i32 0), align 4 + ret void +} + +define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" { + call void @__cxx_global_var_init() + ret void +} + +declare void @test(i8*) + +define void @print() { +; CHECK: %1 = load i8*, i8** @_ZL14buttonInitData.0.0, align 4 + %1 = load i8*, i8** getelementptr inbounds ([1 x %struct.ButtonInitData], [1 x %struct.ButtonInitData]* @_ZL14buttonInitData, i32 0, i32 0, i32 0), align 4 + call void @test(i8* %1) + ret void +} + +!2009 = !{} diff --git a/llvm/test/Transforms/GlobalOpt/externally-initialized.ll b/llvm/test/Transforms/GlobalOpt/externally-initialized.ll new file mode 100644 index 00000000000..c01ba10f49c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/externally-initialized.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +; 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 +@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 +@b = internal externally_initialized global i32 undef + + +define void @foo() { +; CHECK-LABEL: foo +entry: +; CHECK: store i32 42, i32* @a + store i32 42, i32* @a + ret void +} +define i32 @bar() { +; CHECK-LABEL: bar +entry: +; CHECK: %val = load i32, i32* @a + %val = load i32, i32* @a + ret i32 %val +} + +define i32 @baz() { +; CHECK-LABEL: baz +entry: +; CHECK: %val = load i32, i32* @b + %val = load i32, i32* @b + ret i32 %val +} diff --git a/llvm/test/Transforms/GlobalOpt/fastcc.ll b/llvm/test/Transforms/GlobalOpt/fastcc.ll new file mode 100644 index 00000000000..64c4a268ff3 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/fastcc.ll @@ -0,0 +1,55 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +define internal i32 @f(i32* %m) { +; CHECK-LABEL: define internal fastcc i32 @f + %v = load i32, i32* %m + ret i32 %v +} + +define internal x86_thiscallcc i32 @g(i32* %m) { +; CHECK-LABEL: define internal fastcc i32 @g + %v = load i32, i32* %m + ret i32 %v +} + +; Leave this one alone, because the user went out of their way to request this +; convention. +define internal coldcc i32 @h(i32* %m) { +; CHECK-LABEL: define internal coldcc i32 @h + %v = load i32, i32* %m + ret i32 %v +} + +define internal i32 @j(i32* %m) { +; CHECK-LABEL: define internal i32 @j + %v = load i32, i32* %m + ret i32 %v +} + +define internal i32 @inalloca(i32* inalloca %p) { +; CHECK-LABEL: define internal i32 @inalloca(i32* inalloca %p) + %rv = load i32, i32* %p + ret i32 %rv +} + +define void @call_things() { + %m = alloca i32 + call i32 @f(i32* %m) + call x86_thiscallcc i32 @g(i32* %m) + call coldcc i32 @h(i32* %m) + call i32 @j(i32* %m) + %args = alloca inalloca i32 + call i32 @inalloca(i32* inalloca %args) + ret void +} + +@llvm.used = appending global [1 x i8*] [ + i8* bitcast (i32(i32*)* @j to i8*) +], section "llvm.metadata" + +; CHECK-LABEL: define void @call_things() +; CHECK: call fastcc i32 @f +; CHECK: call fastcc i32 @g +; CHECK: call coldcc i32 @h +; CHECK: call i32 @j +; CHECK: call i32 @inalloca(i32* inalloca %args) diff --git a/llvm/test/Transforms/GlobalOpt/global-demotion.ll b/llvm/test/Transforms/GlobalOpt/global-demotion.ll new file mode 100644 index 00000000000..7965cb89620 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/global-demotion.ll @@ -0,0 +1,80 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s + +@G1 = internal global i32 5 +@G2 = internal global i32 5 +@G3 = internal global i32 5 +@G4 = internal global i32 5 +@G5 = internal global i32 5 + +; CHECK-LABEL: @test1 +define internal i32 @test1() norecurse { +; CHECK-NOT: @G1 + store i32 4, i32* @G1 + %a = load i32, i32* @G1 +; CHECK: ret + ret i32 %a +} + +; The load comes before the store which makes @G2 live before the call. +; CHECK-LABEL: @test2 +define internal i32 @test2() norecurse { +; CHECK-NOT: %G2 + %a = load i32, i32* @G2 + store i32 4, i32* @G2 +; CHECK: ret + ret i32 %a +} + +; This global is indexed by a GEP - this makes it partial alias and we bail out. +; FIXME: We don't actually have to bail out in this case. + +; CHECK-LABEL: @test3 +define internal i32 @test3() norecurse { +; CHECK-NOT: %G3 + %x = getelementptr i32,i32* @G3, i32 0 + %a = load i32, i32* %x + store i32 4, i32* @G3 +; CHECK: ret + ret i32 %a +} + +; The global is casted away to a larger type then loaded. The store only partially +; covers the load, so we must not demote. + +; CHECK-LABEL: @test4 +define internal i32 @test4() norecurse { +; CHECK-NOT: %G4 + store i32 4, i32* @G4 + %x = bitcast i32* @G4 to i64* + %a = load i64, i64* %x + %b = trunc i64 %a to i32 +; CHECK: ret + ret i32 %b +} + +; The global is casted away to a smaller type then loaded. This one is fine. + +; CHECK-LABEL: @test5 +define internal i32 @test5() norecurse { +; CHECK-NOT: @G5 + store i32 4, i32* @G5 + %x = bitcast i32* @G5 to i16* + %a = load i16, i16* %x + %b = zext i16 %a to i32 +; CHECK: ret + ret i32 %b +} + +define i32 @main() norecurse { + %a = call i32 @test1() + %b = call i32 @test2() + %c = call i32 @test3() + %d = call i32 @test4() + %e = call i32 @test5() + + %x = or i32 %a, %b + %y = or i32 %x, %c + %z = or i32 %y, %d + %w = or i32 %z, %e + ret i32 %w +} diff --git a/llvm/test/Transforms/GlobalOpt/globalsra-multigep.ll b/llvm/test/Transforms/GlobalOpt/globalsra-multigep.ll new file mode 100644 index 00000000000..87a8486d881 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/globalsra-multigep.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@g_data = internal unnamed_addr global <{ [8 x i16], [8 x i16] }> <{ [8 x i16] [i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16, i16 16], [8 x i16] zeroinitializer }>, align 16 +; We cannot SRA here due to the second gep meaning the access to g_data may be to either element +; CHECK: @g_data = internal unnamed_addr constant <{ [8 x i16], [8 x i16] }> + +define i16 @test(i64 %a1) { +entry: + %g1 = getelementptr inbounds <{ [8 x i16], [8 x i16] }>, <{ [8 x i16], [8 x i16] }>* @g_data, i64 0, i32 0 + %arrayidx.i = getelementptr inbounds [8 x i16], [8 x i16]* %g1, i64 0, i64 %a1 + %r = load i16, i16* %arrayidx.i, align 2 + ret i16 %r +} diff --git a/llvm/test/Transforms/GlobalOpt/globalsra-partial.ll b/llvm/test/Transforms/GlobalOpt/globalsra-partial.ll new file mode 100644 index 00000000000..141ee1bb5a8 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/globalsra-partial.ll @@ -0,0 +1,25 @@ +; In this case, the global cannot be merged as i may be out of range + +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global { i32, [4 x float] } zeroinitializer ; <{ i32, [4 x float] }*> [#uses=3] + +; CHECK: @G = internal unnamed_addr global { i32, [4 x float] } +; CHECK: 12345 +define void @onlystore() { + store i32 12345, i32* getelementptr ({ i32, [4 x float] }, { i32, [4 x float] }* @G, i32 0, i32 0) + ret void +} + +define void @storeinit(i32 %i) { + %Ptr = getelementptr { i32, [4 x float] }, { i32, [4 x float] }* @G, i32 0, i32 1, i32 %i ; <float*> [#uses=1] + store float 1.000000e+00, float* %Ptr + ret void +} + +define float @readval(i32 %i) { + %Ptr = getelementptr { i32, [4 x float] }, { i32, [4 x float] }* @G, i32 0, i32 1, i32 %i ; <float*> [#uses=1] + %V = load float, float* %Ptr ; <float> [#uses=1] + ret float %V +} diff --git a/llvm/test/Transforms/GlobalOpt/globalsra-unknown-index.ll b/llvm/test/Transforms/GlobalOpt/globalsra-unknown-index.ll new file mode 100644 index 00000000000..4607373ab2c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/globalsra-unknown-index.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; globalopt should not sra the global, because it can't see the index. + +%struct.X = type { [3 x i32], [3 x i32] } + +; CHECK: @Y = internal unnamed_addr global [3 x %struct.X] zeroinitializer +@Y = internal global [3 x %struct.X] zeroinitializer + +@addr = external global i8 + +define void @frob() { + store i32 1, i32* getelementptr inbounds ([3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 ptrtoint (i8* @addr to i64)), align 4 + ret void +} + +; CHECK-LABEL: @borf +; CHECK: %a = load +; CHECK: %b = load +; CHECK: add i32 %a, %b +define i32 @borf(i64 %i, i64 %j) { + %p = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0 + %a = load i32, i32* %p + %q = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 0 + %b = load i32, i32* %q + %c = add i32 %a, %b + ret i32 %c +} + +; CHECK-LABEL: @borg +; CHECK: %a = load +; CHECK: %b = load +; CHECK: add i32 %a, %b +define i32 @borg(i64 %i, i64 %j) { + %p = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 1 + %a = load i32, i32* %p + %q = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 1 + %b = load i32, i32* %q + %c = add i32 %a, %b + ret i32 %c +} + +; CHECK-LABEL: @borh +; CHECK: %a = load +; CHECK: %b = load +; CHECK: add i32 %a, %b +define i32 @borh(i64 %i, i64 %j) { + %p = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 2 + %a = load i32, i32* %p + %q = getelementptr inbounds [3 x %struct.X], [3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 2 + %b = load i32, i32* %q + %c = add i32 %a, %b + ret i32 %c +} diff --git a/llvm/test/Transforms/GlobalOpt/globalsra.ll b/llvm/test/Transforms/GlobalOpt/globalsra.ll new file mode 100644 index 00000000000..8098ec84b2e --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/globalsra.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: global +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global { i32, float, { double } } { + i32 1, + float 1.000000e+00, + { double } { double 1.727000e+01 } } ; <{ i32, float, { double } }*> [#uses=3] + +define void @onlystore() { + store i32 123, i32* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G, i32 0, i32 0) + ret void +} + +define float @storeinit() { + store float 1.000000e+00, float* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G, i32 0, i32 1) + %X = load float, float* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G, i32 0, i32 1) ; <float> [#uses=1] + ret float %X +} + +define double @constantize() { + %X = load double, double* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G, i32 0, i32 2, i32 0) ; <double> [#uses=1] + ret double %X +} + +@G2 = internal constant { i32, float, { double } } { + i32 1, + float 1.000000e+00, + { double } { double 1.727000e+01 } } ; <{ i32, float, { double } }*> [#uses=3] + +define void @onlystore2() { + store i32 123, i32* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G2, i32 0, i32 0) + ret void +} + +define float @storeinit2() { + store float 1.000000e+00, float* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G2, i32 0, i32 1) + %X = load float, float* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G2, i32 0, i32 1) ; <float> [#uses=1] + ret float %X +} + +define double @constantize2() { + %X = load double, double* getelementptr ({ i32, float, { double } }, { i32, float, { double } }* @G2, i32 0, i32 2, i32 0) ; <double> [#uses=1] + ret double %X +} diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll new file mode 100644 index 00000000000..c826e7f7a04 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-1-no-null-opt.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = mul i64 %Size, 8 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll new file mode 100644 index 00000000000..28a20ada03f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-1.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X.f0 +; CHECK: @X.f1 + +define void @bar(i64 %Size) nounwind noinline { +entry: + %mallocsize = mul i64 %Size, 8 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll new file mode 100644 index 00000000000..c33bcba9921 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-2-no-null-opt.ll @@ -0,0 +1,39 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i32 %Size) nounwind noinline #0 { +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %0 = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %0, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] ; <i32> [#uses=1] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %2 = load i32, i32* %1, align 4 ; <i32> [#uses=1] + %3 = add i32 %2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll new file mode 100644 index 00000000000..ec05b22b33b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-2.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] +; CHECK: @X.f0 +; CHECK: @X.f1 + +define void @bar(i32 %Size) nounwind noinline { +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %0 = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %0, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] ; <i32> [#uses=1] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %2 = load i32, i32* %1, align 4 ; <i32> [#uses=1] + %3 = add i32 %2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll new file mode 100644 index 00000000000..ba3b0a418a1 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-3-no-null-opt.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = mul i64 8, %Size ; <i64> [#uses=1] +; CHECK: mul i64 8, %Size + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +bb1.thread: +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll new file mode 100644 index 00000000000..67058c8aba2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-3.ll @@ -0,0 +1,46 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X.f0 +; CHECK: @X.f1 + +define void @bar(i64 %Size) nounwind noinline { +entry: + %mallocsize = mul i64 8, %Size ; <i64> [#uses=1] +; CHECK: mul i64 %Size, 4 + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll new file mode 100644 index 00000000000..607c93d1e8a --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-4-no-null-opt.ll @@ -0,0 +1,44 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } + +@X = internal global %struct.foo* null +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i64 %Size) nounwind noinline #0 { +entry: + %mallocsize = shl i64 %Size, 3 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] +; CHECK: shl i64 %Size, 3 + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +; CHECK-LABEL: @baz( +bb1.thread: +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 +; CHECK: load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll new file mode 100644 index 00000000000..71832f34923 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-4.ll @@ -0,0 +1,47 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null +; CHECK: @X.f0 +; CHECK: @X.f1 + +define void @bar(i64 %Size) nounwind noinline { +entry: + %mallocsize = shl i64 %Size, 3 ; <i64> [#uses=1] + %malloccall = tail call i8* @malloc(i64 %mallocsize) ; <i8*> [#uses=1] +; CHECK: mul i64 %Size, 4 + %.sub = bitcast i8* %malloccall to %struct.foo* ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %3, %bb1 ] + %1 = getelementptr %struct.foo, %struct.foo* %0, i32 %i.0.reg2mem.0, i32 0 + %2 = load i32, i32* %1, align 4 + %3 = add i32 %2, %sum.0.reg2mem.0 + %indvar.next = add i32 %i.0.reg2mem.0, 1 + %exitcond = icmp eq i32 %indvar.next, 1200 + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %3 +} + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll new file mode 100644 index 00000000000..06c74e5bfc4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-phi-no-null-opt.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +%struct.foo = type { i32, i32 } + +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] +; CHECK: @X +; CHECK-NOT: @X.f0 + +define void @bar(i32 %Size) nounwind noinline #0 { +; CHECK-LABEL: @bar( +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline #0 { +; CHECK-LABEL: @baz( +bb1.thread: + %tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %tmp = phi %struct.foo* [%tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ] ; <i32> [#uses=2] +; CHECK: %tmp = phi %struct.foo* [ %tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ] + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %tmp3, %bb1 ] ; <i32> [#uses=1] + %tmp1 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %tmp2 = load i32, i32* %tmp1, align 4 ; <i32> [#uses=1] +; CHECK: load i32, i32* %tmp1, align 4 + %tmp6 = add i32 %tmp2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %tmp4 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 1 ; <i32*> [#uses=1] + %tmp5 = load i32 , i32 * %tmp4 +; CHECK: load i32, i32* %tmp4 + %tmp3 = add i32 %tmp5, %tmp6 + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + + %tmpLD2 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] +; CHECK: load %struct.foo*, %struct.foo** @X, align 4 + + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %tmp3 +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll b/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll new file mode 100644 index 00000000000..770220dd07b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/heap-sra-phi.ll @@ -0,0 +1,52 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: tmp.f1 = phi i32* +; CHECK: tmp.f0 = phi i32* +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + + %struct.foo = type { i32, i32 } +@X = internal global %struct.foo* null ; <%struct.foo**> [#uses=2] + +define void @bar(i32 %Size) nounwind noinline { +entry: + %malloccall = tail call i8* @malloc(i64 8000000) ; <i8*> [#uses=1] + %tmp = bitcast i8* %malloccall to [1000000 x %struct.foo]* ; <[1000000 x %struct.foo]*> [#uses=1] + %.sub = getelementptr [1000000 x %struct.foo], [1000000 x %struct.foo]* %tmp, i32 0, i32 0 ; <%struct.foo*> [#uses=1] + store %struct.foo* %.sub, %struct.foo** @X, align 4 + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @baz() nounwind readonly noinline { +bb1.thread: + %tmpLD1 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] + br label %bb1 + +bb1: ; preds = %bb1, %bb1.thread + %tmp = phi %struct.foo* [%tmpLD1, %bb1.thread ], [ %tmpLD2, %bb1 ] ; <i32> [#uses=2] + %i.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %indvar.next, %bb1 ] ; <i32> [#uses=2] + %sum.0.reg2mem.0 = phi i32 [ 0, %bb1.thread ], [ %tmp3, %bb1 ] ; <i32> [#uses=1] + %tmp1 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 0 ; <i32*> [#uses=1] + %tmp2 = load i32, i32* %tmp1, align 4 ; <i32> [#uses=1] + %tmp6 = add i32 %tmp2, %sum.0.reg2mem.0 ; <i32> [#uses=2] + %tmp4 = getelementptr %struct.foo, %struct.foo* %tmp, i32 %i.0.reg2mem.0, i32 1 ; <i32*> [#uses=1] + %tmp5 = load i32 , i32 * %tmp4 + %tmp3 = add i32 %tmp5, %tmp6 + %indvar.next = add i32 %i.0.reg2mem.0, 1 ; <i32> [#uses=2] + + %tmpLD2 = load %struct.foo*, %struct.foo** @X, align 4 ; <%struct.foo*> [#uses=1] + + %exitcond = icmp eq i32 %indvar.next, 1200 ; <i1> [#uses=1] + br i1 %exitcond, label %bb2, label %bb1 + +bb2: ; preds = %bb1 + ret i32 %tmp3 +} + +define void @bam(i64 %Size) nounwind noinline #0 { +entry: + %0 = load %struct.foo*, %struct.foo** @X, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll b/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll new file mode 100644 index 00000000000..59c3a8aa4ba --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/int_sideeffect.ll @@ -0,0 +1,16 @@ +; RUN: opt -S < %s -globalopt | FileCheck %s + +; Static evaluation across a @llvm.sideeffect. + +; CHECK-NOT: store + +declare void @llvm.sideeffect() + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @ctor } ] +@G = global i32 0 + +define internal void @ctor() { + store i32 1, i32* @G + call void @llvm.sideeffect() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/integer-bool-dwarf.ll b/llvm/test/Transforms/GlobalOpt/integer-bool-dwarf.ll new file mode 100644 index 00000000000..6aa35be21d8 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/integer-bool-dwarf.ll @@ -0,0 +1,61 @@ +;RUN: opt -S -globalopt -f %s | FileCheck %s + +;CHECK: @foo = internal unnamed_addr global i1 false, align 4, !dbg ![[VAR:.*]] +;CHECK: ![[VAR]] = !DIGlobalVariableExpression(var: !1, expr: +;CHECK-SAME: !DIExpression(DW_OP_deref, DW_OP_constu, 111, DW_OP_mul, +;CHECK-SAME: DW_OP_constu, 0, DW_OP_plus, DW_OP_stack_value, +;CHECK-SAME: DW_OP_LLVM_fragment, 0, 1)) + +@foo = internal global i32 0, align 4, !dbg !0 + +; Function Attrs: noinline nounwind optnone uwtable +define void @set1() #0 !dbg !11 { +entry: + store i32 111, i32* @foo, align 4, !dbg !14 + ret void, !dbg !15 +} + +; Function Attrs: noinline nounwind optnone uwtable +define void @set2() #0 !dbg !16 { +entry: + store i32 0, i32* @foo, align 4, !dbg !17 + ret void, !dbg !18 +} + +; Function Attrs: noinline nounwind optnone uwtable +define i32 @get() #0 !dbg !19 { +entry: + %0 = load i32, i32* @foo, align 4, !dbg !22 + ret i32 %0, !dbg !23 +} + +attributes #0 = { noinline nounwind optnone uwtable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_LLVM_fragment, 0, 1)) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "integer-bool-dwarf.c", directory: "/") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 6.0.0 "} +!11 = distinct !DISubprogram(name: "set1", scope: !3, file: !3, line: 3, type: !12, isLocal: false, isDefinition: true, scopeLine: 4, isOptimized: false, unit: !2, retainedNodes: !4) +!12 = !DISubroutineType(types: !13) +!13 = !{null} +!14 = !DILocation(line: 5, column: 7, scope: !11) +!15 = !DILocation(line: 6, column: 1, scope: !11) +!16 = distinct !DISubprogram(name: "set2", scope: !3, file: !3, line: 8, type: !12, isLocal: false, isDefinition: true, scopeLine: 9, isOptimized: false, unit: !2, retainedNodes: !4) +!17 = !DILocation(line: 10, column: 7, scope: !16) +!18 = !DILocation(line: 11, column: 1, scope: !16) +!19 = distinct !DISubprogram(name: "get", scope: !3, file: !3, line: 13, type: !20, isLocal: false, isDefinition: true, scopeLine: 14, isOptimized: false, unit: !2, retainedNodes: !4) +!20 = !DISubroutineType(types: !21) +!21 = !{!6} +!22 = !DILocation(line: 15, column: 10, scope: !19) +!23 = !DILocation(line: 15, column: 3, scope: !19) diff --git a/llvm/test/Transforms/GlobalOpt/integer-bool.ll b/llvm/test/Transforms/GlobalOpt/integer-bool.ll new file mode 100644 index 00000000000..617febdc016 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/integer-bool.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -S -globalopt -instcombine | FileCheck %s +;; check that global opt turns integers that only hold 0 or 1 into bools. + +@G = internal addrspace(1) global i32 0 +; CHECK: @G +; CHECK: addrspace(1) +; CHECK: global i1 false + +define void @set1() { + store i32 0, i32 addrspace(1)* @G +; CHECK: store i1 false + ret void +} + +define void @set2() { + store i32 1, i32 addrspace(1)* @G +; CHECK: store i1 true + ret void +} + +define i1 @get() { +; CHECK-LABEL: @get( + %A = load i32, i32 addrspace(1) * @G + %C = icmp slt i32 %A, 2 + ret i1 %C +; CHECK: ret i1 true +} + diff --git a/llvm/test/Transforms/GlobalOpt/invariant-nodatalayout.ll b/llvm/test/Transforms/GlobalOpt/invariant-nodatalayout.ll new file mode 100644 index 00000000000..d1fbe46257d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/invariant-nodatalayout.ll @@ -0,0 +1,17 @@ +; RUN: opt -globalopt -S -o - < %s | FileCheck %s +; The check here is that it doesn't crash. + +declare {}* @llvm.invariant.start.p0i8(i64 %size, i8* nocapture %ptr) + +@object1 = global { i32, i32 } zeroinitializer +; CHECK: @object1 = global { i32, i32 } zeroinitializer + +define void @ctor1() { + %ptr = bitcast {i32, i32}* @object1 to i8* + call {}* @llvm.invariant.start.p0i8(i64 4, i8* %ptr) + ret void +} + +@llvm.global_ctors = appending constant + [1 x { i32, void ()* }] + [ { i32, void ()* } { i32 65535, void ()* @ctor1 } ] diff --git a/llvm/test/Transforms/GlobalOpt/invariant.group.ll b/llvm/test/Transforms/GlobalOpt/invariant.group.ll new file mode 100644 index 00000000000..8a090cbd0d3 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/invariant.group.ll @@ -0,0 +1,79 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +; This test is hint, what could globalOpt optimize and what it can't +; FIXME: @tmp and @tmp2 can be safely set to 42 +; CHECK: @tmp = local_unnamed_addr global i32 0 +; CHECK: @tmp2 = local_unnamed_addr global i32 0 +; CHECK: @tmp3 = global i32 0 + +@tmp = global i32 0 +@tmp2 = global i32 0 +@tmp3 = global i32 0 +@ptrToTmp3 = global i32* null + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] + +define i32 @TheAnswerToLifeTheUniverseAndEverything() { + ret i32 42 +} + +define void @_GLOBAL__I_a() { +enter: + call void @_optimizable() + call void @_not_optimizable() + ret void +} + +define void @_optimizable() { +enter: + %valptr = alloca i32 + + %val = call i32 @TheAnswerToLifeTheUniverseAndEverything() + store i32 %val, i32* @tmp + store i32 %val, i32* %valptr + + %0 = bitcast i32* %valptr to i8* + %barr = call i8* @llvm.launder.invariant.group(i8* %0) + %1 = bitcast i8* %barr to i32* + + %val2 = load i32, i32* %1 + store i32 %val2, i32* @tmp2 + ret void +} + +; We can't step through launder.invariant.group here, because that would change +; this load in @usage_of_globals() +; val = load i32, i32* %ptrVal, !invariant.group !0 +; into +; %val = load i32, i32* @tmp3, !invariant.group !0 +; and then we could assume that %val and %val2 to be the same, which coud be +; false, because @changeTmp3ValAndCallBarrierInside() may change the value +; of @tmp3. +define void @_not_optimizable() { +enter: + store i32 13, i32* @tmp3, !invariant.group !0 + + %0 = bitcast i32* @tmp3 to i8* + %barr = call i8* @llvm.launder.invariant.group(i8* %0) + %1 = bitcast i8* %barr to i32* + + store i32* %1, i32** @ptrToTmp3 + store i32 42, i32* %1, !invariant.group !0 + + ret void +} +define void @usage_of_globals() { +entry: + %ptrVal = load i32*, i32** @ptrToTmp3 + %val = load i32, i32* %ptrVal, !invariant.group !0 + + call void @changeTmp3ValAndCallBarrierInside() + %val2 = load i32, i32* @tmp3, !invariant.group !0 + ret void; +} + +declare void @changeTmp3ValAndCallBarrierInside() + +declare i8* @llvm.launder.invariant.group(i8*) + +!0 = !{} diff --git a/llvm/test/Transforms/GlobalOpt/invariant.ll b/llvm/test/Transforms/GlobalOpt/invariant.ll new file mode 100644 index 00000000000..02ffe2bc424 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/invariant.ll @@ -0,0 +1,59 @@ +; RUN: opt -globalopt -S -o - < %s | FileCheck %s + +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:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare {}* @llvm.invariant.start.p0i8(i64 %size, i8* nocapture %ptr) + +define void @test1(i8* %ptr) { + call {}* @llvm.invariant.start.p0i8(i64 4, i8* %ptr) + ret void +} + +@object1 = global i32 0 +; CHECK: @object1 = constant i32 -1 +define void @ctor1() { + store i32 -1, i32* @object1 + %A = bitcast i32* @object1 to i8* + call void @test1(i8* %A) + ret void +} + + +@object2 = global i32 0 +; CHECK: @object2 = global i32 0 +define void @ctor2() { + store i32 -1, i32* @object2 + %A = bitcast i32* @object2 to i8* + %B = call {}* @llvm.invariant.start.p0i8(i64 4, i8* %A) + %C = bitcast {}* %B to i8* + ret void +} + + +@object3 = global i32 0 +; CHECK: @object3 = global i32 -1 +define void @ctor3() { + store i32 -1, i32* @object3 + %A = bitcast i32* @object3 to i8* + call {}* @llvm.invariant.start.p0i8(i64 3, i8* %A) + ret void +} + + +@object4 = global i32 0 +; CHECK: @object4 = global i32 -1 +define void @ctor4() { + store i32 -1, i32* @object4 + %A = bitcast i32* @object4 to i8* + call {}* @llvm.invariant.start.p0i8(i64 -1, i8* %A) + ret void +} + + +@llvm.global_ctors = appending constant + [4 x { i32, void ()* }] + [ { i32, void ()* } { i32 65535, void ()* @ctor1 }, + { i32, void ()* } { i32 65535, void ()* @ctor2 }, + { i32, void ()* } { i32 65535, void ()* @ctor3 }, + { i32, void ()* } { i32 65535, void ()* @ctor4 } ] diff --git a/llvm/test/Transforms/GlobalOpt/invoke.ll b/llvm/test/Transforms/GlobalOpt/invoke.ll new file mode 100644 index 00000000000..a3019939735 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/invoke.ll @@ -0,0 +1,27 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s +; rdar://11022897 + +; Globalopt should be able to evaluate an invoke. +; CHECK: @tmp = local_unnamed_addr global i32 1 + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] +@tmp = global i32 0 + +define i32 @one() { + ret i32 1 +} + +define void @_GLOBAL__I_a() personality i8* undef { +bb: + %tmp1 = invoke i32 @one() + to label %bb2 unwind label %bb4 + +bb2: ; preds = %bb + store i32 %tmp1, i32* @tmp + ret void + +bb4: ; preds = %bb + %tmp5 = landingpad { i8*, i32 } + filter [0 x i8*] zeroinitializer + unreachable +} diff --git a/llvm/test/Transforms/GlobalOpt/iterate.ll b/llvm/test/Transforms/GlobalOpt/iterate.ll new file mode 100644 index 00000000000..8c6543b685d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/iterate.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: %G + +@G = internal global i32 0 ; <i32*> [#uses=1] +@H = internal global { i32* } { i32* @G } ; <{ i32* }*> [#uses=1] + +define i32 @loadg() { + %G = load i32*, i32** getelementptr ({ i32* }, { i32* }* @H, i32 0, i32 0) ; <i32*> [#uses=1] + %GV = load i32, i32* %G ; <i32> [#uses=1] + ret i32 %GV +} diff --git a/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll new file mode 100644 index 00000000000..d319d162ff4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/load-store-global-no-null-opt.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@a = internal global i64* null, align 8 +; CHECK: @a + +; PR13968 +define void @qux_no_null_opt() nounwind #0 { +; CHECK-LABEL: @qux_no_null_opt( +; CHECK: getelementptr i64*, i64** @a, i32 1 +; CHECK: store i64* inttoptr (i64 1 to i64*), i64** @a + %b = bitcast i64** @a to i8* + %g = getelementptr i64*, i64** @a, i32 1 + %cmp = icmp ne i8* null, %b + %cmp2 = icmp eq i8* null, %b + %cmp3 = icmp eq i64** null, %g + store i64* inttoptr (i64 1 to i64*), i64** @a, align 8 + %l = load i64*, i64** @a, align 8 + ret void +} + +define i64* @bar() { + %X = load i64*, i64** @a, align 8 + ret i64* %X +; CHECK-LABEL: @bar( +; CHECK: load +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/load-store-global.ll b/llvm/test/Transforms/GlobalOpt/load-store-global.ll new file mode 100644 index 00000000000..e01358e8ed3 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/load-store-global.ll @@ -0,0 +1,38 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@G = internal global i32 17 ; <i32*> [#uses=3] +; CHECK-NOT: @G + +define void @foo() { + %V = load i32, i32* @G ; <i32> [#uses=1] + store i32 %V, i32* @G + ret void +; CHECK-LABEL: @foo( +; CHECK-NEXT: ret void +} + +define i32 @bar() { + %X = load i32, i32* @G ; <i32> [#uses=1] + ret i32 %X +; CHECK-LABEL: @bar( +; CHECK-NEXT: ret i32 17 +} + +@a = internal global i64* null, align 8 +; CHECK-NOT: @a + +; PR13968 +define void @qux() nounwind { + %b = bitcast i64** @a to i8* + %g = getelementptr i64*, i64** @a, i32 1 + %cmp = icmp ne i8* null, %b + %cmp2 = icmp eq i8* null, %b + %cmp3 = icmp eq i64** null, %g + store i64* inttoptr (i64 1 to i64*), i64** @a, align 8 + %l = load i64*, i64** @a, align 8 + ret void +; CHECK-LABEL: @qux( +; CHECK-NOT: store +; CHECK-NOT: load +} + diff --git a/llvm/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll b/llvm/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll new file mode 100644 index 00000000000..e5f0eea8013 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll @@ -0,0 +1,70 @@ +; RUN: opt -S < %s -globalopt | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@_ZL1x = internal global [200 x i8]* null, align 8, !dbg !0 + +define i32 @main(i32 %argc, i8** %argv) norecurse !dbg !18 { +; CHECK: define i32 @main +; Make sure we localized the global. +; CHECK: alloca [200 x i8]* +; Make sure the metadata is sane. Currently, we just drop the metadata, +; so it points to nothing. +; CHECK: call void @llvm.dbg.value(metadata !2, +; CHECK: !2 = !{} +entry: + call void @llvm.dbg.value(metadata i32 %argc, metadata !22, metadata !23), !dbg !24 + call void @llvm.dbg.value(metadata i8** %argv, metadata !25, metadata !23), !dbg !26 + %arrayidx = getelementptr inbounds i8*, i8** %argv, i64 0, !dbg !27 + %0 = load i8*, i8** %arrayidx, align 8, !dbg !27 + %1 = bitcast i8* %0 to [200 x i8]*, !dbg !28 + store [200 x i8]* %1, [200 x i8]** @_ZL1x, align 8, !dbg !29 + call void @llvm.dbg.value(metadata i8** bitcast ([200 x i8]** @_ZL1x to i8**), metadata !30, metadata !23), !dbg !31 + %2 = load i8*, i8** bitcast ([200 x i8]** @_ZL1x to i8**), align 8, !dbg !32 + %3 = load i8, i8* %2, align 1, !dbg !33 + %conv = sext i8 %3 to i32, !dbg !33 + ret i32 %conv, !dbg !34 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!15, !16} +!llvm.ident = !{!17} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "x", linkageName: "_ZL1x", scope: !2, file: !14, line: 1, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !13) +!3 = !DIFile(filename: "-", directory: "/") +!4 = !{} +!5 = !{!6, !11} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 1600, elements: !9) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{!10} +!10 = !DISubrange(count: 200) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!13 = !{!0} +!14 = !DIFile(filename: "<stdin>", directory: "/") +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{!"clang"} +!18 = distinct !DISubprogram(name: "main", scope: !14, file: !14, line: 2, type: !19, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !2, retainedNodes: !4) +!19 = !DISubroutineType(types: !20) +!20 = !{!21, !21, !11} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!22 = !DILocalVariable(name: "argc", arg: 1, scope: !18, file: !14, line: 2, type: !21) +!23 = !DIExpression() +!24 = !DILocation(line: 2, column: 14, scope: !18) +!25 = !DILocalVariable(name: "argv", arg: 2, scope: !18, file: !14, line: 2, type: !11) +!26 = !DILocation(line: 2, column: 26, scope: !18) +!27 = !DILocation(line: 2, column: 52, scope: !18) +!28 = !DILocation(line: 2, column: 38, scope: !18) +!29 = !DILocation(line: 2, column: 36, scope: !18) +!30 = !DILocalVariable(name: "y", scope: !18, file: !14, line: 2, type: !11) +!31 = !DILocation(line: 2, column: 68, scope: !18) +!32 = !DILocation(line: 2, column: 92, scope: !18) +!33 = !DILocation(line: 2, column: 91, scope: !18) +!34 = !DILocation(line: 2, column: 84, scope: !18) diff --git a/llvm/test/Transforms/GlobalOpt/localize-constexpr.ll b/llvm/test/Transforms/GlobalOpt/localize-constexpr.ll new file mode 100644 index 00000000000..3fa7db89b04 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/localize-constexpr.ll @@ -0,0 +1,28 @@ +; RUN: opt -S < %s -globalopt | FileCheck %s + +@G = internal global i32 42 + +define i8 @f() norecurse { +; CHECK-LABEL: @f +; CHECK: alloca +; CHECK-NOT: @G +; CHECK: } + store i32 42, i32* @G + %a = load i8, i8* bitcast (i32* @G to i8*) + ret i8 %a +} + +@H = internal global i32 42 +@Halias = alias i32, i32* @H + +; @H can't be localized because @Halias uses it, and @Halias can't be converted to an instruction. +define i8 @g() norecurse { +; CHECK-LABEL: @g +; CHECK-NOT: alloca +; CHECK: @H +; CHECK: } + store i32 42, i32* @H + %a = load i8, i8* bitcast (i32* @H to i8*) + ret i8 %a +} + diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll new file mode 100644 index 00000000000..fc6dab31640 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-1-no-null-opt.ll @@ -0,0 +1,31 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null ; <i32**> [#uses=3] +; CHECK: global + +define void @init() #0 { +; CHECK-LABEL: @init( +; CHECK: store +; CHECK: load + %malloccall = tail call i8* @malloc(i64 4) ; <i8*> [#uses=1] + %P = bitcast i8* %malloccall to i32* ; <i32*> [#uses=1] + store i32* %P, i32** @G + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + store i32 0, i32* %GV + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @get() #0 { +; CHECK-LABEL: @get( +; CHECK: load i32*, i32** @G +; CHECK-NEXT: load i32, i32* %GV + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + %V = load i32, i32* %GV ; <i32> [#uses=1] + ret i32 %V +; CHECK: ret i32 %V +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll new file mode 100644 index 00000000000..a8f127474e3 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-1.ll @@ -0,0 +1,32 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null ; <i32**> [#uses=4] +; CHECK-NOT: global + +define void @init() { + %malloccall = tail call i8* @malloc(i64 4) ; <i8*> [#uses=1] + %P = bitcast i8* %malloccall to i32* ; <i32*> [#uses=1] + store i32* %P, i32** @G + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + store i32 0, i32* %GV + ret void +} + +declare noalias i8* @malloc(i64) + +define i32 @get() { + %GV = load i32*, i32** @G ; <i32*> [#uses=1] + %V = load i32, i32* %GV ; <i32> [#uses=1] + ret i32 %V +; CHECK: ret i32 0 +} + +define void @foo(i64 %Size) nounwind noinline #0 { +entry: + %0 = load i32*, i32** @G, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } + diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll new file mode 100644 index 00000000000..009a33435fd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-2-no-null-opt.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null + +define void @t() #0 { +; CHECK: @t() +; CHECK: call i8* @malloc +; CHECK: bitcast +; CHECK: store +; CHECK: load +; CHECK: getelementptr +; CHECK: store + %malloccall = tail call i8* @malloc(i64 mul (i64 100, i64 4)) + %P = bitcast i8* %malloccall to i32* + store i32* %P, i32** @G + %GV = load i32*, i32** @G + %GVe = getelementptr i32, i32* %GV, i32 40 + store i32 20, i32* %GVe + ret void +} + +declare noalias i8* @malloc(i64) +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll new file mode 100644 index 00000000000..64f379365c7 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-2.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null + +define void @t() { +; CHECK: @t() +; CHECK-NOT: call i8* @malloc +; CHECK-NEXT: ret void + %malloccall = tail call i8* @malloc(i64 mul (i64 100, i64 4)) + %P = bitcast i8* %malloccall to i32* + store i32* %P, i32** @G + %GV = load i32*, i32** @G + %GVe = getelementptr i32, i32* %GV, i32 40 + store i32 20, i32* %GVe + ret void +} + +declare noalias i8* @malloc(i64) + +define void @foo(i64 %Size) nounwind noinline #0 { +entry: + %0 = load i32*, i32** @G, align 4 + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/malloc-promote-3.ll b/llvm/test/Transforms/GlobalOpt/malloc-promote-3.ll new file mode 100644 index 00000000000..1e42c3b89a6 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/malloc-promote-3.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" + +@G = internal global i32* null + +define void @t() { +; CHECK: @t() +; CHECK: call i8* @malloc + %malloccall = tail call i8* @malloc(i64 mul (i64 100, i64 4)) nobuiltin + %P = bitcast i8* %malloccall to i32* + store i32* %P, i32** @G + %GV = load i32*, i32** @G + %GVe = getelementptr i32, i32* %GV, i32 40 + store i32 20, i32* %GVe + ret void +} + +declare noalias i8* @malloc(i64) diff --git a/llvm/test/Transforms/GlobalOpt/memcpy.ll b/llvm/test/Transforms/GlobalOpt/memcpy.ll new file mode 100644 index 00000000000..0e65f381c1c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/memcpy.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: G1 = internal unnamed_addr constant + +@G1 = internal global [58 x i8] c"asdlfkajsdlfkajsd;lfkajds;lfkjasd;flkajsd;lkfja;sdlkfjasd\00" ; <[58 x i8]*> [#uses=1] + +define void @foo() { + %Blah = alloca [58 x i8] + %tmp.0 = getelementptr [58 x i8], [58 x i8]* %Blah, i32 0, i32 0 + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %tmp.0, i8* align 1 getelementptr inbounds ([58 x i8], [58 x i8]* @G1, i32 0, i32 0), i32 58, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind diff --git a/llvm/test/Transforms/GlobalOpt/memset-null.ll b/llvm/test/Transforms/GlobalOpt/memset-null.ll new file mode 100644 index 00000000000..32bd21cfc58 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/memset-null.ll @@ -0,0 +1,29 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +; PR10047 + +%0 = type { i32, void ()* } +%struct.A = type { [100 x i32] } + +; CHECK: @a +@a = global %struct.A zeroinitializer, align 4 +@llvm.global_ctors = appending global [2 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I_a }, %0 { i32 65535, void ()* @_GLOBAL__I_b }] + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) nounwind + +; CHECK-NOT: GLOBAL__I_a +define internal void @_GLOBAL__I_a() nounwind { +entry: + tail call void @llvm.memset.p0i8.i64(i8* align 4 bitcast (%struct.A* @a to i8*), i8 0, i64 400, i1 false) nounwind + ret void +} + +%struct.X = type { i8 } +@y = global i8* null, align 8 +@x = global %struct.X zeroinitializer, align 1 + +define internal void @_GLOBAL__I_b() nounwind { +entry: + %tmp.i.i.i = load i8*, i8** @y, align 8 + tail call void @llvm.memset.p0i8.i64(i8* %tmp.i.i.i, i8 0, i64 10, i1 false) nounwind + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/memset.ll b/llvm/test/Transforms/GlobalOpt/memset.ll new file mode 100644 index 00000000000..90a3db8cb7b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/memset.ll @@ -0,0 +1,31 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +; CHECK-NOT: internal + +; Both globals are write only, delete them. + +@G0 = internal global [58 x i8] c"asdlfkajsdlfkajsd;lfkajds;lfkjasd;flkajsd;lkfja;sdlkfjasd\00" ; <[58 x i8]*> [#uses=1] +@G1 = internal global [4 x i32] [ i32 1, i32 2, i32 3, i32 4 ] ; <[4 x i32]*> [#uses=1] + +define void @foo() { + %Blah = alloca [58 x i8] + %tmp3 = bitcast [58 x i8]* %Blah to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* bitcast ([4 x i32]* @G1 to i8*), i8* %tmp3, i32 16, i1 false) + call void @llvm.memset.p0i8.i32(i8* getelementptr inbounds ([58 x i8], [58 x i8]* @G0, i32 0, i32 0), i8 17, i32 58, i1 false) + ret void +} + +@G0_as1 = internal addrspace(1) global [58 x i8] c"asdlfkajsdlfkajsd;lfkajds;lfkjasd;flkajsd;lkfja;sdlkfjasd\00" ; <[58 x i8]*> [#uses=1] +@G1_as1 = internal addrspace(1) global [4 x i32] [ i32 1, i32 2, i32 3, i32 4 ] ; <[4 x i32]*> [#uses=1] + +define void @foo_as1() { + %Blah = alloca [58 x i8] + %tmp3 = bitcast [58 x i8]* %Blah to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* addrspacecast ([4 x i32] addrspace(1)* @G1_as1 to i8*), i8* %tmp3, i32 16, i1 false) + call void @llvm.memset.p1i8.i32(i8 addrspace(1)* getelementptr inbounds ([58 x i8], [58 x i8] addrspace(1)* @G0_as1, i32 0, i32 0), i8 17, i32 58, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i1) nounwind +declare void @llvm.memset.p1i8.i32(i8 addrspace(1)* nocapture, i8, i32, i1) nounwind diff --git a/llvm/test/Transforms/GlobalOpt/metadata.ll b/llvm/test/Transforms/GlobalOpt/metadata.ll new file mode 100644 index 00000000000..b766349d506 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/metadata.ll @@ -0,0 +1,32 @@ +; RUN: opt -S -globalopt < %s | FileCheck %s + +; PR6112 - When globalopt does RAUW(@G, %G), the metadata reference should drop +; to null. Function local metadata that references @G from a different function +; to that containing %G should likewise drop to null. +@G = internal global i8** null + +define i32 @main(i32 %argc, i8** %argv) norecurse { +; CHECK-LABEL: @main( +; CHECK: %G = alloca + store i8** %argv, i8*** @G + ret i32 0 +} + +define void @foo(i32 %x) { +; Note: these arguments look like MDNodes, but they're really syntactic sugar +; for 'MetadataAsValue::get(ValueAsMetadata::get(Value*))'. When @G drops to +; null, the ValueAsMetadata instance gets replaced by metadata !{}, or +; MDNode::get({}). + call void @llvm.foo(metadata i8*** @G, metadata i32 %x) +; CHECK: call void @llvm.foo(metadata ![[EMPTY:[0-9]+]], metadata i32 %x) + ret void +} + +declare void @llvm.foo(metadata, metadata) nounwind readnone + +!named = !{!0} +; CHECK: !named = !{![[NULL:[0-9]+]]} + +!0 = !{i8*** @G} +; CHECK-DAG: ![[NULL]] = distinct !{null} +; CHECK-DAG: ![[EMPTY]] = !{} diff --git a/llvm/test/Transforms/GlobalOpt/musttail_cc.ll b/llvm/test/Transforms/GlobalOpt/musttail_cc.ll new file mode 100644 index 00000000000..fc927ea91dd --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/musttail_cc.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; PR36546 + +; Check that musttail callee preserves its calling convention + +define i32 @test(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo(i32 %a) + %ca = musttail call i32 @foo(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo(i32 %a) +define internal i32 @foo(i32 %a) { + ret i32 %a +} + +; Check that musttail caller preserves its calling convention + +define i32 @test2(i32 %a) { + %ca = call i32 @foo1(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo1(i32 %a) +define internal i32 @foo1(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo2(i32 %a) + %ca = musttail call i32 @foo2(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo2(i32 %a) +define internal i32 @foo2(i32 %a) { + ret i32 %a +} diff --git a/llvm/test/Transforms/GlobalOpt/naked_functions.ll b/llvm/test/Transforms/GlobalOpt/naked_functions.ll new file mode 100644 index 00000000000..80c3aa8c3b2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/naked_functions.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; Check that naked functions don't get marked with fast calling conventions + +@g = common global i32 0, align 4 + +define i32 @bar() { +entry: + %call = call i32 @foo(i32* @g) +; CHECK: %call = call i32 @foo(i32* @g) + ret i32 %call +} + +define internal i32 @foo(i32*) #0 { +entry: + %retval = alloca i32, align 4 + call void asm sideeffect "ldr r0, [r0] \0Abx lr \0A", ""() + unreachable +} + +; CHECK: define internal i32 @foo(i32*) + +attributes #0 = { naked } diff --git a/llvm/test/Transforms/GlobalOpt/phi-select.ll b/llvm/test/Transforms/GlobalOpt/phi-select.ll new file mode 100644 index 00000000000..86b017c9cb3 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/phi-select.ll @@ -0,0 +1,27 @@ +; Test that PHI nodes and select instructions do not necessarily make stuff +; non-constant. + +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: global + +@X = internal global i32 4 ; <i32*> [#uses=2] +@Y = internal global i32 5 ; <i32*> [#uses=2] + +define i32 @test1(i1 %C) { + %P = select i1 %C, i32* @X, i32* @Y ; <i32*> [#uses=1] + %V = load i32, i32* %P ; <i32> [#uses=1] + ret i32 %V +} + +define i32 @test2(i1 %C) { +; <label>:0 + br i1 %C, label %T, label %Cont + +T: ; preds = %0 + br label %Cont + +Cont: ; preds = %T, %0 + %P = phi i32* [ @X, %0 ], [ @Y, %T ] ; <i32*> [#uses=1] + %V = load i32, i32* %P ; <i32> [#uses=1] + ret i32 %V +} diff --git a/llvm/test/Transforms/GlobalOpt/pr21191.ll b/llvm/test/Transforms/GlobalOpt/pr21191.ll new file mode 100644 index 00000000000..9e201b888be --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/pr21191.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +$c = comdat any +; CHECK: $c = comdat any + +define linkonce_odr void @foo() comdat($c) { + ret void +} +; CHECK: define linkonce_odr void @foo() local_unnamed_addr comdat($c) + +define linkonce_odr void @bar() comdat($c) { + ret void +} +; CHECK: define linkonce_odr void @bar() local_unnamed_addr comdat($c) + +define void @zed() { + call void @foo() + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/pr33686.ll b/llvm/test/Transforms/GlobalOpt/pr33686.ll new file mode 100644 index 00000000000..d6bb98735f4 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/pr33686.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -globalopt %s | FileCheck %s + +@glob = external global i16, align 1 + +define void @beth() { +; CHECK-LABEL: @beth( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret void +; +entry: + ret void + +notreachable: + %patatino = select i1 undef, i16* @glob, i16* %patatino + br label %notreachable +} diff --git a/llvm/test/Transforms/GlobalOpt/preserve-comdats.ll b/llvm/test/Transforms/GlobalOpt/preserve-comdats.ll new file mode 100644 index 00000000000..0148f0024b9 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/preserve-comdats.ll @@ -0,0 +1,37 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s + +$comdat_global = comdat any + +@comdat_global = weak_odr global i8 0, comdat($comdat_global) +@simple_global = internal global i8 0 +; CHECK: @comdat_global = weak_odr global i8 0, comdat{{$}} +; CHECK: @simple_global = internal global i8 42 + +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 65535, void ()* @init_comdat_global, i8* @comdat_global }, + { i32, void ()*, i8* } { i32 65535, void ()* @init_simple_global, i8* null } +] +; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] +; CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @init_comdat_global, i8* @comdat_global }] + +define void @init_comdat_global() { + store i8 42, i8* @comdat_global + ret void +} +; CHECK: define void @init_comdat_global() + +define internal void @init_simple_global() comdat($comdat_global) { + store i8 42, i8* @simple_global + ret void +} +; CHECK-NOT: @init_simple_global() + +define i8* @use_simple() { + ret i8* @simple_global +} +; CHECK: define i8* @use_simple() + +define i8* @use_comdat() { + ret i8* @comdat_global +} +; CHECK: define i8* @use_comdat() diff --git a/llvm/test/Transforms/GlobalOpt/shrink-address-to-bool.ll b/llvm/test/Transforms/GlobalOpt/shrink-address-to-bool.ll new file mode 100644 index 00000000000..1a298b04e9b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/shrink-address-to-bool.ll @@ -0,0 +1,46 @@ +;RUN: opt -S -globalopt -f %s | FileCheck %s + +;CHECK: @foo = {{.*}}, !dbg !0 +@foo = global i64 ptrtoint ([1 x i64]* @baa to i64), align 8, !dbg !0 +@baa = common global [1 x i64] zeroinitializer, align 8, !dbg !6 + +; Function Attrs: noinline nounwind optnone uwtable +define void @fun() #0 !dbg !16 { +entry: + %0 = load i64, i64* @foo, align 8, !dbg !19 + %1 = inttoptr i64 %0 to i64*, !dbg !19 + %cmp = icmp ugt i64* getelementptr inbounds ([1 x i64], [1 x i64]* @baa, i32 0, i32 0), %1, !dbg !20 + %conv = zext i1 %cmp to i32, !dbg !20 + store i64 0, i64* @foo, align 8, !dbg !21 + ret void, !dbg !22 +} + +attributes #0 = { noinline nounwind optnone uwtable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "shrink-address-to-bool.c", directory: "/") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "baa", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !10) +!9 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!10 = !{!11} +!11 = !DISubrange(count: 1) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 6.0.0 "} +!16 = distinct !DISubprogram(name: "fun", scope: !3, file: !3, line: 4, type: !17, isLocal: false, isDefinition: true, scopeLine: 4, isOptimized: false, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{null} +!19 = !DILocation(line: 5, column: 9, scope: !16) +!20 = !DILocation(line: 5, column: 7, scope: !16) +!21 = !DILocation(line: 6, column: 7, scope: !16) +!22 = !DILocation(line: 7, column: 1, scope: !16) diff --git a/llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll b/llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll new file mode 100644 index 00000000000..71019128bb1 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll @@ -0,0 +1,22 @@ +;RUN: opt -S -debugify -globalopt -f %s | FileCheck %s + +@foo = internal global i32 0, align 4 + +define dso_local i32 @bar() { +entry: + store i32 5, i32* @foo, align 4 + %0 = load i32, i32* @foo, align 4 + ret i32 %0 +} + +;CHECK: @bar +;CHECK-NEXT: entry: +;CHECK-NEXT: store i1 true, i1* @foo, !dbg ![[DbgLocStore:[0-9]+]] +;CHECK-NEXT: %.b = load i1, i1* @foo, !dbg ![[DbgLocLoadSel:[0-9]+]] +;CHECK-NEXT: %0 = select i1 %.b, i32 5, i32 0, !dbg ![[DbgLocLoadSel]] +;CHECK-NEXT: call void @llvm.dbg.value({{.*}}), !dbg ![[DbgLocLoadSel]] +;CHECK-NEXT: ret i32 %0, !dbg ![[DbgLocRet:[0-9]+]] + +;CHECK: ![[DbgLocStore]] = !DILocation(line: 1, +;CHECK: ![[DbgLocLoadSel]] = !DILocation(line: 2, +;CHECK: ![[DbgLocRet]] = !DILocation(line: 3, diff --git a/llvm/test/Transforms/GlobalOpt/static-const-bitcast.ll b/llvm/test/Transforms/GlobalOpt/static-const-bitcast.ll new file mode 100644 index 00000000000..52da721b55f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/static-const-bitcast.ll @@ -0,0 +1,62 @@ +; RUN: opt -globalopt %s -S -o - | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.A = type { %class.Wrapper } +%class.Wrapper = type { i32 } + +$Wrapper = comdat any + +@kA = internal global %struct.A zeroinitializer, align 4 +; CHECK: @kA = internal unnamed_addr constant %struct.A { %class.Wrapper { i32 1036831949 } }, align 4 + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { +i32 65535, void ()* @_GLOBAL__sub_I_const_static.cc, i8* null }] + +define dso_local i32 @AsBits(float* %x) #0 { +entry: + %0 = bitcast float* %x to i32* + %1 = load i32, i32* %0, align 4 + ret i32 %1 +} + +define internal void @__cxx_global_var_init() #1 section ".text.startup" { +entry: + call void @Wrapper(%class.Wrapper* getelementptr inbounds (%struct.A, %struct.A* @kA, i32 0, i32 0), float 0x3FB99999A0000000) + %0 = call {}* @llvm.invariant.start.p0i8(i64 4, i8* bitcast (%struct.A* @kA to i8*)) + ret void +} + +define linkonce_odr dso_local void @Wrapper(%class.Wrapper* %this, float %x) unnamed_addr #0 comdat align 2 { +entry: + %x.addr = alloca float, align 4 + store float %x, float* %x.addr, align 4 + %store_ = getelementptr inbounds %class.Wrapper, %class.Wrapper* %this, i32 0, i32 0 + %call = call i32 @AsBits(float* %x.addr) + store i32 %call, i32* %store_, align 4 + ret void +} + +declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) #2 + +; Function Attrs: nounwind uwtable +define dso_local void @LoadIt(%struct.A* %c) #0 { +entry: + %0 = bitcast %struct.A* %c to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.A* @kA to i8*), i64 4, i1 false) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 + +; Function Attrs: uwtable +define internal void @_GLOBAL__sub_I_const_static.cc() #1 section ".text.startup" { +entry: + call void @__cxx_global_var_init() + ret void +} + +attributes #0 = { nounwind uwtable "target-cpu"="x86-64" } +attributes #1 = { uwtable "target-cpu"="x86-64" } +attributes #2 = { argmemonly nounwind } diff --git a/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll new file mode 100644 index 00000000000..709df17e0b5 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer-compare-no-null-opt.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: global + +@G = internal global void ()* null ; <void ()**> [#uses=2] + +define internal void @Actual() { +; CHECK-LABEL: Actual( + ret void +} + +define void @init() { +; CHECK-LABEL: init( +; CHECK: store void ()* @Actual, void ()** @G + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() #0 { +; CHECK-LABEL: doit( + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=2] +; CHECK: %FP = load void ()*, void ()** @G + %CC = icmp eq void ()* %FP, null ; <i1> [#uses=1] +; CHECK: %CC = icmp eq void ()* %FP, null + br i1 %CC, label %isNull, label %DoCall +; CHECK: br i1 %CC, label %isNull, label %DoCall + +DoCall: ; preds = %0 +; CHECK: DoCall: +; CHECK: call void %FP() +; CHECK: ret void + call void %FP( ) + ret void + +isNull: ; preds = %0 +; CHECK: isNull: +; CHECK: ret void + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/storepointer-compare.ll b/llvm/test/Transforms/GlobalOpt/storepointer-compare.ll new file mode 100644 index 00000000000..969443569c2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer-compare.ll @@ -0,0 +1,29 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK: call void @Actual + +; Check that a comparison does not prevent an indirect call from being made +; direct. The global will still remain, but indirect call elim is still good. + +@G = internal global void ()* null ; <void ()**> [#uses=2] + +define internal void @Actual() { + ret void +} + +define void @init() { + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() { + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=2] + %CC = icmp eq void ()* %FP, null ; <i1> [#uses=1] + br i1 %CC, label %isNull, label %DoCall + +DoCall: ; preds = %0 + call void %FP( ) + ret void + +isNull: ; preds = %0 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll b/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll new file mode 100644 index 00000000000..c9a63f0080d --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer-no-null-opt.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +@G = internal global void ()* null ; <void ()**> [#uses=2] +; CHECK: global + +define internal void @Actual() { +; CHECK-LABEL: Actual( + ret void +} + +define void @init() { +; CHECK-LABEL: init( +; CHECK: store void ()* @Actual, void ()** @G + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() #0 { +; CHECK-LABEL: doit( +; CHECK: %FP = load void ()*, void ()** @G +; CHECK: call void %FP() + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=1] + call void %FP( ) + ret void +} + +attributes #0 = { "null-pointer-is-valid"="true" } diff --git a/llvm/test/Transforms/GlobalOpt/storepointer.ll b/llvm/test/Transforms/GlobalOpt/storepointer.ll new file mode 100644 index 00000000000..8edaa64a62b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/storepointer.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: global + +@G = internal global void ()* null ; <void ()**> [#uses=2] + +define internal void @Actual() { + ret void +} + +define void @init() { + store void ()* @Actual, void ()** @G + ret void +} + +define void @doit() { + %FP = load void ()*, void ()** @G ; <void ()*> [#uses=1] + call void %FP( ) + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/tls.ll b/llvm/test/Transforms/GlobalOpt/tls.ll new file mode 100644 index 00000000000..d010b96188f --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/tls.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; RUN: opt -emulated-tls < %s -globalopt -S | FileCheck %s + +declare void @wait() +declare void @signal() +declare void @start_thread(void ()*) + +@x = internal thread_local global [100 x i32] zeroinitializer, align 16 +@ip = internal global i32* null, align 8 + +; PR14309: GlobalOpt would think that the value of @ip is always the address of +; x[1]. However, that address is different for different threads so @ip cannot +; be replaced with a constant. + +define i32 @f() { +entry: + ; Set @ip to point to x[1] for thread 1. + store i32* getelementptr inbounds ([100 x i32], [100 x i32]* @x, i64 0, i64 1), i32** @ip, align 8 + + ; Run g on a new thread. + tail call void @start_thread(void ()* @g) nounwind + tail call void @wait() nounwind + + ; Reset x[1] for thread 1. + store i32 0, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @x, i64 0, i64 1), align 4 + + ; Read the value of @ip, which now points at x[1] for thread 2. + %0 = load i32*, i32** @ip, align 8 + + %1 = load i32, i32* %0, align 4 + ret i32 %1 + +; CHECK-LABEL: @f( +; Make sure that the load from @ip hasn't been removed. +; CHECK: load i32*, i32** @ip +; CHECK: ret +} + +define internal void @g() nounwind uwtable { +entry: + ; Set @ip to point to x[1] for thread 2. + store i32* getelementptr inbounds ([100 x i32], [100 x i32]* @x, i64 0, i64 1), i32** @ip, align 8 + + ; Store 50 in x[1] for thread 2. + store i32 50, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @x, i64 0, i64 1), align 4 + + tail call void @signal() nounwind + ret void + +; CHECK-LABEL: @g( +; Make sure that the store to @ip hasn't been removed. +; CHECK: store {{.*}} @ip +; CHECK: ret +} diff --git a/llvm/test/Transforms/GlobalOpt/trivialstore.ll b/llvm/test/Transforms/GlobalOpt/trivialstore.ll new file mode 100644 index 00000000000..9a490879a41 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/trivialstore.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: G + +@G = internal global i32 17 ; <i32*> [#uses=3] + +define void @foo() { + store i32 17, i32* @G + ret void +} + +define i32 @bar() { + %X = load i32, i32* @G ; <i32> [#uses=1] + ret i32 %X +} + +define internal void @dead() { + store i32 123, i32* @G + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/undef-init.ll b/llvm/test/Transforms/GlobalOpt/undef-init.ll new file mode 100644 index 00000000000..71fad343e56 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/undef-init.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; CHECK-NOT: store + +@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I__Z3foov } ] ; <[1 x { i32, void ()* }]*> [#uses=0] +@X.0 = internal global i32 undef ; <i32*> [#uses=2] + +define i32 @_Z3foov() { +entry: + %tmp.1 = load i32, i32* @X.0 ; <i32> [#uses=1] + ret i32 %tmp.1 +} + +define internal void @_GLOBAL__I__Z3foov() { +entry: + store i32 1, i32* @X.0 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/unnamed-addr.ll b/llvm/test/Transforms/GlobalOpt/unnamed-addr.ll new file mode 100644 index 00000000000..9f11f1bd92c --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/unnamed-addr.ll @@ -0,0 +1,74 @@ +; RUN: opt -globalopt -S < %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 +@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: @d = internal unnamed_addr constant [4 x i8] c"foo\00", align 1 +; CHECK: @e = linkonce_odr local_unnamed_addr global i32 0 + +; CHECK: define internal fastcc void @used_internal() unnamed_addr { +define internal void @used_internal() { + ret void +} + +define i32 @get_e() { + call void @used_internal() + %t = load i32, i32* @e + ret i32 %t +} + +define void @set_e(i32 %x) { + store i32 %x, i32* @e + ret void +} + +define i1 @bah(i64 %i) nounwind readonly optsize ssp { +entry: + %arrayidx4 = getelementptr inbounds [4 x i8], [4 x i8]* @d, i64 0, i64 %i + %tmp5 = load i8, i8* %arrayidx4, align 1 + %array0 = bitcast [4 x i8]* @d to i8* + %tmp6 = load i8, i8* %array0, align 1 + %cmp = icmp eq i8 %tmp5, %tmp6 + 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, i32* @c, align 4 + ret i32 %tmp1 +} diff --git a/llvm/test/Transforms/GlobalOpt/zeroinitializer-gep-load.ll b/llvm/test/Transforms/GlobalOpt/zeroinitializer-gep-load.ll new file mode 100644 index 00000000000..51feb480e3b --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/zeroinitializer-gep-load.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +@zero = internal global [10 x i32] zeroinitializer + +define i32 @test1(i64 %idx) nounwind { + %arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* @zero, i64 0, i64 %idx + %l = load i32, i32* %arrayidx + ret i32 %l +; CHECK-LABEL: @test1( +; CHECK: ret i32 0 +} |