• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt < %s -tailcallelim -S | FileCheck %s
2; PR4323
3
4target 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.
16define 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: }
22entry:
23	%tmp2 = icmp sge i32 %start_arg, %a_len_arg		; <i1> [#uses=1]
24	br i1 %tmp2, label %if, label %else
25
26if:		; preds = %entry
27	ret i32 0
28
29else:		; 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.
40define 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: }
46entry:
47	%tmp2 = icmp sge i32 %start_arg, %a_len_arg		; <i1> [#uses=1]
48	br i1 %tmp2, label %if, label %else
49
50if:		; preds = %entry
51	ret i32 0
52
53else:		; preds = %entry
54	%nullcheck = icmp eq i32* %a_arg, null		; <i1> [#uses=1]
55	br i1 %nullcheck, label %unwind, label %recurse
56
57unwind:		; preds = %else
58	unreachable
59
60recurse:		; 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.
71define 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: }
77entry:
78	%tmp2 = icmp sge i32 %start_arg, %a_len_arg		; <i1> [#uses=1]
79	br i1 %tmp2, label %if, label %else
80
81if:		; preds = %entry
82	ret i32 0
83
84else:		; 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.
96define 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: }
103entry:
104	%tmp2 = icmp sge i32 %start_arg, %a_len_arg		; <i1> [#uses=1]
105	br i1 %tmp2, label %if, label %else
106
107if:		; preds = %entry
108	ret i32 0
109
110else:		; preds = %entry
111	%nullcheck = icmp eq i32* %a_arg, null		; <i1> [#uses=1]
112	br i1 %nullcheck, label %unwind, label %recurse
113
114unwind:		; preds = %else
115	unreachable
116
117recurse:		; 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
126; This load can be moved above the call because the function won't write to it
127; and the a_arg is dereferenceable.
128define fastcc i32 @raise_load_5(i32* dereferenceable(4) %a_arg, i32 %a_len_arg, i32 %start_arg) readonly {
129; CHECK-LABEL: @raise_load_5(
130; CHECK-NOT: call
131; CHECK: load i32, i32*
132; CHECK-NOT: call
133; CHECK: }
134entry:
135	%tmp2 = icmp sge i32 %start_arg, %a_len_arg		; <i1> [#uses=1]
136	br i1 %tmp2, label %if, label %else
137
138if:		; preds = %entry
139	ret i32 0
140
141else:		; preds = %entry
142	%tmp7 = add i32 %start_arg, 1		; <i32> [#uses=1]
143	%tmp8 = call fastcc i32 @raise_load_5(i32* %a_arg, i32 %a_len_arg, i32 %tmp7)		; <i32> [#uses=1]
144	%tmp9 = load i32, i32* %a_arg		; <i32> [#uses=1]
145	%tmp10 = add i32 %tmp9, %tmp8		; <i32> [#uses=1]
146	ret i32 %tmp10
147}
148