diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h b/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h index 57ff3900ef2567..26ae7129f04a22 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h @@ -282,6 +282,14 @@ class CallLowering { CCAssignFn &AssignFnFixed, CCAssignFn &AssignFnVarArg) const; + /// Check whether parameters to a call that are passed in callee saved + /// registers are the same as from the calling function. This needs to be + /// checked for tail call eligibility. + bool parametersInCSRMatch(const MachineRegisterInfo &MRI, + const uint32_t *CallerPreservedMask, + const SmallVectorImpl &ArgLocs, + const SmallVectorImpl &OutVals) const; + /// \returns True if the calling convention for a callee and its caller pass /// results in the same way. Typically used for tail call eligibility checks. /// diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 6666a6d4ea7682..803e1527a4f03f 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -611,6 +611,58 @@ bool CallLowering::analyzeArgInfo(CCState &CCState, return true; } +bool CallLowering::parametersInCSRMatch( + const MachineRegisterInfo &MRI, const uint32_t *CallerPreservedMask, + const SmallVectorImpl &OutLocs, + const SmallVectorImpl &OutArgs) const { + 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; + + MCRegister PhysReg = ArgLoc.getLocReg(); + + // Only look at callee-saved registers. + if (MachineOperand::clobbersPhysReg(CallerPreservedMask, PhysReg)) + continue; + + LLVM_DEBUG( + dbgs() + << "... Call has an argument passed in a callee-saved register.\n"); + + // Check if it was copied from. + const 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 != PhysReg) { + LLVM_DEBUG(dbgs() << "... Callee-saved register was not copied into " + "VReg, cannot tail call.\n"); + return false; + } + } + + return true; +} + bool CallLowering::resultsCompatible(CallLoweringInfo &Info, MachineFunction &MF, SmallVectorImpl &InArgs, diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp index cb81377b767575..0f8b1d6584b1a0 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -623,64 +623,25 @@ bool AArch64CallLowering::areCalleeOutgoingArgsTailCallable( const uint32_t *CallerPreservedMask = TRI->getCallPreservedMask(MF, CallerCC); MachineRegisterInfo &MRI = MF.getRegInfo(); - for (unsigned i = 0; i < OutLocs.size(); ++i) { - auto &ArgLoc = OutLocs[i]; - // If it's not a register, it's fine. - if (!ArgLoc.isRegLoc()) { - if (Info.IsVarArg) { - // Be conservative and disallow variadic memory operands to match SDAG's - // behaviour. - // FIXME: If the caller's calling convention is C, then we can - // potentially use its argument area. However, for cases like fastcc, - // we can't do anything. - LLVM_DEBUG( - dbgs() - << "... Cannot tail call vararg function with stack arguments\n"); - return false; - } - continue; - } - - Register Reg = ArgLoc.getLocReg(); - - // Only look at callee-saved registers. - if (MachineOperand::clobbersPhysReg(CallerPreservedMask, Reg)) - continue; - - LLVM_DEBUG( - dbgs() - << "... 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; - } + if (Info.IsVarArg) { + // Be conservative and disallow variadic memory operands to match SDAG's + // behaviour. + // FIXME: If the caller's calling convention is C, then we can + // potentially use its argument area. However, for cases like fastcc, + // we can't do anything. + for (unsigned i = 0; i < OutLocs.size(); ++i) { + auto &ArgLoc = OutLocs[i]; + if (ArgLoc.isRegLoc()) + continue; - // 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"); + << "... Cannot tail call vararg function with stack arguments\n"); return false; } } - return true; + return parametersInCSRMatch(MRI, CallerPreservedMask, OutLocs, OutArgs); } bool AArch64CallLowering::isEligibleForTailCallOptimization(