1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
3; RUN:   -mcpu=pwr10 -ppc-asm-full-reg-names -ppc-vsr-nums-as-vr < %s | \
4; RUN:   FileCheck %s
5; RUN: llc -verify-machineinstrs -target-abi=elfv2 -mtriple=powerpc64-- \
6; RUN:   -mcpu=pwr10 -ppc-asm-full-reg-names -ppc-vsr-nums-as-vr < %s | \
7; RUN:   FileCheck %s
8
9
10; The tests check the behaviour of PC Relative tail calls. When using
11; PC Relative we are able to do more tail calling than we have done in
12; the past as we no longer need to restore the TOC pointer into R2 after
13; most calls.
14
15@Func = external local_unnamed_addr global i32 (...)*, align 8
16@FuncLocal = common dso_local local_unnamed_addr global i32 (...)* null, align 8
17
18; No calls in this function but we assign the function pointers.
19define dso_local void @AssignFuncPtr() local_unnamed_addr {
20; CHECK-LABEL: AssignFuncPtr:
21; CHECK:       # %bb.0: # %entry
22; CHECK-NEXT:    pld r3, Func@got@pcrel(0), 1
23; CHECK-NEXT:    pld r4, Function@got@pcrel(0), 1
24; CHECK-NEXT:    std r4, 0(r3)
25; CHECK-NEXT:    pstd r4, FuncLocal@PCREL(0), 1
26; CHECK-NEXT:    blr
27entry:
28  store i32 (...)* @Function, i32 (...)** @Func, align 8
29  store i32 (...)* @Function, i32 (...)** @FuncLocal, align 8
30  ret void
31}
32
33declare signext i32 @Function(...)
34
35define dso_local void @TailCallLocalFuncPtr() local_unnamed_addr {
36; CHECK-LABEL: TailCallLocalFuncPtr:
37; CHECK:         .localentry TailCallLocalFuncPtr, 1
38; CHECK-NEXT:  # %bb.0: # %entry
39; CHECK-NEXT:    pld r12, FuncLocal@PCREL(0), 1
40; CHECK-NEXT:    mtctr r12
41; CHECK-NEXT:    bctr
42; CHECK-NEXT:    #TC_RETURNr8 ctr 0
43entry:
44  %0 = load i32 ()*, i32 ()** bitcast (i32 (...)** @FuncLocal to i32 ()**), align 8
45  %call = tail call signext i32 %0()
46  ret void
47}
48
49define dso_local void @TailCallExtrnFuncPtr() local_unnamed_addr {
50; CHECK-LABEL: TailCallExtrnFuncPtr:
51; CHECK:         .localentry TailCallExtrnFuncPtr, 1
52; CHECK-NEXT:  # %bb.0: # %entry
53; CHECK-NEXT:    pld r3, Func@got@pcrel(0), 1
54; CHECK-NEXT:  .Lpcrel0:
55; CHECK-NEXT:    .reloc .Lpcrel0-8,R_PPC64_PCREL_OPT,.-(.Lpcrel0-8)
56; CHECK-NEXT:    ld r12, 0(r3)
57; CHECK-NEXT:    mtctr r12
58; CHECK-NEXT:    bctr
59; CHECK-NEXT:    #TC_RETURNr8 ctr 0
60entry:
61  %0 = load i32 ()*, i32 ()** bitcast (i32 (...)** @Func to i32 ()**), align 8
62  %call = tail call signext i32 %0()
63  ret void
64}
65
66define dso_local signext i32 @TailCallParamFuncPtr(i32 (...)* nocapture %passedfunc) local_unnamed_addr {
67; CHECK-LABEL: TailCallParamFuncPtr:
68; CHECK:         .localentry TailCallParamFuncPtr, 1
69; CHECK-NEXT:  # %bb.0: # %entry
70; CHECK-NEXT:    mtctr r3
71; CHECK-NEXT:    mr r12, r3
72; CHECK-NEXT:    bctr
73; CHECK-NEXT:    #TC_RETURNr8 ctr 0
74entry:
75  %callee.knr.cast = bitcast i32 (...)* %passedfunc to i32 ()*
76  %call = tail call signext i32 %callee.knr.cast()
77  ret i32 %call
78}
79
80define dso_local signext i32 @NoTailIndirectCall(i32 (...)* nocapture %passedfunc, i32 signext %a) local_unnamed_addr {
81; CHECK-LABEL: NoTailIndirectCall:
82; CHECK:         .localentry NoTailIndirectCall, 1
83; CHECK-NEXT:  # %bb.0: # %entry
84; CHECK-NEXT:    mflr r0
85; CHECK-NEXT:    .cfi_def_cfa_offset 48
86; CHECK-NEXT:    .cfi_offset lr, 16
87; CHECK-NEXT:    .cfi_offset r30, -16
88; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
89; CHECK-NEXT:    std r0, 16(r1)
90; CHECK-NEXT:    stdu r1, -48(r1)
91; CHECK-NEXT:    mtctr r3
92; CHECK-NEXT:    mr r12, r3
93; CHECK-NEXT:    mr r30, r4
94; CHECK-NEXT:    bctrl
95; CHECK-NEXT:    add r3, r3, r30
96; CHECK-NEXT:    extsw r3, r3
97; CHECK-NEXT:    addi r1, r1, 48
98; CHECK-NEXT:    ld r0, 16(r1)
99; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
100; CHECK-NEXT:    mtlr r0
101; CHECK-NEXT:    blr
102entry:
103  %callee.knr.cast = bitcast i32 (...)* %passedfunc to i32 ()*
104  %call = tail call signext i32 %callee.knr.cast()
105  %add = add nsw i32 %call, %a
106  ret i32 %add
107}
108
109define dso_local signext i32 @TailCallDirect() local_unnamed_addr {
110; CHECK-LABEL: TailCallDirect:
111; CHECK:         .localentry TailCallDirect, 1
112; CHECK-NEXT:  # %bb.0: # %entry
113; CHECK-NEXT:    b Function@notoc
114; CHECK-NEXT:    #TC_RETURNd8 Function@notoc 0
115entry:
116  %call = tail call signext i32 bitcast (i32 (...)* @Function to i32 ()*)()
117  ret i32 %call
118}
119
120define dso_local signext i32 @NoTailCallDirect(i32 signext %a) local_unnamed_addr {
121; CHECK-LABEL: NoTailCallDirect:
122; CHECK:         .localentry NoTailCallDirect, 1
123; CHECK-NEXT:  # %bb.0: # %entry
124; CHECK-NEXT:    mflr r0
125; CHECK-NEXT:    .cfi_def_cfa_offset 48
126; CHECK-NEXT:    .cfi_offset lr, 16
127; CHECK-NEXT:    .cfi_offset r30, -16
128; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
129; CHECK-NEXT:    std r0, 16(r1)
130; CHECK-NEXT:    stdu r1, -48(r1)
131; CHECK-NEXT:    mr r30, r3
132; CHECK-NEXT:    bl Function@notoc
133; CHECK-NEXT:    add r3, r3, r30
134; CHECK-NEXT:    extsw r3, r3
135; CHECK-NEXT:    addi r1, r1, 48
136; CHECK-NEXT:    ld r0, 16(r1)
137; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
138; CHECK-NEXT:    mtlr r0
139; CHECK-NEXT:    blr
140entry:
141  %call = tail call signext i32 bitcast (i32 (...)* @Function to i32 ()*)()
142  %add = add nsw i32 %call, %a
143  ret i32 %add
144}
145
146define dso_local signext i32 @TailCallDirectLocal() local_unnamed_addr {
147; CHECK-LABEL: TailCallDirectLocal:
148; CHECK:         .localentry TailCallDirectLocal, 1
149; CHECK-NEXT:  # %bb.0: # %entry
150; CHECK-NEXT:    b LocalFunction@notoc
151; CHECK-NEXT:    #TC_RETURNd8 LocalFunction@notoc 0
152entry:
153  %call = tail call fastcc signext i32 @LocalFunction()
154  ret i32 %call
155}
156
157define dso_local signext i32 @NoTailCallDirectLocal(i32 signext %a) local_unnamed_addr {
158; CHECK-LABEL: NoTailCallDirectLocal:
159; CHECK:         .localentry NoTailCallDirectLocal, 1
160; CHECK-NEXT:  # %bb.0: # %entry
161; CHECK-NEXT:    mflr r0
162; CHECK-NEXT:    .cfi_def_cfa_offset 48
163; CHECK-NEXT:    .cfi_offset lr, 16
164; CHECK-NEXT:    .cfi_offset r30, -16
165; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
166; CHECK-NEXT:    std r0, 16(r1)
167; CHECK-NEXT:    stdu r1, -48(r1)
168; CHECK-NEXT:    mr r30, r3
169; CHECK-NEXT:    bl LocalFunction@notoc
170; CHECK-NEXT:    add r3, r3, r30
171; CHECK-NEXT:    extsw r3, r3
172; CHECK-NEXT:    addi r1, r1, 48
173; CHECK-NEXT:    ld r0, 16(r1)
174; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
175; CHECK-NEXT:    mtlr r0
176; CHECK-NEXT:    blr
177entry:
178  %call = tail call fastcc signext i32 @LocalFunction()
179  %add = add nsw i32 %call, %a
180  ret i32 %add
181}
182
183define dso_local signext i32 @TailCallAbs() local_unnamed_addr {
184; CHECK-LABEL: TailCallAbs:
185; CHECK:         .localentry TailCallAbs, 1
186; CHECK-NEXT:  # %bb.0: # %entry
187; CHECK-NEXT:    li r3, 400
188; CHECK-NEXT:    li r12, 400
189; CHECK-NEXT:    mtctr r3
190; CHECK-NEXT:    bctr
191; CHECK-NEXT:    #TC_RETURNr8 ctr 0
192entry:
193  %call = tail call signext i32 inttoptr (i64 400 to i32 ()*)()
194  ret i32 %call
195}
196
197define dso_local signext i32 @NoTailCallAbs(i32 signext %a) local_unnamed_addr {
198; CHECK-LABEL: NoTailCallAbs:
199; CHECK:         .localentry NoTailCallAbs, 1
200; CHECK-NEXT:  # %bb.0: # %entry
201; CHECK-NEXT:    mflr r0
202; CHECK-NEXT:    .cfi_def_cfa_offset 48
203; CHECK-NEXT:    .cfi_offset lr, 16
204; CHECK-NEXT:    .cfi_offset r30, -16
205; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
206; CHECK-NEXT:    std r0, 16(r1)
207; CHECK-NEXT:    stdu r1, -48(r1)
208; CHECK-NEXT:    mr r30, r3
209; CHECK-NEXT:    li r3, 400
210; CHECK-NEXT:    li r12, 400
211; CHECK-NEXT:    mtctr r3
212; CHECK-NEXT:    bctrl
213; CHECK-NEXT:    add r3, r3, r30
214; CHECK-NEXT:    extsw r3, r3
215; CHECK-NEXT:    addi r1, r1, 48
216; CHECK-NEXT:    ld r0, 16(r1)
217; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
218; CHECK-NEXT:    mtlr r0
219; CHECK-NEXT:    blr
220entry:
221  %call = tail call signext i32 inttoptr (i64 400 to i32 ()*)()
222  %add = add nsw i32 %call, %a
223  ret i32 %add
224}
225
226; Function Attrs: noinline
227; This function should be tail called and not inlined.
228define internal fastcc signext i32 @LocalFunction() unnamed_addr #0 {
229; CHECK-LABEL: LocalFunction:
230; CHECK:         .localentry LocalFunction, 1
231; CHECK-NEXT:  # %bb.0: # %entry
232; CHECK-NEXT:    #APP
233; CHECK-NEXT:    li r3, 42
234; CHECK-NEXT:    #NO_APP
235; CHECK-NEXT:    extsw r3, r3
236; CHECK-NEXT:    blr
237entry:
238  %0 = tail call i32 asm "li $0, 42", "=&r"()
239  ret i32 %0
240}
241
242attributes #0 = { noinline }
243
244