@@ -5843,14 +5843,62 @@ static bool mayTailCallThisCC(CallingConv::ID CC) {
5843
5843
}
5844
5844
}
5845
5845
5846
+ static void analyzeCallOperands(const AArch64TargetLowering &TLI,
5847
+ const AArch64Subtarget *Subtarget,
5848
+ const TargetLowering::CallLoweringInfo &CLI,
5849
+ CCState &CCInfo) {
5850
+ const SelectionDAG &DAG = CLI.DAG;
5851
+ CallingConv::ID CalleeCC = CLI.CallConv;
5852
+ bool IsVarArg = CLI.IsVarArg;
5853
+ const SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;
5854
+ bool IsCalleeWin64 = Subtarget->isCallingConvWin64(CalleeCC);
5855
+
5856
+ unsigned NumArgs = Outs.size();
5857
+ for (unsigned i = 0; i != NumArgs; ++i) {
5858
+ MVT ArgVT = Outs[i].VT;
5859
+ ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
5860
+
5861
+ bool UseVarArgCC = false;
5862
+ if (IsVarArg) {
5863
+ // On Windows, the fixed arguments in a vararg call are passed in GPRs
5864
+ // too, so use the vararg CC to force them to integer registers.
5865
+ if (IsCalleeWin64) {
5866
+ UseVarArgCC = true;
5867
+ } else {
5868
+ UseVarArgCC = !Outs[i].IsFixed;
5869
+ }
5870
+ } else {
5871
+ // Get type of the original argument.
5872
+ EVT ActualVT =
5873
+ TLI.getValueType(DAG.getDataLayout(), CLI.Args[Outs[i].OrigArgIndex].Ty,
5874
+ /*AllowUnknown*/ true);
5875
+ MVT ActualMVT = ActualVT.isSimple() ? ActualVT.getSimpleVT() : ArgVT;
5876
+ // If ActualMVT is i1/i8/i16, we should set LocVT to i8/i8/i16.
5877
+ if (ActualMVT == MVT::i1 || ActualMVT == MVT::i8)
5878
+ ArgVT = MVT::i8;
5879
+ else if (ActualMVT == MVT::i16)
5880
+ ArgVT = MVT::i16;
5881
+ }
5882
+
5883
+ CCAssignFn *AssignFn = TLI.CCAssignFnForCall(CalleeCC, UseVarArgCC);
5884
+ bool Res = AssignFn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo);
5885
+ assert(!Res && "Call operand has unhandled type");
5886
+ (void)Res;
5887
+ }
5888
+ }
5889
+
5846
5890
bool AArch64TargetLowering::isEligibleForTailCallOptimization(
5847
- SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg,
5848
- const SmallVectorImpl<ISD::OutputArg> &Outs,
5849
- const SmallVectorImpl<SDValue> &OutVals,
5850
- const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG &DAG) const {
5891
+ const CallLoweringInfo &CLI) const {
5892
+ CallingConv::ID CalleeCC = CLI.CallConv;
5851
5893
if (!mayTailCallThisCC(CalleeCC))
5852
5894
return false;
5853
5895
5896
+ SDValue Callee = CLI.Callee;
5897
+ bool IsVarArg = CLI.IsVarArg;
5898
+ const SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;
5899
+ const SmallVector<SDValue, 32> &OutVals = CLI.OutVals;
5900
+ const SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;
5901
+ const SelectionDAG &DAG = CLI.DAG;
5854
5902
MachineFunction &MF = DAG.getMachineFunction();
5855
5903
const Function &CallerF = MF.getFunction();
5856
5904
CallingConv::ID CallerCC = CallerF.getCallingConv();
@@ -5915,30 +5963,14 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization(
5915
5963
5916
5964
// I want anyone implementing a new calling convention to think long and hard
5917
5965
// about this assert.
5918
- assert((!isVarArg || CalleeCC == CallingConv::C) &&
5966
+ assert((!IsVarArg || CalleeCC == CallingConv::C) &&
5919
5967
"Unexpected variadic calling convention");
5920
5968
5921
5969
LLVMContext &C = *DAG.getContext();
5922
- if (isVarArg && !Outs.empty()) {
5923
- // At least two cases here: if caller is fastcc then we can't have any
5924
- // memory arguments (we'd be expected to clean up the stack afterwards). If
5925
- // caller is C then we could potentially use its argument area.
5926
-
5927
- // FIXME: for now we take the most conservative of these in both cases:
5928
- // disallow all variadic memory operands.
5929
- SmallVector<CCValAssign, 16> ArgLocs;
5930
- CCState CCInfo(CalleeCC, isVarArg, MF, ArgLocs, C);
5931
-
5932
- CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CalleeCC, true));
5933
- for (const CCValAssign &ArgLoc : ArgLocs)
5934
- if (!ArgLoc.isRegLoc())
5935
- return false;
5936
- }
5937
-
5938
5970
// Check that the call results are passed in the same way.
5939
5971
if (!CCState::resultsCompatible(CalleeCC, CallerCC, MF, C, Ins,
5940
- CCAssignFnForCall(CalleeCC, isVarArg ),
5941
- CCAssignFnForCall(CallerCC, isVarArg )))
5972
+ CCAssignFnForCall(CalleeCC, IsVarArg ),
5973
+ CCAssignFnForCall(CallerCC, IsVarArg )))
5942
5974
return false;
5943
5975
// The callee has to preserve all registers the caller needs to preserve.
5944
5976
const AArch64RegisterInfo *TRI = Subtarget->getRegisterInfo();
@@ -5958,9 +5990,22 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization(
5958
5990
return true;
5959
5991
5960
5992
SmallVector<CCValAssign, 16> ArgLocs;
5961
- CCState CCInfo(CalleeCC, isVarArg, MF, ArgLocs, C);
5993
+ CCState CCInfo(CalleeCC, IsVarArg, MF, ArgLocs, C);
5994
+
5995
+ analyzeCallOperands(*this, Subtarget, CLI, CCInfo);
5996
+
5997
+ if (IsVarArg && !(CLI.CB && CLI.CB->isMustTailCall())) {
5998
+ // When we are musttail, additional checks have been done and we can safely ignore this check
5999
+ // At least two cases here: if caller is fastcc then we can't have any
6000
+ // memory arguments (we'd be expected to clean up the stack afterwards). If
6001
+ // caller is C then we could potentially use its argument area.
5962
6002
5963
- CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CalleeCC, isVarArg));
6003
+ // FIXME: for now we take the most conservative of these in both cases:
6004
+ // disallow all variadic memory operands.
6005
+ for (const CCValAssign &ArgLoc : ArgLocs)
6006
+ if (!ArgLoc.isRegLoc())
6007
+ return false;
6008
+ }
5964
6009
5965
6010
const AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
5966
6011
@@ -6051,7 +6096,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
6051
6096
SDValue Chain = CLI.Chain;
6052
6097
SDValue Callee = CLI.Callee;
6053
6098
bool &IsTailCall = CLI.IsTailCall;
6054
- CallingConv::ID CallConv = CLI.CallConv;
6099
+ CallingConv::ID & CallConv = CLI.CallConv;
6055
6100
bool IsVarArg = CLI.IsVarArg;
6056
6101
6057
6102
MachineFunction &MF = DAG.getMachineFunction();
@@ -6061,7 +6106,6 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
6061
6106
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
6062
6107
bool TailCallOpt = MF.getTarget().Options.GuaranteedTailCallOpt;
6063
6108
bool IsSibCall = false;
6064
- bool IsCalleeWin64 = Subtarget->isCallingConvWin64(CallConv);
6065
6109
6066
6110
// Check callee args/returns for SVE registers and set calling convention
6067
6111
// accordingly.
@@ -6079,8 +6123,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
6079
6123
6080
6124
if (IsTailCall) {
6081
6125
// Check if it's really possible to do a tail call.
6082
- IsTailCall = isEligibleForTailCallOptimization(
6083
- Callee, CallConv, IsVarArg, Outs, OutVals, Ins, DAG);
6126
+ IsTailCall = isEligibleForTailCallOptimization(CLI);
6084
6127
6085
6128
// A sibling call is one where we're under the usual C ABI and not planning
6086
6129
// to change that but can still do a tail call:
@@ -6101,56 +6144,17 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
6101
6144
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
6102
6145
6103
6146
if (IsVarArg) {
6104
- // Handle fixed and variable vector arguments differently.
6105
- // Variable vector arguments always go into memory.
6106
6147
unsigned NumArgs = Outs.size();
6107
6148
6108
6149
for (unsigned i = 0; i != NumArgs; ++i) {
6109
- MVT ArgVT = Outs[i].VT;
6110
- if (!Outs[i].IsFixed && ArgVT.isScalableVector())
6150
+ if (!Outs[i].IsFixed && Outs[i].VT.isScalableVector())
6111
6151
report_fatal_error("Passing SVE types to variadic functions is "
6112
6152
"currently not supported");
6113
-
6114
- ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
6115
- bool UseVarArgCC = !Outs[i].IsFixed;
6116
- // On Windows, the fixed arguments in a vararg call are passed in GPRs
6117
- // too, so use the vararg CC to force them to integer registers.
6118
- if (IsCalleeWin64)
6119
- UseVarArgCC = true;
6120
- CCAssignFn *AssignFn = CCAssignFnForCall(CallConv, UseVarArgCC);
6121
- bool Res = AssignFn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo);
6122
- assert(!Res && "Call operand has unhandled type");
6123
- (void)Res;
6124
- }
6125
- } else {
6126
- // At this point, Outs[].VT may already be promoted to i32. To correctly
6127
- // handle passing i8 as i8 instead of i32 on stack, we pass in both i32 and
6128
- // i8 to CC_AArch64_AAPCS with i32 being ValVT and i8 being LocVT.
6129
- // Since AnalyzeCallOperands uses Ins[].VT for both ValVT and LocVT, here
6130
- // we use a special version of AnalyzeCallOperands to pass in ValVT and
6131
- // LocVT.
6132
- unsigned NumArgs = Outs.size();
6133
- for (unsigned i = 0; i != NumArgs; ++i) {
6134
- MVT ValVT = Outs[i].VT;
6135
- // Get type of the original argument.
6136
- EVT ActualVT = getValueType(DAG.getDataLayout(),
6137
- CLI.getArgs()[Outs[i].OrigArgIndex].Ty,
6138
- /*AllowUnknown*/ true);
6139
- MVT ActualMVT = ActualVT.isSimple() ? ActualVT.getSimpleVT() : ValVT;
6140
- ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
6141
- // If ActualMVT is i1/i8/i16, we should set LocVT to i8/i8/i16.
6142
- if (ActualMVT == MVT::i1 || ActualMVT == MVT::i8)
6143
- ValVT = MVT::i8;
6144
- else if (ActualMVT == MVT::i16)
6145
- ValVT = MVT::i16;
6146
-
6147
- CCAssignFn *AssignFn = CCAssignFnForCall(CallConv, /*IsVarArg=*/false);
6148
- bool Res = AssignFn(i, ValVT, ValVT, CCValAssign::Full, ArgFlags, CCInfo);
6149
- assert(!Res && "Call operand has unhandled type");
6150
- (void)Res;
6151
6153
}
6152
6154
}
6153
6155
6156
+ analyzeCallOperands(*this, Subtarget, CLI, CCInfo);
6157
+
6154
6158
// Get a count of how many bytes are to be pushed on the stack.
6155
6159
unsigned NumBytes = CCInfo.getNextStackOffset();
6156
6160
0 commit comments