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: .Lpcrel: 55; CHECK-NEXT: .reloc .Lpcrel-8,R_PPC64_PCREL_OPT,.-(.Lpcrel-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