xref: /llvm-project/llvm/lib/Target/VE/VERegisterInfo.cpp (revision ed8019d9fbed2e6a6b08f8f73e9fa54a24f3ed52)
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/CodeGen/MachineFrameInfo.h"
18 #include "llvm/CodeGen/MachineFunction.h"
19 #include "llvm/CodeGen/MachineInstrBuilder.h"
20 #include "llvm/CodeGen/TargetInstrInfo.h"
21 #include "llvm/IR/Type.h"
22 #include "llvm/Support/Debug.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "ve-register-info"
27 
28 #define GET_REGINFO_TARGET_DESC
29 #include "VEGenRegisterInfo.inc"
30 
31 // VE uses %s10 == %lp to keep return address
32 VERegisterInfo::VERegisterInfo() : VEGenRegisterInfo(VE::SX10) {}
33 
34 const MCPhysReg *
35 VERegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
36   switch (MF->getFunction().getCallingConv()) {
37   case CallingConv::Fast:
38     // Being explicit (same as standard CC).
39   default:
40     return CSR_SaveList;
41   case CallingConv::PreserveAll:
42     return CSR_preserve_all_SaveList;
43   }
44 }
45 
46 const uint32_t *VERegisterInfo::getCallPreservedMask(const MachineFunction &MF,
47                                                      CallingConv::ID CC) const {
48   switch (CC) {
49   case CallingConv::Fast:
50     // Being explicit (same as standard CC).
51   default:
52     return CSR_RegMask;
53   case CallingConv::PreserveAll:
54     return CSR_preserve_all_RegMask;
55   }
56 }
57 
58 const uint32_t *VERegisterInfo::getNoPreservedMask() const {
59   return CSR_NoRegs_RegMask;
60 }
61 
62 BitVector VERegisterInfo::getReservedRegs(const MachineFunction &MF) const {
63   BitVector Reserved(getNumRegs());
64 
65   const Register ReservedRegs[] = {
66       VE::SX8,  // Stack limit
67       VE::SX9,  // Frame pointer
68       VE::SX10, // Link register (return address)
69       VE::SX11, // Stack pointer
70 
71       // FIXME: maybe not need to be reserved
72       VE::SX12, // Outer register
73       VE::SX13, // Id register for dynamic linker
74 
75       VE::SX14, // Thread pointer
76       VE::SX15, // Global offset table register
77       VE::SX16, // Procedure linkage table register
78       VE::SX17, // Linkage-area register
79                 // sx18-sx33 are callee-saved registers
80                 // sx34-sx63 are temporary registers
81   };
82 
83   for (auto R : ReservedRegs)
84     for (MCRegAliasIterator ItAlias(R, this, true); ItAlias.isValid();
85          ++ItAlias)
86       Reserved.set(*ItAlias);
87 
88   // Reserve constant registers.
89   Reserved.set(VE::VM0);
90   Reserved.set(VE::VMP0);
91 
92   return Reserved;
93 }
94 
95 const TargetRegisterClass *
96 VERegisterInfo::getPointerRegClass(const MachineFunction &MF,
97                                    unsigned Kind) const {
98   return &VE::I64RegClass;
99 }
100 
101 static unsigned offsetToDisp(MachineInstr &MI) {
102   // Default offset in instruction's operands (reg+reg+imm).
103   unsigned OffDisp = 2;
104 
105 #define RRCAS_multi_cases(NAME) NAME##rir : case NAME##rii
106 
107   {
108     using namespace llvm::VE;
109     switch (MI.getOpcode()) {
110     case INLINEASM:
111     case RRCAS_multi_cases(TS1AML):
112     case RRCAS_multi_cases(TS1AMW):
113     case RRCAS_multi_cases(CASL):
114     case RRCAS_multi_cases(CASW):
115       // These instructions use AS format (reg+imm).
116       OffDisp = 1;
117       break;
118     }
119   }
120 #undef RRCAS_multi_cases
121 
122   return OffDisp;
123 }
124 
125 namespace {
126 class EliminateFrameIndex {
127   const TargetInstrInfo &TII;
128   const TargetRegisterInfo &TRI;
129   const DebugLoc &DL;
130   MachineBasicBlock &MBB;
131   MachineBasicBlock::iterator II;
132   Register clobber;
133 
134   // Some helper functions for the ease of instruction building.
135   MachineFunction &getFunc() const { return *MBB.getParent(); }
136   inline MCRegister getSubReg(MCRegister Reg, unsigned Idx) const {
137     return TRI.getSubReg(Reg, Idx);
138   }
139   inline const MCInstrDesc &get(unsigned Opcode) const {
140     return TII.get(Opcode);
141   }
142   inline MachineInstrBuilder build(const MCInstrDesc &MCID, Register DestReg) {
143     return BuildMI(MBB, II, DL, MCID, DestReg);
144   }
145   inline MachineInstrBuilder build(unsigned InstOpc, Register DestReg) {
146     return build(get(InstOpc), DestReg);
147   }
148   inline MachineInstrBuilder build(const MCInstrDesc &MCID) {
149     return BuildMI(MBB, II, DL, MCID);
150   }
151   inline MachineInstrBuilder build(unsigned InstOpc) {
152     return build(get(InstOpc));
153   }
154 
155   // Calculate an address of frame index from a frame register and a given
156   // offset if the offset doesn't fit in the immediate field.  Use a clobber
157   // register to hold calculated address.
158   void prepareReplaceFI(MachineInstr &MI, Register &FrameReg, int64_t &Offset,
159                         int64_t Bytes = 0);
160   // Replace the frame index in \p MI with a frame register and a given offset
161   // if it fits in the immediate field.  Otherwise, use pre-calculated address
162   // in a clobber regsiter.
163   void replaceFI(MachineInstr &MI, Register FrameReg, int64_t Offset,
164                  int FIOperandNum);
165 
166   // Expand and eliminate Frame Index of pseudo STQrii and LDQrii.
167   void processSTQ(MachineInstr &MI, Register FrameReg, int64_t Offset,
168                   int FIOperandNum);
169   void processLDQ(MachineInstr &MI, Register FrameReg, int64_t Offset,
170                   int FIOperandNum);
171   // Expand and eliminate Frame Index of pseudo STVMrii and LDVMrii.
172   void processSTVM(MachineInstr &MI, Register FrameReg, int64_t Offset,
173                    int FIOperandNum);
174   void processLDVM(MachineInstr &MI, Register FrameReg, int64_t Offset,
175                    int FIOperandNum);
176   // Expand and eliminate Frame Index of pseudo STVM512rii and LDVM512rii.
177   void processSTVM512(MachineInstr &MI, Register FrameReg, int64_t Offset,
178                       int FIOperandNum);
179   void processLDVM512(MachineInstr &MI, Register FrameReg, int64_t Offset,
180                       int FIOperandNum);
181 
182 public:
183   EliminateFrameIndex(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI,
184                       const DebugLoc &DL, MachineBasicBlock &MBB,
185                       MachineBasicBlock::iterator II)
186       : TII(TII), TRI(TRI), DL(DL), MBB(MBB), II(II), clobber(VE::SX13) {}
187 
188   // Expand and eliminate Frame Index from MI
189   void processMI(MachineInstr &MI, Register FrameReg, int64_t Offset,
190                  int FIOperandNum);
191 };
192 } // namespace
193 
194 // Prepare the frame index if it doesn't fit in the immediate field.  Use
195 // clobber register to hold calculated address.
196 void EliminateFrameIndex::prepareReplaceFI(MachineInstr &MI, Register &FrameReg,
197                                            int64_t &Offset, int64_t Bytes) {
198   if (isInt<32>(Offset) && isInt<32>(Offset + Bytes)) {
199     // If the offset is small enough to fit in the immediate field, directly
200     // encode it.  So, nothing to prepare here.
201     return;
202   }
203 
204   // If the offset doesn't fit, emit following codes.  This clobbers SX13
205   // which we always know is available here.
206   //   lea     %clobber, Offset@lo
207   //   and     %clobber, %clobber, (32)0
208   //   lea.sl  %clobber, Offset@hi(FrameReg, %clobber)
209   build(VE::LEAzii, clobber).addImm(0).addImm(0).addImm(Lo_32(Offset));
210   build(VE::ANDrm, clobber).addReg(clobber).addImm(M0(32));
211   build(VE::LEASLrri, clobber)
212       .addReg(clobber)
213       .addReg(FrameReg)
214       .addImm(Hi_32(Offset));
215 
216   // Use clobber register as a frame register and 0 offset
217   FrameReg = clobber;
218   Offset = 0;
219 }
220 
221 // Replace the frame index in \p MI with a proper byte and framereg offset.
222 void EliminateFrameIndex::replaceFI(MachineInstr &MI, Register FrameReg,
223                                     int64_t Offset, int FIOperandNum) {
224   assert(isInt<32>(Offset));
225 
226   // The offset must be small enough to fit in the immediate field after
227   // call of prepareReplaceFI.  Therefore, we directly encode it.
228   MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false);
229   MI.getOperand(FIOperandNum + offsetToDisp(MI)).ChangeToImmediate(Offset);
230 }
231 
232 void EliminateFrameIndex::processSTQ(MachineInstr &MI, Register FrameReg,
233                                      int64_t Offset, int FIOperandNum) {
234   assert(MI.getOpcode() == VE::STQrii);
235   LLVM_DEBUG(dbgs() << "processSTQ: "; MI.dump());
236 
237   prepareReplaceFI(MI, FrameReg, Offset, 8);
238 
239   Register SrcReg = MI.getOperand(3).getReg();
240   Register SrcHiReg = getSubReg(SrcReg, VE::sub_even);
241   Register SrcLoReg = getSubReg(SrcReg, VE::sub_odd);
242   // VE stores HiReg to 8(addr) and LoReg to 0(addr)
243   MachineInstr *StMI =
244       build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(SrcLoReg);
245   replaceFI(*StMI, FrameReg, Offset, 0);
246   // Mutate to 'hi' store.
247   MI.setDesc(get(VE::STrii));
248   MI.getOperand(3).setReg(SrcHiReg);
249   Offset += 8;
250   replaceFI(MI, FrameReg, Offset, FIOperandNum);
251 }
252 
253 void EliminateFrameIndex::processLDQ(MachineInstr &MI, Register FrameReg,
254                                      int64_t Offset, int FIOperandNum) {
255   assert(MI.getOpcode() == VE::LDQrii);
256   LLVM_DEBUG(dbgs() << "processLDQ: "; MI.dump());
257 
258   prepareReplaceFI(MI, FrameReg, Offset, 8);
259 
260   Register DestReg = MI.getOperand(0).getReg();
261   Register DestHiReg = getSubReg(DestReg, VE::sub_even);
262   Register DestLoReg = getSubReg(DestReg, VE::sub_odd);
263   // VE loads HiReg from 8(addr) and LoReg from 0(addr)
264   MachineInstr *StMI =
265       build(VE::LDrii, DestLoReg).addReg(FrameReg).addImm(0).addImm(0);
266   replaceFI(*StMI, FrameReg, Offset, 1);
267   MI.setDesc(get(VE::LDrii));
268   MI.getOperand(0).setReg(DestHiReg);
269   Offset += 8;
270   replaceFI(MI, FrameReg, Offset, FIOperandNum);
271 }
272 
273 void EliminateFrameIndex::processSTVM(MachineInstr &MI, Register FrameReg,
274                                       int64_t Offset, int FIOperandNum) {
275   assert(MI.getOpcode() == VE::STVMrii);
276   LLVM_DEBUG(dbgs() << "processSTVM: "; MI.dump());
277 
278   // Original MI is:
279   //   STVMrii frame-index, 0, offset, reg (, memory operand)
280   // Convert it to:
281   //   SVMi   tmp-reg, reg, 0
282   //   STrii  frame-reg, 0, offset, tmp-reg
283   //   SVMi   tmp-reg, reg, 1
284   //   STrii  frame-reg, 0, offset+8, tmp-reg
285   //   SVMi   tmp-reg, reg, 2
286   //   STrii  frame-reg, 0, offset+16, tmp-reg
287   //   SVMi   tmp-reg, reg, 3
288   //   STrii  frame-reg, 0, offset+24, tmp-reg
289 
290   prepareReplaceFI(MI, FrameReg, Offset, 24);
291 
292   Register SrcReg = MI.getOperand(3).getReg();
293   bool isKill = MI.getOperand(3).isKill();
294   // FIXME: it would be better to scavenge a register here instead of
295   // reserving SX16 all of the time.
296   Register TmpReg = VE::SX16;
297   for (int i = 0; i < 3; ++i) {
298     build(VE::SVMmr, TmpReg).addReg(SrcReg).addImm(i);
299     MachineInstr *StMI =
300         build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(
301             TmpReg, getKillRegState(true));
302     replaceFI(*StMI, FrameReg, Offset, 0);
303     Offset += 8;
304   }
305   build(VE::SVMmr, TmpReg).addReg(SrcReg, getKillRegState(isKill)).addImm(3);
306   MI.setDesc(get(VE::STrii));
307   MI.getOperand(3).ChangeToRegister(TmpReg, false, false, true);
308   replaceFI(MI, FrameReg, Offset, FIOperandNum);
309 }
310 
311 void EliminateFrameIndex::processLDVM(MachineInstr &MI, Register FrameReg,
312                                       int64_t Offset, int FIOperandNum) {
313   assert(MI.getOpcode() == VE::LDVMrii);
314   LLVM_DEBUG(dbgs() << "processLDVM: "; MI.dump());
315 
316   // Original MI is:
317   //   LDVMri reg, frame-index, 0, offset (, memory operand)
318   // Convert it to:
319   //   LDrii  tmp-reg, frame-reg, 0, offset
320   //   LVMir vm, 0, tmp-reg
321   //   LDrii  tmp-reg, frame-reg, 0, offset+8
322   //   LVMir_m vm, 1, tmp-reg, vm
323   //   LDrii  tmp-reg, frame-reg, 0, offset+16
324   //   LVMir_m vm, 2, tmp-reg, vm
325   //   LDrii  tmp-reg, frame-reg, 0, offset+24
326   //   LVMir_m vm, 3, tmp-reg, vm
327 
328   prepareReplaceFI(MI, FrameReg, Offset, 24);
329 
330   Register DestReg = MI.getOperand(0).getReg();
331   // FIXME: it would be better to scavenge a register here instead of
332   // reserving SX16 all of the time.
333   unsigned TmpReg = VE::SX16;
334   for (int i = 0; i < 4; ++i) {
335     if (i != 3) {
336       MachineInstr *StMI =
337           build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0);
338       replaceFI(*StMI, FrameReg, Offset, 1);
339       Offset += 8;
340     } else {
341       // Last LDrii replace the target instruction.
342       MI.setDesc(get(VE::LDrii));
343       MI.getOperand(0).ChangeToRegister(TmpReg, true);
344     }
345     // First LVM is LVMir.  Others are LVMir_m.  Last LVM places at the
346     // next of the target instruction.
347     if (i == 0)
348       build(VE::LVMir, DestReg).addImm(i).addReg(TmpReg, getKillRegState(true));
349     else if (i != 3)
350       build(VE::LVMir_m, DestReg)
351           .addImm(i)
352           .addReg(TmpReg, getKillRegState(true))
353           .addReg(DestReg);
354     else
355       BuildMI(*MI.getParent(), std::next(II), DL, get(VE::LVMir_m), DestReg)
356           .addImm(3)
357           .addReg(TmpReg, getKillRegState(true))
358           .addReg(DestReg);
359   }
360   replaceFI(MI, FrameReg, Offset, FIOperandNum);
361 }
362 
363 void EliminateFrameIndex::processSTVM512(MachineInstr &MI, Register FrameReg,
364                                          int64_t Offset, int FIOperandNum) {
365   assert(MI.getOpcode() == VE::STVM512rii);
366   LLVM_DEBUG(dbgs() << "processSTVM512: "; MI.dump());
367 
368   prepareReplaceFI(MI, FrameReg, Offset, 56);
369 
370   Register SrcReg = MI.getOperand(3).getReg();
371   Register SrcLoReg = getSubReg(SrcReg, VE::sub_vm_odd);
372   Register SrcHiReg = getSubReg(SrcReg, VE::sub_vm_even);
373   bool isKill = MI.getOperand(3).isKill();
374   // FIXME: it would be better to scavenge a register here instead of
375   // reserving SX16 all of the time.
376   Register TmpReg = VE::SX16;
377   // store low part of VMP
378   MachineInstr *LastMI = nullptr;
379   for (int i = 0; i < 4; ++i) {
380     LastMI = build(VE::SVMmr, TmpReg).addReg(SrcLoReg).addImm(i);
381     MachineInstr *StMI =
382         build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(
383             TmpReg, getKillRegState(true));
384     replaceFI(*StMI, FrameReg, Offset, 0);
385     Offset += 8;
386   }
387   if (isKill)
388     LastMI->addRegisterKilled(SrcLoReg, &TRI, true);
389   // store high part of VMP
390   for (int i = 0; i < 3; ++i) {
391     build(VE::SVMmr, TmpReg).addReg(SrcHiReg).addImm(i);
392     MachineInstr *StMI =
393         build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(
394             TmpReg, getKillRegState(true));
395     replaceFI(*StMI, FrameReg, Offset, 0);
396     Offset += 8;
397   }
398   LastMI = build(VE::SVMmr, TmpReg).addReg(SrcHiReg).addImm(3);
399   if (isKill) {
400     LastMI->addRegisterKilled(SrcHiReg, &TRI, true);
401     // Add implicit super-register kills to the particular MI.
402     LastMI->addRegisterKilled(SrcReg, &TRI, true);
403   }
404   MI.setDesc(get(VE::STrii));
405   MI.getOperand(3).ChangeToRegister(TmpReg, false, false, true);
406   replaceFI(MI, FrameReg, Offset, FIOperandNum);
407 }
408 
409 void EliminateFrameIndex::processLDVM512(MachineInstr &MI, Register FrameReg,
410                                          int64_t Offset, int FIOperandNum) {
411   assert(MI.getOpcode() == VE::LDVM512rii);
412   LLVM_DEBUG(dbgs() << "processLDVM512: "; MI.dump());
413 
414   prepareReplaceFI(MI, FrameReg, Offset, 56);
415 
416   Register DestReg = MI.getOperand(0).getReg();
417   Register DestLoReg = getSubReg(DestReg, VE::sub_vm_odd);
418   Register DestHiReg = getSubReg(DestReg, VE::sub_vm_even);
419   // FIXME: it would be better to scavenge a register here instead of
420   // reserving SX16 all of the time.
421   Register TmpReg = VE::SX16;
422   build(VE::IMPLICIT_DEF, DestReg);
423   for (int i = 0; i < 4; ++i) {
424     MachineInstr *LdMI =
425         build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0);
426     replaceFI(*LdMI, FrameReg, Offset, 1);
427     build(VE::LVMir_m, DestLoReg)
428         .addImm(i)
429         .addReg(TmpReg, getKillRegState(true))
430         .addReg(DestLoReg);
431     Offset += 8;
432   }
433   for (int i = 0; i < 3; ++i) {
434     MachineInstr *LdMI =
435         build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0);
436     replaceFI(*LdMI, FrameReg, Offset, 1);
437     build(VE::LVMir_m, DestHiReg)
438         .addImm(i)
439         .addReg(TmpReg, getKillRegState(true))
440         .addReg(DestHiReg);
441     Offset += 8;
442   }
443   MI.setDesc(get(VE::LDrii));
444   MI.getOperand(0).ChangeToRegister(TmpReg, true);
445   BuildMI(*MI.getParent(), std::next(II), DL, get(VE::LVMir_m), DestHiReg)
446       .addImm(3)
447       .addReg(TmpReg, getKillRegState(true))
448       .addReg(DestHiReg);
449   replaceFI(MI, FrameReg, Offset, FIOperandNum);
450 }
451 
452 void EliminateFrameIndex::processMI(MachineInstr &MI, Register FrameReg,
453                                     int64_t Offset, int FIOperandNum) {
454   switch (MI.getOpcode()) {
455   case VE::STQrii:
456     processSTQ(MI, FrameReg, Offset, FIOperandNum);
457     return;
458   case VE::LDQrii:
459     processLDQ(MI, FrameReg, Offset, FIOperandNum);
460     return;
461   case VE::STVMrii:
462     processSTVM(MI, FrameReg, Offset, FIOperandNum);
463     return;
464   case VE::LDVMrii:
465     processLDVM(MI, FrameReg, Offset, FIOperandNum);
466     return;
467   case VE::STVM512rii:
468     processSTVM512(MI, FrameReg, Offset, FIOperandNum);
469     return;
470   case VE::LDVM512rii:
471     processLDVM512(MI, FrameReg, Offset, FIOperandNum);
472     return;
473   }
474   prepareReplaceFI(MI, FrameReg, Offset);
475   replaceFI(MI, FrameReg, Offset, FIOperandNum);
476 }
477 
478 bool VERegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
479                                          int SPAdj, unsigned FIOperandNum,
480                                          RegScavenger *RS) const {
481   assert(SPAdj == 0 && "Unexpected");
482 
483   MachineInstr &MI = *II;
484   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
485 
486   MachineFunction &MF = *MI.getParent()->getParent();
487   const VESubtarget &Subtarget = MF.getSubtarget<VESubtarget>();
488   const VEFrameLowering &TFI = *getFrameLowering(MF);
489   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
490   const VERegisterInfo &TRI = *Subtarget.getRegisterInfo();
491   DebugLoc DL = MI.getDebugLoc();
492   EliminateFrameIndex EFI(TII, TRI, DL, *MI.getParent(), II);
493 
494   // Retrieve FrameReg and byte offset for stack slot.
495   Register FrameReg;
496   int64_t Offset =
497       TFI.getFrameIndexReference(MF, FrameIndex, FrameReg).getFixed();
498   Offset += MI.getOperand(FIOperandNum + offsetToDisp(MI)).getImm();
499 
500   EFI.processMI(MI, FrameReg, Offset, FIOperandNum);
501   return false;
502 }
503 
504 Register VERegisterInfo::getFrameRegister(const MachineFunction &MF) const {
505   return VE::SX9;
506 }
507