mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-04 05:17:07 +00:00 
			
		
		
		
	Use a loop instruction with a constant extender for a hardware loop instruction that is too far away from the start of the loop. This is cheaper than changing the SA register value. Differential Revision: http://reviews.llvm.org/D9262 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235882 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			188 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
// The loop start address in the LOOPn instruction is encoded as a distance
 | 
						|
// from the LOOPn instruction itself. If the start address is too far from
 | 
						|
// the LOOPn instruction, the instruction needs to use a constant extender.
 | 
						|
// This pass will identify and convert such LOOPn instructions to a proper
 | 
						|
// form.
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
 | 
						|
#include "llvm/ADT/DenseMap.h"
 | 
						|
#include "Hexagon.h"
 | 
						|
#include "HexagonTargetMachine.h"
 | 
						|
#include "llvm/CodeGen/MachineFunction.h"
 | 
						|
#include "llvm/CodeGen/MachineFunctionPass.h"
 | 
						|
#include "llvm/CodeGen/MachineInstrBuilder.h"
 | 
						|
#include "llvm/CodeGen/Passes.h"
 | 
						|
#include "llvm/PassSupport.h"
 | 
						|
#include "llvm/Target/TargetInstrInfo.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
static cl::opt<unsigned> MaxLoopRange(
 | 
						|
    "hexagon-loop-range", cl::Hidden, cl::init(200),
 | 
						|
    cl::desc("Restrict range of loopN instructions (testing only)"));
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
  void initializeHexagonFixupHwLoopsPass(PassRegistry&);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
  struct HexagonFixupHwLoops : public MachineFunctionPass {
 | 
						|
  public:
 | 
						|
    static char ID;
 | 
						|
 | 
						|
    HexagonFixupHwLoops() : MachineFunctionPass(ID) {
 | 
						|
      initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
 | 
						|
    }
 | 
						|
 | 
						|
    bool runOnMachineFunction(MachineFunction &MF) override;
 | 
						|
 | 
						|
    const char *getPassName() const override {
 | 
						|
      return "Hexagon Hardware Loop Fixup";
 | 
						|
    }
 | 
						|
 | 
						|
    void getAnalysisUsage(AnalysisUsage &AU) const override {
 | 
						|
      AU.setPreservesCFG();
 | 
						|
      MachineFunctionPass::getAnalysisUsage(AU);
 | 
						|
    }
 | 
						|
 | 
						|
  private:
 | 
						|
    /// \brief Check the offset between each loop instruction and
 | 
						|
    /// the loop basic block to determine if we can use the LOOP instruction
 | 
						|
    /// or if we need to set the LC/SA registers explicitly.
 | 
						|
    bool fixupLoopInstrs(MachineFunction &MF);
 | 
						|
 | 
						|
    /// \brief Replace loop instruction with the constant extended
 | 
						|
    /// version if the loop label is too far from the loop instruction.
 | 
						|
    void useExtLoopInstr(MachineFunction &MF,
 | 
						|
                         MachineBasicBlock::iterator &MII);
 | 
						|
  };
 | 
						|
 | 
						|
  char HexagonFixupHwLoops::ID = 0;
 | 
						|
}
 | 
						|
 | 
						|
INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
 | 
						|
                "Hexagon Hardware Loops Fixup", false, false)
 | 
						|
 | 
						|
FunctionPass *llvm::createHexagonFixupHwLoops() {
 | 
						|
  return new HexagonFixupHwLoops();
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Returns true if the instruction is a hardware loop instruction.
 | 
						|
static bool isHardwareLoop(const MachineInstr *MI) {
 | 
						|
  return MI->getOpcode() == Hexagon::J2_loop0r ||
 | 
						|
         MI->getOpcode() == Hexagon::J2_loop0i ||
 | 
						|
         MI->getOpcode() == Hexagon::J2_loop1r ||
 | 
						|
         MI->getOpcode() == Hexagon::J2_loop1i;
 | 
						|
}
 | 
						|
 | 
						|
bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
 | 
						|
  return fixupLoopInstrs(MF);
 | 
						|
}
 | 
						|
 | 
						|
/// \brief For Hexagon, if the loop label is to far from the
 | 
						|
/// loop instruction then we need to set the LC0 and SA0 registers
 | 
						|
