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