Don't emit st(0)/st(1) copies as FpMOV instructions. Use FpSET_ST? instead.

Based on a patch by Rafael Espíndola.

Attempt to make the FpSET_ST1 hack more robust, but we are still relying on
FpSET_ST0 preceeding it. This is only for supporting really weird x87 inline
asm.

We support:

  FpSET_ST0
  INLINEASM

  FpSET_ST0
  FpSET_ST1
  INLINEASM

with and without kills on the arguments. We don't support:

  FpSET_ST1
  FpSET_ST0
  INLINEASM

nor

  FpSET_ST1
  INLINEASM

Just Don't Do It!

llvm-svn: 108047
This commit is contained in:
Jakob Stoklund Olesen 2010-07-10 17:42:34 +00:00
parent c4b3bcc051
commit de457896b6
2 changed files with 65 additions and 83 deletions

View File

@ -1006,15 +1006,17 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
case X86::FpSET_ST0_32:
case X86::FpSET_ST0_64:
case X86::FpSET_ST0_80: {
// FpSET_ST0_80 is generated by copyRegToReg for setting up inline asm
// arguments that use an st constraint. We expect a sequence of
// instructions: Fp_SET_ST0 Fp_SET_ST1? INLINEASM
unsigned Op0 = getFPReg(MI->getOperand(0));
// FpSET_ST0_80 is generated by copyRegToReg for both function return
// and inline assembly with the "st" constrain. In the latter case,
// it is possible for ST(0) to be alive after this instruction.
if (!MI->killsRegister(X86::FP0 + Op0)) {
// Duplicate Op0
duplicateToTop(0, 7 /*temp register*/, I);
// Duplicate Op0 into a temporary on the stack top.
// This actually assumes that FP7 is dead.
duplicateToTop(Op0, 7, I);
} else {
// Op0 is killed, so just swap it into position.
moveToTop(Op0, I);
}
--StackTop; // "Forget" we have something on the top of stack!
@ -1022,17 +1024,29 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
}
case X86::FpSET_ST1_32:
case X86::FpSET_ST1_64:
case X86::FpSET_ST1_80:
// StackTop can be 1 if a FpSET_ST0_* was before this. Exchange them.
if (StackTop == 1) {
BuildMI(*MBB, I, dl, TII->get(X86::XCH_F)).addReg(X86::ST1);
++NumFXCH;
StackTop = 0;
break;
case X86::FpSET_ST1_80: {
// Set up st(1) for inline asm. We are assuming that st(0) has already been
// set up by FpSET_ST0, and our StackTop is off by one because of it.
unsigned Op0 = getFPReg(MI->getOperand(0));
// Restore the actual StackTop from before Fp_SET_ST0.
// Note we can't handle Fp_SET_ST1 without a preceeding Fp_SET_ST0, and we
// are not enforcing the constraint.
++StackTop;
unsigned RegOnTop = getStackEntry(0); // This reg must remain in st(0).
if (!MI->killsRegister(X86::FP0 + Op0)) {
// Assume FP6 is not live, use it as a scratch register.
duplicateToTop(Op0, 6, I);
moveToTop(RegOnTop, I);
} else if (getSTReg(Op0) != X86::ST1) {
// We have the wrong value at st(1). Shuffle! Untested!
moveToTop(getStackEntry(1), I);
moveToTop(Op0, I);
moveToTop(RegOnTop, I);
}
assert(StackTop == 2 && "Stack should have two element on it to return!");
--StackTop; // "Forget" we have something on the top of stack!
assert(StackTop >= 2 && "Too few live registers");
StackTop -= 2; // "Forget" both st(0) and st(1).
break;
}
case X86::MOV_Fp3232:
case X86::MOV_Fp3264:
case X86::MOV_Fp6432:
@ -1046,32 +1060,6 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
unsigned SrcReg = getFPReg(MO1);
const MachineOperand &MO0 = MI->getOperand(0);
// These can be created due to inline asm. Two address pass can introduce
// copies from RFP registers to virtual registers.
if (MO0.getReg() == X86::ST0 && SrcReg == 0) {
assert(MO1.isKill());
// Treat %ST0<def> = MOV_Fp8080 %FP0<kill>
// like FpSET_ST0_80 %FP0<kill>, %ST0<imp-def>
assert((StackTop == 1 || StackTop == 2)
&& "Stack should have one or two element on it to return!");
--StackTop; // "Forget" we have something on the top of stack!
break;
} else if (MO0.getReg() == X86::ST1 && SrcReg == 1) {
assert(MO1.isKill());
// Treat %ST1<def> = MOV_Fp8080 %FP1<kill>
// like FpSET_ST1_80 %FP0<kill>, %ST1<imp-def>
// StackTop can be 1 if a FpSET_ST0_* was before this. Exchange them.
if (StackTop == 1) {
BuildMI(*MBB, I, dl, TII->get(X86::XCH_F)).addReg(X86::ST1);
++NumFXCH;
StackTop = 0;
break;
}
assert(StackTop == 2 && "Stack should have two element on it to return!");
--StackTop; // "Forget" we have something on the top of stack!
break;
}
unsigned DestReg = getFPReg(MO0);
if (MI->killsRegister(X86::FP0+SrcReg)) {
// If the input operand is killed, we can just change the owner of the

View File

@ -1898,6 +1898,42 @@ bool X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
const TargetRegisterClass *SrcRC,
DebugLoc DL) const {
// Moving from ST(0) turns into FpGET_ST0_32 etc.
if (SrcReg == X86::ST0 || SrcReg == X86::ST1) {
// Copying from ST(0)/ST(1).
bool isST0 = SrcReg == X86::ST0;
unsigned Opc;
if (DestRC == &X86::RFP32RegClass)
Opc = isST0 ? X86::FpGET_ST0_32 : X86::FpGET_ST1_32;
else if (DestRC == &X86::RFP64RegClass)
Opc = isST0 ? X86::FpGET_ST0_64 : X86::FpGET_ST1_64;
else {
if (DestRC != &X86::RFP80RegClass)
return false;
Opc = isST0 ? X86::FpGET_ST0_80 : X86::FpGET_ST1_80;
}
BuildMI(MBB, MI, DL, get(Opc), DestReg);
return true;
}
// Moving to ST(0) turns into FpSET_ST0_32 etc.
if (DestReg == X86::ST0 || DestReg == X86::ST1) {
// Copying to ST(0) / ST(1).
bool isST0 = DestReg == X86::ST0;
unsigned Opc;
if (SrcRC == &X86::RFP32RegClass)
Opc = isST0 ? X86::FpSET_ST0_32 : X86::FpSET_ST1_32;
else if (SrcRC == &X86::RFP64RegClass)
Opc = isST0 ? X86::FpSET_ST0_64 : X86::FpSET_ST1_64;
else {
if (SrcRC != &X86::RFP80RegClass)
return false;
Opc = isST0 ? X86::FpSET_ST0_80 : X86::FpSET_ST1_80;
}
BuildMI(MBB, MI, DL, get(Opc)).addReg(SrcReg);
return true;
}
// Determine if DstRC and SrcRC have a common superclass in common.
const TargetRegisterClass *CommonRC = DestRC;
if (DestRC == SrcRC)
@ -1968,7 +2004,7 @@ bool X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
Opc = X86::MOV32rr_TC;
} else if (CommonRC == &X86::RFP32RegClass) {
Opc = X86::MOV_Fp3232;
} else if (CommonRC == &X86::RFP64RegClass || CommonRC == &X86::RSTRegClass) {
} else if (CommonRC == &X86::RFP64RegClass) {
Opc = X86::MOV_Fp6464;
} else if (CommonRC == &X86::RFP80RegClass) {
Opc = X86::MOV_Fp8080;
@ -2016,48 +2052,6 @@ bool X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
}
}
// Moving from ST(0) turns into FpGET_ST0_32 etc.
if (SrcRC == &X86::RSTRegClass) {
// Copying from ST(0)/ST(1).
if (SrcReg != X86::ST0 && SrcReg != X86::ST1)
// Can only copy from ST(0)/ST(1) right now
return false;
bool isST0 = SrcReg == X86::ST0;
unsigned Opc;
if (DestRC == &X86::RFP32RegClass)
Opc = isST0 ? X86::FpGET_ST0_32 : X86::FpGET_ST1_32;
else if (DestRC == &X86::RFP64RegClass)
Opc = isST0 ? X86::FpGET_ST0_64 : X86::FpGET_ST1_64;
else {
if (DestRC != &X86::RFP80RegClass)
return false;
Opc = isST0 ? X86::FpGET_ST0_80 : X86::FpGET_ST1_80;
}
BuildMI(MBB, MI, DL, get(Opc), DestReg);
return true;
}
// Moving to ST(0) turns into FpSET_ST0_32 etc.
if (DestRC == &X86::RSTRegClass) {
// Copying to ST(0) / ST(1).
if (DestReg != X86::ST0 && DestReg != X86::ST1)
// Can only copy to TOS right now
return false;
bool isST0 = DestReg == X86::ST0;
unsigned Opc;
if (SrcRC == &X86::RFP32RegClass)
Opc = isST0 ? X86::FpSET_ST0_32 : X86::FpSET_ST1_32;
else if (SrcRC == &X86::RFP64RegClass)
Opc = isST0 ? X86::FpSET_ST0_64 : X86::FpSET_ST1_64;
else {
if (SrcRC != &X86::RFP80RegClass)
return false;
Opc = isST0 ? X86::FpSET_ST0_80 : X86::FpSET_ST1_80;
}
BuildMI(MBB, MI, DL, get(Opc)).addReg(SrcReg);
return true;
}
// Not yet supported!
return false;
}