diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 69 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64CallLowering.cpp | 61 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64CallLowering.h | 11 |
3 files changed, 124 insertions, 17 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 1c8e4541817..04aa072bc31 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -370,6 +370,75 @@ bool CallLowering::handleAssignments(CCState &CCInfo, return true; } +bool CallLowering::analyzeCallResult(CCState &CCState, + SmallVectorImpl<ArgInfo> &Args, + CCAssignFn &Fn) const { + for (unsigned i = 0, e = Args.size(); i < e; ++i) { + MVT VT = MVT::getVT(Args[i].Ty); + if (Fn(i, VT, VT, CCValAssign::Full, Args[i].Flags[0], CCState)) { + // Bail out on anything we can't handle. + LLVM_DEBUG(dbgs() << "Cannot analyze " << EVT(VT).getEVTString() + << " (arg number = " << i << "\n"); + return false; + } + } + return true; +} + +bool CallLowering::resultsCompatible(CallLoweringInfo &Info, + MachineFunction &MF, + SmallVectorImpl<ArgInfo> &InArgs, + CCAssignFn &CalleeAssignFn, + CCAssignFn &CallerAssignFn) const { + const Function &F = MF.getFunction(); + CallingConv::ID CalleeCC = Info.CallConv; + CallingConv::ID CallerCC = F.getCallingConv(); + + if (CallerCC == CalleeCC) + return true; + + SmallVector<CCValAssign, 16> ArgLocs1; + CCState CCInfo1(CalleeCC, false, MF, ArgLocs1, F.getContext()); + if (!analyzeCallResult(CCInfo1, InArgs, CalleeAssignFn)) + return false; + + SmallVector<CCValAssign, 16> ArgLocs2; + CCState CCInfo2(CallerCC, false, MF, ArgLocs2, F.getContext()); + if (!analyzeCallResult(CCInfo2, InArgs, CallerAssignFn)) + return false; + + // We need the argument locations to match up exactly. If there's more in + // one than the other, then we are done. + if (ArgLocs1.size() != ArgLocs2.size()) + return false; + + // Make sure that each location is passed in exactly the same way. + for (unsigned i = 0, e = ArgLocs1.size(); i < e; ++i) { + const CCValAssign &Loc1 = ArgLocs1[i]; + const CCValAssign &Loc2 = ArgLocs2[i]; + + // We need both of them to be the same. So if one is a register and one + // isn't, we're done. + if (Loc1.isRegLoc() != Loc2.isRegLoc()) + return false; + + if (Loc1.isRegLoc()) { + // If they don't have the same register location, we're done. + if (Loc1.getLocReg() != Loc2.getLocReg()) + return false; + + // They matched, so we can move to the next ArgLoc. + continue; + } + + // Loc1 wasn't a RegLoc, so they both must be MemLocs. Check if they match. + if (Loc1.getLocMemOffset() != Loc2.getLocMemOffset()) + return false; + } + + return true; +} + Register CallLowering::ValueHandler::extendRegister(Register ValReg, CCValAssign &VA) { LLT LocTy{VA.getLocVT()}; diff --git a/llvm/lib/Target/AArch64/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/AArch64CallLowering.cpp index 03f20a26259..64e1c84d98d 100644 --- a/llvm/lib/Target/AArch64/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64CallLowering.cpp @@ -431,13 +431,44 @@ static bool mayTailCallThisCC(CallingConv::ID CC) { } } +bool AArch64CallLowering::doCallerAndCalleePassArgsTheSameWay( + CallLoweringInfo &Info, MachineFunction &MF, + SmallVectorImpl<ArgInfo> &InArgs) const { + const Function &CallerF = MF.getFunction(); + CallingConv::ID CalleeCC = Info.CallConv; + CallingConv::ID CallerCC = CallerF.getCallingConv(); + + // If the calling conventions match, then everything must be the same. + if (CalleeCC == CallerCC) + return true; + + // Check if the caller and callee will handle arguments in the same way. + const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>(); + CCAssignFn *CalleeAssignFn = TLI.CCAssignFnForCall(CalleeCC, Info.IsVarArg); + CCAssignFn *CallerAssignFn = + TLI.CCAssignFnForCall(CallerCC, CallerF.isVarArg()); + + if (!resultsCompatible(Info, MF, InArgs, *CalleeAssignFn, *CallerAssignFn)) + return false; + + // Make sure that the caller and callee preserve all of the same registers. + auto TRI = MF.getSubtarget<AArch64Subtarget>().getRegisterInfo(); + const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); + const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); + if (MF.getSubtarget<AArch64Subtarget>().hasCustomCallingConv()) { + TRI->UpdateCustomCallPreservedMask(MF, &CallerPreserved); + TRI->UpdateCustomCallPreservedMask(MF, &CalleePreserved); + } + + return TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved); +} + bool AArch64CallLowering::isEligibleForTailCallOptimization( - MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const { + MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info, + SmallVectorImpl<ArgInfo> &InArgs) const { CallingConv::ID CalleeCC = Info.CallConv; MachineFunction &MF = MIRBuilder.getMF(); const Function &CallerF = MF.getFunction(); - CallingConv::ID CallerCC = CallerF.getCallingConv(); - bool CCMatch = CallerCC == CalleeCC; LLVM_DEBUG(dbgs() << "Attempting to lower call as tail call\n"); @@ -509,11 +540,11 @@ bool AArch64CallLowering::isEligibleForTailCallOptimization( assert((!Info.IsVarArg || CalleeCC == CallingConv::C) && "Unexpected variadic calling convention"); - // For now, only support the case where the calling conventions match. - if (!CCMatch) { + // Look at the incoming values. + if (!doCallerAndCalleePassArgsTheSameWay(Info, MF, InArgs)) { LLVM_DEBUG( dbgs() - << "... Cannot tail call with mismatched calling conventions yet.\n"); + << "... Caller and callee have incompatible calling conventions.\n"); return false; } @@ -552,6 +583,7 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const Function &F = MF.getFunction(); MachineRegisterInfo &MRI = MF.getRegInfo(); auto &DL = F.getParent()->getDataLayout(); + const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>(); if (Info.IsMustTailCall) { // TODO: Until we lower all tail calls, we should fall back on this. @@ -573,13 +605,16 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, SplitArgs.back().Flags[0].setZExt(); } - bool IsSibCall = - Info.IsTailCall && isEligibleForTailCallOptimization(MIRBuilder, Info); + SmallVector<ArgInfo, 8> InArgs; + if (!Info.OrigRet.Ty->isVoidTy()) + splitToValueTypes(Info.OrigRet, InArgs, DL, MRI, F.getCallingConv()); + + bool IsSibCall = Info.IsTailCall && + isEligibleForTailCallOptimization(MIRBuilder, Info, InArgs); if (IsSibCall) MF.getFrameInfo().setHasTailCall(); // Find out which ABI gets to decide where things go. - const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>(); CCAssignFn *AssignFnFixed = TLI.CCAssignFnForCall(Info.CallConv, /*IsVarArg=*/false); CCAssignFn *AssignFnVarArg = @@ -649,14 +684,10 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, // Finally we can copy the returned value back into its virtual-register. In // symmetry with the arugments, the physical register must be an // implicit-define of the call instruction. - CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv()); if (!Info.OrigRet.Ty->isVoidTy()) { - SplitArgs.clear(); - - splitToValueTypes(Info.OrigRet, SplitArgs, DL, MRI, F.getCallingConv()); - + CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv()); CallReturnHandler Handler(MIRBuilder, MRI, MIB, RetAssignFn); - if (!handleAssignments(MIRBuilder, SplitArgs, Handler)) + if (!handleAssignments(MIRBuilder, InArgs, Handler)) return false; } diff --git a/llvm/lib/Target/AArch64/AArch64CallLowering.h b/llvm/lib/Target/AArch64/AArch64CallLowering.h index 0bf250b85a3..696d4d8385a 100644 --- a/llvm/lib/Target/AArch64/AArch64CallLowering.h +++ b/llvm/lib/Target/AArch64/AArch64CallLowering.h @@ -44,8 +44,10 @@ public: CallLoweringInfo &Info) const override; /// Returns true if the call can be lowered as a tail call. - bool isEligibleForTailCallOptimization(MachineIRBuilder &MIRBuilder, - CallLoweringInfo &Info) const; + bool + isEligibleForTailCallOptimization(MachineIRBuilder &MIRBuilder, + CallLoweringInfo &Info, + SmallVectorImpl<ArgInfo> &InArgs) const; bool supportSwiftError() const override { return true; } @@ -60,6 +62,11 @@ private: SmallVectorImpl<ArgInfo> &SplitArgs, const DataLayout &DL, MachineRegisterInfo &MRI, CallingConv::ID CallConv) const; + + bool + doCallerAndCalleePassArgsTheSameWay(CallLoweringInfo &Info, + MachineFunction &MF, + SmallVectorImpl<ArgInfo> &InArgs) const; }; } // end namespace llvm |