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
16#include "llvm/ADT/DenseMap.h"
17#include "Hexagon.h"
18#include "HexagonTargetMachine.h"
19#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/CodeGen/MachineFunctionPass.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/CodeGen/Passes.h"
23#include "llvm/PassSupport.h"
24#include "llvm/Target/TargetInstrInfo.h"
25
26using namespace llvm;
27
28static cl::opt<unsigned> MaxLoopRange(
29    "hexagon-loop-range", cl::Hidden, cl::init(200),
30    cl::desc("Restrict range of loopN instructions (testing only)"));
31
32namespace llvm {
33  FunctionPass *createHexagonFixupHwLoops();
34  void initializeHexagonFixupHwLoopsPass(PassRegistry&);
35}
36
37namespace {
38  struct HexagonFixupHwLoops : public MachineFunctionPass {
39  public:
40    static char ID;
41
42    HexagonFixupHwLoops() : MachineFunctionPass(ID) {
43      initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
44    }
45
46    bool runOnMachineFunction(MachineFunction &MF) override;
47
48    MachineFunctionProperties getRequiredProperties() const override {
49      return MachineFunctionProperties().set(
50          MachineFunctionProperties::Property::AllVRegsAllocated);
51    }
52
53    const char *getPassName() const override {
54      return "Hexagon Hardware Loop Fixup";
55    }
56
57    void getAnalysisUsage(AnalysisUsage &AU) const override {
58      AU.setPreservesCFG();
59      MachineFunctionPass::getAnalysisUsage(AU);
60    }
61
62  private:
63    /// \brief 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    /// \brief 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
77INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
78                "Hexagon Hardware Loops Fixup", false, false)
79
80FunctionPass *llvm::createHexagonFixupHwLoops() {
81  return new HexagonFixupHwLoops();
82}
83
84/// \brief Returns true if the instruction is a hardware loop instruction.
85static 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
92bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
93  if (skipFunction(*MF.getFunction()))
94    return false;
95  return fixupLoopInstrs(MF);
96}
97
98/// \brief 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.
106bool 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      InstOffset += HII->getSize(&*MII);
142      if (MII->isDebugValue()) {
143        ++MII;
144        continue;
145      }
146      if (isHardwareLoop(*MII)) {
147        assert(MII->getOperand(0).isMBB() &&
148               "Expect a basic block as loop operand");
149        int diff = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
150        if ((unsigned)abs(diff) > MaxLoopRange) {
151          useExtLoopInstr(MF, MII);
152          MII = MBB.erase(MII);
153          Changed = true;
154        } else {
155          ++MII;
156        }
157      } else {
158        ++MII;
159      }
160    }
161  }
162
163  return Changed;
164}
165
166/// \brief Replace loop instructions with the constant extended version.
167void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
168                                          MachineBasicBlock::iterator &MII) {
169  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
170  MachineBasicBlock *MBB = MII->getParent();
171  DebugLoc DL = MII->getDebugLoc();
172  MachineInstrBuilder MIB;
173  unsigned newOp;
174  switch (MII->getOpcode()) {
175  case Hexagon::J2_loop0r:
176    newOp = Hexagon::J2_loop0rext;
177    break;
178  case Hexagon::J2_loop0i:
179    newOp = Hexagon::J2_loop0iext;
180    break;
181  case Hexagon::J2_loop1r:
182    newOp = Hexagon::J2_loop1rext;
183    break;
184  case Hexagon::J2_loop1i:
185    newOp = Hexagon::J2_loop1iext;
186    break;
187  default:
188    llvm_unreachable("Invalid Hardware Loop Instruction.");
189  }
190  MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));
191
192  for (unsigned i = 0; i < MII->getNumOperands(); ++i)
193    MIB.addOperand(MII->getOperand(i));
194}
195