1 //===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
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
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
12 //===----------------------------------------------------------------------===//
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"
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)"));
32 FunctionPass
*createHexagonFixupHwLoops();
33 void initializeHexagonFixupHwLoopsPass(PassRegistry
&);
37 struct HexagonFixupHwLoops
: public MachineFunctionPass
{
41 HexagonFixupHwLoops() : MachineFunctionPass(ID
) {
42 initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
45 bool runOnMachineFunction(MachineFunction
&MF
) override
;
47 MachineFunctionProperties
getRequiredProperties() const override
{
48 return MachineFunctionProperties().set(
49 MachineFunctionProperties::Property::NoVRegs
);
52 StringRef
getPassName() const override
{
53 return "Hexagon Hardware Loop Fixup";
56 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
58 MachineFunctionPass::getAnalysisUsage(AU
);
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
);
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
);
73 char HexagonFixupHwLoops::ID
= 0;
76 INITIALIZE_PASS(HexagonFixupHwLoops
, "hwloopsfixup",
77 "Hexagon Hardware Loops Fixup", false, false)
79 FunctionPass
*llvm::createHexagonFixupHwLoops() {
80 return new HexagonFixupHwLoops();
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
;
91 bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction
&MF
) {
92 if (skipFunction(MF
.getFunction()))
94 return fixupLoopInstrs(MF
);
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.
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
) {
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
;
112 const HexagonInstrInfo
*HII
=
113 static_cast<const HexagonInstrInfo
*>(MF
.getSubtarget().getInstrInfo());
115 // First pass - compute the offset of each basic block.
116 for (const MachineBasicBlock
&MBB
: MF
) {
117 if (MBB
.getAlignment() != Align::None()) {
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(InstOffset
, MBB
.getAlignment());
124 BlockToInstOffset
[&MBB
] = InstOffset
;
125 for (const MachineInstr
&MI
: MBB
)
126 InstOffset
+= HII
->getSize(MI
);
129 // Second pass - check each loop instruction to see if it needs to be
131 bool Changed
= false;
132 for (MachineBasicBlock
&MBB
: MF
) {
133 InstOffset
= BlockToInstOffset
[&MBB
];
135 // Loop over all the instructions.
136 MachineBasicBlock::iterator MII
= MBB
.begin();
137 MachineBasicBlock::iterator MIE
= MBB
.end();
139 unsigned InstSize
= HII
->getSize(*MII
);
140 if (MII
->isMetaInstruction()) {
144 if (isHardwareLoop(*MII
)) {
145 assert(MII
->getOperand(0).isMBB() &&
146 "Expect a basic block as loop operand");
147 MachineBasicBlock
*TargetBB
= MII
->getOperand(0).getMBB();
148 unsigned Diff
= AbsoluteDifference(InstOffset
,
149 BlockToInstOffset
[TargetBB
]);
150 if (Diff
> MaxLoopRange
) {
151 useExtLoopInstr(MF
, MII
);
152 MII
= MBB
.erase(MII
);
160 InstOffset
+= InstSize
;
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
;
175 switch (MII
->getOpcode()) {
176 case Hexagon::J2_loop0r
:
177 newOp
= Hexagon::J2_loop0rext
;
179 case Hexagon::J2_loop0i
:
180 newOp
= Hexagon::J2_loop0iext
;
182 case Hexagon::J2_loop1r
:
183 newOp
= Hexagon::J2_loop1rext
;
185 case Hexagon::J2_loop1i
:
186 newOp
= Hexagon::J2_loop1iext
;
189 llvm_unreachable("Invalid Hardware Loop Instruction.");
191 MIB
= BuildMI(*MBB
, MII
, DL
, TII
->get(newOp
));
193 for (unsigned i
= 0; i
< MII
->getNumOperands(); ++i
)
194 MIB
.add(MII
->getOperand(i
));