| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 1 | //===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | // The loop start address in the LOOPn instruction is encoded as a distance | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 9 | // from the LOOPn instruction itself. If the start address is too far from | 
|  | 10 | // the LOOPn instruction, the instruction needs to use a constant extender. | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 11 | // This pass will identify and convert such LOOPn instructions to a proper | 
|  | 12 | // form. | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
| Chandler Carruth | 8a8cd2b | 2014-01-07 11:48:04 +0000 | [diff] [blame] | 15 | #include "Hexagon.h" | 
|  | 16 | #include "HexagonTargetMachine.h" | 
| Chandler Carruth | 6bda14b | 2017-06-06 11:49:48 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/DenseMap.h" | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 18 | #include "llvm/CodeGen/MachineFunction.h" | 
|  | 19 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | 20 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | 21 | #include "llvm/CodeGen/Passes.h" | 
| David Blaikie | 3f833ed | 2017-11-08 01:01:31 +0000 | [diff] [blame] | 22 | #include "llvm/CodeGen/TargetInstrInfo.h" | 
| Krzysztof Parzyszek | 8038dad | 2018-03-23 20:41:44 +0000 | [diff] [blame] | 23 | #include "llvm/Support/MathExtras.h" | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 24 | #include "llvm/PassSupport.h" | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 25 |  | 
|  | 26 | using namespace llvm; | 
|  | 27 |  | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 28 | static cl::opt<unsigned> MaxLoopRange( | 
|  | 29 | "hexagon-loop-range", cl::Hidden, cl::init(200), | 
|  | 30 | cl::desc("Restrict range of loopN instructions (testing only)")); | 
|  | 31 |  | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 32 | namespace llvm { | 
| Colin LeMahieu | 56efafc | 2015-06-15 19:05:35 +0000 | [diff] [blame] | 33 | FunctionPass *createHexagonFixupHwLoops(); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 34 | void initializeHexagonFixupHwLoopsPass(PassRegistry&); | 
|  | 35 | } | 
|  | 36 |  | 
|  | 37 | namespace { | 
|  | 38 | struct HexagonFixupHwLoops : public MachineFunctionPass { | 
|  | 39 | public: | 
|  | 40 | static char ID; | 
|  | 41 |  | 
|  | 42 | HexagonFixupHwLoops() : MachineFunctionPass(ID) { | 
|  | 43 | initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry()); | 
|  | 44 | } | 
|  | 45 |  | 
| Craig Topper | 906c2cd | 2014-04-29 07:58:16 +0000 | [diff] [blame] | 46 | bool runOnMachineFunction(MachineFunction &MF) override; | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 47 |  | 
| Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 48 | MachineFunctionProperties getRequiredProperties() const override { | 
|  | 49 | return MachineFunctionProperties().set( | 
| Matthias Braun | 1eb4736 | 2016-08-25 01:27:13 +0000 | [diff] [blame] | 50 | MachineFunctionProperties::Property::NoVRegs); | 
| Derek Schuff | 1dbf7a5 | 2016-04-04 17:09:25 +0000 | [diff] [blame] | 51 | } | 
|  | 52 |  | 
| Mehdi Amini | 117296c | 2016-10-01 02:56:57 +0000 | [diff] [blame] | 53 | StringRef getPassName() const override { | 
| Craig Topper | 906c2cd | 2014-04-29 07:58:16 +0000 | [diff] [blame] | 54 | return "Hexagon Hardware Loop Fixup"; | 
|  | 55 | } | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 56 |  | 
| Craig Topper | 906c2cd | 2014-04-29 07:58:16 +0000 | [diff] [blame] | 57 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 58 | AU.setPreservesCFG(); | 
|  | 59 | MachineFunctionPass::getAnalysisUsage(AU); | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | private: | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 63 | /// \brief Check the offset between each loop instruction and | 
|  | 64 | /// the loop basic block to determine if we can use the LOOP instruction | 
|  | 65 | /// or if we need to set the LC/SA registers explicitly. | 
|  | 66 | bool fixupLoopInstrs(MachineFunction &MF); | 
|  | 67 |  | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 68 | /// \brief Replace loop instruction with the constant extended | 
|  | 69 | /// version if the loop label is too far from the loop instruction. | 
|  | 70 | void useExtLoopInstr(MachineFunction &MF, | 
|  | 71 | MachineBasicBlock::iterator &MII); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 72 | }; | 
|  | 73 |  | 
|  | 74 | char HexagonFixupHwLoops::ID = 0; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 75 | } | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 76 |  | 
|  | 77 | INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup", | 
|  | 78 | "Hexagon Hardware Loops Fixup", false, false) | 
|  | 79 |  | 
|  | 80 | FunctionPass *llvm::createHexagonFixupHwLoops() { | 
|  | 81 | return new HexagonFixupHwLoops(); | 
|  | 82 | } | 
|  | 83 |  | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 84 | /// \brief Returns true if the instruction is a hardware loop instruction. | 
| Duncan P. N. Exon Smith | 98226e3 | 2016-07-12 01:55:32 +0000 | [diff] [blame] | 85 | static bool isHardwareLoop(const MachineInstr &MI) { | 
|  | 86 | return MI.getOpcode() == Hexagon::J2_loop0r || | 
|  | 87 | MI.getOpcode() == Hexagon::J2_loop0i || | 
|  | 88 | MI.getOpcode() == Hexagon::J2_loop1r || | 
|  | 89 | MI.getOpcode() == Hexagon::J2_loop1i; | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 90 | } | 
|  | 91 |  | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 92 | bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) { | 
| Matthias Braun | f1caa28 | 2017-12-15 22:22:58 +0000 | [diff] [blame] | 93 | if (skipFunction(MF.getFunction())) | 
| Andrew Kaylor | 5b444a2 | 2016-04-26 19:46:28 +0000 | [diff] [blame] | 94 | return false; | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 95 | return fixupLoopInstrs(MF); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 96 | } | 
|  | 97 |  | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 98 | /// \brief For Hexagon, if the loop label is to far from the | 
|  | 99 | /// loop instruction then we need to set the LC0 and SA0 registers | 
|  | 100 | /// explicitly instead of using LOOP(start,count).  This function | 
|  | 101 | /// checks the distance, and generates register assignments if needed. | 
|  | 102 | /// | 
|  | 103 | /// This function makes two passes over the basic blocks.  The first | 
|  | 104 | /// pass computes the offset of the basic block from the start. | 
|  | 105 | /// The second pass checks all the loop instructions. | 
|  | 106 | bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) { | 
|  | 107 |  | 
|  | 108 | // Offset of the current instruction from the start. | 
|  | 109 | unsigned InstOffset = 0; | 
|  | 110 | // Map for each basic block to it's first instruction. | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 111 | DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset; | 
|  | 112 |  | 
|  | 113 | const HexagonInstrInfo *HII = | 
|  | 114 | static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo()); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 115 |  | 
|  | 116 | // First pass - compute the offset of each basic block. | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 117 | for (const MachineBasicBlock &MBB : MF) { | 
|  | 118 | if (MBB.getAlignment()) { | 
|  | 119 | // Although we don't know the exact layout of the final code, we need | 
|  | 120 | // to account for alignment padding somehow. This heuristic pads each | 
|  | 121 | // aligned basic block according to the alignment value. | 
|  | 122 | int ByteAlign = (1u << MBB.getAlignment()) - 1; | 
|  | 123 | InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign); | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | BlockToInstOffset[&MBB] = InstOffset; | 
|  | 127 | for (const MachineInstr &MI : MBB) | 
| Krzysztof Parzyszek | f0b34a5 | 2016-07-29 21:49:42 +0000 | [diff] [blame] | 128 | InstOffset += HII->getSize(MI); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 129 | } | 
|  | 130 |  | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 131 | // Second pass - check each loop instruction to see if it needs to be | 
|  | 132 | // converted. | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 133 | bool Changed = false; | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 134 | for (MachineBasicBlock &MBB : MF) { | 
|  | 135 | InstOffset = BlockToInstOffset[&MBB]; | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 136 |  | 
|  | 137 | // Loop over all the instructions. | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 138 | MachineBasicBlock::iterator MII = MBB.begin(); | 
|  | 139 | MachineBasicBlock::iterator MIE = MBB.end(); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 140 | while (MII != MIE) { | 
| Krzysztof Parzyszek | 8038dad | 2018-03-23 20:41:44 +0000 | [diff] [blame] | 141 | unsigned InstSize = HII->getSize(*MII); | 
| Krzysztof Parzyszek | 709e4f9 | 2017-08-10 15:00:30 +0000 | [diff] [blame] | 142 | if (MII->isMetaInstruction()) { | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 143 | ++MII; | 
|  | 144 | continue; | 
|  | 145 | } | 
| Duncan P. N. Exon Smith | 98226e3 | 2016-07-12 01:55:32 +0000 | [diff] [blame] | 146 | if (isHardwareLoop(*MII)) { | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 147 | assert(MII->getOperand(0).isMBB() && | 
|  | 148 | "Expect a basic block as loop operand"); | 
| Krzysztof Parzyszek | 8038dad | 2018-03-23 20:41:44 +0000 | [diff] [blame] | 149 | MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB(); | 
|  | 150 | unsigned Diff = AbsoluteDifference(InstOffset, | 
|  | 151 | BlockToInstOffset[TargetBB]); | 
|  | 152 | if (Diff > MaxLoopRange) { | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 153 | useExtLoopInstr(MF, MII); | 
|  | 154 | MII = MBB.erase(MII); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 155 | Changed = true; | 
|  | 156 | } else { | 
|  | 157 | ++MII; | 
|  | 158 | } | 
|  | 159 | } else { | 
|  | 160 | ++MII; | 
|  | 161 | } | 
| Krzysztof Parzyszek | 8038dad | 2018-03-23 20:41:44 +0000 | [diff] [blame] | 162 | InstOffset += InstSize; | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 163 | } | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | return Changed; | 
|  | 167 | } | 
|  | 168 |  | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 169 | /// \brief Replace loop instructions with the constant extended version. | 
|  | 170 | void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF, | 
|  | 171 | MachineBasicBlock::iterator &MII) { | 
| Eric Christopher | fc6de42 | 2014-08-05 02:39:49 +0000 | [diff] [blame] | 172 | const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 173 | MachineBasicBlock *MBB = MII->getParent(); | 
|  | 174 | DebugLoc DL = MII->getDebugLoc(); | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 175 | MachineInstrBuilder MIB; | 
|  | 176 | unsigned newOp; | 
|  | 177 | switch (MII->getOpcode()) { | 
|  | 178 | case Hexagon::J2_loop0r: | 
|  | 179 | newOp = Hexagon::J2_loop0rext; | 
|  | 180 | break; | 
|  | 181 | case Hexagon::J2_loop0i: | 
|  | 182 | newOp = Hexagon::J2_loop0iext; | 
|  | 183 | break; | 
|  | 184 | case Hexagon::J2_loop1r: | 
|  | 185 | newOp = Hexagon::J2_loop1rext; | 
|  | 186 | break; | 
|  | 187 | case Hexagon::J2_loop1i: | 
|  | 188 | newOp = Hexagon::J2_loop1iext; | 
|  | 189 | break; | 
|  | 190 | default: | 
|  | 191 | llvm_unreachable("Invalid Hardware Loop Instruction."); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 192 | } | 
| Brendon Cahoon | 55bdeb7 | 2015-04-27 14:16:43 +0000 | [diff] [blame] | 193 | MIB = BuildMI(*MBB, MII, DL, TII->get(newOp)); | 
|  | 194 |  | 
|  | 195 | for (unsigned i = 0; i < MII->getNumOperands(); ++i) | 
| Diana Picus | 116bbab | 2017-01-13 09:58:52 +0000 | [diff] [blame] | 196 | MIB.add(MII->getOperand(i)); | 
| Krzysztof Parzyszek | 9a278f1 | 2013-02-11 21:37:55 +0000 | [diff] [blame] | 197 | } |