LLVM 22.0.0git
HexagonFixupHwLoops.cpp
Go to the documentation of this file.
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"
16#include "llvm/ADT/DenseMap.h"
20#include "llvm/CodeGen/Passes.h"
23#include "llvm/Pass.h"
24
25using namespace llvm;
26
28 "hexagon-loop-range", cl::Hidden, cl::init(200),
29 cl::desc("Restrict range of loopN instructions (testing only)"));
30
31namespace {
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();
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,
63 };
64
65 char HexagonFixupHwLoops::ID = 0;
66}
67
68INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
69 "Hexagon Hardware Loops Fixup", false, false)
70
72 return new HexagonFixupHwLoops();
73}
74
75/// Returns true if the instruction is a hardware loop instruction.
76static 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
83bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
84 if (skipFunction(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.
97bool 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(InstOffset, 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.
130 while (MII != MIE) {
131 unsigned InstSize = HII->getSize(*MII);
132 if (MII->isMetaInstruction()) {
133 ++MII;
134 continue;
135 }
136 if (isHardwareLoop(*MII)) {
137 assert(MII->getOperand(0).isMBB() &&
138 "Expect a basic block as loop operand");
139 MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB();
140 unsigned Diff = AbsoluteDifference(InstOffset,
141 BlockToInstOffset[TargetBB]);
142 if (Diff > MaxLoopRange) {
143 useExtLoopInstr(MF, MII);
144 MII = MBB.erase(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.
160void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
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(*MBB, MII, DL, TII->get(newOp));
184
185 for (unsigned i = 0; i < MII->getNumOperands(); ++i)
186 MIB.add(MII->getOperand(i));
187}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file defines the DenseMap class.
const HexagonInstrInfo * TII
static cl::opt< unsigned > MaxLoopRange("hexagon-loop-range", cl::Hidden, cl::init(200), cl::desc("Restrict range of loopN instructions (testing only)"))
static bool isHardwareLoop(const MachineInstr &MI)
Returns true if the instruction is a hardware loop instruction.
IRTranslator LLVM IR MI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
unsigned getSize(const MachineInstr &MI) const
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
Align getAlignment() const
Return alignment of the basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
virtual const TargetInstrInfo * getInstrInfo() const
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createHexagonFixupHwLoops()
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:155
constexpr T AbsoluteDifference(U X, V Y)
Subtract two unsigned integers, X and Y, of type T and return the absolute value of the result.
Definition MathExtras.h:605