/// explicitly instead of using LOOP(start,count).  This function
 | 
						|
/// checks the distance, and generates register assignments if needed.
 | 
						|
///
 | 
						|
/// This function makes two passes over the basic blocks.  The first
 | 
						|
/// pass computes the offset of the basic block from the start.
 | 
						|
/// The second pass checks all the loop instructions.
 | 
						|
bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
 | 
						|
 | 
						|
  // Offset of the current instruction from the start.
 | 
						|
  unsigned InstOffset = 0;
 | 
						|
  // Map for each basic block to it's first instruction.
 | 
						|
  DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;
 | 
						|
 | 
						|
  const HexagonInstrInfo *HII =
 | 
						|
      static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
 | 
						|
 | 
						|
  // First pass - compute the offset of each basic block.
 | 
						|
  for (const MachineBasicBlock &MBB : MF) {
 | 
						|
    if (MBB.getAlignment()) {
 | 
						|
      // Although we don't know the exact layout of the final code, we need
 | 
						|
      // to account for alignment padding somehow. This heuristic pads each
 | 
						|
      // aligned basic block according to the alignment value.
 | 
						|
      int ByteAlign = (1u << MBB.getAlignment()) - 1;
 | 
						|
      InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
 | 
						|
    }
 | 
						|
 | 
						|
    BlockToInstOffset[&MBB] = InstOffset;
 | 
						|
    for (const MachineInstr &MI : MBB)
 | 
						|
      InstOffset += HII->getSize(&MI);
 | 
						|
  }
 | 
						|
 | 
						|
  // Second pass - check each loop instruction to see if it needs to be
 | 
						|
  // converted.
 | 
						|
  InstOffset = 0;
 | 
						|
  bool Changed = false;
 | 
						|
  for (MachineBasicBlock &MBB : MF) {
 | 
						|
    InstOffset = BlockToInstOffset[&MBB];
 | 
						|
 | 
						|
    // Loop over all the instructions.
 | 
						|
    MachineBasicBlock::iterator MII = MBB.begin();
 | 
						|
    MachineBasicBlock::iterator MIE = MBB.end();
 | 
						|
    while (MII != MIE) {
 | 
						|
      InstOffset += HII->getSize(&*MII);
 | 
						|
      if (MII->isDebugValue()) {
 | 
						|
        ++MII;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (isHardwareLoop(MII)) {
 | 
						|
        assert(MII->getOperand(0).isMBB() &&
 | 
						|
               "Expect a basic block as loop operand");
 | 
						|
        int diff = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
 | 
						|
        if ((unsigned)abs(diff) > MaxLoopRange) {
 | 
						|
          useExtLoopInstr(MF, MII);
 | 
						|
          MII = MBB.erase(MII);
 | 
						|
          Changed = true;
 | 
						|
        } else {
 | 
						|
          ++MII;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        ++MII;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Changed;
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Replace loop instructions with the constant extended version.
 | 
						|
void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
 | 
						|
                                          MachineBasicBlock::iterator &MII) {
 | 
						|
  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
 | 
						|
  MachineBasicBlock *MBB = MII->getParent();
 | 
						|
  DebugLoc DL = MII->getDebugLoc();
 | 
						|
  MachineInstrBuilder MIB;
 | 
						|
  unsigned newOp;
 | 
						|
  switch (MII->getOpcode()) {
 | 
						|
  case Hexagon::J2_loop0r:
 | 
						|
    newOp = Hexagon::J2_loop0rext;
 | 
						|
    break;
 | 
						|
  case Hexagon::J2_loop0i:
 | 
						|
    newOp = Hexagon::J2_loop0iext;
 | 
						|
    break;
 | 
						|
  case Hexagon::J2_loop1r:
 | 
						|
    newOp = Hexagon::J2_loop1rext;
 | 
						|
    break;
 | 
						|
  case Hexagon::J2_loop1i:
 | 
						|
    newOp = Hexagon::J2_loop1iext;
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Invalid Hardware Loop Instruction.");
 | 
						|
  }
 | 
						|
  MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));
 | 
						|
 | 
						|
  for (unsigned i = 0; i < MII->getNumOperands(); ++i)
 | 
						|
    MIB.addOperand(MII->getOperand(i));
 | 
						|
}
 |