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