diff options
Diffstat (limited to 'llvm/lib/Target/X86/X86ExpandPseudo.cpp')
-rw-r--r-- | llvm/lib/Target/X86/X86ExpandPseudo.cpp | 25 |
1 files changed, 25 insertions, 0 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( |