xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- HexagonSplitDouble.cpp ---------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #define DEBUG_TYPE "hsdr"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
12*0b57cec5SDimitry Andric #include "HexagonRegisterInfo.h"
13*0b57cec5SDimitry Andric #include "HexagonSubtarget.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
16*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
17*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
27*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
28*0b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
29*0b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
30*0b57cec5SDimitry Andric #include "llvm/Pass.h"
31*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
32*0b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
33*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
34*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
35*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
36*0b57cec5SDimitry Andric #include <algorithm>
37*0b57cec5SDimitry Andric #include <cassert>
38*0b57cec5SDimitry Andric #include <cstdint>
39*0b57cec5SDimitry Andric #include <limits>
40*0b57cec5SDimitry Andric #include <map>
41*0b57cec5SDimitry Andric #include <set>
42*0b57cec5SDimitry Andric #include <utility>
43*0b57cec5SDimitry Andric #include <vector>
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric using namespace llvm;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric namespace llvm {
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric   FunctionPass *createHexagonSplitDoubleRegs();
50*0b57cec5SDimitry Andric   void initializeHexagonSplitDoubleRegsPass(PassRegistry&);
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric } // end namespace llvm
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric static cl::opt<int> MaxHSDR("max-hsdr", cl::Hidden, cl::init(-1),
55*0b57cec5SDimitry Andric     cl::desc("Maximum number of split partitions"));
56*0b57cec5SDimitry Andric static cl::opt<bool> MemRefsFixed("hsdr-no-mem", cl::Hidden, cl::init(true),
57*0b57cec5SDimitry Andric     cl::desc("Do not split loads or stores"));
58*0b57cec5SDimitry Andric   static cl::opt<bool> SplitAll("hsdr-split-all", cl::Hidden, cl::init(false),
59*0b57cec5SDimitry Andric       cl::desc("Split all partitions"));
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric namespace {
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric   class HexagonSplitDoubleRegs : public MachineFunctionPass {
64*0b57cec5SDimitry Andric   public:
65*0b57cec5SDimitry Andric     static char ID;
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric     HexagonSplitDoubleRegs() : MachineFunctionPass(ID) {}
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric     StringRef getPassName() const override {
70*0b57cec5SDimitry Andric       return "Hexagon Split Double Registers";
71*0b57cec5SDimitry Andric     }
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
74*0b57cec5SDimitry Andric       AU.addRequired<MachineLoopInfo>();
75*0b57cec5SDimitry Andric       AU.addPreserved<MachineLoopInfo>();
76*0b57cec5SDimitry Andric       MachineFunctionPass::getAnalysisUsage(AU);
77*0b57cec5SDimitry Andric     }
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric   private:
82*0b57cec5SDimitry Andric     static const TargetRegisterClass *const DoubleRC;
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric     const HexagonRegisterInfo *TRI = nullptr;
85*0b57cec5SDimitry Andric     const HexagonInstrInfo *TII = nullptr;
86*0b57cec5SDimitry Andric     const MachineLoopInfo *MLI;
87*0b57cec5SDimitry Andric     MachineRegisterInfo *MRI;
88*0b57cec5SDimitry Andric 
89*0b57cec5SDimitry Andric     using USet = std::set<unsigned>;
90*0b57cec5SDimitry Andric     using UUSetMap = std::map<unsigned, USet>;
91*0b57cec5SDimitry Andric     using UUPair = std::pair<unsigned, unsigned>;
92*0b57cec5SDimitry Andric     using UUPairMap = std::map<unsigned, UUPair>;
93*0b57cec5SDimitry Andric     using LoopRegMap = std::map<const MachineLoop *, USet>;
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric     bool isInduction(unsigned Reg, LoopRegMap &IRM) const;
96*0b57cec5SDimitry Andric     bool isVolatileInstr(const MachineInstr *MI) const;
97*0b57cec5SDimitry Andric     bool isFixedInstr(const MachineInstr *MI) const;
98*0b57cec5SDimitry Andric     void partitionRegisters(UUSetMap &P2Rs);
99*0b57cec5SDimitry Andric     int32_t profit(const MachineInstr *MI) const;
100*0b57cec5SDimitry Andric     int32_t profit(unsigned Reg) const;
101*0b57cec5SDimitry Andric     bool isProfitable(const USet &Part, LoopRegMap &IRM) const;
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric     void collectIndRegsForLoop(const MachineLoop *L, USet &Rs);
104*0b57cec5SDimitry Andric     void collectIndRegs(LoopRegMap &IRM);
105*0b57cec5SDimitry Andric 
106*0b57cec5SDimitry Andric     void createHalfInstr(unsigned Opc, MachineInstr *MI,
107*0b57cec5SDimitry Andric         const UUPairMap &PairMap, unsigned SubR);
108*0b57cec5SDimitry Andric     void splitMemRef(MachineInstr *MI, const UUPairMap &PairMap);
109*0b57cec5SDimitry Andric     void splitImmediate(MachineInstr *MI, const UUPairMap &PairMap);
110*0b57cec5SDimitry Andric     void splitCombine(MachineInstr *MI, const UUPairMap &PairMap);
111*0b57cec5SDimitry Andric     void splitExt(MachineInstr *MI, const UUPairMap &PairMap);
112*0b57cec5SDimitry Andric     void splitShift(MachineInstr *MI, const UUPairMap &PairMap);
113*0b57cec5SDimitry Andric     void splitAslOr(MachineInstr *MI, const UUPairMap &PairMap);
114*0b57cec5SDimitry Andric     bool splitInstr(MachineInstr *MI, const UUPairMap &PairMap);
115*0b57cec5SDimitry Andric     void replaceSubregUses(MachineInstr *MI, const UUPairMap &PairMap);
116*0b57cec5SDimitry Andric     void collapseRegPairs(MachineInstr *MI, const UUPairMap &PairMap);
117*0b57cec5SDimitry Andric     bool splitPartition(const USet &Part);
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric     static int Counter;
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric     static void dump_partition(raw_ostream&, const USet&,
122*0b57cec5SDimitry Andric        const TargetRegisterInfo&);
123*0b57cec5SDimitry Andric   };
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric } // end anonymous namespace
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric char HexagonSplitDoubleRegs::ID;
128*0b57cec5SDimitry Andric int HexagonSplitDoubleRegs::Counter = 0;
129*0b57cec5SDimitry Andric const TargetRegisterClass *const HexagonSplitDoubleRegs::DoubleRC =
130*0b57cec5SDimitry Andric     &Hexagon::DoubleRegsRegClass;
131*0b57cec5SDimitry Andric 
132*0b57cec5SDimitry Andric INITIALIZE_PASS(HexagonSplitDoubleRegs, "hexagon-split-double",
133*0b57cec5SDimitry Andric   "Hexagon Split Double Registers", false, false)
134*0b57cec5SDimitry Andric 
135*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
136*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void HexagonSplitDoubleRegs::dump_partition(raw_ostream &os,
137*0b57cec5SDimitry Andric       const USet &Part, const TargetRegisterInfo &TRI) {
138*0b57cec5SDimitry Andric   dbgs() << '{';
139*0b57cec5SDimitry Andric   for (auto I : Part)
140*0b57cec5SDimitry Andric     dbgs() << ' ' << printReg(I, &TRI);
141*0b57cec5SDimitry Andric   dbgs() << " }";
142*0b57cec5SDimitry Andric }
143*0b57cec5SDimitry Andric #endif
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isInduction(unsigned Reg, LoopRegMap &IRM) const {
146*0b57cec5SDimitry Andric   for (auto I : IRM) {
147*0b57cec5SDimitry Andric     const USet &Rs = I.second;
148*0b57cec5SDimitry Andric     if (Rs.find(Reg) != Rs.end())
149*0b57cec5SDimitry Andric       return true;
150*0b57cec5SDimitry Andric   }
151*0b57cec5SDimitry Andric   return false;
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isVolatileInstr(const MachineInstr *MI) const {
155*0b57cec5SDimitry Andric   for (auto &MO : MI->memoperands())
156*0b57cec5SDimitry Andric     if (MO->isVolatile() || MO->isAtomic())
157*0b57cec5SDimitry Andric       return true;
158*0b57cec5SDimitry Andric   return false;
159*0b57cec5SDimitry Andric }
160*0b57cec5SDimitry Andric 
161*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const {
162*0b57cec5SDimitry Andric   if (MI->mayLoad() || MI->mayStore())
163*0b57cec5SDimitry Andric     if (MemRefsFixed || isVolatileInstr(MI))
164*0b57cec5SDimitry Andric       return true;
165*0b57cec5SDimitry Andric   if (MI->isDebugInstr())
166*0b57cec5SDimitry Andric     return false;
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
169*0b57cec5SDimitry Andric   switch (Opc) {
170*0b57cec5SDimitry Andric     default:
171*0b57cec5SDimitry Andric       return true;
172*0b57cec5SDimitry Andric 
173*0b57cec5SDimitry Andric     case TargetOpcode::PHI:
174*0b57cec5SDimitry Andric     case TargetOpcode::COPY:
175*0b57cec5SDimitry Andric       break;
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric     case Hexagon::L2_loadrd_io:
178*0b57cec5SDimitry Andric       // Not handling stack stores (only reg-based addresses).
179*0b57cec5SDimitry Andric       if (MI->getOperand(1).isReg())
180*0b57cec5SDimitry Andric         break;
181*0b57cec5SDimitry Andric       return true;
182*0b57cec5SDimitry Andric     case Hexagon::S2_storerd_io:
183*0b57cec5SDimitry Andric       // Not handling stack stores (only reg-based addresses).
184*0b57cec5SDimitry Andric       if (MI->getOperand(0).isReg())
185*0b57cec5SDimitry Andric         break;
186*0b57cec5SDimitry Andric       return true;
187*0b57cec5SDimitry Andric     case Hexagon::L2_loadrd_pi:
188*0b57cec5SDimitry Andric     case Hexagon::S2_storerd_pi:
189*0b57cec5SDimitry Andric 
190*0b57cec5SDimitry Andric     case Hexagon::A2_tfrpi:
191*0b57cec5SDimitry Andric     case Hexagon::A2_combineii:
192*0b57cec5SDimitry Andric     case Hexagon::A4_combineir:
193*0b57cec5SDimitry Andric     case Hexagon::A4_combineii:
194*0b57cec5SDimitry Andric     case Hexagon::A4_combineri:
195*0b57cec5SDimitry Andric     case Hexagon::A2_combinew:
196*0b57cec5SDimitry Andric     case Hexagon::CONST64:
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric     case Hexagon::A2_sxtw:
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric     case Hexagon::A2_andp:
201*0b57cec5SDimitry Andric     case Hexagon::A2_orp:
202*0b57cec5SDimitry Andric     case Hexagon::A2_xorp:
203*0b57cec5SDimitry Andric     case Hexagon::S2_asl_i_p_or:
204*0b57cec5SDimitry Andric     case Hexagon::S2_asl_i_p:
205*0b57cec5SDimitry Andric     case Hexagon::S2_asr_i_p:
206*0b57cec5SDimitry Andric     case Hexagon::S2_lsr_i_p:
207*0b57cec5SDimitry Andric       break;
208*0b57cec5SDimitry Andric   }
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric   for (auto &Op : MI->operands()) {
211*0b57cec5SDimitry Andric     if (!Op.isReg())
212*0b57cec5SDimitry Andric       continue;
213*0b57cec5SDimitry Andric     unsigned R = Op.getReg();
214*0b57cec5SDimitry Andric     if (!TargetRegisterInfo::isVirtualRegister(R))
215*0b57cec5SDimitry Andric       return true;
216*0b57cec5SDimitry Andric   }
217*0b57cec5SDimitry Andric   return false;
218*0b57cec5SDimitry Andric }
219*0b57cec5SDimitry Andric 
220*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) {
221*0b57cec5SDimitry Andric   using UUMap = std::map<unsigned, unsigned>;
222*0b57cec5SDimitry Andric   using UVect = std::vector<unsigned>;
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric   unsigned NumRegs = MRI->getNumVirtRegs();
225*0b57cec5SDimitry Andric   BitVector DoubleRegs(NumRegs);
226*0b57cec5SDimitry Andric   for (unsigned i = 0; i < NumRegs; ++i) {
227*0b57cec5SDimitry Andric     unsigned R = TargetRegisterInfo::index2VirtReg(i);
228*0b57cec5SDimitry Andric     if (MRI->getRegClass(R) == DoubleRC)
229*0b57cec5SDimitry Andric       DoubleRegs.set(i);
230*0b57cec5SDimitry Andric   }
231*0b57cec5SDimitry Andric 
232*0b57cec5SDimitry Andric   BitVector FixedRegs(NumRegs);
233*0b57cec5SDimitry Andric   for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) {
234*0b57cec5SDimitry Andric     unsigned R = TargetRegisterInfo::index2VirtReg(x);
235*0b57cec5SDimitry Andric     MachineInstr *DefI = MRI->getVRegDef(R);
236*0b57cec5SDimitry Andric     // In some cases a register may exist, but never be defined or used.
237*0b57cec5SDimitry Andric     // It should never appear anywhere, but mark it as "fixed", just to be
238*0b57cec5SDimitry Andric     // safe.
239*0b57cec5SDimitry Andric     if (!DefI || isFixedInstr(DefI))
240*0b57cec5SDimitry Andric       FixedRegs.set(x);
241*0b57cec5SDimitry Andric   }
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric   UUSetMap AssocMap;
244*0b57cec5SDimitry Andric   for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) {
245*0b57cec5SDimitry Andric     if (FixedRegs[x])
246*0b57cec5SDimitry Andric       continue;
247*0b57cec5SDimitry Andric     unsigned R = TargetRegisterInfo::index2VirtReg(x);
248*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << printReg(R, TRI) << " ~~");
249*0b57cec5SDimitry Andric     USet &Asc = AssocMap[R];
250*0b57cec5SDimitry Andric     for (auto U = MRI->use_nodbg_begin(R), Z = MRI->use_nodbg_end();
251*0b57cec5SDimitry Andric          U != Z; ++U) {
252*0b57cec5SDimitry Andric       MachineOperand &Op = *U;
253*0b57cec5SDimitry Andric       MachineInstr *UseI = Op.getParent();
254*0b57cec5SDimitry Andric       if (isFixedInstr(UseI))
255*0b57cec5SDimitry Andric         continue;
256*0b57cec5SDimitry Andric       for (unsigned i = 0, n = UseI->getNumOperands(); i < n; ++i) {
257*0b57cec5SDimitry Andric         MachineOperand &MO = UseI->getOperand(i);
258*0b57cec5SDimitry Andric         // Skip non-registers or registers with subregisters.
259*0b57cec5SDimitry Andric         if (&MO == &Op || !MO.isReg() || MO.getSubReg())
260*0b57cec5SDimitry Andric           continue;
261*0b57cec5SDimitry Andric         unsigned T = MO.getReg();
262*0b57cec5SDimitry Andric         if (!TargetRegisterInfo::isVirtualRegister(T)) {
263*0b57cec5SDimitry Andric           FixedRegs.set(x);
264*0b57cec5SDimitry Andric           continue;
265*0b57cec5SDimitry Andric         }
266*0b57cec5SDimitry Andric         if (MRI->getRegClass(T) != DoubleRC)
267*0b57cec5SDimitry Andric           continue;
268*0b57cec5SDimitry Andric         unsigned u = TargetRegisterInfo::virtReg2Index(T);
269*0b57cec5SDimitry Andric         if (FixedRegs[u])
270*0b57cec5SDimitry Andric           continue;
271*0b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << ' ' << printReg(T, TRI));
272*0b57cec5SDimitry Andric         Asc.insert(T);
273*0b57cec5SDimitry Andric         // Make it symmetric.
274*0b57cec5SDimitry Andric         AssocMap[T].insert(R);
275*0b57cec5SDimitry Andric       }
276*0b57cec5SDimitry Andric     }
277*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << '\n');
278*0b57cec5SDimitry Andric   }
279*0b57cec5SDimitry Andric 
280*0b57cec5SDimitry Andric   UUMap R2P;
281*0b57cec5SDimitry Andric   unsigned NextP = 1;
282*0b57cec5SDimitry Andric   USet Visited;
283*0b57cec5SDimitry Andric   for (int x = DoubleRegs.find_first(); x >= 0; x = DoubleRegs.find_next(x)) {
284*0b57cec5SDimitry Andric     unsigned R = TargetRegisterInfo::index2VirtReg(x);
285*0b57cec5SDimitry Andric     if (Visited.count(R))
286*0b57cec5SDimitry Andric       continue;
287*0b57cec5SDimitry Andric     // Create a new partition for R.
288*0b57cec5SDimitry Andric     unsigned ThisP = FixedRegs[x] ? 0 : NextP++;
289*0b57cec5SDimitry Andric     UVect WorkQ;
290*0b57cec5SDimitry Andric     WorkQ.push_back(R);
291*0b57cec5SDimitry Andric     for (unsigned i = 0; i < WorkQ.size(); ++i) {
292*0b57cec5SDimitry Andric       unsigned T = WorkQ[i];
293*0b57cec5SDimitry Andric       if (Visited.count(T))
294*0b57cec5SDimitry Andric         continue;
295*0b57cec5SDimitry Andric       R2P[T] = ThisP;
296*0b57cec5SDimitry Andric       Visited.insert(T);
297*0b57cec5SDimitry Andric       // Add all registers associated with T.
298*0b57cec5SDimitry Andric       USet &Asc = AssocMap[T];
299*0b57cec5SDimitry Andric       for (USet::iterator J = Asc.begin(), F = Asc.end(); J != F; ++J)
300*0b57cec5SDimitry Andric         WorkQ.push_back(*J);
301*0b57cec5SDimitry Andric     }
302*0b57cec5SDimitry Andric   }
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric   for (auto I : R2P)
305*0b57cec5SDimitry Andric     P2Rs[I.second].insert(I.first);
306*0b57cec5SDimitry Andric }
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric static inline int32_t profitImm(unsigned Imm) {
309*0b57cec5SDimitry Andric   int32_t P = 0;
310*0b57cec5SDimitry Andric   if (Imm == 0 || Imm == 0xFFFFFFFF)
311*0b57cec5SDimitry Andric     P += 10;
312*0b57cec5SDimitry Andric   return P;
313*0b57cec5SDimitry Andric }
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const {
316*0b57cec5SDimitry Andric   unsigned ImmX = 0;
317*0b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
318*0b57cec5SDimitry Andric   switch (Opc) {
319*0b57cec5SDimitry Andric     case TargetOpcode::PHI:
320*0b57cec5SDimitry Andric       for (const auto &Op : MI->operands())
321*0b57cec5SDimitry Andric         if (!Op.getSubReg())
322*0b57cec5SDimitry Andric           return 0;
323*0b57cec5SDimitry Andric       return 10;
324*0b57cec5SDimitry Andric     case TargetOpcode::COPY:
325*0b57cec5SDimitry Andric       if (MI->getOperand(1).getSubReg() != 0)
326*0b57cec5SDimitry Andric         return 10;
327*0b57cec5SDimitry Andric       return 0;
328*0b57cec5SDimitry Andric 
329*0b57cec5SDimitry Andric     case Hexagon::L2_loadrd_io:
330*0b57cec5SDimitry Andric     case Hexagon::S2_storerd_io:
331*0b57cec5SDimitry Andric       return -1;
332*0b57cec5SDimitry Andric     case Hexagon::L2_loadrd_pi:
333*0b57cec5SDimitry Andric     case Hexagon::S2_storerd_pi:
334*0b57cec5SDimitry Andric       return 2;
335*0b57cec5SDimitry Andric 
336*0b57cec5SDimitry Andric     case Hexagon::A2_tfrpi:
337*0b57cec5SDimitry Andric     case Hexagon::CONST64: {
338*0b57cec5SDimitry Andric       uint64_t D = MI->getOperand(1).getImm();
339*0b57cec5SDimitry Andric       unsigned Lo = D & 0xFFFFFFFFULL;
340*0b57cec5SDimitry Andric       unsigned Hi = D >> 32;
341*0b57cec5SDimitry Andric       return profitImm(Lo) + profitImm(Hi);
342*0b57cec5SDimitry Andric     }
343*0b57cec5SDimitry Andric     case Hexagon::A2_combineii:
344*0b57cec5SDimitry Andric     case Hexagon::A4_combineii: {
345*0b57cec5SDimitry Andric       const MachineOperand &Op1 = MI->getOperand(1);
346*0b57cec5SDimitry Andric       const MachineOperand &Op2 = MI->getOperand(2);
347*0b57cec5SDimitry Andric       int32_t Prof1 = Op1.isImm() ? profitImm(Op1.getImm()) : 0;
348*0b57cec5SDimitry Andric       int32_t Prof2 = Op2.isImm() ? profitImm(Op2.getImm()) : 0;
349*0b57cec5SDimitry Andric       return Prof1 + Prof2;
350*0b57cec5SDimitry Andric     }
351*0b57cec5SDimitry Andric     case Hexagon::A4_combineri:
352*0b57cec5SDimitry Andric       ImmX++;
353*0b57cec5SDimitry Andric       // Fall through into A4_combineir.
354*0b57cec5SDimitry Andric       LLVM_FALLTHROUGH;
355*0b57cec5SDimitry Andric     case Hexagon::A4_combineir: {
356*0b57cec5SDimitry Andric       ImmX++;
357*0b57cec5SDimitry Andric       const MachineOperand &OpX = MI->getOperand(ImmX);
358*0b57cec5SDimitry Andric       if (OpX.isImm()) {
359*0b57cec5SDimitry Andric         int64_t V = OpX.getImm();
360*0b57cec5SDimitry Andric         if (V == 0 || V == -1)
361*0b57cec5SDimitry Andric           return 10;
362*0b57cec5SDimitry Andric       }
363*0b57cec5SDimitry Andric       // Fall through into A2_combinew.
364*0b57cec5SDimitry Andric       LLVM_FALLTHROUGH;
365*0b57cec5SDimitry Andric     }
366*0b57cec5SDimitry Andric     case Hexagon::A2_combinew:
367*0b57cec5SDimitry Andric       return 2;
368*0b57cec5SDimitry Andric 
369*0b57cec5SDimitry Andric     case Hexagon::A2_sxtw:
370*0b57cec5SDimitry Andric       return 3;
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric     case Hexagon::A2_andp:
373*0b57cec5SDimitry Andric     case Hexagon::A2_orp:
374*0b57cec5SDimitry Andric     case Hexagon::A2_xorp: {
375*0b57cec5SDimitry Andric       unsigned Rs = MI->getOperand(1).getReg();
376*0b57cec5SDimitry Andric       unsigned Rt = MI->getOperand(2).getReg();
377*0b57cec5SDimitry Andric       return profit(Rs) + profit(Rt);
378*0b57cec5SDimitry Andric     }
379*0b57cec5SDimitry Andric 
380*0b57cec5SDimitry Andric     case Hexagon::S2_asl_i_p_or: {
381*0b57cec5SDimitry Andric       unsigned S = MI->getOperand(3).getImm();
382*0b57cec5SDimitry Andric       if (S == 0 || S == 32)
383*0b57cec5SDimitry Andric         return 10;
384*0b57cec5SDimitry Andric       return -1;
385*0b57cec5SDimitry Andric     }
386*0b57cec5SDimitry Andric     case Hexagon::S2_asl_i_p:
387*0b57cec5SDimitry Andric     case Hexagon::S2_asr_i_p:
388*0b57cec5SDimitry Andric     case Hexagon::S2_lsr_i_p:
389*0b57cec5SDimitry Andric       unsigned S = MI->getOperand(2).getImm();
390*0b57cec5SDimitry Andric       if (S == 0 || S == 32)
391*0b57cec5SDimitry Andric         return 10;
392*0b57cec5SDimitry Andric       if (S == 16)
393*0b57cec5SDimitry Andric         return 5;
394*0b57cec5SDimitry Andric       if (S == 48)
395*0b57cec5SDimitry Andric         return 7;
396*0b57cec5SDimitry Andric       return -10;
397*0b57cec5SDimitry Andric   }
398*0b57cec5SDimitry Andric 
399*0b57cec5SDimitry Andric   return 0;
400*0b57cec5SDimitry Andric }
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric int32_t HexagonSplitDoubleRegs::profit(unsigned Reg) const {
403*0b57cec5SDimitry Andric   assert(TargetRegisterInfo::isVirtualRegister(Reg));
404*0b57cec5SDimitry Andric 
405*0b57cec5SDimitry Andric   const MachineInstr *DefI = MRI->getVRegDef(Reg);
406*0b57cec5SDimitry Andric   switch (DefI->getOpcode()) {
407*0b57cec5SDimitry Andric     case Hexagon::A2_tfrpi:
408*0b57cec5SDimitry Andric     case Hexagon::CONST64:
409*0b57cec5SDimitry Andric     case Hexagon::A2_combineii:
410*0b57cec5SDimitry Andric     case Hexagon::A4_combineii:
411*0b57cec5SDimitry Andric     case Hexagon::A4_combineri:
412*0b57cec5SDimitry Andric     case Hexagon::A4_combineir:
413*0b57cec5SDimitry Andric     case Hexagon::A2_combinew:
414*0b57cec5SDimitry Andric       return profit(DefI);
415*0b57cec5SDimitry Andric     default:
416*0b57cec5SDimitry Andric       break;
417*0b57cec5SDimitry Andric   }
418*0b57cec5SDimitry Andric   return 0;
419*0b57cec5SDimitry Andric }
420*0b57cec5SDimitry Andric 
421*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM)
422*0b57cec5SDimitry Andric       const {
423*0b57cec5SDimitry Andric   unsigned FixedNum = 0, LoopPhiNum = 0;
424*0b57cec5SDimitry Andric   int32_t TotalP = 0;
425*0b57cec5SDimitry Andric 
426*0b57cec5SDimitry Andric   for (unsigned DR : Part) {
427*0b57cec5SDimitry Andric     MachineInstr *DefI = MRI->getVRegDef(DR);
428*0b57cec5SDimitry Andric     int32_t P = profit(DefI);
429*0b57cec5SDimitry Andric     if (P == std::numeric_limits<int>::min())
430*0b57cec5SDimitry Andric       return false;
431*0b57cec5SDimitry Andric     TotalP += P;
432*0b57cec5SDimitry Andric     // Reduce the profitability of splitting induction registers.
433*0b57cec5SDimitry Andric     if (isInduction(DR, IRM))
434*0b57cec5SDimitry Andric       TotalP -= 30;
435*0b57cec5SDimitry Andric 
436*0b57cec5SDimitry Andric     for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end();
437*0b57cec5SDimitry Andric          U != W; ++U) {
438*0b57cec5SDimitry Andric       MachineInstr *UseI = U->getParent();
439*0b57cec5SDimitry Andric       if (isFixedInstr(UseI)) {
440*0b57cec5SDimitry Andric         FixedNum++;
441*0b57cec5SDimitry Andric         // Calculate the cost of generating REG_SEQUENCE instructions.
442*0b57cec5SDimitry Andric         for (auto &Op : UseI->operands()) {
443*0b57cec5SDimitry Andric           if (Op.isReg() && Part.count(Op.getReg()))
444*0b57cec5SDimitry Andric             if (Op.getSubReg())
445*0b57cec5SDimitry Andric               TotalP -= 2;
446*0b57cec5SDimitry Andric         }
447*0b57cec5SDimitry Andric         continue;
448*0b57cec5SDimitry Andric       }
449*0b57cec5SDimitry Andric       // If a register from this partition is used in a fixed instruction,
450*0b57cec5SDimitry Andric       // and there is also a register in this partition that is used in
451*0b57cec5SDimitry Andric       // a loop phi node, then decrease the splitting profit as this can
452*0b57cec5SDimitry Andric       // confuse the modulo scheduler.
453*0b57cec5SDimitry Andric       if (UseI->isPHI()) {
454*0b57cec5SDimitry Andric         const MachineBasicBlock *PB = UseI->getParent();
455*0b57cec5SDimitry Andric         const MachineLoop *L = MLI->getLoopFor(PB);
456*0b57cec5SDimitry Andric         if (L && L->getHeader() == PB)
457*0b57cec5SDimitry Andric           LoopPhiNum++;
458*0b57cec5SDimitry Andric       }
459*0b57cec5SDimitry Andric       // Splittable instruction.
460*0b57cec5SDimitry Andric       int32_t P = profit(UseI);
461*0b57cec5SDimitry Andric       if (P == std::numeric_limits<int>::min())
462*0b57cec5SDimitry Andric         return false;
463*0b57cec5SDimitry Andric       TotalP += P;
464*0b57cec5SDimitry Andric     }
465*0b57cec5SDimitry Andric   }
466*0b57cec5SDimitry Andric 
467*0b57cec5SDimitry Andric   if (FixedNum > 0 && LoopPhiNum > 0)
468*0b57cec5SDimitry Andric     TotalP -= 20*LoopPhiNum;
469*0b57cec5SDimitry Andric 
470*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Partition profit: " << TotalP << '\n');
471*0b57cec5SDimitry Andric   if (SplitAll)
472*0b57cec5SDimitry Andric     return true;
473*0b57cec5SDimitry Andric   return TotalP > 0;
474*0b57cec5SDimitry Andric }
475*0b57cec5SDimitry Andric 
476*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
477*0b57cec5SDimitry Andric       USet &Rs) {
478*0b57cec5SDimitry Andric   const MachineBasicBlock *HB = L->getHeader();
479*0b57cec5SDimitry Andric   const MachineBasicBlock *LB = L->getLoopLatch();
480*0b57cec5SDimitry Andric   if (!HB || !LB)
481*0b57cec5SDimitry Andric     return;
482*0b57cec5SDimitry Andric 
483*0b57cec5SDimitry Andric   // Examine the latch branch. Expect it to be a conditional branch to
484*0b57cec5SDimitry Andric   // the header (either "br-cond header" or "br-cond exit; br header").
485*0b57cec5SDimitry Andric   MachineBasicBlock *TB = nullptr, *FB = nullptr;
486*0b57cec5SDimitry Andric   MachineBasicBlock *TmpLB = const_cast<MachineBasicBlock*>(LB);
487*0b57cec5SDimitry Andric   SmallVector<MachineOperand,2> Cond;
488*0b57cec5SDimitry Andric   bool BadLB = TII->analyzeBranch(*TmpLB, TB, FB, Cond, false);
489*0b57cec5SDimitry Andric   // Only analyzable conditional branches. HII::analyzeBranch will put
490*0b57cec5SDimitry Andric   // the branch opcode as the first element of Cond, and the predicate
491*0b57cec5SDimitry Andric   // operand as the second.
492*0b57cec5SDimitry Andric   if (BadLB || Cond.size() != 2)
493*0b57cec5SDimitry Andric     return;
494*0b57cec5SDimitry Andric   // Only simple jump-conditional (with or without negation).
495*0b57cec5SDimitry Andric   if (!TII->PredOpcodeHasJMP_c(Cond[0].getImm()))
496*0b57cec5SDimitry Andric     return;
497*0b57cec5SDimitry Andric   // Must go to the header.
498*0b57cec5SDimitry Andric   if (TB != HB && FB != HB)
499*0b57cec5SDimitry Andric     return;
500*0b57cec5SDimitry Andric   assert(Cond[1].isReg() && "Unexpected Cond vector from analyzeBranch");
501*0b57cec5SDimitry Andric   // Expect a predicate register.
502*0b57cec5SDimitry Andric   unsigned PR = Cond[1].getReg();
503*0b57cec5SDimitry Andric   assert(MRI->getRegClass(PR) == &Hexagon::PredRegsRegClass);
504*0b57cec5SDimitry Andric 
505*0b57cec5SDimitry Andric   // Get the registers on which the loop controlling compare instruction
506*0b57cec5SDimitry Andric   // depends.
507*0b57cec5SDimitry Andric   unsigned CmpR1 = 0, CmpR2 = 0;
508*0b57cec5SDimitry Andric   const MachineInstr *CmpI = MRI->getVRegDef(PR);
509*0b57cec5SDimitry Andric   while (CmpI->getOpcode() == Hexagon::C2_not)
510*0b57cec5SDimitry Andric     CmpI = MRI->getVRegDef(CmpI->getOperand(1).getReg());
511*0b57cec5SDimitry Andric 
512*0b57cec5SDimitry Andric   int Mask = 0, Val = 0;
513*0b57cec5SDimitry Andric   bool OkCI = TII->analyzeCompare(*CmpI, CmpR1, CmpR2, Mask, Val);
514*0b57cec5SDimitry Andric   if (!OkCI)
515*0b57cec5SDimitry Andric     return;
516*0b57cec5SDimitry Andric   // Eliminate non-double input registers.
517*0b57cec5SDimitry Andric   if (CmpR1 && MRI->getRegClass(CmpR1) != DoubleRC)
518*0b57cec5SDimitry Andric     CmpR1 = 0;
519*0b57cec5SDimitry Andric   if (CmpR2 && MRI->getRegClass(CmpR2) != DoubleRC)
520*0b57cec5SDimitry Andric     CmpR2 = 0;
521*0b57cec5SDimitry Andric   if (!CmpR1 && !CmpR2)
522*0b57cec5SDimitry Andric     return;
523*0b57cec5SDimitry Andric 
524*0b57cec5SDimitry Andric   // Now examine the top of the loop: the phi nodes that could poten-
525*0b57cec5SDimitry Andric   // tially define loop induction registers. The registers defined by
526*0b57cec5SDimitry Andric   // such a phi node would be used in a 64-bit add, which then would
527*0b57cec5SDimitry Andric   // be used in the loop compare instruction.
528*0b57cec5SDimitry Andric 
529*0b57cec5SDimitry Andric   // Get the set of all double registers defined by phi nodes in the
530*0b57cec5SDimitry Andric   // loop header.
531*0b57cec5SDimitry Andric   using UVect = std::vector<unsigned>;
532*0b57cec5SDimitry Andric 
533*0b57cec5SDimitry Andric   UVect DP;
534*0b57cec5SDimitry Andric   for (auto &MI : *HB) {
535*0b57cec5SDimitry Andric     if (!MI.isPHI())
536*0b57cec5SDimitry Andric       break;
537*0b57cec5SDimitry Andric     const MachineOperand &MD = MI.getOperand(0);
538*0b57cec5SDimitry Andric     unsigned R = MD.getReg();
539*0b57cec5SDimitry Andric     if (MRI->getRegClass(R) == DoubleRC)
540*0b57cec5SDimitry Andric       DP.push_back(R);
541*0b57cec5SDimitry Andric   }
542*0b57cec5SDimitry Andric   if (DP.empty())
543*0b57cec5SDimitry Andric     return;
544*0b57cec5SDimitry Andric 
545*0b57cec5SDimitry Andric   auto NoIndOp = [this, CmpR1, CmpR2] (unsigned R) -> bool {
546*0b57cec5SDimitry Andric     for (auto I = MRI->use_nodbg_begin(R), E = MRI->use_nodbg_end();
547*0b57cec5SDimitry Andric          I != E; ++I) {
548*0b57cec5SDimitry Andric       const MachineInstr *UseI = I->getParent();
549*0b57cec5SDimitry Andric       if (UseI->getOpcode() != Hexagon::A2_addp)
550*0b57cec5SDimitry Andric         continue;
551*0b57cec5SDimitry Andric       // Get the output from the add. If it is one of the inputs to the
552*0b57cec5SDimitry Andric       // loop-controlling compare instruction, then R is likely an induc-
553*0b57cec5SDimitry Andric       // tion register.
554*0b57cec5SDimitry Andric       unsigned T = UseI->getOperand(0).getReg();
555*0b57cec5SDimitry Andric       if (T == CmpR1 || T == CmpR2)
556*0b57cec5SDimitry Andric         return false;
557*0b57cec5SDimitry Andric     }
558*0b57cec5SDimitry Andric     return true;
559*0b57cec5SDimitry Andric   };
560*0b57cec5SDimitry Andric   UVect::iterator End = llvm::remove_if(DP, NoIndOp);
561*0b57cec5SDimitry Andric   Rs.insert(DP.begin(), End);
562*0b57cec5SDimitry Andric   Rs.insert(CmpR1);
563*0b57cec5SDimitry Andric   Rs.insert(CmpR2);
564*0b57cec5SDimitry Andric 
565*0b57cec5SDimitry Andric   LLVM_DEBUG({
566*0b57cec5SDimitry Andric     dbgs() << "For loop at " << printMBBReference(*HB) << " ind regs: ";
567*0b57cec5SDimitry Andric     dump_partition(dbgs(), Rs, *TRI);
568*0b57cec5SDimitry Andric     dbgs() << '\n';
569*0b57cec5SDimitry Andric   });
570*0b57cec5SDimitry Andric }
571*0b57cec5SDimitry Andric 
572*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) {
573*0b57cec5SDimitry Andric   using LoopVector = std::vector<MachineLoop *>;
574*0b57cec5SDimitry Andric 
575*0b57cec5SDimitry Andric   LoopVector WorkQ;
576*0b57cec5SDimitry Andric 
577*0b57cec5SDimitry Andric   for (auto I : *MLI)
578*0b57cec5SDimitry Andric     WorkQ.push_back(I);
579*0b57cec5SDimitry Andric   for (unsigned i = 0; i < WorkQ.size(); ++i) {
580*0b57cec5SDimitry Andric     for (auto I : *WorkQ[i])
581*0b57cec5SDimitry Andric       WorkQ.push_back(I);
582*0b57cec5SDimitry Andric   }
583*0b57cec5SDimitry Andric 
584*0b57cec5SDimitry Andric   USet Rs;
585*0b57cec5SDimitry Andric   for (unsigned i = 0, n = WorkQ.size(); i < n; ++i) {
586*0b57cec5SDimitry Andric     MachineLoop *L = WorkQ[i];
587*0b57cec5SDimitry Andric     Rs.clear();
588*0b57cec5SDimitry Andric     collectIndRegsForLoop(L, Rs);
589*0b57cec5SDimitry Andric     if (!Rs.empty())
590*0b57cec5SDimitry Andric       IRM.insert(std::make_pair(L, Rs));
591*0b57cec5SDimitry Andric   }
592*0b57cec5SDimitry Andric }
593*0b57cec5SDimitry Andric 
594*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI,
595*0b57cec5SDimitry Andric       const UUPairMap &PairMap, unsigned SubR) {
596*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
597*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
598*0b57cec5SDimitry Andric   MachineInstr *NewI = BuildMI(B, MI, DL, TII->get(Opc));
599*0b57cec5SDimitry Andric 
600*0b57cec5SDimitry Andric   for (auto &Op : MI->operands()) {
601*0b57cec5SDimitry Andric     if (!Op.isReg()) {
602*0b57cec5SDimitry Andric       NewI->addOperand(Op);
603*0b57cec5SDimitry Andric       continue;
604*0b57cec5SDimitry Andric     }
605*0b57cec5SDimitry Andric     // For register operands, set the subregister.
606*0b57cec5SDimitry Andric     unsigned R = Op.getReg();
607*0b57cec5SDimitry Andric     unsigned SR = Op.getSubReg();
608*0b57cec5SDimitry Andric     bool isVirtReg = TargetRegisterInfo::isVirtualRegister(R);
609*0b57cec5SDimitry Andric     bool isKill = Op.isKill();
610*0b57cec5SDimitry Andric     if (isVirtReg && MRI->getRegClass(R) == DoubleRC) {
611*0b57cec5SDimitry Andric       isKill = false;
612*0b57cec5SDimitry Andric       UUPairMap::const_iterator F = PairMap.find(R);
613*0b57cec5SDimitry Andric       if (F == PairMap.end()) {
614*0b57cec5SDimitry Andric         SR = SubR;
615*0b57cec5SDimitry Andric       } else {
616*0b57cec5SDimitry Andric         const UUPair &P = F->second;
617*0b57cec5SDimitry Andric         R = (SubR == Hexagon::isub_lo) ? P.first : P.second;
618*0b57cec5SDimitry Andric         SR = 0;
619*0b57cec5SDimitry Andric       }
620*0b57cec5SDimitry Andric     }
621*0b57cec5SDimitry Andric     auto CO = MachineOperand::CreateReg(R, Op.isDef(), Op.isImplicit(), isKill,
622*0b57cec5SDimitry Andric           Op.isDead(), Op.isUndef(), Op.isEarlyClobber(), SR, Op.isDebug(),
623*0b57cec5SDimitry Andric           Op.isInternalRead());
624*0b57cec5SDimitry Andric     NewI->addOperand(CO);
625*0b57cec5SDimitry Andric   }
626*0b57cec5SDimitry Andric }
627*0b57cec5SDimitry Andric 
628*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitMemRef(MachineInstr *MI,
629*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
630*0b57cec5SDimitry Andric   bool Load = MI->mayLoad();
631*0b57cec5SDimitry Andric   unsigned OrigOpc = MI->getOpcode();
632*0b57cec5SDimitry Andric   bool PostInc = (OrigOpc == Hexagon::L2_loadrd_pi ||
633*0b57cec5SDimitry Andric                   OrigOpc == Hexagon::S2_storerd_pi);
634*0b57cec5SDimitry Andric   MachineInstr *LowI, *HighI;
635*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
636*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
637*0b57cec5SDimitry Andric 
638*0b57cec5SDimitry Andric   // Index of the base-address-register operand.
639*0b57cec5SDimitry Andric   unsigned AdrX = PostInc ? (Load ? 2 : 1)
640*0b57cec5SDimitry Andric                           : (Load ? 1 : 0);
641*0b57cec5SDimitry Andric   MachineOperand &AdrOp = MI->getOperand(AdrX);
642*0b57cec5SDimitry Andric   unsigned RSA = getRegState(AdrOp);
643*0b57cec5SDimitry Andric   MachineOperand &ValOp = Load ? MI->getOperand(0)
644*0b57cec5SDimitry Andric                                : (PostInc ? MI->getOperand(3)
645*0b57cec5SDimitry Andric                                           : MI->getOperand(2));
646*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(ValOp.getReg());
647*0b57cec5SDimitry Andric   assert(F != PairMap.end());
648*0b57cec5SDimitry Andric 
649*0b57cec5SDimitry Andric   if (Load) {
650*0b57cec5SDimitry Andric     const UUPair &P = F->second;
651*0b57cec5SDimitry Andric     int64_t Off = PostInc ? 0 : MI->getOperand(2).getImm();
652*0b57cec5SDimitry Andric     LowI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.first)
653*0b57cec5SDimitry Andric              .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg())
654*0b57cec5SDimitry Andric              .addImm(Off);
655*0b57cec5SDimitry Andric     HighI = BuildMI(B, MI, DL, TII->get(Hexagon::L2_loadri_io), P.second)
656*0b57cec5SDimitry Andric               .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg())
657*0b57cec5SDimitry Andric               .addImm(Off+4);
658*0b57cec5SDimitry Andric   } else {
659*0b57cec5SDimitry Andric     const UUPair &P = F->second;
660*0b57cec5SDimitry Andric     int64_t Off = PostInc ? 0 : MI->getOperand(1).getImm();
661*0b57cec5SDimitry Andric     LowI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io))
662*0b57cec5SDimitry Andric              .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg())
663*0b57cec5SDimitry Andric              .addImm(Off)
664*0b57cec5SDimitry Andric              .addReg(P.first);
665*0b57cec5SDimitry Andric     HighI = BuildMI(B, MI, DL, TII->get(Hexagon::S2_storeri_io))
666*0b57cec5SDimitry Andric               .addReg(AdrOp.getReg(), RSA & ~RegState::Kill, AdrOp.getSubReg())
667*0b57cec5SDimitry Andric               .addImm(Off+4)
668*0b57cec5SDimitry Andric               .addReg(P.second);
669*0b57cec5SDimitry Andric   }
670*0b57cec5SDimitry Andric 
671*0b57cec5SDimitry Andric   if (PostInc) {
672*0b57cec5SDimitry Andric     // Create the increment of the address register.
673*0b57cec5SDimitry Andric     int64_t Inc = Load ? MI->getOperand(3).getImm()
674*0b57cec5SDimitry Andric                        : MI->getOperand(2).getImm();
675*0b57cec5SDimitry Andric     MachineOperand &UpdOp = Load ? MI->getOperand(1) : MI->getOperand(0);
676*0b57cec5SDimitry Andric     const TargetRegisterClass *RC = MRI->getRegClass(UpdOp.getReg());
677*0b57cec5SDimitry Andric     unsigned NewR = MRI->createVirtualRegister(RC);
678*0b57cec5SDimitry Andric     assert(!UpdOp.getSubReg() && "Def operand with subreg");
679*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(Hexagon::A2_addi), NewR)
680*0b57cec5SDimitry Andric       .addReg(AdrOp.getReg(), RSA)
681*0b57cec5SDimitry Andric       .addImm(Inc);
682*0b57cec5SDimitry Andric     MRI->replaceRegWith(UpdOp.getReg(), NewR);
683*0b57cec5SDimitry Andric     // The original instruction will be deleted later.
684*0b57cec5SDimitry Andric   }
685*0b57cec5SDimitry Andric 
686*0b57cec5SDimitry Andric   // Generate a new pair of memory-operands.
687*0b57cec5SDimitry Andric   MachineFunction &MF = *B.getParent();
688*0b57cec5SDimitry Andric   for (auto &MO : MI->memoperands()) {
689*0b57cec5SDimitry Andric     const MachinePointerInfo &Ptr = MO->getPointerInfo();
690*0b57cec5SDimitry Andric     MachineMemOperand::Flags F = MO->getFlags();
691*0b57cec5SDimitry Andric     int A = MO->getAlignment();
692*0b57cec5SDimitry Andric 
693*0b57cec5SDimitry Andric     auto *Tmp1 = MF.getMachineMemOperand(Ptr, F, 4/*size*/, A);
694*0b57cec5SDimitry Andric     LowI->addMemOperand(MF, Tmp1);
695*0b57cec5SDimitry Andric     auto *Tmp2 = MF.getMachineMemOperand(Ptr, F, 4/*size*/, std::min(A, 4));
696*0b57cec5SDimitry Andric     HighI->addMemOperand(MF, Tmp2);
697*0b57cec5SDimitry Andric   }
698*0b57cec5SDimitry Andric }
699*0b57cec5SDimitry Andric 
700*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitImmediate(MachineInstr *MI,
701*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
702*0b57cec5SDimitry Andric   MachineOperand &Op0 = MI->getOperand(0);
703*0b57cec5SDimitry Andric   MachineOperand &Op1 = MI->getOperand(1);
704*0b57cec5SDimitry Andric   assert(Op0.isReg() && Op1.isImm());
705*0b57cec5SDimitry Andric   uint64_t V = Op1.getImm();
706*0b57cec5SDimitry Andric 
707*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
708*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
709*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(Op0.getReg());
710*0b57cec5SDimitry Andric   assert(F != PairMap.end());
711*0b57cec5SDimitry Andric   const UUPair &P = F->second;
712*0b57cec5SDimitry Andric 
713*0b57cec5SDimitry Andric   // The operand to A2_tfrsi can only have 32 significant bits. Immediate
714*0b57cec5SDimitry Andric   // values in MachineOperand are stored as 64-bit integers, and so the
715*0b57cec5SDimitry Andric   // value -1 may be represented either as 64-bit -1, or 4294967295. Both
716*0b57cec5SDimitry Andric   // will have the 32 higher bits truncated in the end, but -1 will remain
717*0b57cec5SDimitry Andric   // as -1, while the latter may appear to be a large unsigned value
718*0b57cec5SDimitry Andric   // requiring a constant extender. The casting to int32_t will select the
719*0b57cec5SDimitry Andric   // former representation. (The same reasoning applies to all 32-bit
720*0b57cec5SDimitry Andric   // values.)
721*0b57cec5SDimitry Andric   BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first)
722*0b57cec5SDimitry Andric     .addImm(int32_t(V & 0xFFFFFFFFULL));
723*0b57cec5SDimitry Andric   BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second)
724*0b57cec5SDimitry Andric     .addImm(int32_t(V >> 32));
725*0b57cec5SDimitry Andric }
726*0b57cec5SDimitry Andric 
727*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitCombine(MachineInstr *MI,
728*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
729*0b57cec5SDimitry Andric   MachineOperand &Op0 = MI->getOperand(0);
730*0b57cec5SDimitry Andric   MachineOperand &Op1 = MI->getOperand(1);
731*0b57cec5SDimitry Andric   MachineOperand &Op2 = MI->getOperand(2);
732*0b57cec5SDimitry Andric   assert(Op0.isReg());
733*0b57cec5SDimitry Andric 
734*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
735*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
736*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(Op0.getReg());
737*0b57cec5SDimitry Andric   assert(F != PairMap.end());
738*0b57cec5SDimitry Andric   const UUPair &P = F->second;
739*0b57cec5SDimitry Andric 
740*0b57cec5SDimitry Andric   if (!Op1.isReg()) {
741*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.second)
742*0b57cec5SDimitry Andric       .add(Op1);
743*0b57cec5SDimitry Andric   } else {
744*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.second)
745*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), getRegState(Op1), Op1.getSubReg());
746*0b57cec5SDimitry Andric   }
747*0b57cec5SDimitry Andric 
748*0b57cec5SDimitry Andric   if (!Op2.isReg()) {
749*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), P.first)
750*0b57cec5SDimitry Andric       .add(Op2);
751*0b57cec5SDimitry Andric   } else {
752*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first)
753*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), getRegState(Op2), Op2.getSubReg());
754*0b57cec5SDimitry Andric   }
755*0b57cec5SDimitry Andric }
756*0b57cec5SDimitry Andric 
757*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitExt(MachineInstr *MI,
758*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
759*0b57cec5SDimitry Andric   MachineOperand &Op0 = MI->getOperand(0);
760*0b57cec5SDimitry Andric   MachineOperand &Op1 = MI->getOperand(1);
761*0b57cec5SDimitry Andric   assert(Op0.isReg() && Op1.isReg());
762*0b57cec5SDimitry Andric 
763*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
764*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
765*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(Op0.getReg());
766*0b57cec5SDimitry Andric   assert(F != PairMap.end());
767*0b57cec5SDimitry Andric   const UUPair &P = F->second;
768*0b57cec5SDimitry Andric   unsigned RS = getRegState(Op1);
769*0b57cec5SDimitry Andric 
770*0b57cec5SDimitry Andric   BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), P.first)
771*0b57cec5SDimitry Andric     .addReg(Op1.getReg(), RS & ~RegState::Kill, Op1.getSubReg());
772*0b57cec5SDimitry Andric   BuildMI(B, MI, DL, TII->get(Hexagon::S2_asr_i_r), P.second)
773*0b57cec5SDimitry Andric     .addReg(Op1.getReg(), RS, Op1.getSubReg())
774*0b57cec5SDimitry Andric     .addImm(31);
775*0b57cec5SDimitry Andric }
776*0b57cec5SDimitry Andric 
777*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI,
778*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
779*0b57cec5SDimitry Andric   using namespace Hexagon;
780*0b57cec5SDimitry Andric 
781*0b57cec5SDimitry Andric   MachineOperand &Op0 = MI->getOperand(0);
782*0b57cec5SDimitry Andric   MachineOperand &Op1 = MI->getOperand(1);
783*0b57cec5SDimitry Andric   MachineOperand &Op2 = MI->getOperand(2);
784*0b57cec5SDimitry Andric   assert(Op0.isReg() && Op1.isReg() && Op2.isImm());
785*0b57cec5SDimitry Andric   int64_t Sh64 = Op2.getImm();
786*0b57cec5SDimitry Andric   assert(Sh64 >= 0 && Sh64 < 64);
787*0b57cec5SDimitry Andric   unsigned S = Sh64;
788*0b57cec5SDimitry Andric 
789*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(Op0.getReg());
790*0b57cec5SDimitry Andric   assert(F != PairMap.end());
791*0b57cec5SDimitry Andric   const UUPair &P = F->second;
792*0b57cec5SDimitry Andric   unsigned LoR = P.first;
793*0b57cec5SDimitry Andric   unsigned HiR = P.second;
794*0b57cec5SDimitry Andric 
795*0b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
796*0b57cec5SDimitry Andric   bool Right = (Opc == S2_lsr_i_p || Opc == S2_asr_i_p);
797*0b57cec5SDimitry Andric   bool Left = !Right;
798*0b57cec5SDimitry Andric   bool Signed = (Opc == S2_asr_i_p);
799*0b57cec5SDimitry Andric 
800*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
801*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
802*0b57cec5SDimitry Andric   unsigned RS = getRegState(Op1);
803*0b57cec5SDimitry Andric   unsigned ShiftOpc = Left ? S2_asl_i_r
804*0b57cec5SDimitry Andric                            : (Signed ? S2_asr_i_r : S2_lsr_i_r);
805*0b57cec5SDimitry Andric   unsigned LoSR = isub_lo;
806*0b57cec5SDimitry Andric   unsigned HiSR = isub_hi;
807*0b57cec5SDimitry Andric 
808*0b57cec5SDimitry Andric   if (S == 0) {
809*0b57cec5SDimitry Andric     // No shift, subregister copy.
810*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR)
811*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR);
812*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), HiR)
813*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS, HiSR);
814*0b57cec5SDimitry Andric   } else if (S < 32) {
815*0b57cec5SDimitry Andric     const TargetRegisterClass *IntRC = &IntRegsRegClass;
816*0b57cec5SDimitry Andric     unsigned TmpR = MRI->createVirtualRegister(IntRC);
817*0b57cec5SDimitry Andric     // Expansion:
818*0b57cec5SDimitry Andric     // Shift left:    DR = shl R, #s
819*0b57cec5SDimitry Andric     //   LoR  = shl R.lo, #s
820*0b57cec5SDimitry Andric     //   TmpR = extractu R.lo, #s, #32-s
821*0b57cec5SDimitry Andric     //   HiR  = or (TmpR, asl(R.hi, #s))
822*0b57cec5SDimitry Andric     // Shift right:   DR = shr R, #s
823*0b57cec5SDimitry Andric     //   HiR  = shr R.hi, #s
824*0b57cec5SDimitry Andric     //   TmpR = shr R.lo, #s
825*0b57cec5SDimitry Andric     //   LoR  = insert TmpR, R.hi, #s, #32-s
826*0b57cec5SDimitry Andric 
827*0b57cec5SDimitry Andric     // Shift left:
828*0b57cec5SDimitry Andric     //   LoR  = shl R.lo, #s
829*0b57cec5SDimitry Andric     // Shift right:
830*0b57cec5SDimitry Andric     //   TmpR = shr R.lo, #s
831*0b57cec5SDimitry Andric 
832*0b57cec5SDimitry Andric     // Make a special case for A2_aslh and A2_asrh (they are predicable as
833*0b57cec5SDimitry Andric     // opposed to S2_asl_i_r/S2_asr_i_r).
834*0b57cec5SDimitry Andric     if (S == 16 && Left)
835*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_aslh), LoR)
836*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR);
837*0b57cec5SDimitry Andric     else if (S == 16 && Signed)
838*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_asrh), TmpR)
839*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR);
840*0b57cec5SDimitry Andric     else
841*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? LoR : TmpR))
842*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR)
843*0b57cec5SDimitry Andric         .addImm(S);
844*0b57cec5SDimitry Andric 
845*0b57cec5SDimitry Andric     if (Left) {
846*0b57cec5SDimitry Andric       // TmpR = extractu R.lo, #s, #32-s
847*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR)
848*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR)
849*0b57cec5SDimitry Andric         .addImm(S)
850*0b57cec5SDimitry Andric         .addImm(32-S);
851*0b57cec5SDimitry Andric       // HiR  = or (TmpR, asl(R.hi, #s))
852*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR)
853*0b57cec5SDimitry Andric         .addReg(TmpR)
854*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS, HiSR)
855*0b57cec5SDimitry Andric         .addImm(S);
856*0b57cec5SDimitry Andric     } else {
857*0b57cec5SDimitry Andric       // HiR  = shr R.hi, #s
858*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(ShiftOpc), HiR)
859*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR)
860*0b57cec5SDimitry Andric         .addImm(S);
861*0b57cec5SDimitry Andric       // LoR  = insert TmpR, R.hi, #s, #32-s
862*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(S2_insert), LoR)
863*0b57cec5SDimitry Andric         .addReg(TmpR)
864*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS, HiSR)
865*0b57cec5SDimitry Andric         .addImm(S)
866*0b57cec5SDimitry Andric         .addImm(32-S);
867*0b57cec5SDimitry Andric     }
868*0b57cec5SDimitry Andric   } else if (S == 32) {
869*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), (Left ? HiR : LoR))
870*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR));
871*0b57cec5SDimitry Andric     if (!Signed)
872*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR))
873*0b57cec5SDimitry Andric         .addImm(0);
874*0b57cec5SDimitry Andric     else  // Must be right shift.
875*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR)
876*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS, HiSR)
877*0b57cec5SDimitry Andric         .addImm(31);
878*0b57cec5SDimitry Andric   } else if (S < 64) {
879*0b57cec5SDimitry Andric     S -= 32;
880*0b57cec5SDimitry Andric     if (S == 16 && Left)
881*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_aslh), HiR)
882*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, LoSR);
883*0b57cec5SDimitry Andric     else if (S == 16 && Signed)
884*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_asrh), LoR)
885*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, HiSR);
886*0b57cec5SDimitry Andric     else
887*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(ShiftOpc), (Left ? HiR : LoR))
888*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS & ~RegState::Kill, (Left ? LoSR : HiSR))
889*0b57cec5SDimitry Andric         .addImm(S);
890*0b57cec5SDimitry Andric 
891*0b57cec5SDimitry Andric     if (Signed)
892*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(S2_asr_i_r), HiR)
893*0b57cec5SDimitry Andric         .addReg(Op1.getReg(), RS, HiSR)
894*0b57cec5SDimitry Andric         .addImm(31);
895*0b57cec5SDimitry Andric     else
896*0b57cec5SDimitry Andric       BuildMI(B, MI, DL, TII->get(A2_tfrsi), (Left ? LoR : HiR))
897*0b57cec5SDimitry Andric         .addImm(0);
898*0b57cec5SDimitry Andric   }
899*0b57cec5SDimitry Andric }
900*0b57cec5SDimitry Andric 
901*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI,
902*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
903*0b57cec5SDimitry Andric   using namespace Hexagon;
904*0b57cec5SDimitry Andric 
905*0b57cec5SDimitry Andric   MachineOperand &Op0 = MI->getOperand(0);
906*0b57cec5SDimitry Andric   MachineOperand &Op1 = MI->getOperand(1);
907*0b57cec5SDimitry Andric   MachineOperand &Op2 = MI->getOperand(2);
908*0b57cec5SDimitry Andric   MachineOperand &Op3 = MI->getOperand(3);
909*0b57cec5SDimitry Andric   assert(Op0.isReg() && Op1.isReg() && Op2.isReg() && Op3.isImm());
910*0b57cec5SDimitry Andric   int64_t Sh64 = Op3.getImm();
911*0b57cec5SDimitry Andric   assert(Sh64 >= 0 && Sh64 < 64);
912*0b57cec5SDimitry Andric   unsigned S = Sh64;
913*0b57cec5SDimitry Andric 
914*0b57cec5SDimitry Andric   UUPairMap::const_iterator F = PairMap.find(Op0.getReg());
915*0b57cec5SDimitry Andric   assert(F != PairMap.end());
916*0b57cec5SDimitry Andric   const UUPair &P = F->second;
917*0b57cec5SDimitry Andric   unsigned LoR = P.first;
918*0b57cec5SDimitry Andric   unsigned HiR = P.second;
919*0b57cec5SDimitry Andric 
920*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
921*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
922*0b57cec5SDimitry Andric   unsigned RS1 = getRegState(Op1);
923*0b57cec5SDimitry Andric   unsigned RS2 = getRegState(Op2);
924*0b57cec5SDimitry Andric   const TargetRegisterClass *IntRC = &IntRegsRegClass;
925*0b57cec5SDimitry Andric 
926*0b57cec5SDimitry Andric   unsigned LoSR = isub_lo;
927*0b57cec5SDimitry Andric   unsigned HiSR = isub_hi;
928*0b57cec5SDimitry Andric 
929*0b57cec5SDimitry Andric   // Op0 = S2_asl_i_p_or Op1, Op2, Op3
930*0b57cec5SDimitry Andric   // means:  Op0 = or (Op1, asl(Op2, Op3))
931*0b57cec5SDimitry Andric 
932*0b57cec5SDimitry Andric   // Expansion of
933*0b57cec5SDimitry Andric   //   DR = or (R1, asl(R2, #s))
934*0b57cec5SDimitry Andric   //
935*0b57cec5SDimitry Andric   //   LoR  = or (R1.lo, asl(R2.lo, #s))
936*0b57cec5SDimitry Andric   //   Tmp1 = extractu R2.lo, #s, #32-s
937*0b57cec5SDimitry Andric   //   Tmp2 = or R1.hi, Tmp1
938*0b57cec5SDimitry Andric   //   HiR  = or (Tmp2, asl(R2.hi, #s))
939*0b57cec5SDimitry Andric 
940*0b57cec5SDimitry Andric   if (S == 0) {
941*0b57cec5SDimitry Andric     // DR  = or (R1, asl(R2, #0))
942*0b57cec5SDimitry Andric     //    -> or (R1, R2)
943*0b57cec5SDimitry Andric     // i.e. LoR = or R1.lo, R2.lo
944*0b57cec5SDimitry Andric     //      HiR = or R1.hi, R2.hi
945*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(A2_or), LoR)
946*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR)
947*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR);
948*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(A2_or), HiR)
949*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1, HiSR)
950*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2, HiSR);
951*0b57cec5SDimitry Andric   } else if (S < 32) {
952*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), LoR)
953*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR)
954*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR)
955*0b57cec5SDimitry Andric       .addImm(S);
956*0b57cec5SDimitry Andric     unsigned TmpR1 = MRI->createVirtualRegister(IntRC);
957*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(S2_extractu), TmpR1)
958*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2 & ~RegState::Kill, LoSR)
959*0b57cec5SDimitry Andric       .addImm(S)
960*0b57cec5SDimitry Andric       .addImm(32-S);
961*0b57cec5SDimitry Andric     unsigned TmpR2 = MRI->createVirtualRegister(IntRC);
962*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(A2_or), TmpR2)
963*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1, HiSR)
964*0b57cec5SDimitry Andric       .addReg(TmpR1);
965*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR)
966*0b57cec5SDimitry Andric       .addReg(TmpR2)
967*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2, HiSR)
968*0b57cec5SDimitry Andric       .addImm(S);
969*0b57cec5SDimitry Andric   } else if (S == 32) {
970*0b57cec5SDimitry Andric     // DR  = or (R1, asl(R2, #32))
971*0b57cec5SDimitry Andric     //    -> or R1, R2.lo
972*0b57cec5SDimitry Andric     // LoR = R1.lo
973*0b57cec5SDimitry Andric     // HiR = or R1.hi, R2.lo
974*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR)
975*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR);
976*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(A2_or), HiR)
977*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1, HiSR)
978*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2, LoSR);
979*0b57cec5SDimitry Andric   } else if (S < 64) {
980*0b57cec5SDimitry Andric     // DR  = or (R1, asl(R2, #s))
981*0b57cec5SDimitry Andric     //
982*0b57cec5SDimitry Andric     // LoR = R1:lo
983*0b57cec5SDimitry Andric     // HiR = or (R1:hi, asl(R2:lo, #s-32))
984*0b57cec5SDimitry Andric     S -= 32;
985*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::COPY), LoR)
986*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1 & ~RegState::Kill, LoSR);
987*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(S2_asl_i_r_or), HiR)
988*0b57cec5SDimitry Andric       .addReg(Op1.getReg(), RS1, HiSR)
989*0b57cec5SDimitry Andric       .addReg(Op2.getReg(), RS2, LoSR)
990*0b57cec5SDimitry Andric       .addImm(S);
991*0b57cec5SDimitry Andric   }
992*0b57cec5SDimitry Andric }
993*0b57cec5SDimitry Andric 
994*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI,
995*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
996*0b57cec5SDimitry Andric   using namespace Hexagon;
997*0b57cec5SDimitry Andric 
998*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Splitting: " << *MI);
999*0b57cec5SDimitry Andric   bool Split = false;
1000*0b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
1001*0b57cec5SDimitry Andric 
1002*0b57cec5SDimitry Andric   switch (Opc) {
1003*0b57cec5SDimitry Andric     case TargetOpcode::PHI:
1004*0b57cec5SDimitry Andric     case TargetOpcode::COPY: {
1005*0b57cec5SDimitry Andric       unsigned DstR = MI->getOperand(0).getReg();
1006*0b57cec5SDimitry Andric       if (MRI->getRegClass(DstR) == DoubleRC) {
1007*0b57cec5SDimitry Andric         createHalfInstr(Opc, MI, PairMap, isub_lo);
1008*0b57cec5SDimitry Andric         createHalfInstr(Opc, MI, PairMap, isub_hi);
1009*0b57cec5SDimitry Andric         Split = true;
1010*0b57cec5SDimitry Andric       }
1011*0b57cec5SDimitry Andric       break;
1012*0b57cec5SDimitry Andric     }
1013*0b57cec5SDimitry Andric     case A2_andp:
1014*0b57cec5SDimitry Andric       createHalfInstr(A2_and, MI, PairMap, isub_lo);
1015*0b57cec5SDimitry Andric       createHalfInstr(A2_and, MI, PairMap, isub_hi);
1016*0b57cec5SDimitry Andric       Split = true;
1017*0b57cec5SDimitry Andric       break;
1018*0b57cec5SDimitry Andric     case A2_orp:
1019*0b57cec5SDimitry Andric       createHalfInstr(A2_or, MI, PairMap, isub_lo);
1020*0b57cec5SDimitry Andric       createHalfInstr(A2_or, MI, PairMap, isub_hi);
1021*0b57cec5SDimitry Andric       Split = true;
1022*0b57cec5SDimitry Andric       break;
1023*0b57cec5SDimitry Andric     case A2_xorp:
1024*0b57cec5SDimitry Andric       createHalfInstr(A2_xor, MI, PairMap, isub_lo);
1025*0b57cec5SDimitry Andric       createHalfInstr(A2_xor, MI, PairMap, isub_hi);
1026*0b57cec5SDimitry Andric       Split = true;
1027*0b57cec5SDimitry Andric       break;
1028*0b57cec5SDimitry Andric 
1029*0b57cec5SDimitry Andric     case L2_loadrd_io:
1030*0b57cec5SDimitry Andric     case L2_loadrd_pi:
1031*0b57cec5SDimitry Andric     case S2_storerd_io:
1032*0b57cec5SDimitry Andric     case S2_storerd_pi:
1033*0b57cec5SDimitry Andric       splitMemRef(MI, PairMap);
1034*0b57cec5SDimitry Andric       Split = true;
1035*0b57cec5SDimitry Andric       break;
1036*0b57cec5SDimitry Andric 
1037*0b57cec5SDimitry Andric     case A2_tfrpi:
1038*0b57cec5SDimitry Andric     case CONST64:
1039*0b57cec5SDimitry Andric       splitImmediate(MI, PairMap);
1040*0b57cec5SDimitry Andric       Split = true;
1041*0b57cec5SDimitry Andric       break;
1042*0b57cec5SDimitry Andric 
1043*0b57cec5SDimitry Andric     case A2_combineii:
1044*0b57cec5SDimitry Andric     case A4_combineir:
1045*0b57cec5SDimitry Andric     case A4_combineii:
1046*0b57cec5SDimitry Andric     case A4_combineri:
1047*0b57cec5SDimitry Andric     case A2_combinew:
1048*0b57cec5SDimitry Andric       splitCombine(MI, PairMap);
1049*0b57cec5SDimitry Andric       Split = true;
1050*0b57cec5SDimitry Andric       break;
1051*0b57cec5SDimitry Andric 
1052*0b57cec5SDimitry Andric     case A2_sxtw:
1053*0b57cec5SDimitry Andric       splitExt(MI, PairMap);
1054*0b57cec5SDimitry Andric       Split = true;
1055*0b57cec5SDimitry Andric       break;
1056*0b57cec5SDimitry Andric 
1057*0b57cec5SDimitry Andric     case S2_asl_i_p:
1058*0b57cec5SDimitry Andric     case S2_asr_i_p:
1059*0b57cec5SDimitry Andric     case S2_lsr_i_p:
1060*0b57cec5SDimitry Andric       splitShift(MI, PairMap);
1061*0b57cec5SDimitry Andric       Split = true;
1062*0b57cec5SDimitry Andric       break;
1063*0b57cec5SDimitry Andric 
1064*0b57cec5SDimitry Andric     case S2_asl_i_p_or:
1065*0b57cec5SDimitry Andric       splitAslOr(MI, PairMap);
1066*0b57cec5SDimitry Andric       Split = true;
1067*0b57cec5SDimitry Andric       break;
1068*0b57cec5SDimitry Andric 
1069*0b57cec5SDimitry Andric     default:
1070*0b57cec5SDimitry Andric       llvm_unreachable("Instruction not splitable");
1071*0b57cec5SDimitry Andric       return false;
1072*0b57cec5SDimitry Andric   }
1073*0b57cec5SDimitry Andric 
1074*0b57cec5SDimitry Andric   return Split;
1075*0b57cec5SDimitry Andric }
1076*0b57cec5SDimitry Andric 
1077*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI,
1078*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
1079*0b57cec5SDimitry Andric   for (auto &Op : MI->operands()) {
1080*0b57cec5SDimitry Andric     if (!Op.isReg() || !Op.isUse() || !Op.getSubReg())
1081*0b57cec5SDimitry Andric       continue;
1082*0b57cec5SDimitry Andric     unsigned R = Op.getReg();
1083*0b57cec5SDimitry Andric     UUPairMap::const_iterator F = PairMap.find(R);
1084*0b57cec5SDimitry Andric     if (F == PairMap.end())
1085*0b57cec5SDimitry Andric       continue;
1086*0b57cec5SDimitry Andric     const UUPair &P = F->second;
1087*0b57cec5SDimitry Andric     switch (Op.getSubReg()) {
1088*0b57cec5SDimitry Andric       case Hexagon::isub_lo:
1089*0b57cec5SDimitry Andric         Op.setReg(P.first);
1090*0b57cec5SDimitry Andric         break;
1091*0b57cec5SDimitry Andric       case Hexagon::isub_hi:
1092*0b57cec5SDimitry Andric         Op.setReg(P.second);
1093*0b57cec5SDimitry Andric         break;
1094*0b57cec5SDimitry Andric     }
1095*0b57cec5SDimitry Andric     Op.setSubReg(0);
1096*0b57cec5SDimitry Andric   }
1097*0b57cec5SDimitry Andric }
1098*0b57cec5SDimitry Andric 
1099*0b57cec5SDimitry Andric void HexagonSplitDoubleRegs::collapseRegPairs(MachineInstr *MI,
1100*0b57cec5SDimitry Andric       const UUPairMap &PairMap) {
1101*0b57cec5SDimitry Andric   MachineBasicBlock &B = *MI->getParent();
1102*0b57cec5SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
1103*0b57cec5SDimitry Andric 
1104*0b57cec5SDimitry Andric   for (auto &Op : MI->operands()) {
1105*0b57cec5SDimitry Andric     if (!Op.isReg() || !Op.isUse())
1106*0b57cec5SDimitry Andric       continue;
1107*0b57cec5SDimitry Andric     unsigned R = Op.getReg();
1108*0b57cec5SDimitry Andric     if (!TargetRegisterInfo::isVirtualRegister(R))
1109*0b57cec5SDimitry Andric       continue;
1110*0b57cec5SDimitry Andric     if (MRI->getRegClass(R) != DoubleRC || Op.getSubReg())
1111*0b57cec5SDimitry Andric       continue;
1112*0b57cec5SDimitry Andric     UUPairMap::const_iterator F = PairMap.find(R);
1113*0b57cec5SDimitry Andric     if (F == PairMap.end())
1114*0b57cec5SDimitry Andric       continue;
1115*0b57cec5SDimitry Andric     const UUPair &Pr = F->second;
1116*0b57cec5SDimitry Andric     unsigned NewDR = MRI->createVirtualRegister(DoubleRC);
1117*0b57cec5SDimitry Andric     BuildMI(B, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), NewDR)
1118*0b57cec5SDimitry Andric       .addReg(Pr.first)
1119*0b57cec5SDimitry Andric       .addImm(Hexagon::isub_lo)
1120*0b57cec5SDimitry Andric       .addReg(Pr.second)
1121*0b57cec5SDimitry Andric       .addImm(Hexagon::isub_hi);
1122*0b57cec5SDimitry Andric     Op.setReg(NewDR);
1123*0b57cec5SDimitry Andric   }
1124*0b57cec5SDimitry Andric }
1125*0b57cec5SDimitry Andric 
1126*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::splitPartition(const USet &Part) {
1127*0b57cec5SDimitry Andric   using MISet = std::set<MachineInstr *>;
1128*0b57cec5SDimitry Andric 
1129*0b57cec5SDimitry Andric   const TargetRegisterClass *IntRC = &Hexagon::IntRegsRegClass;
1130*0b57cec5SDimitry Andric   bool Changed = false;
1131*0b57cec5SDimitry Andric 
1132*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Splitting partition: ";
1133*0b57cec5SDimitry Andric              dump_partition(dbgs(), Part, *TRI); dbgs() << '\n');
1134*0b57cec5SDimitry Andric 
1135*0b57cec5SDimitry Andric   UUPairMap PairMap;
1136*0b57cec5SDimitry Andric 
1137*0b57cec5SDimitry Andric   MISet SplitIns;
1138*0b57cec5SDimitry Andric   for (unsigned DR : Part) {
1139*0b57cec5SDimitry Andric     MachineInstr *DefI = MRI->getVRegDef(DR);
1140*0b57cec5SDimitry Andric     SplitIns.insert(DefI);
1141*0b57cec5SDimitry Andric 
1142*0b57cec5SDimitry Andric     // Collect all instructions, including fixed ones.  We won't split them,
1143*0b57cec5SDimitry Andric     // but we need to visit them again to insert the REG_SEQUENCE instructions.
1144*0b57cec5SDimitry Andric     for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end();
1145*0b57cec5SDimitry Andric          U != W; ++U)
1146*0b57cec5SDimitry Andric       SplitIns.insert(U->getParent());
1147*0b57cec5SDimitry Andric 
1148*0b57cec5SDimitry Andric     unsigned LoR = MRI->createVirtualRegister(IntRC);
1149*0b57cec5SDimitry Andric     unsigned HiR = MRI->createVirtualRegister(IntRC);
1150*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Created mapping: " << printReg(DR, TRI) << " -> "
1151*0b57cec5SDimitry Andric                       << printReg(HiR, TRI) << ':' << printReg(LoR, TRI)
1152*0b57cec5SDimitry Andric                       << '\n');
1153*0b57cec5SDimitry Andric     PairMap.insert(std::make_pair(DR, UUPair(LoR, HiR)));
1154*0b57cec5SDimitry Andric   }
1155*0b57cec5SDimitry Andric 
1156*0b57cec5SDimitry Andric   MISet Erase;
1157*0b57cec5SDimitry Andric   for (auto MI : SplitIns) {
1158*0b57cec5SDimitry Andric     if (isFixedInstr(MI)) {
1159*0b57cec5SDimitry Andric       collapseRegPairs(MI, PairMap);
1160*0b57cec5SDimitry Andric     } else {
1161*0b57cec5SDimitry Andric       bool Done = splitInstr(MI, PairMap);
1162*0b57cec5SDimitry Andric       if (Done)
1163*0b57cec5SDimitry Andric         Erase.insert(MI);
1164*0b57cec5SDimitry Andric       Changed |= Done;
1165*0b57cec5SDimitry Andric     }
1166*0b57cec5SDimitry Andric   }
1167*0b57cec5SDimitry Andric 
1168*0b57cec5SDimitry Andric   for (unsigned DR : Part) {
1169*0b57cec5SDimitry Andric     // Before erasing "double" instructions, revisit all uses of the double
1170*0b57cec5SDimitry Andric     // registers in this partition, and replace all uses of them with subre-
1171*0b57cec5SDimitry Andric     // gisters, with the corresponding single registers.
1172*0b57cec5SDimitry Andric     MISet Uses;
1173*0b57cec5SDimitry Andric     for (auto U = MRI->use_nodbg_begin(DR), W = MRI->use_nodbg_end();
1174*0b57cec5SDimitry Andric          U != W; ++U)
1175*0b57cec5SDimitry Andric       Uses.insert(U->getParent());
1176*0b57cec5SDimitry Andric     for (auto M : Uses)
1177*0b57cec5SDimitry Andric       replaceSubregUses(M, PairMap);
1178*0b57cec5SDimitry Andric   }
1179*0b57cec5SDimitry Andric 
1180*0b57cec5SDimitry Andric   for (auto MI : Erase) {
1181*0b57cec5SDimitry Andric     MachineBasicBlock *B = MI->getParent();
1182*0b57cec5SDimitry Andric     B->erase(MI);
1183*0b57cec5SDimitry Andric   }
1184*0b57cec5SDimitry Andric 
1185*0b57cec5SDimitry Andric   return Changed;
1186*0b57cec5SDimitry Andric }
1187*0b57cec5SDimitry Andric 
1188*0b57cec5SDimitry Andric bool HexagonSplitDoubleRegs::runOnMachineFunction(MachineFunction &MF) {
1189*0b57cec5SDimitry Andric   if (skipFunction(MF.getFunction()))
1190*0b57cec5SDimitry Andric     return false;
1191*0b57cec5SDimitry Andric 
1192*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Splitting double registers in function: "
1193*0b57cec5SDimitry Andric                     << MF.getName() << '\n');
1194*0b57cec5SDimitry Andric 
1195*0b57cec5SDimitry Andric   auto &ST = MF.getSubtarget<HexagonSubtarget>();
1196*0b57cec5SDimitry Andric   TRI = ST.getRegisterInfo();
1197*0b57cec5SDimitry Andric   TII = ST.getInstrInfo();
1198*0b57cec5SDimitry Andric   MRI = &MF.getRegInfo();
1199*0b57cec5SDimitry Andric   MLI = &getAnalysis<MachineLoopInfo>();
1200*0b57cec5SDimitry Andric 
1201*0b57cec5SDimitry Andric   UUSetMap P2Rs;
1202*0b57cec5SDimitry Andric   LoopRegMap IRM;
1203*0b57cec5SDimitry Andric 
1204*0b57cec5SDimitry Andric   collectIndRegs(IRM);
1205*0b57cec5SDimitry Andric   partitionRegisters(P2Rs);
1206*0b57cec5SDimitry Andric 
1207*0b57cec5SDimitry Andric   LLVM_DEBUG({
1208*0b57cec5SDimitry Andric     dbgs() << "Register partitioning: (partition #0 is fixed)\n";
1209*0b57cec5SDimitry Andric     for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) {
1210*0b57cec5SDimitry Andric       dbgs() << '#' << I->first << " -> ";
1211*0b57cec5SDimitry Andric       dump_partition(dbgs(), I->second, *TRI);
1212*0b57cec5SDimitry Andric       dbgs() << '\n';
1213*0b57cec5SDimitry Andric     }
1214*0b57cec5SDimitry Andric   });
1215*0b57cec5SDimitry Andric 
1216*0b57cec5SDimitry Andric   bool Changed = false;
1217*0b57cec5SDimitry Andric   int Limit = MaxHSDR;
1218*0b57cec5SDimitry Andric 
1219*0b57cec5SDimitry Andric   for (UUSetMap::iterator I = P2Rs.begin(), E = P2Rs.end(); I != E; ++I) {
1220*0b57cec5SDimitry Andric     if (I->first == 0)
1221*0b57cec5SDimitry Andric       continue;
1222*0b57cec5SDimitry Andric     if (Limit >= 0 && Counter >= Limit)
1223*0b57cec5SDimitry Andric       break;
1224*0b57cec5SDimitry Andric     USet &Part = I->second;
1225*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Calculating profit for partition #" << I->first
1226*0b57cec5SDimitry Andric                       << '\n');
1227*0b57cec5SDimitry Andric     if (!isProfitable(Part, IRM))
1228*0b57cec5SDimitry Andric       continue;
1229*0b57cec5SDimitry Andric     Counter++;
1230*0b57cec5SDimitry Andric     Changed |= splitPartition(Part);
1231*0b57cec5SDimitry Andric   }
1232*0b57cec5SDimitry Andric 
1233*0b57cec5SDimitry Andric   return Changed;
1234*0b57cec5SDimitry Andric }
1235*0b57cec5SDimitry Andric 
1236*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonSplitDoubleRegs() {
1237*0b57cec5SDimitry Andric   return new HexagonSplitDoubleRegs();
1238*0b57cec5SDimitry Andric }
1239