Index: llvm/lib/Target/AArch64/AArch64CallLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64CallLowering.cpp +++ llvm/lib/Target/AArch64/AArch64CallLowering.cpp @@ -508,8 +508,10 @@ // supported. auto TRI = MF.getSubtarget().getRegisterInfo(); const uint32_t *CallerPreservedMask = TRI->getCallPreservedMask(MF, CallerCC); + MachineRegisterInfo &MRI = MF.getRegInfo(); - for (auto &ArgLoc : OutLocs) { + for (unsigned i = 0; i < OutLocs.size(); ++i) { + auto &ArgLoc = OutLocs[i]; // If it's not a register, it's fine. if (!ArgLoc.isRegLoc()) continue; @@ -520,12 +522,37 @@ if (MachineOperand::clobbersPhysReg(CallerPreservedMask, Reg)) continue; - // TODO: Port the remainder of this check from TargetLowering to support - // tail calling swiftself. LLVM_DEBUG( dbgs() - << "... Cannot handle callee-saved registers in outgoing args yet.\n"); - return false; + << "... Call has an argument passed in a callee-saved register.\n"); + + // Check if it was copied from. + ArgInfo &OutInfo = OutArgs[i]; + + if (OutInfo.Regs.size() > 1) { + LLVM_DEBUG( + dbgs() << "... Cannot handle arguments in multiple registers.\n"); + return false; + } + + // Check if we copy the register, walking through copies from virtual + // registers. Note that getDefIgnoringCopies does not ignore copies from + // physical registers. + MachineInstr *RegDef = getDefIgnoringCopies(OutInfo.Regs[0], MRI); + if (!RegDef || RegDef->getOpcode() != TargetOpcode::COPY) { + LLVM_DEBUG( + dbgs() + << "... Parameter was not copied into a VReg, cannot tail call.\n"); + return false; + } + + // Got a copy. Verify that it's the same as the register we want. + Register CopyRHS = RegDef->getOperand(1).getReg(); + if (CopyRHS != Reg) { + LLVM_DEBUG(dbgs() << "... Callee-saved register was not copied into " + "VReg, cannot tail call.\n"); + return false; + } } return true; Index: llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll +++ llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll @@ -192,3 +192,24 @@ tail call void @llvm.lifetime.end.p0i8(i64 1, i8* %t) ret void } + +; We can tail call when the callee swiftself is the same as the caller one. +; It would be nice to move this to swiftself.ll, but it's important to verify +; that we get the COPY that makes this safe in the first place. +declare i8* @pluto() +define hidden swiftcc i64 @swiftself_indirect_tail(i64* swiftself %arg) { + ; COMMON-LABEL: name: swiftself_indirect_tail + ; COMMON: bb.1 (%ir-block.0): + ; COMMON: liveins: $x20 + ; COMMON: [[COPY:%[0-9]+]]:_(p0) = COPY $x20 + ; COMMON: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; COMMON: BL @pluto, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $x0 + ; COMMON: [[COPY1:%[0-9]+]]:tcgpr64(p0) = COPY $x0 + ; COMMON: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; COMMON: $x20 = COPY [[COPY]](p0) + ; COMMON: TCRETURNri [[COPY1]](p0), 0, csr_aarch64_aapcs, implicit $sp, implicit $x20 + %tmp = call i8* @pluto() + %tmp1 = bitcast i8* %tmp to i64 (i64*)* + %tmp2 = tail call swiftcc i64 %tmp1(i64* swiftself %arg) + ret i64 %tmp2 +}