1; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s
2; RUN: opt -codegenprepare -S -mtriple=x86_64-linux < %s | FileCheck %s --check-prefix OPT
3
4
5; The exit block containing extractvalue can be duplicated into the BB
6; containing call. And later tail call can be generated.
7
8; CHECK-LABEL: test1:
9; CHECK:       jmp bar # TAILCALL
10; CHECK:       jmp foo # TAILCALL
11
12; OPT-LABEL:   test1
13; OPT:         if.then.i:
14; OPT-NEXT:    tail call { i8*, i64 } @bar
15; OPT-NEXT:    extractvalue
16; OPT-NEXT:    bitcast
17; OPT-NEXT:    ret
18;
19; OPT:         if.end.i:
20; OPT-NEXT:    tail call { i8*, i64 } @foo
21; OPT-NEXT:    extractvalue
22; OPT-NEXT:    bitcast
23; OPT-NEXT:    ret
24
25define i64* @test1(i64 %size) {
26entry:
27  %cmp.i.i = icmp ugt i64 %size, 16384
28  %add.i.i = add i64 %size, 7
29  %div.i.i = lshr i64 %add.i.i, 3
30  %phitmp.i.i = trunc i64 %div.i.i to i32
31  %cmp1.i = icmp eq i32 %phitmp.i.i, 0
32  %cmp.i = or i1 %cmp.i.i, %cmp1.i
33  br i1 %cmp.i, label %if.end.i, label %if.then.i
34  if.then.i:                                        ; preds = %entry
35  %call1.i = tail call { i8*, i64 } @bar(i64 %size)
36  br label %exit
37
38if.end.i:                                         ; preds = %entry
39  %call2.i = tail call { i8*, i64 } @foo(i64 %size)
40  br label %exit
41
42exit:
43  %call1.i.sink = phi { i8*, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
44  %ev = extractvalue { i8*, i64 } %call1.i.sink, 0
45  %result = bitcast i8* %ev to i64*
46  ret i64* %result
47}
48
49
50; The extractvalue extracts a field with non-zero offset, so the exit block
51; can't be duplicated.
52
53; CHECK-LABEL: test2:
54; CHECK:       callq bar
55; CHECK:       callq foo
56
57; OPT-LABEL:   test2
58; OPT:         if.then.i:
59; OPT-NEXT:    tail call { i8*, i64 } @bar
60; OPT-NEXT:    br label %exit
61;
62; OPT:         if.end.i:
63; OPT-NEXT:    tail call { i8*, i64 } @foo
64; OPT-NEXT:    br label %exit
65;
66; OPT:         exit:
67; OPT-NEXT:    phi
68; OPT-NEXT:    extractvalue
69; OPT-NEXT:    ret
70
71define i64 @test2(i64 %size) {
72entry:
73  %cmp.i.i = icmp ugt i64 %size, 16384
74  %add.i.i = add i64 %size, 7
75  %div.i.i = lshr i64 %add.i.i, 3
76  %phitmp.i.i = trunc i64 %div.i.i to i32
77  %cmp1.i = icmp eq i32 %phitmp.i.i, 0
78  %cmp.i = or i1 %cmp.i.i, %cmp1.i
79  br i1 %cmp.i, label %if.end.i, label %if.then.i
80  if.then.i:                                        ; preds = %entry
81  %call1.i = tail call { i8*, i64 } @bar(i64 %size)
82  br label %exit
83
84if.end.i:                                         ; preds = %entry
85  %call2.i = tail call { i8*, i64 } @foo(i64 %size)
86  br label %exit
87
88exit:
89  %call1.i.sink = phi { i8*, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
90  %ev = extractvalue { i8*, i64 } %call1.i.sink, 1
91  ret i64 %ev
92}
93
94
95; The extractvalue accesses a nest struct type, the extracted field has zero
96; offset, so the exit block can still be duplicated, and tail call generated.
97
98; CHECK-LABEL: test3:
99; CHECK:       jmp baz # TAILCALL
100; CHECK:       jmp qux # TAILCALL
101
102; OPT-LABEL:   test3
103; OPT:         if.then.i:
104; OPT-NEXT:    tail call { { i8*, i64 }, i64 } @baz
105; OPT-NEXT:    extractvalue
106; OPT-NEXT:    bitcast
107; OPT-NEXT:    ret
108;
109; OPT:         if.end.i:
110; OPT-NEXT:    tail call { { i8*, i64 }, i64 } @qux
111; OPT-NEXT:    extractvalue
112; OPT-NEXT:    bitcast
113; OPT-NEXT:    ret
114
115define i64* @test3(i64 %size) {
116entry:
117  %cmp.i.i = icmp ugt i64 %size, 16384
118  %add.i.i = add i64 %size, 7
119  %div.i.i = lshr i64 %add.i.i, 3
120  %phitmp.i.i = trunc i64 %div.i.i to i32
121  %cmp1.i = icmp eq i32 %phitmp.i.i, 0
122  %cmp.i = or i1 %cmp.i.i, %cmp1.i
123  br i1 %cmp.i, label %if.end.i, label %if.then.i
124
125if.then.i:                                        ; preds = %entry
126  %call1.i = tail call { {i8*, i64}, i64 } @baz(i64 %size)
127  br label %exit
128
129if.end.i:                                         ; preds = %entry
130  %call2.i = tail call { {i8*, i64}, i64 } @qux(i64 %size)
131  br label %exit
132
133exit:
134  %call1.i.sink = phi { {i8*, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
135  %ev = extractvalue { {i8*, i64}, i64 } %call1.i.sink, 0, 0
136  %result = bitcast i8* %ev to i64*
137  ret i64* %result
138}
139
140
141; The extractvalue accesses a nest struct with non-zero offset, so the exit
142; block can't be duplicated.
143
144; CHECK-LABEL: test4:
145; CHECK:       callq baz
146; CHECK:       callq qux
147
148; OPT-LABEL:   test4
149; OPT:         if.then.i:
150; OPT-NEXT:    tail call { { i8*, i64 }, i64 } @baz
151; OPT-NEXT:    br label %exit
152;
153; OPT:         if.end.i:
154; OPT-NEXT:    tail call { { i8*, i64 }, i64 } @qux
155; OPT-NEXT:    br label %exit
156;
157; OPT:         exit:
158; OPT-NEXT:    phi
159; OPT-NEXT:    extractvalue
160; OPT-NEXT:    ret
161
162define i64 @test4(i64 %size) {
163entry:
164  %cmp.i.i = icmp ugt i64 %size, 16384
165  %add.i.i = add i64 %size, 7
166  %div.i.i = lshr i64 %add.i.i, 3
167  %phitmp.i.i = trunc i64 %div.i.i to i32
168  %cmp1.i = icmp eq i32 %phitmp.i.i, 0
169  %cmp.i = or i1 %cmp.i.i, %cmp1.i
170  br i1 %cmp.i, label %if.end.i, label %if.then.i
171
172if.then.i:                                        ; preds = %entry
173  %call1.i = tail call { {i8*, i64}, i64 } @baz(i64 %size)
174  br label %exit
175
176if.end.i:                                         ; preds = %entry
177  %call2.i = tail call { {i8*, i64}, i64 } @qux(i64 %size)
178  br label %exit
179
180exit:
181  %call1.i.sink = phi { {i8*, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
182  %ev = extractvalue { {i8*, i64}, i64 } %call1.i.sink, 0, 1
183  ret i64 %ev
184}
185
186
187declare dso_local { i8*, i64 } @foo(i64)
188declare dso_local { i8*, i64 } @bar(i64)
189declare dso_local { {i8*, i64}, i64 } @baz(i64)
190declare dso_local { {i8*, i64}, i64 } @qux(i64)
191