1 //===-- FPMover.cpp - Sparc double-precision floating point move fixer ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Expand FpMOVD/FpABSD/FpNEGD instructions into their single-precision pieces. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #define DEBUG_TYPE "fpmover" 15 #include "Sparc.h" 16 #include "SparcSubtarget.h" 17 #include "llvm/CodeGen/MachineFunctionPass.h" 18 #include "llvm/CodeGen/MachineInstrBuilder.h" 19 #include "llvm/Target/TargetMachine.h" 20 #include "llvm/Target/TargetInstrInfo.h" 21 #include "llvm/ADT/Statistic.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/ErrorHandling.h" 24 #include "llvm/Support/raw_ostream.h" 25 using namespace llvm; 26 27 STATISTIC(NumFpDs , "Number of instructions translated"); 28 STATISTIC(NoopFpDs, "Number of noop instructions removed"); 29 30 namespace { 31 struct FPMover : public MachineFunctionPass { 32 /// Target machine description which we query for reg. names, data 33 /// layout, etc. 34 /// 35 TargetMachine &TM; 36 37 static char ID; 38 explicit FPMover(TargetMachine &tm) 39 : MachineFunctionPass(ID), TM(tm) { } 40 41 virtual const char *getPassName() const { 42 return "Sparc Double-FP Move Fixer"; 43 } 44 45 bool runOnMachineBasicBlock(MachineBasicBlock &MBB); 46 bool runOnMachineFunction(MachineFunction &F); 47 }; 48 char FPMover::ID = 0; 49 } // end of anonymous namespace 50 51 /// createSparcFPMoverPass - Returns a pass that turns FpMOVD 52 /// instructions into FMOVS instructions 53 /// 54 FunctionPass *llvm::createSparcFPMoverPass(TargetMachine &tm) { 55 return new FPMover(tm); 56 } 57 58 /// getDoubleRegPair - Given a DFP register, return the even and odd FP 59 /// registers that correspond to it. 60 static void getDoubleRegPair(unsigned DoubleReg, unsigned &EvenReg, 61 unsigned &OddReg) { 62 static const unsigned EvenHalvesOfPairs[] = { 63 SP::F0, SP::F2, SP::F4, SP::F6, SP::F8, SP::F10, SP::F12, SP::F14, 64 SP::F16, SP::F18, SP::F20, SP::F22, SP::F24, SP::F26, SP::F28, SP::F30 65 }; 66 static const unsigned OddHalvesOfPairs[] = { 67 SP::F1, SP::F3, SP::F5, SP::F7, SP::F9, SP::F11, SP::F13, SP::F15, 68 SP::F17, SP::F19, SP::F21, SP::F23, SP::F25, SP::F27, SP::F29, SP::F31 69 }; 70 static const unsigned DoubleRegsInOrder[] = { 71 SP::D0, SP::D1, SP::D2, SP::D3, SP::D4, SP::D5, SP::D6, SP::D7, SP::D8, 72 SP::D9, SP::D10, SP::D11, SP::D12, SP::D13, SP::D14, SP::D15 73 }; 74 for (unsigned i = 0; i < sizeof(DoubleRegsInOrder)/sizeof(unsigned); ++i) 75 if (DoubleRegsInOrder[i] == DoubleReg) { 76 EvenReg = EvenHalvesOfPairs[i]; 77 OddReg = OddHalvesOfPairs[i]; 78 return; 79 } 80 llvm_unreachable("Can't find reg"); 81 } 82 83 /// runOnMachineBasicBlock - Fixup FpMOVD instructions in this MBB. 84 /// 85 bool FPMover::runOnMachineBasicBlock(MachineBasicBlock &MBB) { 86 bool Changed = false; 87 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { 88 MachineInstr *MI = I++; 89 DebugLoc dl = MI->getDebugLoc(); 90 if (MI->getOpcode() == SP::FpMOVD || MI->getOpcode() == SP::FpABSD || 91 MI->getOpcode() == SP::FpNEGD) { 92 Changed = true; 93 unsigned DestDReg = MI->getOperand(0).getReg(); 94 unsigned SrcDReg = MI->getOperand(1).getReg(); 95 if (DestDReg == SrcDReg && MI->getOpcode() == SP::FpMOVD) { 96 MBB.erase(MI); // Eliminate the noop copy. 97 ++NoopFpDs; 98 continue; 99 } 100 101 unsigned EvenSrcReg = 0, OddSrcReg = 0, EvenDestReg = 0, OddDestReg = 0; 102 getDoubleRegPair(DestDReg, EvenDestReg, OddDestReg); 103 getDoubleRegPair(SrcDReg, EvenSrcReg, OddSrcReg); 104 105 const TargetInstrInfo *TII = TM.getInstrInfo(); 106 if (MI->getOpcode() == SP::FpMOVD) 107 MI->setDesc(TII->get(SP::FMOVS)); 108 else if (MI->getOpcode() == SP::FpNEGD) 109 MI->setDesc(TII->get(SP::FNEGS)); 110 else if (MI->getOpcode() == SP::FpABSD) 111 MI->setDesc(TII->get(SP::FABSS)); 112 else 113 llvm_unreachable("Unknown opcode!"); 114 115 MI->getOperand(0).setReg(EvenDestReg); 116 MI->getOperand(1).setReg(EvenSrcReg); 117 DEBUG(errs() << "FPMover: the modified instr is: " << *MI); 118 // Insert copy for the other half of the double. 119 if (DestDReg != SrcDReg) { 120 MI = BuildMI(MBB, I, dl, TM.getInstrInfo()->get(SP::FMOVS), OddDestReg) 121 .addReg(OddSrcReg); 122 DEBUG(errs() << "FPMover: the inserted instr is: " << *MI); 123 } 124 ++NumFpDs; 125 } 126 } 127 return Changed; 128 } 129 130 bool FPMover::runOnMachineFunction(MachineFunction &F) { 131 // If the target has V9 instructions, the fp-mover pseudos will never be 132 // emitted. Avoid a scan of the instructions to improve compile time. 133 if (TM.getSubtarget<SparcSubtarget>().isV9()) 134 return false; 135 136 bool Changed = false; 137 for (MachineFunction::iterator FI = F.begin(), FE = F.end(); 138 FI != FE; ++FI) 139 Changed |= runOnMachineBasicBlock(*FI); 140 return Changed; 141 } 142