[Reland][Runtimes] Merge 'compile_commands.json' files from runtimes build (#116303)
[llvm-project.git] / llvm / test / CodeGen / X86 / tailcall-extract.ll
blob7a6c75c44ca7dd25ae3720f74ad4b608a032230c
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.
8 ; CHECK-LABEL: test1:
9 ; CHECK:       je foo # TAILCALL
10 ; CHECK:       jmp bar # TAILCALL
12 ; OPT-LABEL:   test1
13 ; OPT:         if.then.i:
14 ; OPT-NEXT:    tail call { ptr, i64 } @bar
15 ; OPT-NEXT:    extractvalue
16 ; OPT-NEXT:    ret
18 ; OPT:         if.end.i:
19 ; OPT-NEXT:    tail call { ptr, i64 } @foo
20 ; OPT-NEXT:    extractvalue
21 ; OPT-NEXT:    ret
23 define ptr @test1(i64 %size) {
24 entry:
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)
34   br label %exit
36 if.end.i:                                         ; preds = %entry
37   %call2.i = tail call { ptr, i64 } @foo(i64 %size)
38   br label %exit
40 exit:
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
43   ret ptr %ev
47 ; The extractvalue extracts a field with non-zero offset, so the exit block
48 ; can't be duplicated.
50 ; CHECK-LABEL: test2:
51 ; CHECK:       callq bar
52 ; CHECK:       callq foo
54 ; OPT-LABEL:   test2
55 ; OPT:         if.then.i:
56 ; OPT-NEXT:    tail call { ptr, i64 } @bar
57 ; OPT-NEXT:    br label %exit
59 ; OPT:         if.end.i:
60 ; OPT-NEXT:    tail call { ptr, i64 } @foo
61 ; OPT-NEXT:    br label %exit
63 ; OPT:         exit:
64 ; OPT-NEXT:    phi
65 ; OPT-NEXT:    extractvalue
66 ; OPT-NEXT:    ret
68 define i64 @test2(i64 %size) {
69 entry:
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)
79   br label %exit
81 if.end.i:                                         ; preds = %entry
82   %call2.i = tail call { ptr, i64 } @foo(i64 %size)
83   br label %exit
85 exit:
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
88   ret i64 %ev
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.
95 ; CHECK-LABEL: test3:
96 ; CHECK:       je qux # TAILCALL
97 ; CHECK:       jmp baz # TAILCALL
99 ; OPT-LABEL:   test3
100 ; OPT:         if.then.i:
101 ; OPT-NEXT:    tail call { { ptr, i64 }, i64 } @baz
102 ; OPT-NEXT:    extractvalue
103 ; OPT-NEXT:    ret
105 ; OPT:         if.end.i:
106 ; OPT-NEXT:    tail call { { ptr, i64 }, i64 } @qux
107 ; OPT-NEXT:    extractvalue
108 ; OPT-NEXT:    ret
110 define ptr @test3(i64 %size) {
111 entry:
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)
122   br label %exit
124 if.end.i:                                         ; preds = %entry
125   %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size)
126   br label %exit
128 exit:
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
131   ret ptr %ev
135 ; The extractvalue accesses a nest struct with non-zero offset, so the exit
136 ; block can't be duplicated.
138 ; CHECK-LABEL: test4:
139 ; CHECK:       callq baz
140 ; CHECK:       callq qux
142 ; OPT-LABEL:   test4
143 ; OPT:         if.then.i:
144 ; OPT-NEXT:    tail call { { ptr, i64 }, i64 } @baz
145 ; OPT-NEXT:    br label %exit
147 ; OPT:         if.end.i:
148 ; OPT-NEXT:    tail call { { ptr, i64 }, i64 } @qux
149 ; OPT-NEXT:    br label %exit
151 ; OPT:         exit:
152 ; OPT-NEXT:    phi
153 ; OPT-NEXT:    extractvalue
154 ; OPT-NEXT:    ret
156 define i64 @test4(i64 %size) {
157 entry:
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)
168   br label %exit
170 if.end.i:                                         ; preds = %entry
171   %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size)
172   br label %exit
174 exit:
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
177   ret i64 %ev
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)