Home | History | Annotate | Download | only in Hexagon
      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 
     28 using namespace llvm;
     29 
     30 namespace llvm {
     31   void initializeHexagonFixupHwLoopsPass(PassRegistry&);
     32 }
     33 
     34 namespace {
     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 
     74 INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
     75                 "Hexagon Hardware Loops Fixup", false, false)
     76 
     77 FunctionPass *llvm::createHexagonFixupHwLoops() {
     78   return new HexagonFixupHwLoops();
     79 }
     80 
     81 
     82 /// \brief Returns true if the instruction is a hardware loop instruction.
     83 static bool isHardwareLoop(const MachineInstr *MI) {
     84   return MI->getOpcode() == Hexagon::LOOP0_r ||
     85          MI->getOpcode() == Hexagon::LOOP0_i;
     86 }
     87 
     88 
     89 bool 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.
    103 bool 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.
    160 void HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
    161                                            MachineBasicBlock::iterator &MII,
    162                                            RegScavenger &RS) {
    163   const TargetInstrInfo *TII = MF.getTarget().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::TFCR), Hexagon::LC0)
    172       .addReg(MII->getOperand(1).getReg());
    173   } else {
    174     // Trip count is an immediate.
    175     BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFRI), Scratch)
    176       .addImm(MII->getOperand(1).getImm());
    177     BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), 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::TFCR), Hexagon::SA0)
    184     .addReg(Scratch);
    185 }
    186