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