1 //===-- VERegisterInfo.cpp - VE Register Information ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the VE implementation of the TargetRegisterInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "VERegisterInfo.h"
14 #include "VE.h"
15 #include "VESubtarget.h"
16 #include "llvm/ADT/BitVector.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/CodeGen/MachineFrameInfo.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
21 #include "llvm/CodeGen/MachineRegisterInfo.h"
22 #include "llvm/CodeGen/TargetInstrInfo.h"
23 #include "llvm/IR/Type.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/ErrorHandling.h"
27 
28 using namespace llvm;
29 
30 #define DEBUG_TYPE "ve-register-info"
31 
32 #define GET_REGINFO_TARGET_DESC
33 #include "VEGenRegisterInfo.inc"
34 
35 // VE uses %s10 == %lp to keep return address
36 VERegisterInfo::VERegisterInfo() : VEGenRegisterInfo(VE::SX10) {}
37 
38 const MCPhysReg *
39 VERegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
40   switch (MF->getFunction().getCallingConv()) {
41   case CallingConv::Fast:
42     // Being explicit (same as standard CC).
43   default:
44     return CSR_SaveList;
45   case CallingConv::PreserveAll:
46     return CSR_preserve_all_SaveList;
47   }
48 }
49 
50 const uint32_t *VERegisterInfo::getCallPreservedMask(const MachineFunction &MF,
51                                                      CallingConv::ID CC) const {
52   switch (CC) {
53   case CallingConv::Fast:
54     // Being explicit (same as standard CC).
55   default:
56     return CSR_RegMask;
57   case CallingConv::PreserveAll:
58     return CSR_preserve_all_RegMask;
59   }
60 }
61 
62 const uint32_t *VERegisterInfo::getNoPreservedMask() const {
63   return CSR_NoRegs_RegMask;
64 }
65 
66 BitVector VERegisterInfo::getReservedRegs(const MachineFunction &MF) const {
67   BitVector Reserved(getNumRegs());
68 
69   const Register ReservedRegs[] = {
70       VE::SX8,  // Stack limit
71       VE::SX9,  // Frame pointer
72       VE::SX10, // Link register (return address)
73       VE::SX11, // Stack pointer
74 
75       // FIXME: maybe not need to be reserved
76       VE::SX12, // Outer register
77       VE::SX13, // Id register for dynamic linker
78 
79       VE::SX14, // Thread pointer
80       VE::SX15, // Global offset table register
81       VE::SX16, // Procedure linkage table register
82       VE::SX17, // Linkage-area register
83                 // sx18-sx33 are callee-saved registers
84                 // sx34-sx63 are temporary registers
85   };
86 
87   for (auto R : ReservedRegs)
88     for (MCRegAliasIterator ItAlias(R, this, true); ItAlias.isValid();
89          ++ItAlias)
90       Reserved.set(*ItAlias);
91 
92   // Reserve constant registers.
93   Reserved.set(VE::VM0);
94   Reserved.set(VE::VMP0);
95 
96   return Reserved;
97 }
98 
99 bool VERegisterInfo::isConstantPhysReg(MCRegister PhysReg) const {
100   switch (PhysReg) {
101   case VE::VM0:
102   case VE::VMP0:
103     return true;
104   default:
105     return false;
106   }
107 }
108 
109 const TargetRegisterClass *
110 VERegisterInfo::getPointerRegClass(const MachineFunction &MF,
111                                    unsigned Kind) const {
112   return &VE::I64RegClass;
113 }
114 
115 static unsigned offsetToDisp(MachineInstr &MI) {
116   // Default offset in instruction's operands (reg+reg+imm).
117   unsigned OffDisp = 2;
118 
119 #define RRCAS_multi_cases(NAME) NAME##rir : case NAME##rii
120 
121   {
122     using namespace llvm::VE;
123     switch (MI.getOpcode()) {
124     case RRCAS_multi_cases(TS1AML):
125     case RRCAS_multi_cases(TS1AMW):
126     case RRCAS_multi_cases(CASL):
127     case RRCAS_multi_cases(CASW):
128       // These instructions use AS format (reg+imm).
129       OffDisp = 1;
130       break;
131     }
132   }
133 #undef RRCAS_multi_cases
134 
135   return OffDisp;
136 }
137 
138 class EliminateFrameIndex {
139   const TargetInstrInfo &TII;
140   const TargetRegisterInfo &TRI;
141   const DebugLoc &DL;
142   MachineBasicBlock &MBB;
143   MachineBasicBlock::iterator II;
144   Register clobber;
145 
146   // Some helper functions for the ease of instruction building.
147   MachineFunction &getFunc() const { return *MBB.getParent(); }
148   inline MCRegister getSubReg(MCRegister Reg, unsigned Idx) const {
149     return TRI.getSubReg(Reg, Idx);
150   }
151   inline const MCInstrDesc &get(unsigned Opcode) const {
152     return TII.get(Opcode);
153   }
154   inline MachineInstrBuilder build(const MCInstrDesc &MCID, Register DestReg) {
155     return BuildMI(MBB, II, DL, MCID, DestReg);
156   }
157   inline MachineInstrBuilder build(unsigned InstOpc, Register DestReg) {
158     return build(get(InstOpc), DestReg);
159   }
160   inline MachineInstrBuilder build(const MCInstrDesc &MCID) {
161     return BuildMI(MBB, II, DL, MCID);
162   }
163   inline MachineInstrBuilder build(unsigned InstOpc) {
164     return build(get(InstOpc));
165   }
166 
167   // Calculate an address of frame index from a frame register and a given
168   // offset if the offset doesn't fit in the immediate field.  Use a clobber
169   // register to hold calculated address.
170   void prepareReplaceFI(MachineInstr &MI, Register &FrameReg, int64_t &Offset,
171                         int64_t Bytes = 0);
172   // Replace the frame index in \p MI with a frame register and a given offset
173   // if it fits in the immediate field.  Otherwise, use pre-calculated address
174   // in a clobber regsiter.
175   void replaceFI(MachineInstr &MI, Register FrameReg, int64_t Offset,
176                  int FIOperandNum);
177 
178   // Expand and eliminate Frame Index of pseudo STQrii and LDQrii.
179   void processSTQ(MachineInstr &MI, Register FrameReg, int64_t Offset,
180                   int FIOperandNum);
181   void processLDQ(MachineInstr &MI, Register FrameReg, int64_t Offset,
182                   int FIOperandNum);
183 
184 public:
185   EliminateFrameIndex(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI,
186                       const DebugLoc &DL, MachineBasicBlock &MBB,
187                       MachineBasicBlock::iterator II)
188       : TII(TII), TRI(TRI), DL(DL), MBB(MBB), II(II), clobber(VE::SX13) {}
189 
190   // Expand and eliminate Frame Index from MI
191   void processMI(MachineInstr &MI, Register FrameReg, int64_t Offset,
192                  int FIOperandNum);
193 };
194 
195 // Prepare the frame index if it doesn't fit in the immediate field.  Use
196 // clobber register to hold calculated address.
197 void EliminateFrameIndex::prepareReplaceFI(MachineInstr &MI, Register &FrameReg,
198                                            int64_t &Offset, int64_t Bytes) {
199   if (isInt<32>(Offset) && isInt<32>(Offset + Bytes)) {
200     // If the offset is small enough to fit in the immediate field, directly
201     // encode it.  So, nothing to prepare here.
202     return;
203   }
204 
205   // If the offset doesn't fit, emit following codes.  This clobbers SX13
206   // which we always know is available here.
207   //   lea     %clobber, Offset@lo
208   //   and     %clobber, %clobber, (32)0
209   //   lea.sl  %clobber, Offset@hi(FrameReg, %clobber)
210   build(VE::LEAzii, clobber).addImm(0).addImm(0).addImm(Lo_32(Offset));
211   build(VE::ANDrm, clobber).addReg(clobber).addImm(M0(32));
212   build(VE::LEASLrri, clobber)
213       .addReg(clobber)
214       .addReg(FrameReg)
215       .addImm(Hi_32(Offset));
216 
217   // Use clobber register as a frame register and 0 offset
218   FrameReg = clobber;
219   Offset = 0;
220 }
221 
222 // Replace the frame index in \p MI with a proper byte and framereg offset.
223 void EliminateFrameIndex::replaceFI(MachineInstr &MI, Register FrameReg,
224                                     int64_t Offset, int FIOperandNum) {
225   assert(isInt<32>(Offset));
226 
227   // The offset must be small enough to fit in the immediate field after
228   // call of prepareReplaceFI.  Therefore, we directly encode it.
229   MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false);
230   MI.getOperand(FIOperandNum + offsetToDisp(MI)).ChangeToImmediate(Offset);
231 }
232 
233 void EliminateFrameIndex::processSTQ(MachineInstr &MI, Register FrameReg,
234                                      int64_t Offset, int FIOperandNum) {
235   assert(MI.getOpcode() == VE::STQrii);
236   LLVM_DEBUG(dbgs() << "processSTQ: "; MI.dump());
237 
238   prepareReplaceFI(MI, FrameReg, Offset, 8);
239 
240   Register SrcReg = MI.getOperand(3).getReg();
241   Register SrcHiReg = getSubReg(SrcReg, VE::sub_even);
242   Register SrcLoReg = getSubReg(SrcReg, VE::sub_odd);
243   // VE stores HiReg to 8(addr) and LoReg to 0(addr)
244   MachineInstr *StMI =
245       build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(SrcLoReg);
246   replaceFI(*StMI, FrameReg, Offset, 0);
247   // Mutate to 'hi' store.
248   MI.setDesc(get(VE::STrii));
249   MI.getOperand(3).setReg(SrcHiReg);
250   Offset += 8;
251   replaceFI(MI, FrameReg, Offset, FIOperandNum);
252 }
253 
254 void EliminateFrameIndex::processLDQ(MachineInstr &MI, Register FrameReg,
255                                      int64_t Offset, int FIOperandNum) {
256   assert(MI.getOpcode() == VE::LDQrii);
257   LLVM_DEBUG(dbgs() << "processLDQ: "; MI.dump());
258 
259   prepareReplaceFI(MI, FrameReg, Offset, 8);
260 
261   Register DestReg = MI.getOperand(0).getReg();
262   Register DestHiReg = getSubReg(DestReg, VE::sub_even);
263   Register DestLoReg = getSubReg(DestReg, VE::sub_odd);
264   // VE loads HiReg from 8(addr) and LoReg from 0(addr)
265   MachineInstr *StMI =
266       build(VE::LDrii, DestLoReg).addReg(FrameReg).addImm(0).addImm(0);
267   replaceFI(*StMI, FrameReg, Offset, 1);
268   MI.setDesc(get(VE::LDrii));
269   MI.getOperand(0).setReg(DestHiReg);
270   Offset += 8;
271   replaceFI(MI, FrameReg, Offset, FIOperandNum);
272 }
273 
274 void EliminateFrameIndex::processMI(MachineInstr &MI, Register FrameReg,
275                                     int64_t Offset, int FIOperandNum) {
276   switch (MI.getOpcode()) {
277   case VE::STQrii:
278     processSTQ(MI, FrameReg, Offset, FIOperandNum);
279     return;
280   case VE::LDQrii:
281     processLDQ(MI, FrameReg, Offset, FIOperandNum);
282     return;
283   }
284   prepareReplaceFI(MI, FrameReg, Offset);
285   replaceFI(MI, FrameReg, Offset, FIOperandNum);
286 }
287 
288 void VERegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
289                                          int SPAdj, unsigned FIOperandNum,
290                                          RegScavenger *RS) const {
291   assert(SPAdj == 0 && "Unexpected");
292 
293   MachineInstr &MI = *II;
294   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
295 
296   MachineFunction &MF = *MI.getParent()->getParent();
297   const VESubtarget &Subtarget = MF.getSubtarget<VESubtarget>();
298   const VEFrameLowering &TFI = *getFrameLowering(MF);
299   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
300   const VERegisterInfo &TRI = *Subtarget.getRegisterInfo();
301   DebugLoc DL = MI.getDebugLoc();
302   EliminateFrameIndex EFI(TII, TRI, DL, *MI.getParent(), II);
303 
304   // Retrieve FrameReg and byte offset for stack slot.
305   Register FrameReg;
306   int64_t Offset =
307       TFI.getFrameIndexReference(MF, FrameIndex, FrameReg).getFixed();
308   Offset += MI.getOperand(FIOperandNum + offsetToDisp(MI)).getImm();
309 
310   EFI.processMI(MI, FrameReg, Offset, FIOperandNum);
311 }
312 
313 Register VERegisterInfo::getFrameRegister(const MachineFunction &MF) const {
314   return VE::SX9;
315 }
316