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"
23*5ffd83dbSDimitry Andric #include "llvm/Pass.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
HexagonFixupHwLoops__anonb4b12bc10111::HexagonFixupHwLoops410b57cec5SDimitry Andric HexagonFixupHwLoops() : MachineFunctionPass(ID) {
420b57cec5SDimitry Andric initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
460b57cec5SDimitry Andric
getRequiredProperties__anonb4b12bc10111::HexagonFixupHwLoops470b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
480b57cec5SDimitry Andric return MachineFunctionProperties().set(
490b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric
getPassName__anonb4b12bc10111::HexagonFixupHwLoops520b57cec5SDimitry Andric StringRef getPassName() const override {
530b57cec5SDimitry Andric return "Hexagon Hardware Loop Fixup";
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
getAnalysisUsage__anonb4b12bc10111::HexagonFixupHwLoops560b57cec5SDimitry 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
createHexagonFixupHwLoops()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.
isHardwareLoop(const MachineInstr & MI)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
runOnMachineFunction(MachineFunction & MF)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.
fixupLoopInstrs(MachineFunction & MF)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*5ffd83dbSDimitry Andric if (MBB.getAlignment() != Align(1)) {
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.
1218bcb0991SDimitry 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.
useExtLoopInstr(MachineFunction & MF,MachineBasicBlock::iterator & MII)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