Path: blob/main/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp
35267 views
//===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6// The loop start address in the LOOPn instruction is encoded as a distance7// from the LOOPn instruction itself. If the start address is too far from8// the LOOPn instruction, the instruction needs to use a constant extender.9// This pass will identify and convert such LOOPn instructions to a proper10// form.11//===----------------------------------------------------------------------===//1213#include "Hexagon.h"14#include "HexagonTargetMachine.h"15#include "llvm/ADT/DenseMap.h"16#include "llvm/CodeGen/MachineFunction.h"17#include "llvm/CodeGen/MachineFunctionPass.h"18#include "llvm/CodeGen/MachineInstrBuilder.h"19#include "llvm/CodeGen/Passes.h"20#include "llvm/CodeGen/TargetInstrInfo.h"21#include "llvm/Support/MathExtras.h"22#include "llvm/Pass.h"2324using namespace llvm;2526static cl::opt<unsigned> MaxLoopRange(27"hexagon-loop-range", cl::Hidden, cl::init(200),28cl::desc("Restrict range of loopN instructions (testing only)"));2930namespace llvm {31FunctionPass *createHexagonFixupHwLoops();32void initializeHexagonFixupHwLoopsPass(PassRegistry&);33}3435namespace {36struct HexagonFixupHwLoops : public MachineFunctionPass {37public:38static char ID;3940HexagonFixupHwLoops() : MachineFunctionPass(ID) {41initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());42}4344bool runOnMachineFunction(MachineFunction &MF) override;4546MachineFunctionProperties getRequiredProperties() const override {47return MachineFunctionProperties().set(48MachineFunctionProperties::Property::NoVRegs);49}5051StringRef getPassName() const override {52return "Hexagon Hardware Loop Fixup";53}5455void getAnalysisUsage(AnalysisUsage &AU) const override {56AU.setPreservesCFG();57MachineFunctionPass::getAnalysisUsage(AU);58}5960private:61/// Check the offset between each loop instruction and62/// the loop basic block to determine if we can use the LOOP instruction63/// or if we need to set the LC/SA registers explicitly.64bool fixupLoopInstrs(MachineFunction &MF);6566/// Replace loop instruction with the constant extended67/// version if the loop label is too far from the loop instruction.68void useExtLoopInstr(MachineFunction &MF,69MachineBasicBlock::iterator &MII);70};7172char HexagonFixupHwLoops::ID = 0;73}7475INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",76"Hexagon Hardware Loops Fixup", false, false)7778FunctionPass *llvm::createHexagonFixupHwLoops() {79return new HexagonFixupHwLoops();80}8182/// Returns true if the instruction is a hardware loop instruction.83static bool isHardwareLoop(const MachineInstr &MI) {84return MI.getOpcode() == Hexagon::J2_loop0r ||85MI.getOpcode() == Hexagon::J2_loop0i ||86MI.getOpcode() == Hexagon::J2_loop1r ||87MI.getOpcode() == Hexagon::J2_loop1i;88}8990bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {91if (skipFunction(MF.getFunction()))92return false;93return fixupLoopInstrs(MF);94}9596/// For Hexagon, if the loop label is to far from the97/// loop instruction then we need to set the LC0 and SA0 registers98/// explicitly instead of using LOOP(start,count). This function99/// checks the distance, and generates register assignments if needed.100///101/// This function makes two passes over the basic blocks. The first102/// pass computes the offset of the basic block from the start.103/// The second pass checks all the loop instructions.104bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {105106// Offset of the current instruction from the start.107unsigned InstOffset = 0;108// Map for each basic block to it's first instruction.109DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;110111const HexagonInstrInfo *HII =112static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());113114// First pass - compute the offset of each basic block.115for (const MachineBasicBlock &MBB : MF) {116if (MBB.getAlignment() != Align(1)) {117// Although we don't know the exact layout of the final code, we need118// to account for alignment padding somehow. This heuristic pads each119// aligned basic block according to the alignment value.120InstOffset = alignTo(InstOffset, MBB.getAlignment());121}122123BlockToInstOffset[&MBB] = InstOffset;124for (const MachineInstr &MI : MBB)125InstOffset += HII->getSize(MI);126}127128// Second pass - check each loop instruction to see if it needs to be129// converted.130bool Changed = false;131for (MachineBasicBlock &MBB : MF) {132InstOffset = BlockToInstOffset[&MBB];133134// Loop over all the instructions.135MachineBasicBlock::iterator MII = MBB.begin();136MachineBasicBlock::iterator MIE = MBB.end();137while (MII != MIE) {138unsigned InstSize = HII->getSize(*MII);139if (MII->isMetaInstruction()) {140++MII;141continue;142}143if (isHardwareLoop(*MII)) {144assert(MII->getOperand(0).isMBB() &&145"Expect a basic block as loop operand");146MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB();147unsigned Diff = AbsoluteDifference(InstOffset,148BlockToInstOffset[TargetBB]);149if (Diff > MaxLoopRange) {150useExtLoopInstr(MF, MII);151MII = MBB.erase(MII);152Changed = true;153} else {154++MII;155}156} else {157++MII;158}159InstOffset += InstSize;160}161}162163return Changed;164}165166/// Replace loop instructions with the constant extended version.167void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,168MachineBasicBlock::iterator &MII) {169const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();170MachineBasicBlock *MBB = MII->getParent();171DebugLoc DL = MII->getDebugLoc();172MachineInstrBuilder MIB;173unsigned newOp;174switch (MII->getOpcode()) {175case Hexagon::J2_loop0r:176newOp = Hexagon::J2_loop0rext;177break;178case Hexagon::J2_loop0i:179newOp = Hexagon::J2_loop0iext;180break;181case Hexagon::J2_loop1r:182newOp = Hexagon::J2_loop1rext;183break;184case Hexagon::J2_loop1i:185newOp = Hexagon::J2_loop1iext;186break;187default:188llvm_unreachable("Invalid Hardware Loop Instruction.");189}190MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));191192for (unsigned i = 0; i < MII->getNumOperands(); ++i)193MIB.add(MII->getOperand(i));194}195196197