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 { |
32 | struct HexagonFixupHwLoops : public MachineFunctionPass { |
33 | public: |
34 | static char ID; |
35 | |
36 | HexagonFixupHwLoops() : MachineFunctionPass(ID) {} |
37 | |
38 | bool runOnMachineFunction(MachineFunction &MF) override; |
39 | |
40 | MachineFunctionProperties getRequiredProperties() const override { |
41 | return MachineFunctionProperties().setNoVRegs(); |
42 | } |
43 | |
44 | StringRef getPassName() const override { |
45 | return "Hexagon Hardware Loop Fixup" ; |
46 | } |
47 | |
48 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
49 | AU.setPreservesCFG(); |
50 | MachineFunctionPass::getAnalysisUsage(AU); |
51 | } |
52 | |
53 | private: |
54 | /// Check the offset between each loop instruction and |
55 | /// the loop basic block to determine if we can use the LOOP instruction |
56 | /// or if we need to set the LC/SA registers explicitly. |
57 | bool fixupLoopInstrs(MachineFunction &MF); |
58 | |
59 | /// Replace loop instruction with the constant extended |
60 | /// version if the loop label is too far from the loop instruction. |
61 | void useExtLoopInstr(MachineFunction &MF, |
62 | MachineBasicBlock::iterator &MII); |
63 | }; |
64 | |
65 | char HexagonFixupHwLoops::ID = 0; |
66 | } |
67 | |
68 | INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup" , |
69 | "Hexagon Hardware Loops Fixup" , false, false) |
70 | |
71 | FunctionPass *llvm::createHexagonFixupHwLoops() { |
72 | return new HexagonFixupHwLoops(); |
73 | } |
74 | |
75 | /// Returns true if the instruction is a hardware loop instruction. |
76 | static bool isHardwareLoop(const MachineInstr &MI) { |
77 | return MI.getOpcode() == Hexagon::J2_loop0r || |
78 | MI.getOpcode() == Hexagon::J2_loop0i || |
79 | MI.getOpcode() == Hexagon::J2_loop1r || |
80 | MI.getOpcode() == Hexagon::J2_loop1i; |
81 | } |
82 | |
83 | bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) { |
84 | if (skipFunction(F: MF.getFunction())) |
85 | return false; |
86 | return fixupLoopInstrs(MF); |
87 | } |
88 | |
89 | /// For Hexagon, if the loop label is to far from the |
90 | /// loop instruction then we need to set the LC0 and SA0 registers |
91 | /// explicitly instead of using LOOP(start,count). This function |
92 | /// checks the distance, and generates register assignments if needed. |
93 | /// |
94 | /// This function makes two passes over the basic blocks. The first |
95 | /// pass computes the offset of the basic block from the start. |
96 | /// The second pass checks all the loop instructions. |
97 | bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) { |
98 | |
99 | // Offset of the current instruction from the start. |
100 | unsigned InstOffset = 0; |
101 | // Map for each basic block to it's first instruction. |
102 | DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset; |
103 | |
104 | const HexagonInstrInfo *HII = |
105 | static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
106 | |
107 | // First pass - compute the offset of each basic block. |
108 | for (const MachineBasicBlock &MBB : MF) { |
109 | if (MBB.getAlignment() != Align(1)) { |
110 | // Although we don't know the exact layout of the final code, we need |
111 | // to account for alignment padding somehow. This heuristic pads each |
112 | // aligned basic block according to the alignment value. |
113 | InstOffset = alignTo(Size: InstOffset, A: MBB.getAlignment()); |
114 | } |
115 | |
116 | BlockToInstOffset[&MBB] = InstOffset; |
117 | for (const MachineInstr &MI : MBB) |
118 | InstOffset += HII->getSize(MI); |
119 | } |
120 | |
121 | // Second pass - check each loop instruction to see if it needs to be |
122 | // converted. |
123 | bool Changed = false; |
124 | for (MachineBasicBlock &MBB : MF) { |
125 | InstOffset = BlockToInstOffset[&MBB]; |
126 | |
127 | // Loop over all the instructions. |
128 | MachineBasicBlock::iterator MII = MBB.begin(); |
129 | MachineBasicBlock::iterator MIE = MBB.end(); |
130 | while (MII != MIE) { |
131 | unsigned InstSize = HII->getSize(MI: *MII); |
132 | if (MII->isMetaInstruction()) { |
133 | ++MII; |
134 | continue; |
135 | } |
136 | if (isHardwareLoop(MI: *MII)) { |
137 | assert(MII->getOperand(0).isMBB() && |
138 | "Expect a basic block as loop operand" ); |
139 | MachineBasicBlock *TargetBB = MII->getOperand(i: 0).getMBB(); |
140 | unsigned Diff = AbsoluteDifference(X: InstOffset, |
141 | Y: BlockToInstOffset[TargetBB]); |
142 | if (Diff > MaxLoopRange) { |
143 | useExtLoopInstr(MF, MII); |
144 | MII = MBB.erase(I: MII); |
145 | Changed = true; |
146 | } else { |
147 | ++MII; |
148 | } |
149 | } else { |
150 | ++MII; |
151 | } |
152 | InstOffset += InstSize; |
153 | } |
154 | } |
155 | |
156 | return Changed; |
157 | } |
158 | |
159 | /// 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(BB&: *MBB, I: MII, MIMD: DL, MCID: TII->get(Opcode: newOp)); |
184 | |
185 | for (unsigned i = 0; i < MII->getNumOperands(); ++i) |
186 | MIB.add(MO: MII->getOperand(i)); |
187 | } |
188 | |