[x86] Fix retq/retl handling in 64-bit mode

This finishes the job started in r198756, and creates separate opcodes for
64-bit vs. 32-bit versions of the rest of the RET instructions too.

LRETL/LRETQ are interesting... I can't see any justification for their
existence in the SDM. There should be no 'LRETL' in 64-bit mode, and no
need for a REX.W prefix for LRETQ. But this is what GAS does, and my
Sandybridge CPU and an Opteron 6376 concur when tested as follows:

asm __volatile__("pushq $0x1234\nmovq $0x33,%rax\nsalq $32,%rax\norq $1f,%rax\npushq %rax\nlretl $8\n1:");
asm __volatile__("pushq $1234\npushq $0x33\npushq $1f\nlretq $8\n1:");
asm __volatile__("pushq $0x33\npushq $1f\nlretq\n1:");
asm __volatile__("pushq $0x1234\npushq $0x33\npushq $1f\nlretq $8\n1:");

cf. PR8592 and commit r118903, which added LRETQ. I only added LRETIQ to
match it.

I don't quite understand how the Intel syntax parsing for ret
instructions is working, despite r154468 allegedly fixing it. Aren't the
explicitly sized 'retw', 'retd' and 'retq' supposed to work? I have at
least made the 'lretq' work with (and indeed *require*) the 'q'.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199106 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Woodhouse 2014-01-13 14:05:59 +00:00
parent 7f2eff792a
commit f71254859e
6 changed files with 110 additions and 11 deletions

View File

@ -1673,7 +1673,8 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
case X86::RETQ:
case X86::RETL:
case X86::RETI:
case X86::RETIL:
case X86::RETIQ:
// If RET has an FP register use operand, pass the first one in ST(0) and
// the second one in ST(1).

View File

@ -109,7 +109,8 @@ static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB,
default: return 0;
case X86::RETL:
case X86::RETQ:
case X86::RETI:
case X86::RETIL:
case X86::RETIQ:
case X86::TCRETURNdi:
case X86::TCRETURNri:
case X86::TCRETURNmi:
@ -731,7 +732,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
llvm_unreachable("Can only insert epilog into returning blocks");
case X86::RETQ:
case X86::RETL:
case X86::RETI:
case X86::RETIL:
case X86::RETIQ:
case X86::TCRETURNdi:
case X86::TCRETURNri:
case X86::TCRETURNmi:
@ -888,8 +890,9 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
// Delete the pseudo instruction TCRETURN.
MBB.erase(MBBI);
} else if ((RetOpcode == X86::RETQ || RetOpcode == X86::RETI ||
RetOpcode == X86::RETL) && (X86FI->getTCReturnAddrDelta() < 0)) {
} else if ((RetOpcode == X86::RETQ || RetOpcode == X86::RETL ||
RetOpcode == X86::RETIQ || RetOpcode == X86::RETIL) &&
(X86FI->getTCReturnAddrDelta() < 0)) {
// Add the return addr area delta back since we are not tail calling.
int delta = -1*X86FI->getTCReturnAddrDelta();
MBBI = MBB.getLastNonDebugInstr();

View File

@ -30,20 +30,27 @@ let isTerminator = 1, isReturn = 1, isBarrier = 1,
def RETW : I <0xC3, RawFrm, (outs), (ins),
"ret{w}",
[], IIC_RET>, OpSize;
def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
def RETIL : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
"ret{l}\t$amt",
[(X86retflag timm:$amt)], IIC_RET_IMM>, OpSize16;
[(X86retflag timm:$amt)], IIC_RET_IMM>, OpSize16,
Requires<[Not64BitMode]>;
def RETIQ : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
"ret{q}\t$amt",
[(X86retflag timm:$amt)], IIC_RET_IMM>,
Requires<[In64BitMode]>;
def RETIW : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt),
"ret{w}\t$amt",
[], IIC_RET_IMM>, OpSize;
def LRETL : I <0xCB, RawFrm, (outs), (ins),
"{l}ret{l|f}", [], IIC_RET>, OpSize16;
def LRETQ : RI <0xCB, RawFrm, (outs), (ins),
"{l}ret{|f}q", [], IIC_RET>, Requires<[In64BitMode]>;
def LRETW : I <0xCB, RawFrm, (outs), (ins),
"{l}ret{w|f}", [], IIC_RET>, OpSize;
def LRETQ : RI <0xCB, RawFrm, (outs), (ins),
"{l}ret{q|f}", [], IIC_RET>;
def LRETI : Ii16<0xCA, RawFrm, (outs), (ins i16imm:$amt),
def LRETIL : Ii16<0xCA, RawFrm, (outs), (ins i16imm:$amt),
"{l}ret{l|f}\t$amt", [], IIC_RET>, OpSize16;
def LRETIQ : RIi16<0xCA, RawFrm, (outs), (ins i16imm:$amt),
"{l}ret{|f}q\t$amt", [], IIC_RET>, Requires<[In64BitMode]>;
def LRETIW : Ii16<0xCA, RawFrm, (outs), (ins i16imm:$amt),
"{l}ret{w|f}\t$amt", [], IIC_RET>, OpSize;
}

