1 ; RUN: opt < %s -tailcallelim -S | FileCheck %s 2 ; PR4323 3 4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 5 6 ; Several cases where tail call elimination should move the load above the call, 7 ; then eliminate the tail recursion. 8 9 10 @global = external global i32 ; <i32*> [#uses=1] 11 @extern_weak_global = extern_weak global i32 ; <i32*> [#uses=1] 12 13 14 ; This load can be moved above the call because the function won't write to it 15 ; and the call has no side effects. 16 define fastcc i32 @raise_load_1(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) nounwind readonly { 17 ; CHECK-LABEL: @raise_load_1( 18 ; CHECK-NOT: call 19 ; CHECK: load i32, i32* 20 ; CHECK-NOT: call 21 ; CHECK: } 22 entry: 23 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 24 br i1 %tmp2, label %if, label %else 25 26 if: ; preds = %entry 27 ret i32 0 28 29 else: ; preds = %entry 30 %tmp7 = add i32 %start_arg, 1 ; <i32> [#uses=1] 31 %tmp8 = call fastcc i32 @raise_load_1(i32* %a_arg, i32 %a_len_arg, i32 %tmp7) ; <i32> [#uses=1] 32 %tmp9 = load i32, i32* %a_arg ; <i32> [#uses=1] 33 %tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1] 34 ret i32 %tmp10 35 } 36 37 38 ; This load can be moved above the call because the function won't write to it 39 ; and the load provably can't trap. 40 define fastcc i32 @raise_load_2(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) readonly { 41 ; CHECK-LABEL: @raise_load_2( 42 ; CHECK-NOT: call 43 ; CHECK: load i32, i32* 44 ; CHECK-NOT: call 45 ; CHECK: } 46 entry: 47 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 48 br i1 %tmp2, label %if, label %else 49 50 if: ; preds = %entry 51 ret i32 0 52 53 else: ; preds = %entry 54 %nullcheck = icmp eq i32* %a_arg, null ; <i1> [#uses=1] 55 br i1 %nullcheck, label %unwind, label %recurse 56 57 unwind: ; preds = %else 58 unreachable 59 60 recurse: ; preds = %else 61 %tmp7 = add i32 %start_arg, 1 ; <i32> [#uses=1] 62 %tmp8 = call fastcc i32 @raise_load_2(i32* %a_arg, i32 %a_len_arg, i32 %tmp7) ; <i32> [#uses=1] 63 %tmp9 = load i32, i32* @global ; <i32> [#uses=1] 64 %tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1] 65 ret i32 %tmp10 66 } 67 68 69 ; This load can be safely moved above the call (even though it's from an 70 ; extern_weak global) because the call has no side effects. 71 define fastcc i32 @raise_load_3(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) nounwind readonly { 72 ; CHECK-LABEL: @raise_load_3( 73 ; CHECK-NOT: call 74 ; CHECK: load i32, i32* 75 ; CHECK-NOT: call 76 ; CHECK: } 77 entry: 78 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 79 br i1 %tmp2, label %if, label %else 80 81 if: ; preds = %entry 82 ret i32 0 83 84 else: ; preds = %entry 85 %tmp7 = add i32 %start_arg, 1 ; <i32> [#uses=1] 86 %tmp8 = call fastcc i32 @raise_load_3(i32* %a_arg, i32 %a_len_arg, i32 %tmp7) ; <i32> [#uses=1] 87 %tmp9 = load i32, i32* @extern_weak_global ; <i32> [#uses=1] 88 %tmp10 = add i32 %tmp9, %tmp8 ; <i32> [#uses=1] 89 ret i32 %tmp10 90 } 91 92 93 ; The second load can be safely moved above the call even though it's from an 94 ; unknown pointer (which normally means it might trap) because the first load 95 ; proves it doesn't trap. 96 define fastcc i32 @raise_load_4(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) readonly { 97 ; CHECK-LABEL: @raise_load_4( 98 ; CHECK-NOT: call 99 ; CHECK: load i32, i32* 100 ; CHECK-NEXT: load i32, i32* 101 ; CHECK-NOT: call 102 ; CHECK: } 103 entry: 104 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 105 br i1 %tmp2, label %if, label %else 106 107 if: ; preds = %entry 108 ret i32 0 109 110 else: ; preds = %entry 111 %nullcheck = icmp eq i32* %a_arg, null ; <i1> [#uses=1] 112 br i1 %nullcheck, label %unwind, label %recurse 113 114 unwind: ; preds = %else 115 unreachable 116 117 recurse: ; preds = %else 118 %tmp7 = add i32 %start_arg, 1 ; <i32> [#uses=1] 119 %first = load i32, i32* %a_arg ; <i32> [#uses=1] 120 %tmp8 = call fastcc i32 @raise_load_4(i32* %a_arg, i32 %first, i32 %tmp7) ; <i32> [#uses=1] 121 %second = load i32, i32* %a_arg ; <i32> [#uses=1] 122 %tmp10 = add i32 %second, %tmp8 ; <i32> [#uses=1] 123 ret i32 %tmp10 124 } 125