1 //===-- CSKYRegisterInfo.h - CSKY Register Information Impl ---*- 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 CSKY implementation of the TargetRegisterInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CSKYRegisterInfo.h"
14 #include "CSKY.h"
15 #include "CSKYSubtarget.h"
16 #include "llvm/CodeGen/MachineFunction.h"
17 #include "llvm/CodeGen/RegisterScavenging.h"
18 #include "llvm/MC/MCContext.h"
19 
20 #define GET_REGINFO_TARGET_DESC
21 #include "CSKYGenRegisterInfo.inc"
22 
23 using namespace llvm;
24 
25 CSKYRegisterInfo::CSKYRegisterInfo()
26     : CSKYGenRegisterInfo(CSKY::R15, 0, 0, 0) {}
27 
28 const uint32_t *
29 CSKYRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
30                                        CallingConv::ID Id) const {
31   const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>();
32   return CSR_I32_RegMask;
33 }
34 
35 Register CSKYRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
36   const TargetFrameLowering *TFI = getFrameLowering(MF);
37   return TFI->hasFP(MF) ? CSKY::R8 : CSKY::R14;
38 }
39 
40 BitVector CSKYRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
41   const CSKYFrameLowering *TFI = getFrameLowering(MF);
42   const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>();
43   BitVector Reserved(getNumRegs());
44 
45   // Reserve the base register if we need to allocate
46   // variable-sized objects at runtime.
47   if (TFI->hasBP(MF))
48     markSuperRegs(Reserved, CSKY::R7); // bp
49 
50   if (TFI->hasFP(MF))
51     markSuperRegs(Reserved, CSKY::R8); // fp
52 
53   if (!STI.hasE2()) {
54     for (unsigned i = 0; i < 6; i++)
55       markSuperRegs(Reserved, CSKY::R8 + i); // R8 - R13
56   }
57 
58   markSuperRegs(Reserved, CSKY::R14); // sp
59   markSuperRegs(Reserved, CSKY::R15); // lr
60 
61   if (!STI.hasHighRegisters()) {
62     for (unsigned i = 0; i < 10; i++)
63       markSuperRegs(Reserved, CSKY::R16 + i); // R16 - R25
64   }
65 
66   markSuperRegs(Reserved, CSKY::R26);
67   markSuperRegs(Reserved, CSKY::R27);
68   markSuperRegs(Reserved, CSKY::R28); // gp
69   markSuperRegs(Reserved, CSKY::R29);
70   markSuperRegs(Reserved, CSKY::R30);
71   markSuperRegs(Reserved, CSKY::R31); // tp
72 
73   assert(checkAllSuperRegsMarked(Reserved));
74   return Reserved;
75 }
76 
77 const uint32_t *CSKYRegisterInfo::getNoPreservedMask() const {
78   return CSR_NoRegs_RegMask;
79 }
80 
81 const MCPhysReg *
82 CSKYRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
83   const CSKYSubtarget &STI = MF->getSubtarget<CSKYSubtarget>();
84   if (MF->getFunction().hasFnAttribute("interrupt")) {
85     return CSR_GPR_ISR_SaveList;
86   }
87 
88   return CSR_I32_SaveList;
89 }
90 
91 static bool IsLegalOffset(const CSKYInstrInfo *TII, MachineInstr *MI,
92                           int &Offset) {
93   const MCInstrDesc &Desc = MI->getDesc();
94   unsigned AddrMode = (Desc.TSFlags & CSKYII::AddrModeMask);
95   unsigned i = 0;
96   for (; !MI->getOperand(i).isFI(); ++i) {
97     assert(i + 1 < MI->getNumOperands() &&
98            "Instr doesn't have FrameIndex operand!");
99   }
100 
101   if (MI->getOpcode() == CSKY::ADDI32) {
102     if (!isUInt<12>(std::abs(Offset) - 1))
103       return false;
104     if (Offset < 0) {
105       MI->setDesc(TII->get(CSKY::SUBI32));
106       Offset = -Offset;
107     }
108 
109     return true;
110   }
111 
112   if (MI->getOpcode() == CSKY::ADDI16XZ)
113     return false;
114 
115   if (Offset < 0)
116     return false;
117 
118   unsigned NumBits = 0;
119   unsigned Scale = 1;
120   switch (AddrMode) {
121   case CSKYII::AddrMode32B:
122     Scale = 1;
123     NumBits = 12;
124     break;
125   case CSKYII::AddrMode32H:
126     Scale = 2;
127     NumBits = 12;
128     break;
129   case CSKYII::AddrMode32WD:
130     Scale = 4;
131     NumBits = 12;
132     break;
133   case CSKYII::AddrMode16B:
134     Scale = 1;
135     NumBits = 5;
136     break;
137   case CSKYII::AddrMode16H:
138     Scale = 2;
139     NumBits = 5;
140     break;
141   case CSKYII::AddrMode16W:
142     Scale = 4;
143     NumBits = 5;
144     break;
145   case CSKYII::AddrMode32SDF:
146     Scale = 4;
147     NumBits = 8;
148     break;
149   default:
150     llvm_unreachable("Unsupported addressing mode!");
151   }
152 
153   // Cannot encode offset.
154   if ((Offset & (Scale - 1)) != 0)
155     return false;
156 
157   unsigned Mask = (1 << NumBits) - 1;
158   if ((unsigned)Offset <= Mask * Scale)
159     return true;
160 
161   // Offset out of range.
162   return false;
163 }
164 
165 void CSKYRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
166                                            int SPAdj, unsigned FIOperandNum,
167                                            RegScavenger *RS) const {
168   assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
169 
170   MachineInstr *MI = &*II;
171   MachineBasicBlock &MBB = *MI->getParent();
172   MachineFunction &MF = *MI->getParent()->getParent();
173   MachineRegisterInfo &MRI = MF.getRegInfo();
174   const CSKYInstrInfo *TII = MF.getSubtarget<CSKYSubtarget>().getInstrInfo();
175   DebugLoc DL = MI->getDebugLoc();
176   const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>();
177 
178   switch (MI->getOpcode()) {
179   default:
180     break;
181   case CSKY::RESTORE_CARRY: {
182     Register NewReg = STI.hasE2()
183                           ? MRI.createVirtualRegister(&CSKY::GPRRegClass)
184                           : MRI.createVirtualRegister(&CSKY::mGPRRegClass);
185 
186     auto *Temp = BuildMI(MBB, II, DL, TII->get(CSKY::LD32W), NewReg)
187                      .add(MI->getOperand(1))
188                      .add(MI->getOperand(2))
189                      .getInstr();
190 
191     BuildMI(MBB, II, DL, TII->get(STI.hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16),
192             MI->getOperand(0).getReg())
193         .addReg(NewReg, getKillRegState(true))
194         .addImm(0);
195 
196     MI = Temp;
197 
198     MBB.erase(II);
199     break;
200   }
201   case CSKY::SPILL_CARRY: {
202     Register NewReg;
203     if (STI.hasE2()) {
204       NewReg = MRI.createVirtualRegister(&CSKY::GPRRegClass);
205       BuildMI(MBB, II, DL, TII->get(CSKY::MVC32), NewReg)
206           .add(MI->getOperand(0));
207     } else {
208       NewReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass);
209       BuildMI(MBB, II, DL, TII->get(CSKY::MOVI16), NewReg).addImm(0);
210       BuildMI(MBB, II, DL, TII->get(CSKY::ADDC16))
211           .addReg(NewReg, RegState::Define)
212           .addReg(MI->getOperand(0).getReg(), RegState::Define)
213           .addReg(NewReg, getKillRegState(true))
214           .addReg(NewReg, getKillRegState(true))
215           .addReg(MI->getOperand(0).getReg());
216 
217       BuildMI(MBB, II, DL, TII->get(CSKY::BTSTI16), MI->getOperand(0).getReg())
218           .addReg(NewReg)
219           .addImm(0);
220     }
221 
222     MI = BuildMI(MBB, II, DL, TII->get(CSKY::ST32W))
223              .addReg(NewReg, getKillRegState(true))
224              .add(MI->getOperand(1))
225              .add(MI->getOperand(2))
226              .getInstr();
227 
228     MBB.erase(II);
229 
230     break;
231   }
232   }
233 
234   int FrameIndex = MI->getOperand(FIOperandNum).getIndex();
235   Register FrameReg;
236   int Offset = getFrameLowering(MF)
237                    ->getFrameIndexReference(MF, FrameIndex, FrameReg)
238                    .getFixed() +
239                MI->getOperand(FIOperandNum + 1).getImm();
240 
241   if (!isInt<32>(Offset))
242     report_fatal_error(
243         "Frame offsets outside of the signed 32-bit range not supported");
244 
245   bool FrameRegIsKill = false;
246   MachineBasicBlock::iterator NewII(MI);
247   if (!IsLegalOffset(TII, MI, Offset)) {
248     assert(isInt<32>(Offset) && "Int32 expected");
249     // The offset won't fit in an immediate, so use a scratch register instead
250     // Modify Offset and FrameReg appropriately
251     assert(Offset >= 0);
252     Register ScratchReg = TII->movImm(MBB, NewII, DL, Offset);
253     BuildMI(MBB, NewII, DL,
254             TII->get(STI.hasE2() ? CSKY::ADDU32 : CSKY::ADDU16XZ), ScratchReg)
255         .addReg(ScratchReg, RegState::Kill)
256         .addReg(FrameReg);
257 
258     Offset = 0;
259     FrameReg = ScratchReg;
260     FrameRegIsKill = true;
261   }
262 
263   if (Offset == 0 &&
264       (MI->getOpcode() == CSKY::ADDI32 || MI->getOpcode() == CSKY::ADDI16XZ)) {
265     MI->setDesc(TII->get(TargetOpcode::COPY));
266     MI->getOperand(FIOperandNum)
267         .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
268     MI->RemoveOperand(FIOperandNum + 1);
269   } else {
270     MI->getOperand(FIOperandNum)
271         .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
272     MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
273   }
274 }
275