summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp69
-rw-r--r--llvm/lib/Target/AArch64/AArch64CallLowering.cpp61
-rw-r--r--llvm/lib/Target/AArch64/AArch64CallLowering.h11
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
OpenPOWER on IntegriCloud