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