xref: /freebsd/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
181ad6265SDimitry Andric //===- LoongArchRegisterInfo.cpp - LoongArch Register Information -*- C++ -*-=//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file contains the LoongArch implementation of the TargetRegisterInfo
1081ad6265SDimitry Andric // class.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "LoongArchRegisterInfo.h"
1581ad6265SDimitry Andric #include "LoongArch.h"
16bdd1243dSDimitry Andric #include "LoongArchInstrInfo.h"
1781ad6265SDimitry Andric #include "LoongArchSubtarget.h"
18*1db9f3b2SDimitry Andric #include "MCTargetDesc/LoongArchBaseInfo.h"
19bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
2381ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
2581ad6265SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
2681ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric using namespace llvm;
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric #define GET_REGINFO_TARGET_DESC
3181ad6265SDimitry Andric #include "LoongArchGenRegisterInfo.inc"
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric LoongArchRegisterInfo::LoongArchRegisterInfo(unsigned HwMode)
3481ad6265SDimitry Andric     : LoongArchGenRegisterInfo(LoongArch::R1, /*DwarfFlavour*/ 0,
3581ad6265SDimitry Andric                                /*EHFlavor*/ 0,
3681ad6265SDimitry Andric                                /*PC*/ 0, HwMode) {}
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric const MCPhysReg *
3981ad6265SDimitry Andric LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
4081ad6265SDimitry Andric   auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>();
4181ad6265SDimitry Andric 
42bdd1243dSDimitry Andric   if (MF->getFunction().getCallingConv() == CallingConv::GHC)
43bdd1243dSDimitry Andric     return CSR_NoRegs_SaveList;
4481ad6265SDimitry Andric   switch (Subtarget.getTargetABI()) {
4581ad6265SDimitry Andric   default:
4681ad6265SDimitry Andric     llvm_unreachable("Unrecognized ABI");
4781ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32S:
4881ad6265SDimitry Andric   case LoongArchABI::ABI_LP64S:
4981ad6265SDimitry Andric     return CSR_ILP32S_LP64S_SaveList;
5081ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32F:
5181ad6265SDimitry Andric   case LoongArchABI::ABI_LP64F:
5281ad6265SDimitry Andric     return CSR_ILP32F_LP64F_SaveList;
5381ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32D:
5481ad6265SDimitry Andric   case LoongArchABI::ABI_LP64D:
5581ad6265SDimitry Andric     return CSR_ILP32D_LP64D_SaveList;
5681ad6265SDimitry Andric   }
5781ad6265SDimitry Andric }
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric const uint32_t *
6081ad6265SDimitry Andric LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
6181ad6265SDimitry Andric                                             CallingConv::ID CC) const {
6281ad6265SDimitry Andric   auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>();
6381ad6265SDimitry Andric 
64bdd1243dSDimitry Andric   if (CC == CallingConv::GHC)
65bdd1243dSDimitry Andric     return CSR_NoRegs_RegMask;
6681ad6265SDimitry Andric   switch (Subtarget.getTargetABI()) {
6781ad6265SDimitry Andric   default:
6881ad6265SDimitry Andric     llvm_unreachable("Unrecognized ABI");
6981ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32S:
7081ad6265SDimitry Andric   case LoongArchABI::ABI_LP64S:
7181ad6265SDimitry Andric     return CSR_ILP32S_LP64S_RegMask;
7281ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32F:
7381ad6265SDimitry Andric   case LoongArchABI::ABI_LP64F:
7481ad6265SDimitry Andric     return CSR_ILP32F_LP64F_RegMask;
7581ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32D:
7681ad6265SDimitry Andric   case LoongArchABI::ABI_LP64D:
7781ad6265SDimitry Andric     return CSR_ILP32D_LP64D_RegMask;
7881ad6265SDimitry Andric   }
7981ad6265SDimitry Andric }
8081ad6265SDimitry Andric 
8181ad6265SDimitry Andric const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const {
8281ad6265SDimitry Andric   return CSR_NoRegs_RegMask;
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric BitVector
8681ad6265SDimitry Andric LoongArchRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
8781ad6265SDimitry Andric   const LoongArchFrameLowering *TFI = getFrameLowering(MF);
8881ad6265SDimitry Andric   BitVector Reserved(getNumRegs());
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric   // Use markSuperRegs to ensure any register aliases are also reserved
9181ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R0);  // zero
9281ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R2);  // tp
9381ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R3);  // sp
9481ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R21); // non-allocatable
9581ad6265SDimitry Andric   if (TFI->hasFP(MF))
9681ad6265SDimitry Andric     markSuperRegs(Reserved, LoongArch::R22); // fp
9781ad6265SDimitry Andric   // Reserve the base register if we need to realign the stack and allocate
9881ad6265SDimitry Andric   // variable-sized objects at runtime.
9981ad6265SDimitry Andric   if (TFI->hasBP(MF))
10081ad6265SDimitry Andric     markSuperRegs(Reserved, LoongArchABI::getBPReg()); // bp
10181ad6265SDimitry Andric 
10281ad6265SDimitry Andric   assert(checkAllSuperRegsMarked(Reserved));
10381ad6265SDimitry Andric   return Reserved;
10481ad6265SDimitry Andric }
10581ad6265SDimitry Andric 
10681ad6265SDimitry Andric Register
10781ad6265SDimitry Andric LoongArchRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
10881ad6265SDimitry Andric   const TargetFrameLowering *TFI = getFrameLowering(MF);
10981ad6265SDimitry Andric   return TFI->hasFP(MF) ? LoongArch::R22 : LoongArch::R3;
11081ad6265SDimitry Andric }
11181ad6265SDimitry Andric 
112bdd1243dSDimitry Andric bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
11381ad6265SDimitry Andric                                                 int SPAdj,
11481ad6265SDimitry Andric                                                 unsigned FIOperandNum,
11581ad6265SDimitry Andric                                                 RegScavenger *RS) const {
116753f127fSDimitry Andric   // TODO: this implementation is a temporary placeholder which does just
117753f127fSDimitry Andric   // enough to allow other aspects of code generation to be tested.
118753f127fSDimitry Andric 
11981ad6265SDimitry Andric   assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
120753f127fSDimitry Andric 
121753f127fSDimitry Andric   MachineInstr &MI = *II;
122bdd1243dSDimitry Andric   assert(MI.getOperand(FIOperandNum + 1).isImm() &&
123bdd1243dSDimitry Andric          "Unexpected FI-consuming insn");
124bdd1243dSDimitry Andric 
125bdd1243dSDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
126753f127fSDimitry Andric   MachineFunction &MF = *MI.getParent()->getParent();
127bdd1243dSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
128bdd1243dSDimitry Andric   const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>();
129bdd1243dSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
130753f127fSDimitry Andric   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
131753f127fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
132bdd1243dSDimitry Andric   bool IsLA64 = STI.is64Bit();
133bdd1243dSDimitry Andric   unsigned MIOpc = MI.getOpcode();
134753f127fSDimitry Andric 
135753f127fSDimitry Andric   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
136753f127fSDimitry Andric   Register FrameReg;
137753f127fSDimitry Andric   StackOffset Offset =
138753f127fSDimitry Andric       TFI->getFrameIndexReference(MF, FrameIndex, FrameReg) +
139753f127fSDimitry Andric       StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm());
140753f127fSDimitry Andric 
141bdd1243dSDimitry Andric   bool FrameRegIsKill = false;
142bdd1243dSDimitry Andric 
143753f127fSDimitry Andric   if (!isInt<12>(Offset.getFixed())) {
144bdd1243dSDimitry Andric     unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
145bdd1243dSDimitry Andric     unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
146bdd1243dSDimitry Andric 
147bdd1243dSDimitry Andric     // The offset won't fit in an immediate, so use a scratch register instead.
148bdd1243dSDimitry Andric     // Modify Offset and FrameReg appropriately.
149bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
150bdd1243dSDimitry Andric     TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed());
151bdd1243dSDimitry Andric     if (MIOpc == Addi) {
152bdd1243dSDimitry Andric       BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
153bdd1243dSDimitry Andric           .addReg(FrameReg)
154bdd1243dSDimitry Andric           .addReg(ScratchReg, RegState::Kill);
155bdd1243dSDimitry Andric       MI.eraseFromParent();
156bdd1243dSDimitry Andric       return true;
157bdd1243dSDimitry Andric     }
158bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
159bdd1243dSDimitry Andric         .addReg(FrameReg)
160bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill);
161bdd1243dSDimitry Andric     Offset = StackOffset::getFixed(0);
162bdd1243dSDimitry Andric     FrameReg = ScratchReg;
163bdd1243dSDimitry Andric     FrameRegIsKill = true;
164753f127fSDimitry Andric   }
165753f127fSDimitry Andric 
166bdd1243dSDimitry Andric   // Spill CFRs.
167bdd1243dSDimitry Andric   if (MIOpc == LoongArch::PseudoST_CFR) {
168bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
169bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVCF2GR), ScratchReg)
170bdd1243dSDimitry Andric         .add(MI.getOperand(0));
171bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
172bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill)
173bdd1243dSDimitry Andric         .addReg(FrameReg)
174bdd1243dSDimitry Andric         .addImm(Offset.getFixed());
175bdd1243dSDimitry Andric     MI.eraseFromParent();
176bdd1243dSDimitry Andric     return true;
177bdd1243dSDimitry Andric   }
178bdd1243dSDimitry Andric 
179bdd1243dSDimitry Andric   // Reload CFRs.
180bdd1243dSDimitry Andric   if (MIOpc == LoongArch::PseudoLD_CFR) {
181bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
182bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::LD_D : LoongArch::LD_W),
183bdd1243dSDimitry Andric             ScratchReg)
184bdd1243dSDimitry Andric         .addReg(FrameReg)
185bdd1243dSDimitry Andric         .addImm(Offset.getFixed());
186bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVGR2CF))
187bdd1243dSDimitry Andric         .add(MI.getOperand(0))
188bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill);
189bdd1243dSDimitry Andric     MI.eraseFromParent();
190bdd1243dSDimitry Andric     return true;
191bdd1243dSDimitry Andric   }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric   MI.getOperand(FIOperandNum)
194bdd1243dSDimitry Andric       .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
195753f127fSDimitry Andric   MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed());
196bdd1243dSDimitry Andric   return false;
19781ad6265SDimitry Andric }
198*1db9f3b2SDimitry Andric 
199*1db9f3b2SDimitry Andric bool LoongArchRegisterInfo::canRealignStack(const MachineFunction &MF) const {
200*1db9f3b2SDimitry Andric   if (!TargetRegisterInfo::canRealignStack(MF))
201*1db9f3b2SDimitry Andric     return false;
202*1db9f3b2SDimitry Andric 
203*1db9f3b2SDimitry Andric   const MachineRegisterInfo *MRI = &MF.getRegInfo();
204*1db9f3b2SDimitry Andric   const LoongArchFrameLowering *TFI = getFrameLowering(MF);
205*1db9f3b2SDimitry Andric 
206*1db9f3b2SDimitry Andric   // Stack realignment requires a frame pointer.  If we already started
207*1db9f3b2SDimitry Andric   // register allocation with frame pointer elimination, it is too late now.
208*1db9f3b2SDimitry Andric   if (!MRI->canReserveReg(LoongArch::R22))
209*1db9f3b2SDimitry Andric     return false;
210*1db9f3b2SDimitry Andric 
211*1db9f3b2SDimitry Andric   // We may also need a base pointer if there are dynamic allocas or stack
212*1db9f3b2SDimitry Andric   // pointer adjustments around calls.
213*1db9f3b2SDimitry Andric   if (TFI->hasReservedCallFrame(MF))
214*1db9f3b2SDimitry Andric     return true;
215*1db9f3b2SDimitry Andric 
216*1db9f3b2SDimitry Andric   // A base pointer is required and allowed.  Check that it isn't too late to
217*1db9f3b2SDimitry Andric   // reserve it.
218*1db9f3b2SDimitry Andric   return MRI->canReserveReg(LoongArchABI::getBPReg());
219*1db9f3b2SDimitry Andric }
220