[Hexagon] Use constant extenders to fix up hardware loops
[oota-llvm.git] / lib / Target / Hexagon / HexagonFixupHwLoops.cpp
1 //===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
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 // The loop start address in the LOOPn instruction is encoded as a distance
9 // from the LOOPn instruction itself. If the start address is too far from
10 // the LOOPn instruction, the instruction needs to use a constant extender.
11 // This pass will identify and convert such LOOPn instructions to a proper
12 // form.
13 //===----------------------------------------------------------------------===//
14
15
16 #include "llvm/ADT/DenseMap.h"
17 #include "Hexagon.h"
18 #include "HexagonTargetMachine.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/Passes.h"
23 #include "llvm/PassSupport.h"
24 #include "llvm/Target/TargetInstrInfo.h"
25
26 using namespace llvm;
27
28 static cl::opt<unsigned> MaxLoopRange(
29     "hexagon-loop-range", cl::Hidden, cl::init(200),
30     cl::desc("Restrict range of loopN instructions (testing only)"));
31
32 namespace llvm {
33   void initializeHexagonFixupHwLoopsPass(PassRegistry&);
34 }
35
36 namespace {
37   struct HexagonFixupHwLoops : public MachineFunctionPass {
38   public:
39     static char ID;
40
41     HexagonFixupHwLoops() : MachineFunctionPass(ID) {
42       initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
43     }
44
45     bool runOnMachineFunction(MachineFunction &MF) override;
46
47     const char *getPassName() const override {
48       return "Hexagon Hardware Loop Fixup";
49     }
50
51     void getAnalysisUsage(AnalysisUsage &AU) const override {
52       AU.setPreservesCFG();
53       MachineFunctionPass::getAnalysisUsage(AU);
54     }
55
56   private:
57     /// \brief Check the offset between each loop instruction and
58     /// the loop basic block to determine if we can use the LOOP instruction
59     /// or if we need to set the LC/SA registers explicitly.
60     bool fixupLoopInstrs(MachineFunction &MF);
61
62     /// \brief Replace loop instruction with the constant extended
63     /// version if the loop label is too far from the loop instruction.
64     void useExtLoopInstr(MachineFunction &MF,
65                          MachineBasicBlock::iterator &MII);
66   };
67
68   char HexagonFixupHwLoops::ID = 0;
69 }
70
71 INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
72                 "Hexagon Hardware Loops Fixup", false, false)
73
74 FunctionPass *llvm::createHexagonFixupHwLoops() {
75   return new HexagonFixupHwLoops();
76 }
77
78 /// \brief Returns true if the instruction is a hardware loop instruction.
79 static bool isHardwareLoop(const MachineInstr *MI) {
80   return MI->getOpcode() == Hexagon::J2_loop0r ||
81          MI->getOpcode() == Hexagon::J2_loop0i ||
82          MI->getOpcode() == Hexagon::J2_loop1r ||
83          MI->getOpcode() == Hexagon::J2_loop1i;
84 }
85
86 bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
87   return fixupLoopInstrs(MF);
88 }
89
90 /// \brief For Hexagon, if the loop label is to far from the
91 /// loop instruction then we need to set the LC0 and SA0 registers
92 /// explicitly instead of using LOOP(start,count).  This function
93 /// checks the distance, and generates register assignments if needed.
94 ///
95 /// This function makes two passes over the basic blocks.  The first
96 /// pass computes the offset of the basic block from the start.
97 /// The second pass checks all the loop instructions.
98 bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
99
100   // Offset of the current instruction from the start.
101   unsigned InstOffset = 0;
102   // Map for each basic block to it's first instruction.
103   DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;
104
105   const HexagonInstrInfo *HII =
106       static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
107
108   // First pass - compute the offset of each basic block.
109   for (const MachineBasicBlock &MBB : MF) {
110     if (MBB.getAlignment()) {
111       // Although we don't know the exact layout of the final code, we need
112       // to account for alignment padding somehow. This heuristic pads each
113       // aligned basic block according to the alignment value.
114       int ByteAlign = (1u << MBB.getAlignment()) - 1;
115       InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
116     }
117
118     BlockToInstOffset[&MBB] = InstOffset;
119     for (const MachineInstr &MI : MBB)
120       InstOffset += HII->getSize(&MI);
121   }
122
123   // Second pass - check each loop instruction to see if it needs to be
124   // converted.
125   InstOffset = 0;
126   bool Changed = false;
127   for (MachineBasicBlock &MBB : MF) {
128     InstOffset = BlockToInstOffset[&MBB];
129
130     // Loop over all the instructions.
131     MachineBasicBlock::iterator MII = MBB.begin();
132     MachineBasicBlock::iterator MIE = MBB.end();
133     while (MII != MIE) {
134       InstOffset += HII->getSize(&*MII);
135       if (MII->isDebugValue()) {
136         ++MII;
137         continue;
138       }
139       if (isHardwareLoop(MII)) {
140         assert(MII->getOperand(0).isMBB() &&
141                "Expect a basic block as loop operand");
142         int diff = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
143         if ((unsigned)abs(diff) > MaxLoopRange) {
144           useExtLoopInstr(MF, MII);
145           MII = MBB.erase(MII);
146           Changed = true;
147         } else {
148           ++MII;
149         }
150       } else {
151         ++MII;
152       }
153     }
154   }
155
156   return Changed;
157 }
158
159 /// \brief Replace loop instructions with the constant extended version.
160 void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
161                                           MachineBasicBlock::iterator &MII) {
162   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
163   MachineBasicBlock *MBB = MII->getParent();
164   DebugLoc DL = MII->getDebugLoc();
165   MachineInstrBuilder MIB;
166   unsigned newOp;
167   switch (MII->getOpcode()) {
168   case Hexagon::J2_loop0r:
169     newOp = Hexagon::J2_loop0rext;
170     break;
171   case Hexagon::J2_loop0i:
172     newOp = Hexagon::J2_loop0iext;
173     break;
174   case Hexagon::J2_loop1r:
175     newOp = Hexagon::J2_loop1rext;
176     break;
177   case Hexagon::J2_loop1i:
178     newOp = Hexagon::J2_loop1iext;
179     break;
180   default:
181     llvm_unreachable("Invalid Hardware Loop Instruction.");
182   }
183   MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));
184
185   for (unsigned i = 0; i < MII->getNumOperands(); ++i)
186     MIB.addOperand(MII->getOperand(i));
187 }