summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CallingConvLower.cpp8
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp86
-rw-r--r--lib/Target/X86/X86ISelLowering.h2
3 files changed, 81 insertions, 15 deletions
diff --git a/lib/CodeGen/CallingConvLower.cpp b/lib/CodeGen/CallingConvLower.cpp
index bfb6ba1023..7768e28979 100644
--- a/lib/CodeGen/CallingConvLower.cpp
+++ b/lib/CodeGen/CallingConvLower.cpp
@@ -48,8 +48,12 @@ void CCState::HandleByVal(unsigned ValNo, MVT ValVT,
if (MinAlign > (int)Align)
Align = MinAlign;
TM.getTargetLowering()->HandleByVal(const_cast<CCState*>(this), Size);
- unsigned Offset = AllocateStack(Size, Align);
- addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ if (Size != 0) {
+ unsigned Offset = AllocateStack(Size, Align);
+ addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ } else {
+ addLoc(CCValAssign::getReg(ValNo, ValVT, getFirstByValReg(), LocVT, LocInfo));
+ }
}
/// MarkAllocated - Mark a register and all of its aliases as allocated.
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index ff4a283b58..d0e2abdf5f 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -2091,19 +2091,36 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
}
if (VA.isRegLoc()) {
- RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
- if (isVarArg && IsWin64) {
- // Win64 ABI requires argument XMM reg to be copied to the corresponding
- // shadow reg if callee is a varargs function.
- unsigned ShadowReg = 0;
- switch (VA.getLocReg()) {
- case X86::XMM0: ShadowReg = X86::RCX; break;
- case X86::XMM1: ShadowReg = X86::RDX; break;
- case X86::XMM2: ShadowReg = X86::R8; break;
- case X86::XMM3: ShadowReg = X86::R9; break;
+ if (isByVal && (!IsSibcall && !isTailCall)) {
+ // 64-bit only. x86_32 passes everything on the stack.
+ assert(CCInfo.isFirstByValRegValid() && "isByVal, but no valid register assigned!");
+ EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+ unsigned int i, j;
+ for (i = 0, j = CCInfo.getFirstByValReg(); j <= X86::R9; i++, j++) {
+ SDValue Const = DAG.getConstant(8*i, MVT::i64);
+ SDValue AddArg = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, Const);
+ SDValue Load = DAG.getLoad(PtrVT, dl, Chain, AddArg,
+ MachinePointerInfo(),
+ false, false, 0);
+ MemOpChains.push_back(Load.getValue(1));
+ RegsToPass.push_back(std::make_pair(j, Load));
+ }
+ CCInfo.clearFirstByValReg();
+ } else {
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ if (isVarArg && IsWin64) {
+ // Win64 ABI requires argument XMM reg to be copied to the corresponding
+ // shadow reg if callee is a varargs function.
+ unsigned ShadowReg = 0;
+ switch (VA.getLocReg()) {
+ case X86::XMM0: ShadowReg = X86::RCX; break;
+ case X86::XMM1: ShadowReg = X86::RDX; break;
+ case X86::XMM2: ShadowReg = X86::R8; break;
+ case X86::XMM3: ShadowReg = X86::R9; break;
+ }
+ if (ShadowReg)
+ RegsToPass.push_back(std::make_pair(ShadowReg, Arg));
}
- if (ShadowReg)
- RegsToPass.push_back(std::make_pair(ShadowReg, Arg));
}
} else if (!IsSibcall && (!isTailCall || isByVal)) {
assert(VA.isMemLoc());
@@ -2438,6 +2455,47 @@ X86TargetLowering::GetAlignedArgumentStackSize(unsigned StackSize,
return Offset;
}
+/// HandleByVal - Every parameter *after* a byval parameter is passed
+/// on the stack. Remember the next parameter register to allocate,
+/// and then confiscate the rest of the parameter registers to insure
+/// this.
+void
+X86TargetLowering::HandleByVal(CCState *State, unsigned &size) const {
+ // X86_32 passes all parameters on the stack, byval or whatever.
+ // X86_64 does not split parameters between registers and memory; if
+ // the parameter does not fit entirely inside the remaining
+ // parameter registers, it goes on the stack.
+ static const unsigned RegList2[] = {
+ X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9
+ };
+
+ if (!Subtarget->is64Bit())
+ return;
+
+ if (size > 16) // X86_64 aggregates > 16 bytes are passed in memory.
+ return;
+
+ unsigned reg = State->getFirstUnallocated(RegList2, 6);
+
+ if (reg == 6) // Out of regs to allocate.
+ return;
+
+ // We expect the size to be 32 bits, or some non-zero multiple of 64 bits.
+ unsigned nregs = size / 8;
+ if (nregs == 0) nregs=1; // 32-bit case.
+
+ unsigned regs_available = 6 - reg;
+
+ if (nregs <= regs_available) {
+ size = 0;
+ State->setFirstByValReg(RegList2[reg]);
+ while (nregs--) {
+ State->AllocateReg(RegList2[reg]);
+ reg++;
+ }
+ }
+}
+
/// MatchingStackOffset - Return true if the given stack call argument is
/// already available in the same position (relatively) of the caller's
/// incoming argument stack.
@@ -2602,7 +2660,7 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
}
CCInfo.AnalyzeCallOperands(Outs, CC_X86);
- if (CCInfo.getNextStackOffset()) {
+ if (ArgLocs.size()) {
MachineFunction &MF = DAG.getMachineFunction();
if (MF.getInfo<X86MachineFunctionInfo>()->getBytesToPopOnReturn())
return false;
@@ -2619,6 +2677,8 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
ISD::ArgFlagsTy Flags = Outs[i].Flags;
if (VA.getLocInfo() == CCValAssign::Indirect)
return false;
+ if (Flags.isByVal())
+ return false;
if (!VA.isRegLoc()) {
if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags,
MFI, MRI, TII))
diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h
index ca84a99045..905d54f27c 100644
--- a/lib/Target/X86/X86ISelLowering.h
+++ b/lib/Target/X86/X86ISelLowering.h
@@ -728,6 +728,8 @@ namespace llvm {
// Call lowering helpers.
+ void HandleByVal(CCState *, unsigned &) const;
+
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
/// for tail call optimization. Targets which want to do tail call
/// optimization should implement this function.