diff options
author | David Majnemer <david.majnemer@gmail.com> | 2016-03-04 22:56:17 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2016-03-04 22:56:17 +0000 |
commit | d2f767d2f6832e5d6bf13ff7f3a309bcd2b8f502 (patch) | |
tree | 64f1583e8232461c32ab0557e66ffda8a39c4320 /llvm/lib/Target | |
parent | 5c3701c621cf480070de72bf244939b6440be33d (diff) | |
download | bcm5719-llvm-d2f767d2f6832e5d6bf13ff7f3a309bcd2b8f502.tar.gz bcm5719-llvm-d2f767d2f6832e5d6bf13ff7f3a309bcd2b8f502.zip |
[X86] Support cleaning more than 2**16 bytes of stack
The x86 ret instruction has a 16 bit immediate indicating how many bytes
to pop off of the stack beyond the return address.
There is a problem when extremely large structs are passed by value: we
might not be able to fit the number of bytes to pop into the return
instruction.
To fix this, expand RET_FLAG a little later and use a special sequence
to clean the stack:
pop %ecx ; return address is now in %ecx
add $n, %esp ; clean the stack
push %ecx ; bring the return address back on the stack
ret ; pop the return address and jmp to it's value
llvm-svn: 262755
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r-- | llvm/lib/Target/X86/X86ExpandPseudo.cpp | 25 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FloatingPoint.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86InstrControl.td | 12 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86InstrInfo.td | 2 |
6 files changed, 35 insertions, 8 deletions
diff --git a/llvm/lib/Target/X86/X86ExpandPseudo.cpp b/llvm/lib/Target/X86/X86ExpandPseudo.cpp index de89dfd0d23..6093c33a144 100644 --- a/llvm/lib/Target/X86/X86ExpandPseudo.cpp +++ b/llvm/lib/Target/X86/X86ExpandPseudo.cpp @@ -152,6 +152,31 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB, MBB.erase(MBBI); return true; } + case X86::RET: { + // Adjust stack to erase error code + int64_t StackAdj = MBBI->getOperand(0).getImm(); + MachineInstrBuilder MIB; + if (StackAdj == 0) { + MIB = BuildMI(MBB, MBBI, DL, + TII->get(STI->is64Bit() ? X86::RETQ : X86::RETL)); + } else if (isUInt<16>(StackAdj)) { + MIB = BuildMI(MBB, MBBI, DL, + TII->get(STI->is64Bit() ? X86::RETIQ : X86::RETIL)) + .addImm(StackAdj); + } else { + assert(!Is64Bit && "shouldn't need to do this for x86_64 targets!"); + // A ret can only handle immediates as big as 2**16-1. If we need to pop + // off bytes before the return address, we must do it manually. + BuildMI(MBB, MBBI, DL, X86::POP32r).addReg(X86::ECX, RegState::Define); + X86FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true); + BuildMI(MBB, MBBI, DL, X86::PUSH32r).addReg(X86::ECX); + MIB = BuildMI(MBB, MBBI, DL, X86::RETL); + } + for (unsigned I = 1, E = MBBI->getNumOperands(); I != E; ++I) + MIB.addOperand(MBBI->getOperand(I)); + MBB.erase(MBBI); + return true; + } case X86::EH_RESTORE: { // Restore ESP and EBP, and optionally ESI if required. bool IsSEH = isAsynchronousEHPersonality(classifyEHPersonality( diff --git a/llvm/lib/Target/X86/X86FloatingPoint.cpp b/llvm/lib/Target/X86/X86FloatingPoint.cpp index 324c248448e..80cb8679fbe 100644 --- a/llvm/lib/Target/X86/X86FloatingPoint.cpp +++ b/llvm/lib/Target/X86/X86FloatingPoint.cpp @@ -1509,6 +1509,7 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &Inst) { return; } + case X86::RET: case X86::RETQ: case X86::RETL: case X86::RETIL: diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index de56259f744..c52ce15cf6a 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -159,6 +159,7 @@ static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB, unsigned Opc = MBBI->getOpcode(); switch (Opc) { default: return 0; + case X86::RET: case X86::RETL: case X86::RETQ: case X86::RETIL: diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 2a11eddaf15..65b8fb88b6d 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -2211,7 +2211,7 @@ X86TargetLowering::LowerReturn(SDValue Chain, RetOps.push_back(Chain); // Operand #0 = Chain (updated below) // Operand #1 = Bytes To Pop RetOps.push_back(DAG.getTargetConstant(FuncInfo->getBytesToPopOnReturn(), dl, - MVT::i16)); + MVT::i32)); // Copy the result values into the output registers. for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { diff --git a/llvm/lib/Target/X86/X86InstrControl.td b/llvm/lib/Target/X86/X86InstrControl.td index 8c351a51c46..bb5f9117f03 100644 --- a/llvm/lib/Target/X86/X86InstrControl.td +++ b/llvm/lib/Target/X86/X86InstrControl.td @@ -22,21 +22,21 @@ let isTerminator = 1, isReturn = 1, isBarrier = 1, hasCtrlDep = 1, FPForm = SpecialFP, SchedRW = [WriteJumpLd] in { def RETL : I <0xC3, RawFrm, (outs), (ins variable_ops), - "ret{l}", [(X86retflag 0)], IIC_RET>, OpSize32, + "ret{l}", [], IIC_RET>, OpSize32, Requires<[Not64BitMode]>; def RETQ : I <0xC3, RawFrm, (outs), (ins variable_ops), - "ret{q}", [(X86retflag 0)], IIC_RET>, OpSize32, + "ret{q}", [], IIC_RET>, OpSize32, Requires<[In64BitMode]>; def RETW : I <0xC3, RawFrm, (outs), (ins), "ret{w}", [], IIC_RET>, OpSize16; def RETIL : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops), "ret{l}\t$amt", - [(X86retflag timm:$amt)], IIC_RET_IMM>, OpSize32, + [], IIC_RET_IMM>, OpSize32, Requires<[Not64BitMode]>; def RETIQ : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops), "ret{q}\t$amt", - [(X86retflag timm:$amt)], IIC_RET_IMM>, OpSize32, + [], IIC_RET_IMM>, OpSize32, Requires<[In64BitMode]>; def RETIW : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt), "ret{w}\t$amt", @@ -64,8 +64,8 @@ let isTerminator = 1, isReturn = 1, isBarrier = 1, def IRET64 : RI <0xcf, RawFrm, (outs), (ins), "iretq", [], IIC_IRET>, Requires<[In64BitMode]>; let isCodeGenOnly = 1 in - def IRET : PseudoI<(outs), (ins i16imm:$adj), [(X86iret timm:$adj)]>; - + def IRET : PseudoI<(outs), (ins i32imm:$adj), [(X86iret timm:$adj)]>; + def RET : PseudoI<(outs), (ins i32imm:$adj, variable_ops), [(X86retflag timm:$adj)]>; } // Unconditional branches. diff --git a/llvm/lib/Target/X86/X86InstrInfo.td b/llvm/lib/Target/X86/X86InstrInfo.td index 70106251bbe..aaf87a7b42a 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.td +++ b/llvm/lib/Target/X86/X86InstrInfo.td @@ -76,7 +76,7 @@ def SDTLockBinaryArithWithFlags : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisInt<2>]>; -def SDTX86Ret : SDTypeProfile<0, -1, [SDTCisVT<0, i16>]>; +def SDTX86Ret : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>; def SDT_X86CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; def SDT_X86CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, |