1234285Sdim//===-- HexagonExpandPredSpillCode.cpp - Expand Predicate Spill Code ------===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim// The Hexagon processor has no instructions that load or store predicate
10239462Sdim// registers directly.  So, when these registers must be spilled a general
11239462Sdim// purpose register must be found and the value copied to/from it from/to
12239462Sdim// the predicate register.  This code currently does not use the register
13234285Sdim// scavenger mechanism available in the allocator.  There are two registers
14234285Sdim// reserved to allow spilling/restoring predicate registers.  One is used to
15234285Sdim// hold the predicate value.  The other is used when stack frame offsets are
16234285Sdim// too large.
17234285Sdim//
18234285Sdim//===----------------------------------------------------------------------===//
19234285Sdim
20249423Sdim#include "Hexagon.h"
21249423Sdim#include "HexagonMachineFunctionInfo.h"
22249423Sdim#include "HexagonSubtarget.h"
23234285Sdim#include "llvm/ADT/Statistic.h"
24234285Sdim#include "llvm/CodeGen/LatencyPriorityQueue.h"
25234285Sdim#include "llvm/CodeGen/MachineDominators.h"
26234285Sdim#include "llvm/CodeGen/MachineFunctionPass.h"
27234285Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
28234285Sdim#include "llvm/CodeGen/MachineLoopInfo.h"
29234285Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
30234285Sdim#include "llvm/CodeGen/Passes.h"
31234285Sdim#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
32234285Sdim#include "llvm/CodeGen/SchedulerRegistry.h"
33234285Sdim#include "llvm/Support/Compiler.h"
34234285Sdim#include "llvm/Support/Debug.h"
35234285Sdim#include "llvm/Support/MathExtras.h"
36249423Sdim#include "llvm/Target/TargetInstrInfo.h"
37249423Sdim#include "llvm/Target/TargetMachine.h"
38249423Sdim#include "llvm/Target/TargetRegisterInfo.h"
39234285Sdim
40234285Sdimusing namespace llvm;
41234285Sdim
42234285Sdim
43251662Sdimnamespace llvm {
44288943Sdim  FunctionPass *createHexagonExpandPredSpillCode();
45251662Sdim  void initializeHexagonExpandPredSpillCodePass(PassRegistry&);
46251662Sdim}
47251662Sdim
48251662Sdim
49234285Sdimnamespace {
50234285Sdim
51234285Sdimclass HexagonExpandPredSpillCode : public MachineFunctionPass {
52234285Sdim public:
53234285Sdim    static char ID;
54288943Sdim    HexagonExpandPredSpillCode() : MachineFunctionPass(ID) {
55251662Sdim      PassRegistry &Registry = *PassRegistry::getPassRegistry();
56251662Sdim      initializeHexagonExpandPredSpillCodePass(Registry);
57251662Sdim    }
58234285Sdim
59276479Sdim    const char *getPassName() const override {
60234285Sdim      return "Hexagon Expand Predicate Spill Code";
61234285Sdim    }
62276479Sdim    bool runOnMachineFunction(MachineFunction &Fn) override;
63234285Sdim};
64234285Sdim
65234285Sdim
66234285Sdimchar HexagonExpandPredSpillCode::ID = 0;
67234285Sdim
68234285Sdim
69234285Sdimbool HexagonExpandPredSpillCode::runOnMachineFunction(MachineFunction &Fn) {
70234285Sdim
71288943Sdim  const HexagonSubtarget &QST = Fn.getSubtarget<HexagonSubtarget>();
72288943Sdim  const HexagonInstrInfo *TII = QST.getInstrInfo();
73234285Sdim
74234285Sdim  // Loop over all of the basic blocks.
75234285Sdim  for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
76234285Sdim       MBBb != MBBe; ++MBBb) {
77296417Sdim    MachineBasicBlock *MBB = &*MBBb;
78234285Sdim    // Traverse the basic block.
79234285Sdim    for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
80234285Sdim         ++MII) {
81234285Sdim      MachineInstr *MI = MII;
82234285Sdim      int Opc = MI->getOpcode();
83288943Sdim      if (Opc == Hexagon::S2_storerb_pci_pseudo ||
84288943Sdim          Opc == Hexagon::S2_storerh_pci_pseudo ||
85288943Sdim          Opc == Hexagon::S2_storeri_pci_pseudo ||
86288943Sdim          Opc == Hexagon::S2_storerd_pci_pseudo ||
87288943Sdim          Opc == Hexagon::S2_storerf_pci_pseudo) {
88288943Sdim        unsigned Opcode;
89288943Sdim        if (Opc == Hexagon::S2_storerd_pci_pseudo)
90288943Sdim          Opcode = Hexagon::S2_storerd_pci;
91288943Sdim        else if (Opc == Hexagon::S2_storeri_pci_pseudo)
92288943Sdim          Opcode = Hexagon::S2_storeri_pci;
93288943Sdim        else if (Opc == Hexagon::S2_storerh_pci_pseudo)
94288943Sdim          Opcode = Hexagon::S2_storerh_pci;
95288943Sdim        else if (Opc == Hexagon::S2_storerf_pci_pseudo)
96288943Sdim          Opcode = Hexagon::S2_storerf_pci;
97288943Sdim        else if (Opc == Hexagon::S2_storerb_pci_pseudo)
98288943Sdim          Opcode = Hexagon::S2_storerb_pci;
99288943Sdim        else
100288943Sdim          llvm_unreachable("wrong Opc");
101288943Sdim        MachineOperand &Op0 = MI->getOperand(0);
102288943Sdim        MachineOperand &Op1 = MI->getOperand(1);
103288943Sdim        MachineOperand &Op2 = MI->getOperand(2);
104288943Sdim        MachineOperand &Op3 = MI->getOperand(3); // Modifier value.
105288943Sdim        MachineOperand &Op4 = MI->getOperand(4);
106288943Sdim        // Emit a "C6 = Rn, C6 is the control register for M0".
107288943Sdim        BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr),
108288943Sdim                Hexagon::C6)->addOperand(Op3);
109288943Sdim        // Replace the pseude circ_ldd by the real circ_ldd.
110288943Sdim        MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(),
111288943Sdim                                      TII->get(Opcode));
112288943Sdim        NewMI->addOperand(Op0);
113288943Sdim        NewMI->addOperand(Op1);
114288943Sdim        NewMI->addOperand(Op4);
115288943Sdim        NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0,
116288943Sdim                                                    false, /*isDef*/
117288943Sdim                                                    false, /*isImpl*/
118288943Sdim                                                    true   /*isKill*/));
119288943Sdim        NewMI->addOperand(Op2);
120288943Sdim        MII = MBB->erase(MI);
121288943Sdim        --MII;
122288943Sdim      } else if (Opc == Hexagon::L2_loadrd_pci_pseudo ||
123288943Sdim                 Opc == Hexagon::L2_loadri_pci_pseudo ||
124288943Sdim                 Opc == Hexagon::L2_loadrh_pci_pseudo ||
125288943Sdim                 Opc == Hexagon::L2_loadruh_pci_pseudo||
126288943Sdim                 Opc == Hexagon::L2_loadrb_pci_pseudo ||
127288943Sdim                 Opc == Hexagon::L2_loadrub_pci_pseudo) {
128288943Sdim        unsigned Opcode;
129288943Sdim        if (Opc == Hexagon::L2_loadrd_pci_pseudo)
130288943Sdim          Opcode = Hexagon::L2_loadrd_pci;
131288943Sdim        else if (Opc == Hexagon::L2_loadri_pci_pseudo)
132288943Sdim          Opcode = Hexagon::L2_loadri_pci;
133288943Sdim        else if (Opc == Hexagon::L2_loadrh_pci_pseudo)
134288943Sdim          Opcode = Hexagon::L2_loadrh_pci;
135288943Sdim        else if (Opc == Hexagon::L2_loadruh_pci_pseudo)
136288943Sdim          Opcode = Hexagon::L2_loadruh_pci;
137288943Sdim        else if (Opc == Hexagon::L2_loadrb_pci_pseudo)
138288943Sdim          Opcode = Hexagon::L2_loadrb_pci;
139288943Sdim        else if (Opc == Hexagon::L2_loadrub_pci_pseudo)
140288943Sdim          Opcode = Hexagon::L2_loadrub_pci;
141288943Sdim        else
142288943Sdim          llvm_unreachable("wrong Opc");
143288943Sdim
144288943Sdim        MachineOperand &Op0 = MI->getOperand(0);
145288943Sdim        MachineOperand &Op1 = MI->getOperand(1);
146288943Sdim        MachineOperand &Op2 = MI->getOperand(2);
147288943Sdim        MachineOperand &Op4 = MI->getOperand(4); // Modifier value.
148288943Sdim        MachineOperand &Op5 = MI->getOperand(5);
149288943Sdim        // Emit a "C6 = Rn, C6 is the control register for M0".
150288943Sdim        BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr),
151288943Sdim                Hexagon::C6)->addOperand(Op4);
152288943Sdim        // Replace the pseude circ_ldd by the real circ_ldd.
153288943Sdim        MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(),
154288943Sdim                                      TII->get(Opcode));
155288943Sdim        NewMI->addOperand(Op1);
156288943Sdim        NewMI->addOperand(Op0);
157288943Sdim        NewMI->addOperand(Op2);
158288943Sdim        NewMI->addOperand(Op5);
159288943Sdim        NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0,
160288943Sdim                                                    false, /*isDef*/
161288943Sdim                                                    false, /*isImpl*/
162288943Sdim                                                    true   /*isKill*/));
163288943Sdim        MII = MBB->erase(MI);
164288943Sdim        --MII;
165288943Sdim      } else if (Opc == Hexagon::L2_loadrd_pbr_pseudo ||
166288943Sdim                 Opc == Hexagon::L2_loadri_pbr_pseudo ||
167288943Sdim                 Opc == Hexagon::L2_loadrh_pbr_pseudo ||
168288943Sdim                 Opc == Hexagon::L2_loadruh_pbr_pseudo||
169288943Sdim                 Opc == Hexagon::L2_loadrb_pbr_pseudo ||
170288943Sdim                 Opc == Hexagon::L2_loadrub_pbr_pseudo) {
171288943Sdim        unsigned Opcode;
172288943Sdim        if (Opc == Hexagon::L2_loadrd_pbr_pseudo)
173288943Sdim          Opcode = Hexagon::L2_loadrd_pbr;
174288943Sdim        else if (Opc == Hexagon::L2_loadri_pbr_pseudo)
175288943Sdim          Opcode = Hexagon::L2_loadri_pbr;
176288943Sdim        else if (Opc == Hexagon::L2_loadrh_pbr_pseudo)
177288943Sdim          Opcode = Hexagon::L2_loadrh_pbr;
178288943Sdim        else if (Opc == Hexagon::L2_loadruh_pbr_pseudo)
179288943Sdim          Opcode = Hexagon::L2_loadruh_pbr;
180288943Sdim        else if (Opc == Hexagon::L2_loadrb_pbr_pseudo)
181288943Sdim          Opcode = Hexagon::L2_loadrb_pbr;
182288943Sdim        else if (Opc == Hexagon::L2_loadrub_pbr_pseudo)
183288943Sdim          Opcode = Hexagon::L2_loadrub_pbr;
184288943Sdim        else
185288943Sdim          llvm_unreachable("wrong Opc");
186288943Sdim        MachineOperand &Op0 = MI->getOperand(0);
187288943Sdim        MachineOperand &Op1 = MI->getOperand(1);
188288943Sdim        MachineOperand &Op2 = MI->getOperand(2);
189288943Sdim        MachineOperand &Op4 = MI->getOperand(4); // Modifier value.
190288943Sdim        // Emit a "C6 = Rn, C6 is the control register for M0".
191288943Sdim        BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr),
192288943Sdim                Hexagon::C6)->addOperand(Op4);
193288943Sdim        // Replace the pseudo brev_ldd by the real brev_ldd.
194288943Sdim        MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(),
195288943Sdim                                      TII->get(Opcode));
196288943Sdim        NewMI->addOperand(Op1);
197288943Sdim        NewMI->addOperand(Op0);
198288943Sdim        NewMI->addOperand(Op2);
199288943Sdim        NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0,
200288943Sdim                                                    false, /*isDef*/
201288943Sdim                                                    false, /*isImpl*/
202288943Sdim                                                    true   /*isKill*/));
203288943Sdim        MII = MBB->erase(MI);
204288943Sdim        --MII;
205288943Sdim      } else if (Opc == Hexagon::S2_storerd_pbr_pseudo ||
206288943Sdim                 Opc == Hexagon::S2_storeri_pbr_pseudo ||
207288943Sdim                 Opc == Hexagon::S2_storerh_pbr_pseudo ||
208288943Sdim                 Opc == Hexagon::S2_storerb_pbr_pseudo ||
209288943Sdim                 Opc == Hexagon::S2_storerf_pbr_pseudo) {
210288943Sdim        unsigned Opcode;
211288943Sdim        if (Opc == Hexagon::S2_storerd_pbr_pseudo)
212288943Sdim          Opcode = Hexagon::S2_storerd_pbr;
213288943Sdim        else if (Opc == Hexagon::S2_storeri_pbr_pseudo)
214288943Sdim          Opcode = Hexagon::S2_storeri_pbr;
215288943Sdim        else if (Opc == Hexagon::S2_storerh_pbr_pseudo)
216288943Sdim          Opcode = Hexagon::S2_storerh_pbr;
217288943Sdim        else if (Opc == Hexagon::S2_storerf_pbr_pseudo)
218288943Sdim          Opcode = Hexagon::S2_storerf_pbr;
219288943Sdim        else if (Opc == Hexagon::S2_storerb_pbr_pseudo)
220288943Sdim          Opcode = Hexagon::S2_storerb_pbr;
221288943Sdim        else
222288943Sdim          llvm_unreachable("wrong Opc");
223288943Sdim        MachineOperand &Op0 = MI->getOperand(0);
224288943Sdim        MachineOperand &Op1 = MI->getOperand(1);
225288943Sdim        MachineOperand &Op2 = MI->getOperand(2);
226288943Sdim        MachineOperand &Op3 = MI->getOperand(3); // Modifier value.
227288943Sdim        // Emit a "C6 = Rn, C6 is the control register for M0".
228288943Sdim        BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr),
229288943Sdim                Hexagon::C6)->addOperand(Op3);
230288943Sdim        // Replace the pseudo brev_ldd by the real brev_ldd.
231288943Sdim        MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(),
232288943Sdim                                      TII->get(Opcode));
233288943Sdim        NewMI->addOperand(Op0);
234288943Sdim        NewMI->addOperand(Op1);
235288943Sdim        NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0,
236288943Sdim                                                    false, /*isDef*/
237288943Sdim                                                    false, /*isImpl*/
238288943Sdim                                                    true   /*isKill*/));
239288943Sdim        NewMI->addOperand(Op2);
240288943Sdim        MII = MBB->erase(MI);
241288943Sdim        --MII;
242288943Sdim      } else if (Opc == Hexagon::STriw_pred) {
243234285Sdim        // STriw_pred [R30], ofst, SrcReg;
244234285Sdim        unsigned FP = MI->getOperand(0).getReg();
245288943Sdim        assert(FP == QST.getRegisterInfo()->getFrameRegister() &&
246288943Sdim               "Not a Frame Pointer, Nor a Spill Slot");
247234285Sdim        assert(MI->getOperand(1).isImm() && "Not an offset");
248234285Sdim        int Offset = MI->getOperand(1).getImm();
249234285Sdim        int SrcReg = MI->getOperand(2).getReg();
250234285Sdim        assert(Hexagon::PredRegsRegClass.contains(SrcReg) &&
251234285Sdim               "Not a predicate register");
252280031Sdim        if (!TII->isValidOffset(Hexagon::S2_storeri_io, Offset)) {
253288943Sdim          if (!TII->isValidOffset(Hexagon::A2_addi, Offset)) {
254234285Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(),
255234285Sdim                    TII->get(Hexagon::CONST32_Int_Real),
256234285Sdim                      HEXAGON_RESERVED_REG_1).addImm(Offset);
257280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_add),
258234285Sdim                    HEXAGON_RESERVED_REG_1)
259234285Sdim              .addReg(FP).addReg(HEXAGON_RESERVED_REG_1);
260280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr),
261234285Sdim                      HEXAGON_RESERVED_REG_2).addReg(SrcReg);
262234285Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(),
263280031Sdim                    TII->get(Hexagon::S2_storeri_io))
264234285Sdim              .addReg(HEXAGON_RESERVED_REG_1)
265234285Sdim              .addImm(0).addReg(HEXAGON_RESERVED_REG_2);
266234285Sdim          } else {
267288943Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_addi),
268234285Sdim                      HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset);
269280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr),
270234285Sdim                      HEXAGON_RESERVED_REG_2).addReg(SrcReg);
271239462Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(),
272280031Sdim                          TII->get(Hexagon::S2_storeri_io))
273234285Sdim              .addReg(HEXAGON_RESERVED_REG_1)
274234285Sdim              .addImm(0)
275234285Sdim              .addReg(HEXAGON_RESERVED_REG_2);
276234285Sdim          }
277234285Sdim        } else {
278280031Sdim          BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr),
279234285Sdim                    HEXAGON_RESERVED_REG_2).addReg(SrcReg);
280239462Sdim          BuildMI(*MBB, MII, MI->getDebugLoc(),
281280031Sdim                        TII->get(Hexagon::S2_storeri_io)).
282234285Sdim                    addReg(FP).addImm(Offset).addReg(HEXAGON_RESERVED_REG_2);
283234285Sdim        }
284234285Sdim        MII = MBB->erase(MI);
285234285Sdim        --MII;
286234285Sdim      } else if (Opc == Hexagon::LDriw_pred) {
287234285Sdim        // DstReg = LDriw_pred [R30], ofst.
288234285Sdim        int DstReg = MI->getOperand(0).getReg();
289234285Sdim        assert(Hexagon::PredRegsRegClass.contains(DstReg) &&
290234285Sdim               "Not a predicate register");
291234285Sdim        unsigned FP = MI->getOperand(1).getReg();
292288943Sdim        assert(FP == QST.getRegisterInfo()->getFrameRegister() &&
293288943Sdim               "Not a Frame Pointer, Nor a Spill Slot");
294234285Sdim        assert(MI->getOperand(2).isImm() && "Not an offset");
295234285Sdim        int Offset = MI->getOperand(2).getImm();
296280031Sdim        if (!TII->isValidOffset(Hexagon::L2_loadri_io, Offset)) {
297288943Sdim          if (!TII->isValidOffset(Hexagon::A2_addi, Offset)) {
298234285Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(),
299234285Sdim                    TII->get(Hexagon::CONST32_Int_Real),
300234285Sdim                      HEXAGON_RESERVED_REG_1).addImm(Offset);
301280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_add),
302234285Sdim                    HEXAGON_RESERVED_REG_1)
303234285Sdim              .addReg(FP)
304234285Sdim              .addReg(HEXAGON_RESERVED_REG_1);
305280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io),
306234285Sdim                      HEXAGON_RESERVED_REG_2)
307234285Sdim              .addReg(HEXAGON_RESERVED_REG_1)
308234285Sdim              .addImm(0);
309280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp),
310234285Sdim                      DstReg).addReg(HEXAGON_RESERVED_REG_2);
311234285Sdim          } else {
312288943Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_addi),
313234285Sdim                      HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset);
314280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io),
315234285Sdim                      HEXAGON_RESERVED_REG_2)
316234285Sdim              .addReg(HEXAGON_RESERVED_REG_1)
317234285Sdim              .addImm(0);
318280031Sdim            BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp),
319234285Sdim                      DstReg).addReg(HEXAGON_RESERVED_REG_2);
320234285Sdim          }
321234285Sdim        } else {
322280031Sdim          BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io),
323234285Sdim                    HEXAGON_RESERVED_REG_2).addReg(FP).addImm(Offset);
324280031Sdim          BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp),
325234285Sdim                    DstReg).addReg(HEXAGON_RESERVED_REG_2);
326234285Sdim        }
327234285Sdim        MII = MBB->erase(MI);
328234285Sdim        --MII;
329234285Sdim      }
330234285Sdim    }
331234285Sdim  }
332234285Sdim
333234285Sdim  return true;
334234285Sdim}
335234285Sdim
336234285Sdim}
337234285Sdim
338234285Sdim//===----------------------------------------------------------------------===//
339234285Sdim//                         Public Constructor Functions
340234285Sdim//===----------------------------------------------------------------------===//
341234285Sdim
342251662Sdimstatic void initializePassOnce(PassRegistry &Registry) {
343251662Sdim  const char *Name = "Hexagon Expand Predicate Spill Code";
344251662Sdim  PassInfo *PI = new PassInfo(Name, "hexagon-spill-pred",
345251662Sdim                              &HexagonExpandPredSpillCode::ID,
346276479Sdim                              nullptr, false, false);
347251662Sdim  Registry.registerPass(*PI, true);
348251662Sdim}
349251662Sdim
350251662Sdimvoid llvm::initializeHexagonExpandPredSpillCodePass(PassRegistry &Registry) {
351251662Sdim  CALL_ONCE_INITIALIZATION(initializePassOnce)
352251662Sdim}
353251662Sdim
354251662SdimFunctionPass*
355288943Sdimllvm::createHexagonExpandPredSpillCode() {
356288943Sdim  return new HexagonExpandPredSpillCode();
357234285Sdim}
358