Handle tail call with byval arguments.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@95351 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2010-02-05 02:21:12 +00:00
parent 1ac23b1038
commit 5f94193b36
2 changed files with 107 additions and 25 deletions

View File

@ -1790,11 +1790,15 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
MachineFunction &MF = DAG.getMachineFunction();
bool Is64Bit = Subtarget->is64Bit();
bool IsStructRet = CallIsStructReturn(Outs);
bool IsSibcall = false;
if (isTailCall)
if (isTailCall) {
// Check if it's really possible to do a tail call.
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, isVarArg,
Outs, Ins, DAG);
if (!PerformTailCallOpt && isTailCall)
IsSibcall = true;
}
assert(!(isVarArg && CallConv == CallingConv::Fast) &&
"Var args not supported with calling convention fastcc");
@ -1809,7 +1813,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
unsigned NumBytes = CCInfo.getNextStackOffset();
if (FuncIsMadeTailCallSafe(CallConv))
NumBytes = GetAlignedArgumentStackSize(NumBytes, DAG);
else if (isTailCall && !PerformTailCallOpt)
else if (IsSibcall)
// This is a sibcall. The memory operands are available in caller's
// own caller's stack.
NumBytes = 0;
@ -1884,15 +1888,12 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
} else {
if (!isTailCall || (isTailCall && isByVal)) {
assert(VA.isMemLoc());
if (StackPtr.getNode() == 0)
StackPtr = DAG.getCopyFromReg(Chain, dl, X86StackPtr, getPointerTy());
MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Arg,
dl, DAG, VA, Flags));
}
} else if ((!isTailCall || isByVal) && !IsSibcall) {
assert(VA.isMemLoc());
if (StackPtr.getNode() == 0)
StackPtr = DAG.getCopyFromReg(Chain, dl, X86StackPtr, getPointerTy());
MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Arg,
dl, DAG, VA, Flags));
}
}
@ -2245,6 +2246,50 @@ unsigned X86TargetLowering::GetAlignedArgumentStackSize(unsigned StackSize,
return Offset;
}
/// MatchingStackOffset - Return true if the given stack call argument is
/// already available in the same position (relatively) of the caller's
/// incoming argument stack.
static
bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
MachineFrameInfo *MFI, const MachineRegisterInfo *MRI,
const X86InstrInfo *TII) {
int FI;
if (Arg.getOpcode() == ISD::CopyFromReg) {
unsigned VR = cast<RegisterSDNode>(Arg.getOperand(1))->getReg();
if (!VR || TargetRegisterInfo::isPhysicalRegister(VR))
return false;
MachineInstr *Def = MRI->getVRegDef(VR);
if (!Def)
return false;
if (!Flags.isByVal()) {
if (!TII->isLoadFromStackSlot(Def, FI))
return false;
} else {
unsigned Opcode = Def->getOpcode();
if ((Opcode == X86::LEA32r || Opcode == X86::LEA64r) &&
Def->getOperand(1).isFI()) {
FI = Def->getOperand(1).getIndex();
if (MFI->getObjectSize(FI) != Flags.getByValSize())
return false;
} else
return false;
}
} else {
LoadSDNode *Ld = dyn_cast<LoadSDNode>(Arg);
if (!Ld)
return false;
SDValue Ptr = Ld->getBasePtr();
FrameIndexSDNode *FINode = dyn_cast<FrameIndexSDNode>(Ptr);
if (!FINode)
return false;
FI = FINode->getIndex();
}
if (!MFI->isFixedObjectIndex(FI))
return false;
return Offset == MFI->getObjectOffset(FI);
}
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
/// for tail call optimization. Targets which want to do tail call
/// optimization should implement this function.
@ -2295,27 +2340,19 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
// Check if the arguments are already laid out in the right way as
// the caller's fixed stack objects.
MachineFrameInfo *MFI = MF.getFrameInfo();
const MachineRegisterInfo *MRI = &MF.getRegInfo();
const X86InstrInfo *TII =
((X86TargetMachine&)getTargetMachine()).getInstrInfo();
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
EVT RegVT = VA.getLocVT();
SDValue Arg = Outs[i].Val;
ISD::ArgFlagsTy Flags = Outs[i].Flags;
if (Flags.isByVal())
return false; // TODO
if (VA.getLocInfo() == CCValAssign::Indirect)
return false;
if (!VA.isRegLoc()) {
LoadSDNode *Ld = dyn_cast<LoadSDNode>(Arg);
if (!Ld)
return false;
SDValue Ptr = Ld->getBasePtr();
FrameIndexSDNode *FINode = dyn_cast<FrameIndexSDNode>(Ptr);
if (!FINode)
return false;
int FI = FINode->getIndex();
if (!MFI->isFixedObjectIndex(FI))
return false;
if (VA.getLocMemOffset() != MFI->getObjectOffset(FI))
if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags,
MFI, MRI, TII))
return false;
}
}

View File

@ -70,7 +70,7 @@ define i32 @t6(i32 %x) nounwind ssp {
entry:
; 32: t6:
; 32: call {{_?}}t6
; 32: call {{_?}}bar
; 32: jmp {{_?}}bar
; 64: t6:
; 64: jmp {{_?}}t6
@ -140,3 +140,48 @@ entry:
}
declare i32 @foo4()
define i32 @t11(i32 %x, i32 %y, i32 %z.0, i32 %z.1, i32 %z.2) nounwind ssp {
; In 32-bit mode, it's emitting a bunch of dead loads that are not being
; eliminated currently.
; 32: t11:
; 32: jmp {{_?}}foo5
; 64: t11:
; 64: jmp {{_?}}foo5
entry:
%0 = icmp eq i32 %x, 0
br i1 %0, label %bb6, label %bb
bb:
%1 = tail call i32 @foo5(i32 %x, i32 %y, i32 %z.0, i32 %z.1, i32 %z.2) nounwind
ret i32 %1
bb6:
ret i32 0
}
declare i32 @foo5(i32, i32, i32, i32, i32)
%struct.t = type { i32, i32, i32, i32, i32 }
define i32 @t12(i32 %x, i32 %y, %struct.t* byval align 4 %z) nounwind ssp {
; 32: t12:
; 32: jmp {{_?}}foo6
; 64: t12:
; 64: jmp {{_?}}foo6
entry:
%0 = icmp eq i32 %x, 0
br i1 %0, label %bb2, label %bb
bb:
%1 = tail call i32 @foo6(i32 %x, i32 %y, %struct.t* byval align 4 %z) nounwind
ret i32 %1
bb2:
ret i32 0
}
declare i32 @foo6(i32, i32, %struct.t* byval align 4)