mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224612 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			186 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			186 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 loop needs to be set up manually, i.e. via
 | |
| // direct transfers to SAn and LCn.
 | |
| // 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/CodeGen/RegisterScavenging.h"
 | |
| #include "llvm/PassSupport.h"
 | |
| #include "llvm/Target/TargetInstrInfo.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| 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 Maximum distance between the loop instr and the basic block.
 | |
|     /// Just an estimate.
 | |
|     static const unsigned MAX_LOOP_DISTANCE = 200;
 | |
| 
 | |
|     /// \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 Add the instruction to set the LC and SA registers explicitly.
 | |
|     void convertLoopInstr(MachineFunction &MF,
 | |
|                           MachineBasicBlock::iterator &MII,
 | |
|                           RegScavenger &RS);
 | |
| 
 | |
|   };
 | |
| 
 | |
|   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;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
 | |
|   bool Changed = fixupLoopInstrs(MF);
 | |
|   return Changed;
 | |
| }
 | |
| 
 | |
| 
 | |
| /// \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<MachineBasicBlock*, unsigned> BlockToInstOffset;
 | |
| 
 | |
|   // First pass - compute the offset of each basic block.
 | |
|   for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
 | |
|        MBB != MBBe; ++MBB) {
 | |
|     BlockToInstOffset[MBB] = InstOffset;
 | |
|     InstOffset += (MBB->size() * 4);
 | |
|   }
 | |
| 
 | |
|   // Second pass - check each loop instruction to see if it needs to
 | |
|   // be converted.
 | |
|   InstOffset = 0;
 | |
|   bool Changed = false;
 | |
|   RegScavenger RS;
 | |
| 
 | |
|   // Loop over all the basic blocks.
 | |
|   for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
 | |
|        MBB != MBBe; ++MBB) {
 | |
|     InstOffset = BlockToInstOffset[MBB];
 | |
|     RS.enterBasicBlock(MBB);
 | |
| 
 | |
|     // Loop over all the instructions.
 | |
|     MachineBasicBlock::iterator MIE = MBB->end();
 | |
|     MachineBasicBlock::iterator MII = MBB->begin();
 | |
|     while (MII != MIE) {
 | |
|       if (isHardwareLoop(MII)) {
 | |
|         RS.forward(MII);
 | |
|         assert(MII->getOperand(0).isMBB() &&
 | |
|                "Expect a basic block as loop operand");
 | |
|         int Sub = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
 | |
|         unsigned Dist = Sub > 0 ? Sub : -Sub;
 | |
|         if (Dist > MAX_LOOP_DISTANCE) {
 | |
|           // Convert to explicity setting LC0 and SA0.
 | |
|           convertLoopInstr(MF, MII, RS);
 | |
|           MII = MBB->erase(MII);
 | |
|           Changed = true;
 | |
|         } else {
 | |
|           ++MII;
 | |
|         }
 | |
|       } else {
 | |
|         ++MII;
 | |
|       }
 | |
|       InstOffset += 4;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Changed;
 | |
| }
 | |
| 
 | |
| 
 | |
| /// \brief convert a loop instruction to a sequence of instructions that
 | |
| /// set the LC0 and SA0 register explicitly.
 | |
| void HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
 | |
|                                            MachineBasicBlock::iterator &MII,
 | |
|                                            RegScavenger &RS) {
 | |
|   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
 | |
|   MachineBasicBlock *MBB = MII->getParent();
 | |
|   DebugLoc DL = MII->getDebugLoc();
 | |
|   unsigned Scratch = RS.scavengeRegister(&Hexagon::IntRegsRegClass, MII, 0);
 | |
| 
 | |
|   // First, set the LC0 with the trip count.
 | |
|   if (MII->getOperand(1).isReg()) {
 | |
|     // Trip count is a register
 | |
|     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
 | |
|       .addReg(MII->getOperand(1).getReg());
 | |
|   } else {
 | |
|     // Trip count is an immediate.
 | |
|     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrsi), Scratch)
 | |
|       .addImm(MII->getOperand(1).getImm());
 | |
|     BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::LC0)
 | |
|       .addReg(Scratch);
 | |
|   }
 | |
|   // Then, set the SA0 with the loop start address.
 | |
|   BuildMI(*MBB, MII, DL, TII->get(Hexagon::CONST32_Label), Scratch)
 | |
|     .addMBB(MII->getOperand(0).getMBB());
 | |
|   BuildMI(*MBB, MII, DL, TII->get(Hexagon::A2_tfrrcr), Hexagon::SA0)
 | |
|     .addReg(Scratch);
 | |
| }
 |