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