1 ; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s
2 ; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' -S -mtriple=x86_64-linux < %s | FileCheck %s --check-prefix OPT
5 ; The exit block containing extractvalue can be duplicated into the BB
6 ; containing call. And later tail call can be generated.
9 ; CHECK: je foo # TAILCALL
10 ; CHECK: jmp bar # TAILCALL
14 ; OPT-NEXT: tail call { ptr, i64 } @bar
15 ; OPT-NEXT: extractvalue
19 ; OPT-NEXT: tail call { ptr, i64 } @foo
20 ; OPT-NEXT: extractvalue
23 define ptr @test1(i64 %size) {
25 %cmp.i.i = icmp ugt i64 %size, 16384
26 %add.i.i = add i64 %size, 7
27 %div.i.i = lshr i64 %add.i.i, 3
28 %phitmp.i.i = trunc i64 %div.i.i to i32
29 %cmp1.i = icmp eq i32 %phitmp.i.i, 0
30 %cmp.i = or i1 %cmp.i.i, %cmp1.i
31 br i1 %cmp.i, label %if.end.i, label %if.then.i
32 if.then.i: ; preds = %entry
33 %call1.i = tail call { ptr, i64 } @bar(i64 %size)
36 if.end.i: ; preds = %entry
37 %call2.i = tail call { ptr, i64 } @foo(i64 %size)
41 %call1.i.sink = phi { ptr, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
42 %ev = extractvalue { ptr, i64 } %call1.i.sink, 0
47 ; The extractvalue extracts a field with non-zero offset, so the exit block
48 ; can't be duplicated.
56 ; OPT-NEXT: tail call { ptr, i64 } @bar
57 ; OPT-NEXT: br label %exit
60 ; OPT-NEXT: tail call { ptr, i64 } @foo
61 ; OPT-NEXT: br label %exit
65 ; OPT-NEXT: extractvalue
68 define i64 @test2(i64 %size) {
70 %cmp.i.i = icmp ugt i64 %size, 16384
71 %add.i.i = add i64 %size, 7
72 %div.i.i = lshr i64 %add.i.i, 3
73 %phitmp.i.i = trunc i64 %div.i.i to i32
74 %cmp1.i = icmp eq i32 %phitmp.i.i, 0
75 %cmp.i = or i1 %cmp.i.i, %cmp1.i
76 br i1 %cmp.i, label %if.end.i, label %if.then.i
77 if.then.i: ; preds = %entry
78 %call1.i = tail call { ptr, i64 } @bar(i64 %size)
81 if.end.i: ; preds = %entry
82 %call2.i = tail call { ptr, i64 } @foo(i64 %size)
86 %call1.i.sink = phi { ptr, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
87 %ev = extractvalue { ptr, i64 } %call1.i.sink, 1
92 ; The extractvalue accesses a nest struct type, the extracted field has zero
93 ; offset, so the exit block can still be duplicated, and tail call generated.
96 ; CHECK: je qux # TAILCALL
97 ; CHECK: jmp baz # TAILCALL
101 ; OPT-NEXT: tail call { { ptr, i64 }, i64 } @baz
102 ; OPT-NEXT: extractvalue
106 ; OPT-NEXT: tail call { { ptr, i64 }, i64 } @qux
107 ; OPT-NEXT: extractvalue
110 define ptr @test3(i64 %size) {
112 %cmp.i.i = icmp ugt i64 %size, 16384
113 %add.i.i = add i64 %size, 7
114 %div.i.i = lshr i64 %add.i.i, 3
115 %phitmp.i.i = trunc i64 %div.i.i to i32
116 %cmp1.i = icmp eq i32 %phitmp.i.i, 0
117 %cmp.i = or i1 %cmp.i.i, %cmp1.i
118 br i1 %cmp.i, label %if.end.i, label %if.then.i
120 if.then.i: ; preds = %entry
121 %call1.i = tail call { {ptr, i64}, i64 } @baz(i64 %size)
124 if.end.i: ; preds = %entry
125 %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size)
129 %call1.i.sink = phi { {ptr, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
130 %ev = extractvalue { {ptr, i64}, i64 } %call1.i.sink, 0, 0
135 ; The extractvalue accesses a nest struct with non-zero offset, so the exit
136 ; block can't be duplicated.
138 ; CHECK-LABEL: test4:
144 ; OPT-NEXT: tail call { { ptr, i64 }, i64 } @baz
145 ; OPT-NEXT: br label %exit
148 ; OPT-NEXT: tail call { { ptr, i64 }, i64 } @qux
149 ; OPT-NEXT: br label %exit
153 ; OPT-NEXT: extractvalue
156 define i64 @test4(i64 %size) {
158 %cmp.i.i = icmp ugt i64 %size, 16384
159 %add.i.i = add i64 %size, 7
160 %div.i.i = lshr i64 %add.i.i, 3
161 %phitmp.i.i = trunc i64 %div.i.i to i32
162 %cmp1.i = icmp eq i32 %phitmp.i.i, 0
163 %cmp.i = or i1 %cmp.i.i, %cmp1.i
164 br i1 %cmp.i, label %if.end.i, label %if.then.i
166 if.then.i: ; preds = %entry
167 %call1.i = tail call { {ptr, i64}, i64 } @baz(i64 %size)
170 if.end.i: ; preds = %entry
171 %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size)
175 %call1.i.sink = phi { {ptr, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ]
176 %ev = extractvalue { {ptr, i64}, i64 } %call1.i.sink, 0, 1
181 declare dso_local { ptr, i64 } @foo(i64)
182 declare dso_local { ptr, i64 } @bar(i64)
183 declare dso_local { {ptr, i64}, i64 } @baz(i64)
184 declare dso_local { {ptr, i64}, i64 } @qux(i64)