xref: /llvm-project/llvm/test/CodeGen/PowerPC/pcrel-tail-calls.ll (revision 5403c59c608c08c8ecd4303763f08eb046eb5e4d)
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 ptr, align 8
16@FuncLocal = common dso_local local_unnamed_addr global ptr 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 ptr @Function, ptr @Func, align 8
29  store ptr @Function, ptr @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:       # %bb.0: # %entry
38; CHECK-NEXT:    pld r12, FuncLocal@PCREL(0), 1
39; CHECK-NEXT:    mtctr r12
40; CHECK-NEXT:    bctr
41; CHECK-NEXT:    #TC_RETURNr8 ctr 0
42entry:
43  %0 = load ptr, ptr @FuncLocal, align 8
44  %call = tail call signext i32 %0()
45  ret void
46}
47
48define dso_local void @TailCallExtrnFuncPtr() local_unnamed_addr {
49; CHECK-LABEL: TailCallExtrnFuncPtr:
50; CHECK:       # %bb.0: # %entry
51; CHECK-NEXT:    pld r3, Func@got@pcrel(0), 1
52; CHECK-NEXT:  .Lpcrel0:
53; CHECK-NEXT:    .reloc .Lpcrel0-8,R_PPC64_PCREL_OPT,.-(.Lpcrel0-8)
54; CHECK-NEXT:    ld r12, 0(r3)
55; CHECK-NEXT:    mtctr r12
56; CHECK-NEXT:    bctr
57; CHECK-NEXT:    #TC_RETURNr8 ctr 0
58entry:
59  %0 = load ptr, ptr @Func, align 8
60  %call = tail call signext i32 %0()
61  ret void
62}
63
64define dso_local signext i32 @TailCallParamFuncPtr(ptr nocapture %passedfunc) local_unnamed_addr {
65; CHECK-LABEL: TailCallParamFuncPtr:
66; CHECK:       # %bb.0: # %entry
67; CHECK-NEXT:    mtctr r3
68; CHECK-NEXT:    mr r12, r3
69; CHECK-NEXT:    bctr
70; CHECK-NEXT:    #TC_RETURNr8 ctr 0
71entry:
72  %call = tail call signext i32 %passedfunc()
73  ret i32 %call
74}
75
76define dso_local signext i32 @NoTailIndirectCall(ptr nocapture %passedfunc, i32 signext %a) local_unnamed_addr {
77; CHECK-LABEL: NoTailIndirectCall:
78; CHECK:       # %bb.0: # %entry
79; CHECK-NEXT:    mflr r0
80; CHECK-NEXT:    .cfi_def_cfa_offset 48
81; CHECK-NEXT:    .cfi_offset lr, 16
82; CHECK-NEXT:    .cfi_offset r30, -16
83; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
84; CHECK-NEXT:    std r0, 16(r1)
85; CHECK-NEXT:    stdu r1, -48(r1)
86; CHECK-NEXT:    mr r12, r3
87; CHECK-NEXT:    mtctr r3
88; CHECK-NEXT:    mr r30, r4
89; CHECK-NEXT:    bctrl
90; CHECK-NEXT:    add r3, r3, r30
91; CHECK-NEXT:    extsw r3, r3
92; CHECK-NEXT:    addi r1, r1, 48
93; CHECK-NEXT:    ld r0, 16(r1)
94; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
95; CHECK-NEXT:    mtlr r0
96; CHECK-NEXT:    blr
97entry:
98  %call = tail call signext i32 %passedfunc()
99  %add = add nsw i32 %call, %a
100  ret i32 %add
101}
102
103define dso_local signext i32 @TailCallDirect() local_unnamed_addr {
104; CHECK-LABEL: TailCallDirect:
105; CHECK:       # %bb.0: # %entry
106; CHECK-NEXT:    b Function@notoc
107; CHECK-NEXT:    #TC_RETURNd8 Function@notoc 0
108entry:
109  %call = tail call signext i32 @Function()
110  ret i32 %call
111}
112
113define dso_local signext i32 @NoTailCallDirect(i32 signext %a) local_unnamed_addr {
114; CHECK-LABEL: NoTailCallDirect:
115; CHECK:       # %bb.0: # %entry
116; CHECK-NEXT:    mflr r0
117; CHECK-NEXT:    .cfi_def_cfa_offset 48
118; CHECK-NEXT:    .cfi_offset lr, 16
119; CHECK-NEXT:    .cfi_offset r30, -16
120; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
121; CHECK-NEXT:    std r0, 16(r1)
122; CHECK-NEXT:    stdu r1, -48(r1)
123; CHECK-NEXT:    mr r30, r3
124; CHECK-NEXT:    bl Function@notoc
125; CHECK-NEXT:    add r3, r3, r30
126; CHECK-NEXT:    extsw r3, r3
127; CHECK-NEXT:    addi r1, r1, 48
128; CHECK-NEXT:    ld r0, 16(r1)
129; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
130; CHECK-NEXT:    mtlr r0
131; CHECK-NEXT:    blr
132entry:
133  %call = tail call signext i32 @Function()
134  %add = add nsw i32 %call, %a
135  ret i32 %add
136}
137
138define dso_local signext i32 @TailCallDirectLocal() local_unnamed_addr {
139; CHECK-LABEL: TailCallDirectLocal:
140; CHECK:       # %bb.0: # %entry
141; CHECK-NEXT:    b LocalFunction@notoc
142; CHECK-NEXT:    #TC_RETURNd8 LocalFunction@notoc 0
143entry:
144  %call = tail call fastcc signext i32 @LocalFunction()
145  ret i32 %call
146}
147
148define dso_local signext i32 @NoTailCallDirectLocal(i32 signext %a) local_unnamed_addr {
149; CHECK-LABEL: NoTailCallDirectLocal:
150; CHECK:       # %bb.0: # %entry
151; CHECK-NEXT:    mflr r0
152; CHECK-NEXT:    .cfi_def_cfa_offset 48
153; CHECK-NEXT:    .cfi_offset lr, 16
154; CHECK-NEXT:    .cfi_offset r30, -16
155; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
156; CHECK-NEXT:    std r0, 16(r1)
157; CHECK-NEXT:    stdu r1, -48(r1)
158; CHECK-NEXT:    mr r30, r3
159; CHECK-NEXT:    bl LocalFunction@notoc
160; CHECK-NEXT:    add r3, r3, r30
161; CHECK-NEXT:    extsw r3, r3
162; CHECK-NEXT:    addi r1, r1, 48
163; CHECK-NEXT:    ld r0, 16(r1)
164; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
165; CHECK-NEXT:    mtlr r0
166; CHECK-NEXT:    blr
167entry:
168  %call = tail call fastcc signext i32 @LocalFunction()
169  %add = add nsw i32 %call, %a
170  ret i32 %add
171}
172
173define dso_local signext i32 @TailCallAbs() local_unnamed_addr {
174; CHECK-LABEL: TailCallAbs:
175; CHECK:       # %bb.0: # %entry
176; CHECK-NEXT:    li r3, 400
177; CHECK-NEXT:    li r12, 400
178; CHECK-NEXT:    mtctr r3
179; CHECK-NEXT:    bctr
180; CHECK-NEXT:    #TC_RETURNr8 ctr 0
181entry:
182  %call = tail call signext i32 inttoptr (i64 400 to ptr)()
183  ret i32 %call
184}
185
186define dso_local signext i32 @NoTailCallAbs(i32 signext %a) local_unnamed_addr {
187; CHECK-LABEL: NoTailCallAbs:
188; CHECK:       # %bb.0: # %entry
189; CHECK-NEXT:    mflr r0
190; CHECK-NEXT:    .cfi_def_cfa_offset 48
191; CHECK-NEXT:    .cfi_offset lr, 16
192; CHECK-NEXT:    .cfi_offset r30, -16
193; CHECK-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
194; CHECK-NEXT:    std r0, 16(r1)
195; CHECK-NEXT:    stdu r1, -48(r1)
196; CHECK-NEXT:    mr r30, r3
197; CHECK-NEXT:    li r3, 400
198; CHECK-NEXT:    li r12, 400
199; CHECK-NEXT:    mtctr r3
200; CHECK-NEXT:    bctrl
201; CHECK-NEXT:    add r3, r3, r30
202; CHECK-NEXT:    extsw r3, r3
203; CHECK-NEXT:    addi r1, r1, 48
204; CHECK-NEXT:    ld r0, 16(r1)
205; CHECK-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
206; CHECK-NEXT:    mtlr r0
207; CHECK-NEXT:    blr
208entry:
209  %call = tail call signext i32 inttoptr (i64 400 to ptr)()
210  %add = add nsw i32 %call, %a
211  ret i32 %add
212}
213
214; Function Attrs: noinline
215; This function should be tail called and not inlined.
216define internal fastcc signext i32 @LocalFunction() unnamed_addr #0 {
217; CHECK-LABEL: LocalFunction:
218; CHECK:       # %bb.0: # %entry
219; CHECK-NEXT:    #APP
220; CHECK-NEXT:    li r3, 42
221; CHECK-NEXT:    #NO_APP
222; CHECK-NEXT:    extsw r3, r3
223; CHECK-NEXT:    blr
224entry:
225  %0 = tail call i32 asm "li $0, 42", "=&r"()
226  ret i32 %0
227}
228
229attributes #0 = { noinline }
230
231