xref: /minix3/external/bsd/llvm/dist/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc // The loop start address in the LOOPn instruction is encoded as a distance
9f4a2713aSLionel Sambuc // from the LOOPn instruction itself.  If the start address is too far from
10f4a2713aSLionel Sambuc // the LOOPn instruction, the loop needs to be set up manually, i.e. via
11f4a2713aSLionel Sambuc // direct transfers to SAn and LCn.
12f4a2713aSLionel Sambuc // This pass will identify and convert such LOOPn instructions to a proper
13f4a2713aSLionel Sambuc // form.
14f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
15f4a2713aSLionel Sambuc 
16f4a2713aSLionel Sambuc 
17f4a2713aSLionel Sambuc #include "llvm/ADT/DenseMap.h"
18*0a6a1f1dSLionel Sambuc #include "Hexagon.h"
19*0a6a1f1dSLionel Sambuc #include "HexagonTargetMachine.h"
20f4a2713aSLionel Sambuc #include "llvm/CodeGen/MachineFunction.h"
21f4a2713aSLionel Sambuc #include "llvm/CodeGen/MachineFunctionPass.h"
22f4a2713aSLionel Sambuc #include "llvm/CodeGen/MachineInstrBuilder.h"
23f4a2713aSLionel Sambuc #include "llvm/CodeGen/Passes.h"
24f4a2713aSLionel Sambuc #include "llvm/CodeGen/RegisterScavenging.h"
25f4a2713aSLionel Sambuc #include "llvm/PassSupport.h"
26f4a2713aSLionel Sambuc #include "llvm/Target/TargetInstrInfo.h"
27f4a2713aSLionel Sambuc 
28f4a2713aSLionel Sambuc using namespace llvm;
29f4a2713aSLionel Sambuc 
30f4a2713aSLionel Sambuc namespace llvm {
31f4a2713aSLionel Sambuc   void initializeHexagonFixupHwLoopsPass(PassRegistry&);
32f4a2713aSLionel Sambuc }
33f4a2713aSLionel Sambuc 
34f4a2713aSLionel Sambuc namespace {
35f4a2713aSLionel Sambuc   struct HexagonFixupHwLoops : public MachineFunctionPass {
36f4a2713aSLionel Sambuc   public:
37f4a2713aSLionel Sambuc     static char ID;
38f4a2713aSLionel Sambuc 
HexagonFixupHwLoops__anon1566fb340111::HexagonFixupHwLoops39f4a2713aSLionel Sambuc     HexagonFixupHwLoops() : MachineFunctionPass(ID) {
40f4a2713aSLionel Sambuc       initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
41f4a2713aSLionel Sambuc     }
42f4a2713aSLionel Sambuc 
43*0a6a1f1dSLionel Sambuc     bool runOnMachineFunction(MachineFunction &MF) override;
44f4a2713aSLionel Sambuc 
getPassName__anon1566fb340111::HexagonFixupHwLoops45*0a6a1f1dSLionel Sambuc     const char *getPassName() const override {
46*0a6a1f1dSLionel Sambuc       return "Hexagon Hardware Loop Fixup";
47*0a6a1f1dSLionel Sambuc     }
48f4a2713aSLionel Sambuc 
getAnalysisUsage__anon1566fb340111::HexagonFixupHwLoops49*0a6a1f1dSLionel Sambuc     void getAnalysisUsage(AnalysisUsage &AU) const override {
50f4a2713aSLionel Sambuc       AU.setPreservesCFG();
51f4a2713aSLionel Sambuc       MachineFunctionPass::getAnalysisUsage(AU);
52f4a2713aSLionel Sambuc     }
53f4a2713aSLionel Sambuc 
54f4a2713aSLionel Sambuc   private:
55f4a2713aSLionel Sambuc     /// \brief Maximum distance between the loop instr and the basic block.
56f4a2713aSLionel Sambuc     /// Just an estimate.
57f4a2713aSLionel Sambuc     static const unsigned MAX_LOOP_DISTANCE = 200;
58f4a2713aSLionel Sambuc 
59f4a2713aSLionel Sambuc     /// \brief Check the offset between each loop instruction and
60f4a2713aSLionel Sambuc     /// the loop basic block to determine if we can use the LOOP instruction
61f4a2713aSLionel Sambuc     /// or if we need to set the LC/SA registers explicitly.
62f4a2713aSLionel Sambuc     bool fixupLoopInstrs(MachineFunction &MF);
63f4a2713aSLionel Sambuc 
64f4a2713aSLionel Sambuc     /// \brief Add the instruction to set the LC and SA registers explicitly.
65f4a2713aSLionel Sambuc     void convertLoopInstr(MachineFunction &MF,
66f4a2713aSLionel Sambuc                           MachineBasicBlock::iterator &MII,
67f4a2713aSLionel Sambuc                           RegScavenger &RS);
68f4a2713aSLionel Sambuc 
69f4a2713aSLionel Sambuc   };
70f4a2713aSLionel Sambuc 
71f4a2713aSLionel Sambuc   char HexagonFixupHwLoops::ID = 0;
72f4a2713aSLionel Sambuc }
73f4a2713aSLionel Sambuc 
74f4a2713aSLionel Sambuc INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
75f4a2713aSLionel Sambuc                 "Hexagon Hardware Loops Fixup", false, false)
76f4a2713aSLionel Sambuc 
createHexagonFixupHwLoops()77f4a2713aSLionel Sambuc FunctionPass *llvm::createHexagonFixupHwLoops() {
78f4a2713aSLionel Sambuc   return new HexagonFixupHwLoops();
79f4a2713aSLionel Sambuc }
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc 
82f4a2713aSLionel Sambuc /// \brief Returns true if the instruction is a hardware loop instruction.
isHardwareLoop(const MachineInstr * MI)83f4a2713aSLionel Sambuc static bool isHardwareLoop(const MachineInstr *MI) {
84*0a6a1f1dSLionel Sambuc   return MI->getOpcode() == Hexagon::J2_loop0r ||
85*0a6a1f1dSLionel Sambuc          MI->getOpcode() == Hexagon::J2_loop0i;
86f4a2713aSLionel Sambuc }
87f4a2713aSLionel Sambuc 
88f4a2713aSLionel Sambuc 
runOnMachineFunction(MachineFunction & MF)89f4a2713aSLionel Sambuc bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
90f4a2713aSLionel Sambuc   bool Changed = fixupLoopInstrs(MF);
91f4a2713aSLionel Sambuc   return Changed;
92f4a2713aSLionel Sambuc }
93f4a2713aSLionel Sambuc 
94f4a2713aSLionel Sambuc 
95f4a2713aSLionel Sambuc /// \brief For Hexagon, if the loop label is to far from the
96f4a2713aSLionel Sambuc /// loop instruction then we need to set the LC0 and SA0 registers
97f4a2713aSLionel Sambuc /// explicitly instead of using LOOP(start,count).  This function
98f4a2713aSLionel Sambuc /// checks the distance, and generates register assignments if needed.
99f4a2713aSLionel Sambuc ///
100f4a2713aSLionel Sambuc /// This function makes two passes over the basic blocks.  The first
101f4a2713aSLionel Sambuc /// pass computes the offset of the basic block from the start.
102f4a2713aSLionel Sambuc /// The second pass checks all the loop instructions.
fixupLoopInstrs(MachineFunction & MF)103f4a2713aSLionel Sambuc bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
104f4a2713aSLionel Sambuc 
105f4a2713aSLionel Sambuc   // Offset of the current instruction from the start.
106f4a2713aSLionel Sambuc   unsigned InstOffset = 0;
107f4a2713aSLionel Sambuc   // Map for each basic block to it's first instruction.
108f4a2713aSLionel Sambuc   DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
109f4a2713aSLionel Sambuc 
110f4a2713aSLionel Sambuc   // First pass - compute the offset of each basic block.
111f4a2713aSLionel Sambuc   for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
112f4a2713aSLionel Sambuc        MBB != MBBe; ++MBB) {
113f4a2713aSLionel Sambuc     BlockToInstOffset[MBB] = InstOffset;
114f4a2713aSLionel Sambuc     InstOffset += (MBB->size() * 4);
115f4a2713aSLionel Sambuc   }
116f4a2713aSLionel Sambuc 
117f4a2713aSLionel Sambuc   // Second pass - check each loop instruction to see if it needs to
118f4a2713aSLionel Sambuc   // be converted.
119f4a2713aSLionel Sambuc   InstOffset = 0;
120f4a2713aSLionel Sambuc   bool Changed = false;
121f4a2713aSLionel Sambuc   RegScavenger RS;
122f4a2713aSLionel Sambuc 
123f4a2713aSLionel Sambuc   // Loop over all the basic blocks.
124f4a2713aSLionel Sambuc   for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
125f4a2713aSLionel Sambuc        MBB != MBBe; ++MBB) {
126f4a2713aSLionel Sambuc     InstOffset = BlockToInstOffset[MBB];
127f4a2713aSLionel Sambuc     RS.enterBasicBlock(MBB);
128f4a2713aSLionel Sambuc 
129f4a2713aSLionel Sambuc     // Loop over all the instructions.
130f4a2713aSLionel Sambuc     MachineBasicBlock::iterator MIE = MBB->end();
131f4a2713aSLionel Sambuc     MachineBasicBlock::iterator MII = MBB->begin();
132f4a2713aSLionel Sambuc     while (MII != MIE) {
133f4a2713aSLionel Sambuc       if (isHardwareLoop(MII)) {
134f4a2713aSLionel Sambuc         RS.forward(MII);
135f4a2713aSLionel Sambuc         assert(MII->getOperand(0).isMBB() &&
136f4a2713aSLionel Sambuc                "Expect a basic block as loop operand");
137f4a2713aSLionel Sambuc         int Sub = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
138f4a2713aSLionel Sambuc         unsigned Dist = Sub > 0 ? Sub : -Sub;
139f4a2713aSLionel Sambuc         if (Dist > MAX_LOOP_DISTANCE) {
140f4a2713aSLionel Sambuc           // Convert to explicity setting LC0 and SA0.
141f4a2713aSLionel Sambuc           convertLoopInstr(MF, MII, RS);
142f4a2713aSLionel Sambuc           MII = MBB->erase(MII);
143f4a2713aSLionel Sambuc           Changed = true;
144f4a2713aSLionel Sambuc         } else {
145f4a2713aSLionel Sambuc           ++MII;
146f4a2713aSLionel Sambuc         }
147f4a2713aSLionel Sambuc       } else {
148f4a2713aSLionel Sambuc         ++MII;
149f4a2713aSLionel Sambuc       }
150f4a2713aSLionel Sambuc       InstOffset += 4;
151f4a2713aSLionel Sambuc     }
152f4a2713aSLionel Sambuc   }
153f4a2713aSLionel Sambuc 
154f4a2713aSLionel Sambuc   return Changed;
155f4a2713aSLionel Sambuc }
156f4a2713aSLionel Sambuc 
157f4a2713aSLionel Sambuc 
158f4a2713aSLionel Sambuc /// \brief convert a loop instruction to a sequence of instructions that
159f4a2713aSLionel Sambuc /// set the LC0 and SA0 register explicitly.
convertLoopInstr(MachineFunction & MF,MachineBasicBlock::iterator & MII,RegScavenger & RS)160f4a2713aSLionel Sambuc void HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
161f4a2713aSLionel Sambuc                                            MachineBasicBlock::iterator &MII,
162f4a2713aSLionel Sambuc                                            RegScavenger &RS) {
163*0a6a1f1dSLionel Sambuc   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
164f4a2713aSLionel Sambuc   MachineBasicBlock *MBB = MII->getParent();
165f4a2713aSLionel Sambuc   DebugLoc DL = MII->getDebugLoc();
166f4a2713aSLionel Sambuc   unsigned Scratch = RS.scavengeRegister(&Hexagon::IntRegsRegClass, MII, 0);
167f4a2713aSLionel Sambuc 
168f4a2713aSLionel Sambuc   // First, set the LC0 with the trip count.
169f4a2713aSLionel Sambuc   if (MII->getOperand(1).isReg()) {
170f4a2713aSLionel Sambuc     // Trip count is a register
171*0a6a1f1dSLionel Sambuc     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
172f4a2713aSLionel Sambuc       .addReg(MII->getOperand(1).getReg());
173f4a2713aSLionel Sambuc   } else {
174f4a2713aSLionel Sambuc     // Trip count is an immediate.
175*0a6a1f1dSLionel Sambuc     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrsi), Scratch)
176f4a2713aSLionel Sambuc       .addImm(MII->getOperand(1).getImm());
177*0a6a1f1dSLionel Sambuc     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
178f4a2713aSLionel Sambuc       .addReg(Scratch);
179f4a2713aSLionel Sambuc   }
180f4a2713aSLionel Sambuc   // Then, set the SA0 with the loop start address.
181f4a2713aSLionel Sambuc   BuildMI(*MBB, MII, DL, TII->get(Hexagon::CONST32_Label), Scratch)
182f4a2713aSLionel Sambuc     .addMBB(MII->getOperand(0).getMBB());
183*0a6a1f1dSLionel Sambuc   BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::SA0)
184f4a2713aSLionel Sambuc     .addReg(Scratch);
185f4a2713aSLionel Sambuc }
186