From: Jakob Stoklund Olesen Date: Sat, 10 Jul 2010 17:42:34 +0000 (+0000) Subject: Don't emit st(0)/st(1) copies as FpMOV instructions. Use FpSET_ST? instead. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=2b336bc4fed0812db24ead970f4d1ac0562af563;p=oota-llvm.git 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! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108047 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/X86FloatingPoint.cpp b/lib/Target/X86/X86FloatingPoint.cpp index bf60c882dd3..cee4ad70201 100644 --- a/lib/Target/X86/X86FloatingPoint.cpp +++ b/lib/Target/X86/X86FloatingPoint.cpp @@ -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 = MOV_Fp8080 %FP0 - // like FpSET_ST0_80 %FP0, %ST0 - 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 = MOV_Fp8080 %FP1 - // like FpSET_ST1_80 %FP0, %ST1 - // 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 diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index f277774dfba..63eb38f848a 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -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; }