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/Pass.h" |
24 | |
25 | using namespace llvm; |
26 | |
27 | static cl::opt<unsigned> MaxLoopRange( |
28 | "hexagon-loop-range" , cl::Hidden, cl::init(Val: 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 | |
41 | HexagonFixupHwLoops() : MachineFunctionPass(ID) { |
42 | initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry()); |
43 | } |
44 | |
45 | bool runOnMachineFunction(MachineFunction &MF) override; |
46 | |
47 | MachineFunctionProperties getRequiredProperties() const override { |
48 | return MachineFunctionProperties().set( |
49 | MachineFunctionProperties::Property::NoVRegs); |
50 | } |
51 | |
52 | StringRef getPassName() const override { |
53 | return "Hexagon Hardware Loop Fixup" ; |
54 | } |
55 | |
56 | 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 | |
79 | FunctionPass *llvm::createHexagonFixupHwLoops() { |
80 | return new HexagonFixupHwLoops(); |
81 | } |
82 | |
83 | /// Returns true if the instruction is a hardware loop instruction. |
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 | |
91 | bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) { |
92 | if (skipFunction(F: 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. |
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() != Align(1)) { |
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 | InstOffset = alignTo(Size: InstOffset, A: MBB.getAlignment()); |
122 | } |
123 | |
124 | BlockToInstOffset[&MBB] = InstOffset; |
125 | for (const MachineInstr &MI : MBB) |
126 | InstOffset += HII->getSize(MI); |
127 | } |
128 | |
129 | // Second pass - check each loop instruction to see if it needs to be |
130 | // converted. |
131 | bool Changed = false; |
132 | for (MachineBasicBlock &MBB : MF) { |
133 | InstOffset = BlockToInstOffset[&MBB]; |
134 | |
135 | // Loop over all the instructions. |
136 | MachineBasicBlock::iterator MII = MBB.begin(); |
137 | MachineBasicBlock::iterator MIE = MBB.end(); |
138 | while (MII != MIE) { |
139 | unsigned InstSize = HII->getSize(MI: *MII); |
140 | if (MII->isMetaInstruction()) { |
141 | ++MII; |
142 | continue; |
143 | } |
144 | if (isHardwareLoop(MI: *MII)) { |
145 | assert(MII->getOperand(0).isMBB() && |
146 | "Expect a basic block as loop operand" ); |
147 | MachineBasicBlock *TargetBB = MII->getOperand(i: 0).getMBB(); |
148 | unsigned Diff = AbsoluteDifference(X: InstOffset, |
149 | Y: BlockToInstOffset[TargetBB]); |
150 | if (Diff > MaxLoopRange) { |
151 | useExtLoopInstr(MF, MII); |
152 | MII = MBB.erase(I: MII); |
153 | Changed = true; |
154 | } else { |
155 | ++MII; |
156 | } |
157 | } else { |
158 | ++MII; |
159 | } |
160 | InstOffset += InstSize; |
161 | } |
162 | } |
163 | |
164 | return Changed; |
165 | } |
166 | |
167 | /// Replace loop instructions with the constant extended version. |
168 | void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF, |
169 | MachineBasicBlock::iterator &MII) { |
170 | const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); |
171 | MachineBasicBlock *MBB = MII->getParent(); |
172 | DebugLoc DL = MII->getDebugLoc(); |
173 | MachineInstrBuilder MIB; |
174 | unsigned newOp; |
175 | switch (MII->getOpcode()) { |
176 | case Hexagon::J2_loop0r: |
177 | newOp = Hexagon::J2_loop0rext; |
178 | break; |
179 | case Hexagon::J2_loop0i: |
180 | newOp = Hexagon::J2_loop0iext; |
181 | break; |
182 | case Hexagon::J2_loop1r: |
183 | newOp = Hexagon::J2_loop1rext; |
184 | break; |
185 | case Hexagon::J2_loop1i: |
186 | newOp = Hexagon::J2_loop1iext; |
187 | break; |
188 | default: |
189 | llvm_unreachable("Invalid Hardware Loop Instruction." ); |
190 | } |
191 | MIB = BuildMI(BB&: *MBB, I: MII, MIMD: DL, MCID: TII->get(Opcode: newOp)); |
192 | |
193 | for (unsigned i = 0; i < MII->getNumOperands(); ++i) |
194 | MIB.add(MO: MII->getOperand(i)); |
195 | } |
196 | |