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