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