brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.3 KiB · 882a44a Raw
188 lines · cpp
1//===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7// The loop start address in the LOOPn instruction is encoded as a distance8// from the LOOPn instruction itself. If the start address is too far from9// the LOOPn instruction, the instruction needs to use a constant extender.10// This pass will identify and convert such LOOPn instructions to a proper11// form.12//===----------------------------------------------------------------------===//13 14#include "Hexagon.h"15#include "HexagonTargetMachine.h"16#include "llvm/ADT/DenseMap.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/MachineFunctionPass.h"19#include "llvm/CodeGen/MachineInstrBuilder.h"20#include "llvm/CodeGen/Passes.h"21#include "llvm/CodeGen/TargetInstrInfo.h"22#include "llvm/Support/MathExtras.h"23#include "llvm/Pass.h"24 25using namespace llvm;26 27static cl::opt<unsigned> MaxLoopRange(28    "hexagon-loop-range", cl::Hidden, cl::init(200),29    cl::desc("Restrict range of loopN instructions (testing only)"));30 31namespace {32  struct HexagonFixupHwLoops : public MachineFunctionPass {33  public:34    static char ID;35 36    HexagonFixupHwLoops() : MachineFunctionPass(ID) {}37 38    bool runOnMachineFunction(MachineFunction &MF) override;39 40    MachineFunctionProperties getRequiredProperties() const override {41      return MachineFunctionProperties().setNoVRegs();42    }43 44    StringRef getPassName() const override {45      return "Hexagon Hardware Loop Fixup";46    }47 48    void getAnalysisUsage(AnalysisUsage &AU) const override {49      AU.setPreservesCFG();50      MachineFunctionPass::getAnalysisUsage(AU);51    }52 53  private:54    /// Check the offset between each loop instruction and55    /// the loop basic block to determine if we can use the LOOP instruction56    /// or if we need to set the LC/SA registers explicitly.57    bool fixupLoopInstrs(MachineFunction &MF);58 59    /// Replace loop instruction with the constant extended60    /// version if the loop label is too far from the loop instruction.61    void useExtLoopInstr(MachineFunction &MF,62                         MachineBasicBlock::iterator &MII);63  };64 65  char HexagonFixupHwLoops::ID = 0;66}67 68INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",69                "Hexagon Hardware Loops Fixup", false, false)70 71FunctionPass *llvm::createHexagonFixupHwLoops() {72  return new HexagonFixupHwLoops();73}74 75/// Returns true if the instruction is a hardware loop instruction.76static bool isHardwareLoop(const MachineInstr &MI) {77  return MI.getOpcode() == Hexagon::J2_loop0r ||78         MI.getOpcode() == Hexagon::J2_loop0i ||79         MI.getOpcode() == Hexagon::J2_loop1r ||80         MI.getOpcode() == Hexagon::J2_loop1i;81}82 83bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {84  if (skipFunction(MF.getFunction()))85    return false;86  return fixupLoopInstrs(MF);87}88 89/// For Hexagon, if the loop label is to far from the90/// loop instruction then we need to set the LC0 and SA0 registers91/// explicitly instead of using LOOP(start,count).  This function92/// checks the distance, and generates register assignments if needed.93///94/// This function makes two passes over the basic blocks.  The first95/// pass computes the offset of the basic block from the start.96/// The second pass checks all the loop instructions.97bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {98 99  // Offset of the current instruction from the start.100  unsigned InstOffset = 0;101  // Map for each basic block to it's first instruction.102  DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;103 104  const HexagonInstrInfo *HII =105      static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());106 107  // First pass - compute the offset of each basic block.108  for (const MachineBasicBlock &MBB : MF) {109    if (MBB.getAlignment() != Align(1)) {110      // Although we don't know the exact layout of the final code, we need111      // to account for alignment padding somehow. This heuristic pads each112      // aligned basic block according to the alignment value.113      InstOffset = alignTo(InstOffset, MBB.getAlignment());114    }115 116    BlockToInstOffset[&MBB] = InstOffset;117    for (const MachineInstr &MI : MBB)118      InstOffset += HII->getSize(MI);119  }120 121  // Second pass - check each loop instruction to see if it needs to be122  // converted.123  bool Changed = false;124  for (MachineBasicBlock &MBB : MF) {125    InstOffset = BlockToInstOffset[&MBB];126 127    // Loop over all the instructions.128    MachineBasicBlock::iterator MII = MBB.begin();129    MachineBasicBlock::iterator MIE = MBB.end();130    while (MII != MIE) {131      unsigned InstSize = HII->getSize(*MII);132      if (MII->isMetaInstruction()) {133        ++MII;134        continue;135      }136      if (isHardwareLoop(*MII)) {137        assert(MII->getOperand(0).isMBB() &&138               "Expect a basic block as loop operand");139        MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB();140        unsigned Diff = AbsoluteDifference(InstOffset,141                                           BlockToInstOffset[TargetBB]);142        if (Diff > MaxLoopRange) {143          useExtLoopInstr(MF, MII);144          MII = MBB.erase(MII);145          Changed = true;146        } else {147          ++MII;148        }149      } else {150        ++MII;151      }152      InstOffset += InstSize;153    }154  }155 156  return Changed;157}158 159/// Replace loop instructions with the constant extended version.160void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,161                                          MachineBasicBlock::iterator &MII) {162  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();163  MachineBasicBlock *MBB = MII->getParent();164  DebugLoc DL = MII->getDebugLoc();165  MachineInstrBuilder MIB;166  unsigned newOp;167  switch (MII->getOpcode()) {168  case Hexagon::J2_loop0r:169    newOp = Hexagon::J2_loop0rext;170    break;171  case Hexagon::J2_loop0i:172    newOp = Hexagon::J2_loop0iext;173    break;174  case Hexagon::J2_loop1r:175    newOp = Hexagon::J2_loop1rext;176    break;177  case Hexagon::J2_loop1i:178    newOp = Hexagon::J2_loop1iext;179    break;180  default:181    llvm_unreachable("Invalid Hardware Loop Instruction.");182  }183  MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));184 185  for (unsigned i = 0; i < MII->getNumOperands(); ++i)186    MIB.add(MII->getOperand(i));187}188