10b57cec5SDimitry Andric //===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric // The loop start address in the LOOPn instruction is encoded as a distance 80b57cec5SDimitry Andric // from the LOOPn instruction itself. If the start address is too far from 90b57cec5SDimitry Andric // the LOOPn instruction, the instruction needs to use a constant extender. 100b57cec5SDimitry Andric // This pass will identify and convert such LOOPn instructions to a proper 110b57cec5SDimitry Andric // form. 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "Hexagon.h" 150b57cec5SDimitry Andric #include "HexagonTargetMachine.h" 160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 220b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 230b57cec5SDimitry Andric #include "llvm/PassSupport.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric static cl::opt<unsigned> MaxLoopRange( 280b57cec5SDimitry Andric "hexagon-loop-range", cl::Hidden, cl::init(200), 290b57cec5SDimitry Andric cl::desc("Restrict range of loopN instructions (testing only)")); 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace llvm { 320b57cec5SDimitry Andric FunctionPass *createHexagonFixupHwLoops(); 330b57cec5SDimitry Andric void initializeHexagonFixupHwLoopsPass(PassRegistry&); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric namespace { 370b57cec5SDimitry Andric struct HexagonFixupHwLoops : public MachineFunctionPass { 380b57cec5SDimitry Andric public: 390b57cec5SDimitry Andric static char ID; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric HexagonFixupHwLoops() : MachineFunctionPass(ID) { 420b57cec5SDimitry Andric initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry()); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 480b57cec5SDimitry Andric return MachineFunctionProperties().set( 490b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric StringRef getPassName() const override { 530b57cec5SDimitry Andric return "Hexagon Hardware Loop Fixup"; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 570b57cec5SDimitry Andric AU.setPreservesCFG(); 580b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric private: 620b57cec5SDimitry Andric /// Check the offset between each loop instruction and 630b57cec5SDimitry Andric /// the loop basic block to determine if we can use the LOOP instruction 640b57cec5SDimitry Andric /// or if we need to set the LC/SA registers explicitly. 650b57cec5SDimitry Andric bool fixupLoopInstrs(MachineFunction &MF); 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric /// Replace loop instruction with the constant extended 680b57cec5SDimitry Andric /// version if the loop label is too far from the loop instruction. 690b57cec5SDimitry Andric void useExtLoopInstr(MachineFunction &MF, 700b57cec5SDimitry Andric MachineBasicBlock::iterator &MII); 710b57cec5SDimitry Andric }; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric char HexagonFixupHwLoops::ID = 0; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup", 770b57cec5SDimitry Andric "Hexagon Hardware Loops Fixup", false, false) 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric FunctionPass *llvm::createHexagonFixupHwLoops() { 800b57cec5SDimitry Andric return new HexagonFixupHwLoops(); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric /// Returns true if the instruction is a hardware loop instruction. 840b57cec5SDimitry Andric static bool isHardwareLoop(const MachineInstr &MI) { 850b57cec5SDimitry Andric return MI.getOpcode() == Hexagon::J2_loop0r || 860b57cec5SDimitry Andric MI.getOpcode() == Hexagon::J2_loop0i || 870b57cec5SDimitry Andric MI.getOpcode() == Hexagon::J2_loop1r || 880b57cec5SDimitry Andric MI.getOpcode() == Hexagon::J2_loop1i; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) { 920b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 930b57cec5SDimitry Andric return false; 940b57cec5SDimitry Andric return fixupLoopInstrs(MF); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric /// For Hexagon, if the loop label is to far from the 980b57cec5SDimitry Andric /// loop instruction then we need to set the LC0 and SA0 registers 990b57cec5SDimitry Andric /// explicitly instead of using LOOP(start,count). This function 1000b57cec5SDimitry Andric /// checks the distance, and generates register assignments if needed. 1010b57cec5SDimitry Andric /// 1020b57cec5SDimitry Andric /// This function makes two passes over the basic blocks. The first 1030b57cec5SDimitry Andric /// pass computes the offset of the basic block from the start. 1040b57cec5SDimitry Andric /// The second pass checks all the loop instructions. 1050b57cec5SDimitry Andric bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) { 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // Offset of the current instruction from the start. 1080b57cec5SDimitry Andric unsigned InstOffset = 0; 1090b57cec5SDimitry Andric // Map for each basic block to it's first instruction. 1100b57cec5SDimitry Andric DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric const HexagonInstrInfo *HII = 1130b57cec5SDimitry Andric static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo()); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric // First pass - compute the offset of each basic block. 1160b57cec5SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 117*8bcb0991SDimitry Andric if (MBB.getAlignment() != Align::None()) { 1180b57cec5SDimitry Andric // Although we don't know the exact layout of the final code, we need 1190b57cec5SDimitry Andric // to account for alignment padding somehow. This heuristic pads each 1200b57cec5SDimitry Andric // aligned basic block according to the alignment value. 121*8bcb0991SDimitry Andric InstOffset = alignTo(InstOffset, MBB.getAlignment()); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric BlockToInstOffset[&MBB] = InstOffset; 1250b57cec5SDimitry Andric for (const MachineInstr &MI : MBB) 1260b57cec5SDimitry Andric InstOffset += HII->getSize(MI); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // Second pass - check each loop instruction to see if it needs to be 1300b57cec5SDimitry Andric // converted. 1310b57cec5SDimitry Andric bool Changed = false; 1320b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) { 1330b57cec5SDimitry Andric InstOffset = BlockToInstOffset[&MBB]; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // Loop over all the instructions. 1360b57cec5SDimitry Andric MachineBasicBlock::iterator MII = MBB.begin(); 1370b57cec5SDimitry Andric MachineBasicBlock::iterator MIE = MBB.end(); 1380b57cec5SDimitry Andric while (MII != MIE) { 1390b57cec5SDimitry Andric unsigned InstSize = HII->getSize(*MII); 1400b57cec5SDimitry Andric if (MII->isMetaInstruction()) { 1410b57cec5SDimitry Andric ++MII; 1420b57cec5SDimitry Andric continue; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric if (isHardwareLoop(*MII)) { 1450b57cec5SDimitry Andric assert(MII->getOperand(0).isMBB() && 1460b57cec5SDimitry Andric "Expect a basic block as loop operand"); 1470b57cec5SDimitry Andric MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB(); 1480b57cec5SDimitry Andric unsigned Diff = AbsoluteDifference(InstOffset, 1490b57cec5SDimitry Andric BlockToInstOffset[TargetBB]); 1500b57cec5SDimitry Andric if (Diff > MaxLoopRange) { 1510b57cec5SDimitry Andric useExtLoopInstr(MF, MII); 1520b57cec5SDimitry Andric MII = MBB.erase(MII); 1530b57cec5SDimitry Andric Changed = true; 1540b57cec5SDimitry Andric } else { 1550b57cec5SDimitry Andric ++MII; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric } else { 1580b57cec5SDimitry Andric ++MII; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric InstOffset += InstSize; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric return Changed; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric /// Replace loop instructions with the constant extended version. 1680b57cec5SDimitry Andric void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF, 1690b57cec5SDimitry Andric MachineBasicBlock::iterator &MII) { 1700b57cec5SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 1710b57cec5SDimitry Andric MachineBasicBlock *MBB = MII->getParent(); 1720b57cec5SDimitry Andric DebugLoc DL = MII->getDebugLoc(); 1730b57cec5SDimitry Andric MachineInstrBuilder MIB; 1740b57cec5SDimitry Andric unsigned newOp; 1750b57cec5SDimitry Andric switch (MII->getOpcode()) { 1760b57cec5SDimitry Andric case Hexagon::J2_loop0r: 1770b57cec5SDimitry Andric newOp = Hexagon::J2_loop0rext; 1780b57cec5SDimitry Andric break; 1790b57cec5SDimitry Andric case Hexagon::J2_loop0i: 1800b57cec5SDimitry Andric newOp = Hexagon::J2_loop0iext; 1810b57cec5SDimitry Andric break; 1820b57cec5SDimitry Andric case Hexagon::J2_loop1r: 1830b57cec5SDimitry Andric newOp = Hexagon::J2_loop1rext; 1840b57cec5SDimitry Andric break; 1850b57cec5SDimitry Andric case Hexagon::J2_loop1i: 1860b57cec5SDimitry Andric newOp = Hexagon::J2_loop1iext; 1870b57cec5SDimitry Andric break; 1880b57cec5SDimitry Andric default: 1890b57cec5SDimitry Andric llvm_unreachable("Invalid Hardware Loop Instruction."); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric MIB = BuildMI(*MBB, MII, DL, TII->get(newOp)); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric for (unsigned i = 0; i < MII->getNumOperands(); ++i) 1940b57cec5SDimitry Andric MIB.add(MII->getOperand(i)); 1950b57cec5SDimitry Andric } 196