Changeset View
Changeset View
Standalone View
Standalone View
lib/Target/ARM/ARMISelLowering.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 1,830 Lines • ▼ Show 20 Lines | ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, | ||||
bool doesNotRet = CLI.DoesNotReturn; | bool doesNotRet = CLI.DoesNotReturn; | ||||
bool isVarArg = CLI.IsVarArg; | bool isVarArg = CLI.IsVarArg; | ||||
MachineFunction &MF = DAG.getMachineFunction(); | MachineFunction &MF = DAG.getMachineFunction(); | ||||
bool isStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet(); | bool isStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet(); | ||||
bool isThisReturn = false; | bool isThisReturn = false; | ||||
bool isSibCall = false; | bool isSibCall = false; | ||||
auto Attr = MF.getFunction().getFnAttribute("disable-tail-calls"); | auto Attr = MF.getFunction().getFnAttribute("disable-tail-calls"); | ||||
bool PreferIndirect = false; | |||||
// Disable tail calls if they're not supported. | // Disable tail calls if they're not supported. | ||||
if (!Subtarget->supportsTailCall() || Attr.getValueAsString() == "true") | if (!Subtarget->supportsTailCall() || Attr.getValueAsString() == "true") | ||||
isTailCall = false; | isTailCall = false; | ||||
if (isa<GlobalAddressSDNode>(Callee)) { | |||||
// If we're optimizing for minimum size and the function is called three or | |||||
// more times in this block, we can improve codesize by calling indirectly | |||||
// as BLXr has a 16-bit encoding. | |||||
auto *GV = cast<GlobalAddressSDNode>(Callee)->getGlobal(); | |||||
auto *BB = CLI.CS.getParent(); | |||||
PreferIndirect = | |||||
Subtarget->isThumb() && Subtarget->hasMinSize() && | |||||
count_if(GV->users(), [&BB](const User *U) { | |||||
return isa<Instruction>(U) && cast<Instruction>(U)->getParent() == BB; | |||||
}) > 2; | |||||
} | |||||
if (isTailCall) { | if (isTailCall) { | ||||
// Check if it's really possible to do a tail call. | // Check if it's really possible to do a tail call. | ||||
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, | isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, | ||||
isVarArg, isStructRet, MF.getFunction().hasStructRetAttr(), | isVarArg, isStructRet, MF.getFunction().hasStructRetAttr(), | ||||
Outs, OutVals, Ins, DAG); | Outs, OutVals, Ins, DAG, PreferIndirect); | ||||
if (!isTailCall && CLI.CS && CLI.CS.isMustTailCall()) | if (!isTailCall && CLI.CS && CLI.CS.isMustTailCall()) | ||||
report_fatal_error("failed to perform tail call elimination on a call " | report_fatal_error("failed to perform tail call elimination on a call " | ||||
"site marked musttail"); | "site marked musttail"); | ||||
// We don't support GuaranteedTailCallOpt for ARM, only automatically | // We don't support GuaranteedTailCallOpt for ARM, only automatically | ||||
// detected sibcalls. | // detected sibcalls. | ||||
if (isTailCall) { | if (isTailCall) { | ||||
++NumTailCalls; | ++NumTailCalls; | ||||
isSibCall = true; | isSibCall = true; | ||||
Show All 10 Lines | ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, | ||||
unsigned NumBytes = CCInfo.getNextStackOffset(); | unsigned NumBytes = CCInfo.getNextStackOffset(); | ||||
// For tail calls, memory operands are available in our caller's stack. | // For tail calls, memory operands are available in our caller's stack. | ||||
if (isSibCall) | if (isSibCall) | ||||
NumBytes = 0; | NumBytes = 0; | ||||
// Adjust the stack pointer for the new arguments... | // Adjust the stack pointer for the new arguments... | ||||
// These operations are automatically eliminated by the prolog/epilog pass | // These operations are automatically eliminated by the prolog/epilog pass | ||||
if (!isSibCall) | else | ||||
dmgreen: This looks like an unrelated change (and a little harder to parse to me, with the comment and… | |||||
dmgreenUnsubmitted Also, is isSibCall ever different to isTailCall? Do we need both? dmgreen: Also, is isSibCall ever different to isTailCall? Do we need both? | |||||
dnsampaioAuthorUnsubmitted Indeed it is not used. Will do a little of clean up as well by removing it. dnsampaio: Indeed it is not used. Will do a little of clean up as well by removing it. | |||||
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); | Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); | ||||
SDValue StackPtr = | SDValue StackPtr = | ||||
DAG.getCopyFromReg(Chain, dl, ARM::SP, getPointerTy(DAG.getDataLayout())); | DAG.getCopyFromReg(Chain, dl, ARM::SP, getPointerTy(DAG.getDataLayout())); | ||||
RegsToPassVector RegsToPass; | RegsToPassVector RegsToPass; | ||||
SmallVector<SDValue, 8> MemOpChains; | SmallVector<SDValue, 8> MemOpChains; | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | if (isa<GlobalAddressSDNode>(Callee)) { | ||||
// Get the address of the callee into a register | // Get the address of the callee into a register | ||||
SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, 4); | SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, 4); | ||||
CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | ||||
Callee = DAG.getLoad( | Callee = DAG.getLoad( | ||||
PtrVt, dl, DAG.getEntryNode(), CPAddr, | PtrVt, dl, DAG.getEntryNode(), CPAddr, | ||||
MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | ||||
} | } | ||||
} else if (isa<GlobalAddressSDNode>(Callee)) { | } else if (isa<GlobalAddressSDNode>(Callee)) { | ||||
// If we're optimizing for minimum size and the function is called three or | |||||
// more times in this block, we can improve codesize by calling indirectly | |||||
// as BLXr has a 16-bit encoding. | |||||
auto *GV = cast<GlobalAddressSDNode>(Callee)->getGlobal(); | |||||
auto *BB = CLI.CS.getParent(); | |||||
bool PreferIndirect = | |||||
Subtarget->isThumb() && Subtarget->hasMinSize() && | |||||
count_if(GV->users(), [&BB](const User *U) { | |||||
return isa<Instruction>(U) && cast<Instruction>(U)->getParent() == BB; | |||||
}) > 2; | |||||
if (!PreferIndirect) { | if (!PreferIndirect) { | ||||
isDirect = true; | isDirect = true; | ||||
bool isDef = GV->isStrongDefinitionForLinker(); | bool isDef = GV->isStrongDefinitionForLinker(); | ||||
// ARM call to a local ARM function is predicable. | // ARM call to a local ARM function is predicable. | ||||
isLocalARMFunc = !Subtarget->isThumb() && (isDef || !ARMInterworking); | isLocalARMFunc = !Subtarget->isThumb() && (isDef || !ARMInterworking); | ||||
// tBX takes a register source operand. | // tBX takes a register source operand. | ||||
if (isStub && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { | if (isStub && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | |||||
ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, | ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, | ||||
CallingConv::ID CalleeCC, | CallingConv::ID CalleeCC, | ||||
bool isVarArg, | bool isVarArg, | ||||
bool isCalleeStructRet, | bool isCalleeStructRet, | ||||
bool isCallerStructRet, | bool isCallerStructRet, | ||||
const SmallVectorImpl<ISD::OutputArg> &Outs, | const SmallVectorImpl<ISD::OutputArg> &Outs, | ||||
const SmallVectorImpl<SDValue> &OutVals, | const SmallVectorImpl<SDValue> &OutVals, | ||||
const SmallVectorImpl<ISD::InputArg> &Ins, | const SmallVectorImpl<ISD::InputArg> &Ins, | ||||
SelectionDAG& DAG) const { | SelectionDAG& DAG, | ||||
const bool PreferIndirect) const { | |||||
MachineFunction &MF = DAG.getMachineFunction(); | MachineFunction &MF = DAG.getMachineFunction(); | ||||
const Function &CallerF = MF.getFunction(); | const Function &CallerF = MF.getFunction(); | ||||
CallingConv::ID CallerCC = CallerF.getCallingConv(); | CallingConv::ID CallerCC = CallerF.getCallingConv(); | ||||
assert(Subtarget->supportsTailCall()); | assert(Subtarget->supportsTailCall()); | ||||
// Tail calls to function pointers cannot be optimized for Thumb1 if the args | // Indirect tail calls cannot be optimized for Thumb1 if the args | ||||
// to the call take up r0-r3. The reason is that there are no legal registers | // to the call take up r0-r3. The reason is that there are no legal registers | ||||
// left to hold the pointer to the function to be called. | // left to hold the pointer to the function to be called. | ||||
if (Subtarget->isThumb1Only() && Outs.size() >= 4 && | if (Subtarget->isThumb1Only() && Outs.size() >= 4 && | ||||
!isa<GlobalAddressSDNode>(Callee.getNode())) | (!isa<GlobalAddressSDNode>(Callee.getNode()) || PreferIndirect)) | ||||
return false; | return false; | ||||
Not Done ReplyInline ActionsPerhaps call this "IsIndirect" on this side of the call? dmgreen: Perhaps call this "IsIndirect" on this side of the call? | |||||
// Look for obvious safe cases to perform tail call optimization that do not | // Look for obvious safe cases to perform tail call optimization that do not | ||||
// require ABI changes. This is what gcc calls sibcall. | // require ABI changes. This is what gcc calls sibcall. | ||||
// Exception-handling functions need a special set of instructions to indicate | // Exception-handling functions need a special set of instructions to indicate | ||||
// a return to the hardware. Tail-calling another function would probably | // a return to the hardware. Tail-calling another function would probably | ||||
// break this. | // break this. | ||||
if (CallerF.hasFnAttribute("interrupt")) | if (CallerF.hasFnAttribute("interrupt")) | ||||
▲ Show 20 Lines • Show All 13,007 Lines • Show Last 20 Lines |
This looks like an unrelated change (and a little harder to parse to me, with the comment and newly between the if and the else).