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