blob: 85d7ac0089096dc623c227cdb7b4ddb8e6d9d7a7 [file] [log] [blame]
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +00001//===---- HexagonFixupHwLoops.cpp - Fixup HW loops too far from LOOPn. ----===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +00006//
7// The loop start address in the LOOPn instruction is encoded as a distance
Brendon Cahoon55bdeb72015-04-27 14:16:43 +00008// from the LOOPn instruction itself. If the start address is too far from
9// the LOOPn instruction, the instruction needs to use a constant extender.
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000010// This pass will identify and convert such LOOPn instructions to a proper
11// form.
12//===----------------------------------------------------------------------===//
13
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000014#include "Hexagon.h"
15#include "HexagonTargetMachine.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000016#include "llvm/ADT/DenseMap.h"
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000017#include "llvm/CodeGen/MachineFunction.h"
18#include "llvm/CodeGen/MachineFunctionPass.h"
19#include "llvm/CodeGen/MachineInstrBuilder.h"
20#include "llvm/CodeGen/Passes.h"
David Blaikie3f833ed2017-11-08 01:01:31 +000021#include "llvm/CodeGen/TargetInstrInfo.h"
Krzysztof Parzyszek8038dad2018-03-23 20:41:44 +000022#include "llvm/Support/MathExtras.h"
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000023#include "llvm/PassSupport.h"
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000024
25using namespace llvm;
26
Brendon Cahoon55bdeb72015-04-27 14:16:43 +000027static cl::opt<unsigned> MaxLoopRange(
28 "hexagon-loop-range", cl::Hidden, cl::init(200),
29 cl::desc("Restrict range of loopN instructions (testing only)"));
30
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000031namespace llvm {
Colin LeMahieu56efafc2015-06-15 19:05:35 +000032 FunctionPass *createHexagonFixupHwLoops();
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000033 void initializeHexagonFixupHwLoopsPass(PassRegistry&);
34}
35
36namespace {
37 struct HexagonFixupHwLoops : public MachineFunctionPass {
38 public:
39 static char ID;
40
41 HexagonFixupHwLoops() : MachineFunctionPass(ID) {
42 initializeHexagonFixupHwLoopsPass(*PassRegistry::getPassRegistry());
43 }
44
Craig Topper906c2cd2014-04-29 07:58:16 +000045 bool runOnMachineFunction(MachineFunction &MF) override;
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000046
Derek Schuff1dbf7a52016-04-04 17:09:25 +000047 MachineFunctionProperties getRequiredProperties() const override {
48 return MachineFunctionProperties().set(
Matthias Braun1eb47362016-08-25 01:27:13 +000049 MachineFunctionProperties::Property::NoVRegs);
Derek Schuff1dbf7a52016-04-04 17:09:25 +000050 }
51
Mehdi Amini117296c2016-10-01 02:56:57 +000052 StringRef getPassName() const override {
Craig Topper906c2cd2014-04-29 07:58:16 +000053 return "Hexagon Hardware Loop Fixup";
54 }
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000055
Craig Topper906c2cd2014-04-29 07:58:16 +000056 void getAnalysisUsage(AnalysisUsage &AU) const override {
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000057 AU.setPreservesCFG();
58 MachineFunctionPass::getAnalysisUsage(AU);
59 }
60
61 private:
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000062 /// Check the offset between each loop instruction and
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000063 /// the loop basic block to determine if we can use the LOOP instruction
64 /// or if we need to set the LC/SA registers explicitly.
65 bool fixupLoopInstrs(MachineFunction &MF);
66
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000067 /// Replace loop instruction with the constant extended
Brendon Cahoon55bdeb72015-04-27 14:16:43 +000068 /// version if the loop label is too far from the loop instruction.
69 void useExtLoopInstr(MachineFunction &MF,
70 MachineBasicBlock::iterator &MII);
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000071 };
72
73 char HexagonFixupHwLoops::ID = 0;
Alexander Kornienkof00654e2015-06-23 09:49:53 +000074}
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000075
76INITIALIZE_PASS(HexagonFixupHwLoops, "hwloopsfixup",
77 "Hexagon Hardware Loops Fixup", false, false)
78
79FunctionPass *llvm::createHexagonFixupHwLoops() {
80 return new HexagonFixupHwLoops();
81}
82
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000083/// Returns true if the instruction is a hardware loop instruction.
Duncan P. N. Exon Smith98226e32016-07-12 01:55:32 +000084static bool isHardwareLoop(const MachineInstr &MI) {
85 return MI.getOpcode() == Hexagon::J2_loop0r ||
86 MI.getOpcode() == Hexagon::J2_loop0i ||
87 MI.getOpcode() == Hexagon::J2_loop1r ||
88 MI.getOpcode() == Hexagon::J2_loop1i;
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000089}
90
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000091bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
Matthias Braunf1caa282017-12-15 22:22:58 +000092 if (skipFunction(MF.getFunction()))
Andrew Kaylor5b444a22016-04-26 19:46:28 +000093 return false;
Brendon Cahoon55bdeb72015-04-27 14:16:43 +000094 return fixupLoopInstrs(MF);
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000095}
96
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000097/// For Hexagon, if the loop label is to far from the
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +000098/// loop instruction then we need to set the LC0 and SA0 registers
99/// explicitly instead of using LOOP(start,count). This function
100/// checks the distance, and generates register assignments if needed.
101///
102/// This function makes two passes over the basic blocks. The first
103/// pass computes the offset of the basic block from the start.
104/// The second pass checks all the loop instructions.
105bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
106
107 // Offset of the current instruction from the start.
108 unsigned InstOffset = 0;
109 // Map for each basic block to it's first instruction.
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000110 DenseMap<const MachineBasicBlock *, unsigned> BlockToInstOffset;
111
112 const HexagonInstrInfo *HII =
113 static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000114
115 // First pass - compute the offset of each basic block.
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000116 for (const MachineBasicBlock &MBB : MF) {
Guillaume Chateletd4c46712019-09-18 15:49:49 +0000117 if (MBB.getAlignment() != llvm::Align::None()) {
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000118 // Although we don't know the exact layout of the final code, we need
119 // to account for alignment padding somehow. This heuristic pads each
120 // aligned basic block according to the alignment value.
Guillaume Chateletd4c46712019-09-18 15:49:49 +0000121 InstOffset = alignTo(InstOffset, MBB.getAlignment());
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000122 }
123
124 BlockToInstOffset[&MBB] = InstOffset;
125 for (const MachineInstr &MI : MBB)
Krzysztof Parzyszekf0b34a52016-07-29 21:49:42 +0000126 InstOffset += HII->getSize(MI);
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000127 }
128
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000129 // Second pass - check each loop instruction to see if it needs to be
130 // converted.
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000131 bool Changed = false;
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000132 for (MachineBasicBlock &MBB : MF) {
133 InstOffset = BlockToInstOffset[&MBB];
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000134
135 // Loop over all the instructions.
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000136 MachineBasicBlock::iterator MII = MBB.begin();
137 MachineBasicBlock::iterator MIE = MBB.end();
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000138 while (MII != MIE) {
Krzysztof Parzyszek8038dad2018-03-23 20:41:44 +0000139 unsigned InstSize = HII->getSize(*MII);
Krzysztof Parzyszek709e4f92017-08-10 15:00:30 +0000140 if (MII->isMetaInstruction()) {
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000141 ++MII;
142 continue;
143 }
Duncan P. N. Exon Smith98226e32016-07-12 01:55:32 +0000144 if (isHardwareLoop(*MII)) {
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000145 assert(MII->getOperand(0).isMBB() &&
146 "Expect a basic block as loop operand");
Krzysztof Parzyszek8038dad2018-03-23 20:41:44 +0000147 MachineBasicBlock *TargetBB = MII->getOperand(0).getMBB();
148 unsigned Diff = AbsoluteDifference(InstOffset,
149 BlockToInstOffset[TargetBB]);
150 if (Diff > MaxLoopRange) {
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000151 useExtLoopInstr(MF, MII);
152 MII = MBB.erase(MII);
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000153 Changed = true;
154 } else {
155 ++MII;
156 }
157 } else {
158 ++MII;
159 }
Krzysztof Parzyszek8038dad2018-03-23 20:41:44 +0000160 InstOffset += InstSize;
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000161 }
162 }
163
164 return Changed;
165}
166
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000167/// Replace loop instructions with the constant extended version.
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000168void HexagonFixupHwLoops::useExtLoopInstr(MachineFunction &MF,
169 MachineBasicBlock::iterator &MII) {
Eric Christopherfc6de422014-08-05 02:39:49 +0000170 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000171 MachineBasicBlock *MBB = MII->getParent();
172 DebugLoc DL = MII->getDebugLoc();
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000173 MachineInstrBuilder MIB;
174 unsigned newOp;
175 switch (MII->getOpcode()) {
176 case Hexagon::J2_loop0r:
177 newOp = Hexagon::J2_loop0rext;
178 break;
179 case Hexagon::J2_loop0i:
180 newOp = Hexagon::J2_loop0iext;
181 break;
182 case Hexagon::J2_loop1r:
183 newOp = Hexagon::J2_loop1rext;
184 break;
185 case Hexagon::J2_loop1i:
186 newOp = Hexagon::J2_loop1iext;
187 break;
188 default:
189 llvm_unreachable("Invalid Hardware Loop Instruction.");
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000190 }
Brendon Cahoon55bdeb72015-04-27 14:16:43 +0000191 MIB = BuildMI(*MBB, MII, DL, TII->get(newOp));
192
193 for (unsigned i = 0; i < MII->getNumOperands(); ++i)
Diana Picus116bbab2017-01-13 09:58:52 +0000194 MIB.add(MII->getOperand(i));
Krzysztof Parzyszek9a278f12013-02-11 21:37:55 +0000195}