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. 14define fastcc i32 @raise_load_1(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) nounwind readonly { 15entry: 16 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 17 br i1 %tmp2, label %if, label %else 18 19if: ; preds = %entry 20 ret i32 0 21 22else: ; 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. 34define fastcc i32 @raise_load_2(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) readonly { 35entry: 36 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 37 br i1 %tmp2, label %if, label %else 38 39if: ; preds = %entry 40 ret i32 0 41 42else: ; preds = %entry 43 %nullcheck = icmp eq i32* %a_arg, null ; <i1> [#uses=1] 44 br i1 %nullcheck, label %unwind, label %recurse 45 46unwind: ; preds = %else 47 unreachable 48 49recurse: ; 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. 61define fastcc i32 @raise_load_3(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) nounwind readonly { 62entry: 63 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 64 br i1 %tmp2, label %if, label %else 65 66if: ; preds = %entry 67 ret i32 0 68 69else: ; 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. 82define fastcc i32 @raise_load_4(i32* %a_arg, i32 %a_len_arg, i32 %start_arg) readonly { 83entry: 84 %tmp2 = icmp sge i32 %start_arg, %a_len_arg ; <i1> [#uses=1] 85 br i1 %tmp2, label %if, label %else 86 87if: ; preds = %entry 88 ret i32 0 89 90else: ; preds = %entry 91 %nullcheck = icmp eq i32* %a_arg, null ; <i1> [#uses=1] 92 br i1 %nullcheck, label %unwind, label %recurse 93 94unwind: ; preds = %else 95 unreachable 96 97recurse: ; 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