1249259Sdim//===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim// The loop start address in the LOOPn instruction is encoded as a distance
9249259Sdim// from the LOOPn instruction itself.  If the start address is too far from
10249259Sdim// the LOOPn instruction, the loop needs to be set up manually, i.e. via
11249259Sdim// direct transfers to SAn and LCn.
12249259Sdim// This pass will identify and convert such LOOPn instructions to a proper
13249259Sdim// form.
14249259Sdim//===----------------------------------------------------------------------===//
15249259Sdim
16249259Sdim
17249259Sdim#include "llvm/ADT/DenseMap.h"
18249259Sdim#include "llvm/CodeGen/MachineFunction.h"
19249259Sdim#include "llvm/CodeGen/MachineFunctionPass.h"
20249259Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
21249259Sdim#include "llvm/CodeGen/Passes.h"
22249259Sdim#include "llvm/CodeGen/RegisterScavenging.h"
23249259Sdim#include "llvm/PassSupport.h"
24249259Sdim#include "llvm/Target/TargetInstrInfo.h"
25249259Sdim#include "Hexagon.h"
26249259Sdim#include "HexagonTargetMachine.h"
27249259Sdim
28249259Sdimusing namespace llvm;
29249259Sdim
30249259Sdimnamespace llvm {
31249259Sdim  void initializeHexagonFixupHwLoopsPass(PassRegistry&);
32249259Sdim}
33249259Sdim
34249259Sdimnamespace {
35249259Sdim  struct HexagonFixupHwLoops : public MachineFunctionPass {
36249259Sdim  public:
37249259Sdim    static char ID;
38249259Sdim
39249259Sdim    HexagonFixupHwLoops() : MachineFunctionPass(ID) {
40249259Sdim      initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
41249259Sdim    }
42249259Sdim
43249259Sdim    virtual bool runOnMachineFunction(MachineFunction &MF);
44249259Sdim
45249259Sdim    const char *getPassName() const { return "Hexagon Hardware Loop Fixup"; }
46249259Sdim
47249259Sdim    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
48249259Sdim      AU.setPreservesCFG();
49249259Sdim      MachineFunctionPass::getAnalysisUsage(AU);
50249259Sdim    }
51249259Sdim
52249259Sdim  private:
53249259Sdim    /// \brief Maximum distance between the loop instr and the basic block.
54249259Sdim    /// Just an estimate.
55249259Sdim    static const unsigned MAX_LOOP_DISTANCE = 200;
56249259Sdim
57249259Sdim    /// \brief Check the offset between each loop instruction and
58249259Sdim    /// the loop basic block to determine if we can use the LOOP instruction
59249259Sdim    /// or if we need to set the LC/SA registers explicitly.
60249259Sdim    bool fixupLoopInstrs(MachineFunction &MF);
61249259Sdim
62249259Sdim    /// \brief Add the instruction to set the LC and SA registers explicitly.
63249259Sdim    void convertLoopInstr(MachineFunction &MF,
64249259Sdim                          MachineBasicBlock::iterator &MII,
65249259Sdim                          RegScavenger &RS);
66249259Sdim
67249259Sdim  };
68249259Sdim
69249259Sdim  char HexagonFixupHwLoops::ID = 0;
70249259Sdim}
71249259Sdim
72249259SdimINITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
73249259Sdim                "Hexagon Hardware Loops Fixup", false, false)
74249259Sdim
75249259SdimFunctionPass *llvm::createHexagonFixupHwLoops() {
76249259Sdim  return new HexagonFixupHwLoops();
77249259Sdim}
78249259Sdim
79249259Sdim
80249259Sdim/// \brief Returns true if the instruction is a hardware loop instruction.
81249259Sdimstatic bool isHardwareLoop(const MachineInstr *MI) {
82249259Sdim  return MI->getOpcode() == Hexagon::LOOP0_r ||
83249259Sdim         MI->getOpcode() == Hexagon::LOOP0_i;
84249259Sdim}
85249259Sdim
86249259Sdim
87249259Sdimbool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
88249259Sdim  bool Changed = fixupLoopInstrs(MF);
89249259Sdim  return Changed;
90249259Sdim}
91249259Sdim
92249259Sdim
93249259Sdim/// \brief For Hexagon, if the loop label is to far from the
94249259Sdim/// loop instruction then we need to set the LC0 and SA0 registers
95249259Sdim/// explicitly instead of using LOOP(start,count).  This function
96249259Sdim/// checks the distance, and generates register assignments if needed.
97249259Sdim///
98249259Sdim/// This function makes two passes over the basic blocks.  The first
99249259Sdim/// pass computes the offset of the basic block from the start.
100249259Sdim/// The second pass checks all the loop instructions.
101249259Sdimbool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
102249259Sdim
103249259Sdim  // Offset of the current instruction from the start.
104249259Sdim  unsigned InstOffset = 0;
105249259Sdim  // Map for each basic block to it's first instruction.
106249259Sdim  DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
107249259Sdim
108249259Sdim  // First pass - compute the offset of each basic block.
109249259Sdim  for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
110249259Sdim       MBB != MBBe; ++MBB) {
111249259Sdim    BlockToInstOffset[MBB] = InstOffset;
112249259Sdim    InstOffset += (MBB->size() * 4);
113249259Sdim  }
114249259Sdim
115249259Sdim  // Second pass - check each loop instruction to see if it needs to
116249259Sdim  // be converted.
117249259Sdim  InstOffset = 0;
118249259Sdim  bool Changed = false;
119249259Sdim  RegScavenger RS;
120249259Sdim
121249259Sdim  // Loop over all the basic blocks.
122249259Sdim  for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
123249259Sdim       MBB != MBBe; ++MBB) {
124249259Sdim    InstOffset = BlockToInstOffset[MBB];
125249259Sdim    RS.enterBasicBlock(MBB);
126249259Sdim
127249259Sdim    // Loop over all the instructions.
128249259Sdim    MachineBasicBlock::iterator MIE = MBB->end();
129249259Sdim    MachineBasicBlock::iterator MII = MBB->begin();
130249259Sdim    while (MII != MIE) {
131249259Sdim      if (isHardwareLoop(MII)) {
132249259Sdim        RS.forward(MII);
133249259Sdim        assert(MII->getOperand(0).isMBB() &&
134249259Sdim               "Expect a basic block as loop operand");
135249259Sdim        int Sub = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
136249259Sdim        unsigned Dist = Sub > 0 ? Sub : -Sub;
137249259Sdim        if (Dist > MAX_LOOP_DISTANCE) {
138249259Sdim          // Convert to explicity setting LC0 and SA0.
139249259Sdim          convertLoopInstr(MF, MII, RS);
140249259Sdim          MII = MBB->erase(MII);
141249259Sdim          Changed = true;
142249259Sdim        } else {
143249259Sdim          ++MII;
144249259Sdim        }
145249259Sdim      } else {
146249259Sdim        ++MII;
147249259Sdim      }
148249259Sdim      InstOffset += 4;
149249259Sdim    }
150249259Sdim  }
151249259Sdim
152249259Sdim  return Changed;
153249259Sdim}
154249259Sdim
155249259Sdim
156249259Sdim/// \brief convert a loop instruction to a sequence of instructions that
157249259Sdim/// set the LC0 and SA0 register explicitly.
158249259Sdimvoid HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
159249259Sdim                                           MachineBasicBlock::iterator &MII,
160249259Sdim                                           RegScavenger &RS) {
161249259Sdim  const TargetInstrInfo *TII = MF.getTarget().getInstrInfo();
162249259Sdim  MachineBasicBlock *MBB = MII->getParent();
163249259Sdim  DebugLoc DL = MII->getDebugLoc();
164249259Sdim  unsigned Scratch = RS.scavengeRegister(&Hexagon::IntRegsRegClass, MII, 0);
165249259Sdim
166249259Sdim  // First, set the LC0 with the trip count.
167249259Sdim  if (MII->getOperand(1).isReg()) {
168249259Sdim    // Trip count is a register
169249259Sdim    BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::LC0)
170249259Sdim      .addReg(MII->getOperand(1).getReg());
171249259Sdim  } else {
172249259Sdim    // Trip count is an immediate.
173249259Sdim    BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFRI), Scratch)
174249259Sdim      .addImm(MII->getOperand(1).getImm());
175249259Sdim    BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::LC0)
176249259Sdim      .addReg(Scratch);
177249259Sdim  }
178249259Sdim  // Then, set the SA0 with the loop start address.
179249259Sdim  BuildMI(*MBB, MII, DL, TII->get(Hexagon::CONST32_Label), Scratch)
180249259Sdim    .addMBB(MII->getOperand(0).getMBB());
181249259Sdim  BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::SA0)
182249259Sdim    .addReg(Scratch);
183249259Sdim}
184