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