1//===--- HexagonGenMemAbsolute.cpp - Generate Load/Store Set Absolute ---===//
2//
3// 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
6//
7//===----------------------------------------------------------------------===//
8
9// This pass traverses through all the basic blocks in a function and converts
10// an indexed load/store with offset "0" to a absolute-set load/store
11// instruction as long as the use of the register in the new instruction
12// dominates the rest of the uses and there are more than 2 uses.
13
14#include "HexagonTargetMachine.h"
15#include "llvm/ADT/Statistic.h"
16#include "llvm/CodeGen/MachineDominators.h"
17#include "llvm/CodeGen/MachineFunctionPass.h"
18#include "llvm/CodeGen/MachineInstrBuilder.h"
19#include "llvm/CodeGen/MachineRegisterInfo.h"
20#include "llvm/CodeGen/Passes.h"
21#include "llvm/CodeGen/TargetInstrInfo.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/raw_ostream.h"
24#include "llvm/Target/TargetMachine.h"
25
26#define DEBUG_TYPE "hexagon-abs"
27
28using namespace llvm;
29
30STATISTIC(HexagonNumLoadAbsConversions,
31 "Number of Load instructions converted to absolute-set form");
32STATISTIC(HexagonNumStoreAbsConversions,
33 "Number of Store instructions converted to absolute-set form");
34
35namespace llvm {
36FunctionPass *createHexagonGenMemAbsolute();
37void initializeHexagonGenMemAbsolutePass(PassRegistry &Registry);
38} // namespace llvm
39
40namespace {
41
42class HexagonGenMemAbsolute : public MachineFunctionPass {
43 const HexagonInstrInfo *TII;
44 MachineRegisterInfo *MRI;
45 const TargetRegisterInfo *TRI;
46
47public:
48 static char ID;
49 HexagonGenMemAbsolute() : MachineFunctionPass(ID), TII(0), MRI(0), TRI(0) {
50 initializeHexagonGenMemAbsolutePass(Registry&: *PassRegistry::getPassRegistry());
51 }
52
53 StringRef getPassName() const override {
54 return "Hexagon Generate Load/Store Set Absolute Address Instruction";
55 }
56
57 void getAnalysisUsage(AnalysisUsage &AU) const override {
58 MachineFunctionPass::getAnalysisUsage(AU);
59 AU.addRequired<MachineDominatorTreeWrapperPass>();
60 AU.addPreserved<MachineDominatorTreeWrapperPass>();
61 }
62
63 bool runOnMachineFunction(MachineFunction &Fn) override;
64
65private:
66 static bool isValidIndexedLoad(int &Opcode, int &NewOpcode);
67 static bool isValidIndexedStore(int &Opcode, int &NewOpcode);
68};
69} // namespace
70
71char HexagonGenMemAbsolute::ID = 0;
72
73INITIALIZE_PASS(HexagonGenMemAbsolute, "hexagon-gen-load-absolute",
74 "Hexagon Generate Load/Store Set Absolute Address Instruction",
75 false, false)
76
77bool HexagonGenMemAbsolute::runOnMachineFunction(MachineFunction &Fn) {
78 if (skipFunction(F: Fn.getFunction()))
79 return false;
80
81 TII = Fn.getSubtarget<HexagonSubtarget>().getInstrInfo();
82 MRI = &Fn.getRegInfo();
83 TRI = Fn.getRegInfo().getTargetRegisterInfo();
84
85 MachineDominatorTree &MDT =
86 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
87
88 // Loop over all of the basic blocks
89 for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
90 MBBb != MBBe; ++MBBb) {
91 MachineBasicBlock *MBB = &*MBBb;
92 // Traverse the basic block
93 for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
94 ++MII) {
95 MachineInstr *MI = &*MII;
96 int Opc = MI->getOpcode();
97 if (Opc != Hexagon::CONST32 && Opc != Hexagon::A2_tfrsi)
98 continue;
99
100 const MachineOperand &MO = MI->getOperand(i: 0);
101 if (!MO.isReg() || !MO.isDef())
102 continue;
103
104 unsigned DstReg = MO.getReg();
105 if (MRI->use_nodbg_empty(RegNo: DstReg))
106 continue;
107
108 typedef MachineRegisterInfo::use_nodbg_iterator use_iterator;
109 use_iterator NextUseMI = MRI->use_nodbg_begin(RegNo: DstReg);
110
111 MachineInstr *NextMI = NextUseMI->getParent();
112 int NextOpc = NextMI->getOpcode();
113 int NewOpc;
114 bool IsLoad = isValidIndexedLoad(Opcode&: NextOpc, NewOpcode&: NewOpc);
115
116 if (!IsLoad && !isValidIndexedStore(Opcode&: NextOpc, NewOpcode&: NewOpc))
117 continue;
118
119 // Base and Offset positions for load and store instructions
120 // Load R(dest), R(base), Imm -> R(dest) = mem(R(base) + Imm)
121 // Store R(base), Imm, R (src) -> mem(R(base) + Imm) = R(src)
122 unsigned BaseRegPos, ImmPos, RegPos;
123 if (!TII->getBaseAndOffsetPosition(MI: *NextMI, BasePos&: BaseRegPos, OffsetPos&: ImmPos))
124 continue;
125 RegPos = IsLoad ? 0 : 2;
126
127 bool IsGlobal = MI->getOperand(i: 1).isGlobal();
128 if (!MI->getOperand(i: 1).isImm() && !IsGlobal)
129 continue;
130
131 const MachineOperand *BaseOp = nullptr;
132 int64_t Offset;
133 bool Scalable;
134 TII->getMemOperandWithOffset(MI: *NextMI, BaseOp, Offset, OffsetIsScalable&: Scalable, TRI);
135
136 // Ensure BaseOp is non-null and register type.
137 if (!BaseOp || !BaseOp->isReg())
138 continue;
139
140 if (Scalable)
141 continue;
142
143 unsigned BaseReg = BaseOp->getReg();
144 if ((DstReg != BaseReg) || (Offset != 0))
145 continue;
146
147 const MachineOperand &MO0 = NextMI->getOperand(i: RegPos);
148
149 if (!MO0.isReg())
150 continue;
151
152 unsigned LoadStoreReg = MO0.getReg();
153
154 // Store: Bail out if the src and base are same (def and use on same
155 // register).
156 if (LoadStoreReg == BaseReg)
157 continue;
158
159 // Insert the absolute-set instruction "I" only if the use of the
160 // BaseReg in "I" dominates the rest of the uses of BaseReg and if
161 // there are more than 2 uses of this BaseReg.
162 bool Dominates = true;
163 unsigned Counter = 0;
164 for (use_iterator I = NextUseMI, E = MRI->use_nodbg_end(); I != E; ++I) {
165 Counter++;
166 if (!MDT.dominates(A: NextMI, B: I->getParent()))
167 Dominates = false;
168 }
169
170 if ((!Dominates) || (Counter < 3))
171 continue;
172
173 // If we reach here, we have met all the conditions required for the
174 // replacement of the absolute instruction.
175 LLVM_DEBUG({
176 dbgs() << "Found a pair of instructions for absolute-set "
177 << (IsLoad ? "load" : "store") << "\n";
178 dbgs() << *MI;
179 dbgs() << *NextMI;
180 });
181 MachineBasicBlock *ParentBlock = NextMI->getParent();
182 MachineInstrBuilder MIB;
183 if (IsLoad) { // Insert absolute-set load instruction
184 ++HexagonNumLoadAbsConversions;
185 MIB = BuildMI(BB&: *ParentBlock, I: NextMI, MIMD: NextMI->getDebugLoc(),
186 MCID: TII->get(Opcode: NewOpc), DestReg: LoadStoreReg)
187 .addReg(RegNo: DstReg, flags: RegState::Define);
188 } else { // Insert absolute-set store instruction
189 ++HexagonNumStoreAbsConversions;
190 MIB = BuildMI(BB&: *ParentBlock, I: NextMI, MIMD: NextMI->getDebugLoc(),
191 MCID: TII->get(Opcode: NewOpc), DestReg: DstReg);
192 }
193
194 MachineOperand ImmOperand = MI->getOperand(i: 1);
195 if (IsGlobal)
196 MIB.addGlobalAddress(GV: ImmOperand.getGlobal(), Offset: ImmOperand.getOffset(),
197 TargetFlags: ImmOperand.getTargetFlags());
198 else
199 MIB.addImm(Val: ImmOperand.getImm());
200
201 if (IsLoad)
202 MIB->getOperand(i: 0).setSubReg(MO0.getSubReg());
203 else
204 MIB.addReg(RegNo: LoadStoreReg, flags: 0, SubReg: MO0.getSubReg());
205
206 LLVM_DEBUG(dbgs() << "Replaced with " << *MIB << "\n");
207 // Erase the instructions that got replaced.
208 MII = MBB->erase(I: MI);
209 --MII;
210 NextMI->getParent()->erase(I: NextMI);
211 }
212 }
213
214 return true;
215}
216
217bool HexagonGenMemAbsolute::isValidIndexedLoad(int &Opc, int &NewOpc) {
218
219 bool Result = true;
220 switch (Opc) {
221 case Hexagon::L2_loadrb_io:
222 NewOpc = Hexagon::L4_loadrb_ap;
223 break;
224 case Hexagon::L2_loadrh_io:
225 NewOpc = Hexagon::L4_loadrh_ap;
226 break;
227 case Hexagon::L2_loadri_io:
228 NewOpc = Hexagon::L4_loadri_ap;
229 break;
230 case Hexagon::L2_loadrd_io:
231 NewOpc = Hexagon::L4_loadrd_ap;
232 break;
233 case Hexagon::L2_loadruh_io:
234 NewOpc = Hexagon::L4_loadruh_ap;
235 break;
236 case Hexagon::L2_loadrub_io:
237 NewOpc = Hexagon::L4_loadrub_ap;
238 break;
239 default:
240 Result = false;
241 }
242
243 return Result;
244}
245
246bool HexagonGenMemAbsolute::isValidIndexedStore(int &Opc, int &NewOpc) {
247
248 bool Result = true;
249 switch (Opc) {
250 case Hexagon::S2_storerd_io:
251 NewOpc = Hexagon::S4_storerd_ap;
252 break;
253 case Hexagon::S2_storeri_io:
254 NewOpc = Hexagon::S4_storeri_ap;
255 break;
256 case Hexagon::S2_storerh_io:
257 NewOpc = Hexagon::S4_storerh_ap;
258 break;
259 case Hexagon::S2_storerb_io:
260 NewOpc = Hexagon::S4_storerb_ap;
261 break;
262 default:
263 Result = false;
264 }
265
266 return Result;
267}
268
269//===----------------------------------------------------------------------===//
270// Public Constructor Functions
271//===----------------------------------------------------------------------===//
272
273FunctionPass *llvm::createHexagonGenMemAbsolute() {
274 return new HexagonGenMemAbsolute();
275}
276