View File

@ -736,6 +736,9 @@ class RI<bits<8> o, Format F, dag outs, dag ins, string asm,
class RIi8 <bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern, InstrItinClass itin = NoItinerary>
: Ii8<o, F, outs, ins, asm, pattern, itin>, REX_W;
class RIi16 <bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern, InstrItinClass itin = NoItinerary>
: Ii16<o, F, outs, ins, asm, pattern, itin>, REX_W;
class RIi32 <bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern, InstrItinClass itin = NoItinerary>
: Ii32<o, F, outs, ins, asm, pattern, itin>, REX_W;

View File

@ -2162,7 +2162,7 @@ def : MnemonicAlias<"cdq", "cltd", "att">;
def : MnemonicAlias<"cdqe", "cltq", "att">;
def : MnemonicAlias<"cqo", "cqto", "att">;
// lret maps to lretl, it is not ambiguous with lretq.
// In 64-bit mode lret maps to lretl; it is not ambiguous with lretq.
def : MnemonicAlias<"lret", "lretw", "att">, Requires<[In16BitMode]>;
def : MnemonicAlias<"lret", "lretl", "att">, Requires<[Not16BitMode]>;

85
test/MC/X86/ret.s Normal file
View File

@ -0,0 +1,85 @@
// RUN: not llvm-mc -triple x86_64-unknown-unknown --show-encoding %s 2> %t.err | FileCheck --check-prefix=64 %s
// RUN: FileCheck --check-prefix=ERR64 < %t.err %s
// RUN: not llvm-mc -triple i386-unknown-unknown --show-encoding %s 2> %t.err | FileCheck --check-prefix=32 %s
// RUN: FileCheck --check-prefix=ERR32 < %t.err %s
ret
// 64: retq
// 64: encoding: [0xc3]
// 32: retl
// 32: encoding: [0xc3]
retw
// 64: retw
// 64: encoding: [0x66,0xc3]
// 32: retw
// 32: encoding: [0x66,0xc3]
retl
// ERR64: error: instruction requires: Not 64-bit mode
// 32: retl
// 32: encoding: [0xc3]
retq
// 64: retq
// 64: encoding: [0xc3]
// ERR32: error: instruction requires: 64-bit mode
ret $0
// 64: retq $0
// 64: encoding: [0xc2,0x00,0x00]
// 32: retl $0
// 32: encoding: [0xc2,0x00,0x00]
retw $0
// 64: retw $0
// 64: encoding: [0x66,0xc2,0x00,0x00]
// 32: retw $0
// 32: encoding: [0x66,0xc2,0x00,0x00]
retl $0
// ERR64: error: instruction requires: Not 64-bit mode
// 32: retl $0
// 32: encoding: [0xc2,0x00,0x00]
retq $0
// 64: retq $0
// 64: encoding: [0xc2,0x00,0x00]
// ERR32: error: instruction requires: 64-bit mode
lret
// 64: lretl
// 64: encoding: [0xcb]
// 32: lretl
// 32: encoding: [0xcb]
lretw
// 64: lretw
// 64: encoding: [0x66,0xcb]
// 32: lretw
// 32: encoding: [0x66,0xcb]
lretl
// 64: lretl
// 64: encoding: [0xcb]
// 32: lretl
// 32: encoding: [0xcb]
lretq
// 64: lretq
// 64: encoding: [0x48,0xcb]
// ERR32: error: instruction requires: 64-bit mode
lret $0
// 64: lretl $0
// 64: encoding: [0xca,0x00,0x00]
// 32: lretl $0
// 32: encoding: [0xca,0x00,0x00]
lretw $0
// 64: lretw $0
// 64: encoding: [0x66,0xca,0x00,0x00]
// 32: lretw $0
// 32: encoding: [0x66,0xca,0x00,0x00]
lretl $0
// 64: lretl $0
// 64: encoding: [0xca,0x00,0x00]
// 32: lretl $0
// 32: encoding: [0xca,0x00,0x00]
lretq $0
// 64: lretq $0
// 64: encoding: [0x48,0xca,0x00,0x00]
// ERR32: error: instruction requires: 64-bit mode