1 //===- LoongArchRegisterInfo.cpp - LoongArch Register Information -*- C++ -*-=//
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 LoongArch implementation of the TargetRegisterInfo
10 // class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "LoongArchRegisterInfo.h"
15 #include "LoongArch.h"
16 #include "LoongArchInstrInfo.h"
17 #include "LoongArchSubtarget.h"
18 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
19 #include "llvm/CodeGen/MachineFrameInfo.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/RegisterScavenging.h"
23 #include "llvm/CodeGen/TargetFrameLowering.h"
24 #include "llvm/CodeGen/TargetInstrInfo.h"
25 #include "llvm/Support/ErrorHandling.h"
26 
27 using namespace llvm;
28 
29 #define GET_REGINFO_TARGET_DESC
30 #include "LoongArchGenRegisterInfo.inc"
31 
32 LoongArchRegisterInfo::LoongArchRegisterInfo(unsigned HwMode)
33     : LoongArchGenRegisterInfo(LoongArch::R1, /*DwarfFlavour*/ 0,
34                                /*EHFlavor*/ 0,
35                                /*PC*/ 0, HwMode) {}
36 
37 const MCPhysReg *
38 LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
39   auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>();
40 
41   if (MF->getFunction().getCallingConv() == CallingConv::GHC)
42     return CSR_NoRegs_SaveList;
43   switch (Subtarget.getTargetABI()) {
44   default:
45     llvm_unreachable("Unrecognized ABI");
46   case LoongArchABI::ABI_ILP32S:
47   case LoongArchABI::ABI_LP64S:
48     return CSR_ILP32S_LP64S_SaveList;
49   case LoongArchABI::ABI_ILP32F:
50   case LoongArchABI::ABI_LP64F:
51     return CSR_ILP32F_LP64F_SaveList;
52   case LoongArchABI::ABI_ILP32D:
53   case LoongArchABI::ABI_LP64D:
54     return CSR_ILP32D_LP64D_SaveList;
55   }
56 }
57 
58 const uint32_t *
59 LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
60                                             CallingConv::ID CC) const {
61   auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>();
62 
63   if (CC == CallingConv::GHC)
64     return CSR_NoRegs_RegMask;
65   switch (Subtarget.getTargetABI()) {
66   default:
67     llvm_unreachable("Unrecognized ABI");
68   case LoongArchABI::ABI_ILP32S:
69   case LoongArchABI::ABI_LP64S:
70     return CSR_ILP32S_LP64S_RegMask;
71   case LoongArchABI::ABI_ILP32F:
72   case LoongArchABI::ABI_LP64F:
73     return CSR_ILP32F_LP64F_RegMask;
74   case LoongArchABI::ABI_ILP32D:
75   case LoongArchABI::ABI_LP64D:
76     return CSR_ILP32D_LP64D_RegMask;
77   }
78 }
79 
80 const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const {
81   return CSR_NoRegs_RegMask;
82 }
83 
84 BitVector
85 LoongArchRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
86   const LoongArchFrameLowering *TFI = getFrameLowering(MF);
87   BitVector Reserved(getNumRegs());
88 
89   // Use markSuperRegs to ensure any register aliases are also reserved
90   markSuperRegs(Reserved, LoongArch::R0);  // zero
91   markSuperRegs(Reserved, LoongArch::R2);  // tp
92   markSuperRegs(Reserved, LoongArch::R3);  // sp
93   markSuperRegs(Reserved, LoongArch::R21); // non-allocatable
94   if (TFI->hasFP(MF))
95     markSuperRegs(Reserved, LoongArch::R22); // fp
96   // Reserve the base register if we need to realign the stack and allocate
97   // variable-sized objects at runtime.
98   if (TFI->hasBP(MF))
99     markSuperRegs(Reserved, LoongArchABI::getBPReg()); // bp
100 
101   assert(checkAllSuperRegsMarked(Reserved));
102   return Reserved;
103 }
104 
105 Register
106 LoongArchRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
107   const TargetFrameLowering *TFI = getFrameLowering(MF);
108   return TFI->hasFP(MF) ? LoongArch::R22 : LoongArch::R3;
109 }
110 
111 bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
112                                                 int SPAdj,
113                                                 unsigned FIOperandNum,
114                                                 RegScavenger *RS) const {
115   // TODO: this implementation is a temporary placeholder which does just
116   // enough to allow other aspects of code generation to be tested.
117 
118   assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
119 
120   MachineInstr &MI = *II;
121   assert(MI.getOperand(FIOperandNum + 1).isImm() &&
122          "Unexpected FI-consuming insn");
123 
124   MachineBasicBlock &MBB = *MI.getParent();
125   MachineFunction &MF = *MI.getParent()->getParent();
126   MachineRegisterInfo &MRI = MF.getRegInfo();
127   const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>();
128   const LoongArchInstrInfo *TII = STI.getInstrInfo();
129   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
130   DebugLoc DL = MI.getDebugLoc();
131   bool IsLA64 = STI.is64Bit();
132   unsigned MIOpc = MI.getOpcode();
133 
134   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
135   Register FrameReg;
136   StackOffset Offset =
137       TFI->getFrameIndexReference(MF, FrameIndex, FrameReg) +
138       StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm());
139 
140   bool FrameRegIsKill = false;
141 
142   if (!isInt<12>(Offset.getFixed())) {
143     unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
144     unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
145 
146     // The offset won't fit in an immediate, so use a scratch register instead.
147     // Modify Offset and FrameReg appropriately.
148     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
149     TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed());
150     if (MIOpc == Addi) {
151       BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
152           .addReg(FrameReg)
153           .addReg(ScratchReg, RegState::Kill);
154       MI.eraseFromParent();
155       return true;
156     }
157     BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
158         .addReg(FrameReg)
159         .addReg(ScratchReg, RegState::Kill);
160     Offset = StackOffset::getFixed(0);
161     FrameReg = ScratchReg;
162     FrameRegIsKill = true;
163   }
164 
165   // Spill CFRs.
166   if (MIOpc == LoongArch::PseudoST_CFR) {
167     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
168     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVCF2GR), ScratchReg)
169         .add(MI.getOperand(0));
170     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
171         .addReg(ScratchReg, RegState::Kill)
172         .addReg(FrameReg)
173         .addImm(Offset.getFixed());
174     MI.eraseFromParent();
175     return true;
176   }
177 
178   // Reload CFRs.
179   if (MIOpc == LoongArch::PseudoLD_CFR) {
180     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
181     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::LD_D : LoongArch::LD_W),
182             ScratchReg)
183         .addReg(FrameReg)
184         .addImm(Offset.getFixed());
185     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVGR2CF))
186         .add(MI.getOperand(0))
187         .addReg(ScratchReg, RegState::Kill);
188     MI.eraseFromParent();
189     return true;
190   }
191 
192   MI.getOperand(FIOperandNum)
193       .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
194   MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed());
195   return false;
196 }
197