xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
16*bdd1243dSDimitry Andric #include "LoongArchInstrInfo.h"
1781ad6265SDimitry Andric #include "LoongArchSubtarget.h"
18*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
2381ad6265SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
2481ad6265SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
2581ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric using namespace llvm;
2881ad6265SDimitry Andric 
2981ad6265SDimitry Andric #define GET_REGINFO_TARGET_DESC
3081ad6265SDimitry Andric #include "LoongArchGenRegisterInfo.inc"
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric LoongArchRegisterInfo::LoongArchRegisterInfo(unsigned HwMode)
3381ad6265SDimitry Andric     : LoongArchGenRegisterInfo(LoongArch::R1, /*DwarfFlavour*/ 0,
3481ad6265SDimitry Andric                                /*EHFlavor*/ 0,
3581ad6265SDimitry Andric                                /*PC*/ 0, HwMode) {}
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric const MCPhysReg *
3881ad6265SDimitry Andric LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
3981ad6265SDimitry Andric   auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>();
4081ad6265SDimitry Andric 
41*bdd1243dSDimitry Andric   if (MF->getFunction().getCallingConv() == CallingConv::GHC)
42*bdd1243dSDimitry Andric     return CSR_NoRegs_SaveList;
4381ad6265SDimitry Andric   switch (Subtarget.getTargetABI()) {
4481ad6265SDimitry Andric   default:
4581ad6265SDimitry Andric     llvm_unreachable("Unrecognized ABI");
4681ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32S:
4781ad6265SDimitry Andric   case LoongArchABI::ABI_LP64S:
4881ad6265SDimitry Andric     return CSR_ILP32S_LP64S_SaveList;
4981ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32F:
5081ad6265SDimitry Andric   case LoongArchABI::ABI_LP64F:
5181ad6265SDimitry Andric     return CSR_ILP32F_LP64F_SaveList;
5281ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32D:
5381ad6265SDimitry Andric   case LoongArchABI::ABI_LP64D:
5481ad6265SDimitry Andric     return CSR_ILP32D_LP64D_SaveList;
5581ad6265SDimitry Andric   }
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric 
5881ad6265SDimitry Andric const uint32_t *
5981ad6265SDimitry Andric LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
6081ad6265SDimitry Andric                                             CallingConv::ID CC) const {
6181ad6265SDimitry Andric   auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>();
6281ad6265SDimitry Andric 
63*bdd1243dSDimitry Andric   if (CC == CallingConv::GHC)
64*bdd1243dSDimitry Andric     return CSR_NoRegs_RegMask;
6581ad6265SDimitry Andric   switch (Subtarget.getTargetABI()) {
6681ad6265SDimitry Andric   default:
6781ad6265SDimitry Andric     llvm_unreachable("Unrecognized ABI");
6881ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32S:
6981ad6265SDimitry Andric   case LoongArchABI::ABI_LP64S:
7081ad6265SDimitry Andric     return CSR_ILP32S_LP64S_RegMask;
7181ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32F:
7281ad6265SDimitry Andric   case LoongArchABI::ABI_LP64F:
7381ad6265SDimitry Andric     return CSR_ILP32F_LP64F_RegMask;
7481ad6265SDimitry Andric   case LoongArchABI::ABI_ILP32D:
7581ad6265SDimitry Andric   case LoongArchABI::ABI_LP64D:
7681ad6265SDimitry Andric     return CSR_ILP32D_LP64D_RegMask;
7781ad6265SDimitry Andric   }
7881ad6265SDimitry Andric }
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const {
8181ad6265SDimitry Andric   return CSR_NoRegs_RegMask;
8281ad6265SDimitry Andric }
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric BitVector
8581ad6265SDimitry Andric LoongArchRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
8681ad6265SDimitry Andric   const LoongArchFrameLowering *TFI = getFrameLowering(MF);
8781ad6265SDimitry Andric   BitVector Reserved(getNumRegs());
8881ad6265SDimitry Andric 
8981ad6265SDimitry Andric   // Use markSuperRegs to ensure any register aliases are also reserved
9081ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R0);  // zero
9181ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R2);  // tp
9281ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R3);  // sp
9381ad6265SDimitry Andric   markSuperRegs(Reserved, LoongArch::R21); // non-allocatable
9481ad6265SDimitry Andric   if (TFI->hasFP(MF))
9581ad6265SDimitry Andric     markSuperRegs(Reserved, LoongArch::R22); // fp
9681ad6265SDimitry Andric   // Reserve the base register if we need to realign the stack and allocate
9781ad6265SDimitry Andric   // variable-sized objects at runtime.
9881ad6265SDimitry Andric   if (TFI->hasBP(MF))
9981ad6265SDimitry Andric     markSuperRegs(Reserved, LoongArchABI::getBPReg()); // bp
10081ad6265SDimitry Andric 
101*bdd1243dSDimitry Andric   // FIXME: To avoid generating COPY instructions between CFRs, only use $fcc0.
102*bdd1243dSDimitry Andric   // This is required to work around the fact that COPY instruction between CFRs
103*bdd1243dSDimitry Andric   // is not provided in LoongArch.
104*bdd1243dSDimitry Andric   if (MF.getSubtarget<LoongArchSubtarget>().hasBasicF())
105*bdd1243dSDimitry Andric     for (size_t Reg = LoongArch::FCC1; Reg <= LoongArch::FCC7; ++Reg)
106*bdd1243dSDimitry Andric       markSuperRegs(Reserved, Reg);
107*bdd1243dSDimitry Andric 
10881ad6265SDimitry Andric   assert(checkAllSuperRegsMarked(Reserved));
10981ad6265SDimitry Andric   return Reserved;
11081ad6265SDimitry Andric }
11181ad6265SDimitry Andric 
11281ad6265SDimitry Andric Register
11381ad6265SDimitry Andric LoongArchRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
11481ad6265SDimitry Andric   const TargetFrameLowering *TFI = getFrameLowering(MF);
11581ad6265SDimitry Andric   return TFI->hasFP(MF) ? LoongArch::R22 : LoongArch::R3;
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric 
118*bdd1243dSDimitry Andric bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
11981ad6265SDimitry Andric                                                 int SPAdj,
12081ad6265SDimitry Andric                                                 unsigned FIOperandNum,
12181ad6265SDimitry Andric                                                 RegScavenger *RS) const {
122753f127fSDimitry Andric   // TODO: this implementation is a temporary placeholder which does just
123753f127fSDimitry Andric   // enough to allow other aspects of code generation to be tested.
124753f127fSDimitry Andric 
12581ad6265SDimitry Andric   assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
126753f127fSDimitry Andric 
127753f127fSDimitry Andric   MachineInstr &MI = *II;
128*bdd1243dSDimitry Andric   assert(MI.getOperand(FIOperandNum + 1).isImm() &&
129*bdd1243dSDimitry Andric          "Unexpected FI-consuming insn");
130*bdd1243dSDimitry Andric 
131*bdd1243dSDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
132753f127fSDimitry Andric   MachineFunction &MF = *MI.getParent()->getParent();
133*bdd1243dSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
134*bdd1243dSDimitry Andric   const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>();
135*bdd1243dSDimitry Andric   const LoongArchInstrInfo *TII = STI.getInstrInfo();
136753f127fSDimitry Andric   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
137753f127fSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
138*bdd1243dSDimitry Andric   bool IsLA64 = STI.is64Bit();
139*bdd1243dSDimitry Andric   unsigned MIOpc = MI.getOpcode();
140753f127fSDimitry Andric 
141753f127fSDimitry Andric   int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
142753f127fSDimitry Andric   Register FrameReg;
143753f127fSDimitry Andric   StackOffset Offset =
144753f127fSDimitry Andric       TFI->getFrameIndexReference(MF, FrameIndex, FrameReg) +
145753f127fSDimitry Andric       StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm());
146753f127fSDimitry Andric 
147*bdd1243dSDimitry Andric   bool FrameRegIsKill = false;
148*bdd1243dSDimitry Andric 
149753f127fSDimitry Andric   if (!isInt<12>(Offset.getFixed())) {
150*bdd1243dSDimitry Andric     unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
151*bdd1243dSDimitry Andric     unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
152*bdd1243dSDimitry Andric 
153*bdd1243dSDimitry Andric     // The offset won't fit in an immediate, so use a scratch register instead.
154*bdd1243dSDimitry Andric     // Modify Offset and FrameReg appropriately.
155*bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
156*bdd1243dSDimitry Andric     TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed());
157*bdd1243dSDimitry Andric     if (MIOpc == Addi) {
158*bdd1243dSDimitry Andric       BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
159*bdd1243dSDimitry Andric           .addReg(FrameReg)
160*bdd1243dSDimitry Andric           .addReg(ScratchReg, RegState::Kill);
161*bdd1243dSDimitry Andric       MI.eraseFromParent();
162*bdd1243dSDimitry Andric       return true;
163*bdd1243dSDimitry Andric     }
164*bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
165*bdd1243dSDimitry Andric         .addReg(FrameReg)
166*bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill);
167*bdd1243dSDimitry Andric     Offset = StackOffset::getFixed(0);
168*bdd1243dSDimitry Andric     FrameReg = ScratchReg;
169*bdd1243dSDimitry Andric     FrameRegIsKill = true;
170753f127fSDimitry Andric   }
171753f127fSDimitry Andric 
172*bdd1243dSDimitry Andric   // Spill CFRs.
173*bdd1243dSDimitry Andric   if (MIOpc == LoongArch::PseudoST_CFR) {
174*bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
175*bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVCF2GR), ScratchReg)
176*bdd1243dSDimitry Andric         .add(MI.getOperand(0));
177*bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
178*bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill)
179*bdd1243dSDimitry Andric         .addReg(FrameReg)
180*bdd1243dSDimitry Andric         .addImm(Offset.getFixed());
181*bdd1243dSDimitry Andric     MI.eraseFromParent();
182*bdd1243dSDimitry Andric     return true;
183*bdd1243dSDimitry Andric   }
184*bdd1243dSDimitry Andric 
185*bdd1243dSDimitry Andric   // Reload CFRs.
186*bdd1243dSDimitry Andric   if (MIOpc == LoongArch::PseudoLD_CFR) {
187*bdd1243dSDimitry Andric     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
188*bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::LD_D : LoongArch::LD_W),
189*bdd1243dSDimitry Andric             ScratchReg)
190*bdd1243dSDimitry Andric         .addReg(FrameReg)
191*bdd1243dSDimitry Andric         .addImm(Offset.getFixed());
192*bdd1243dSDimitry Andric     BuildMI(MBB, II, DL, TII->get(LoongArch::MOVGR2CF))
193*bdd1243dSDimitry Andric         .add(MI.getOperand(0))
194*bdd1243dSDimitry Andric         .addReg(ScratchReg, RegState::Kill);
195*bdd1243dSDimitry Andric     MI.eraseFromParent();
196*bdd1243dSDimitry Andric     return true;
197*bdd1243dSDimitry Andric   }
198*bdd1243dSDimitry Andric 
199*bdd1243dSDimitry Andric   MI.getOperand(FIOperandNum)
200*bdd1243dSDimitry Andric       .ChangeToRegister(FrameReg, false, false, FrameRegIsKill);
201753f127fSDimitry Andric   MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed());
202*bdd1243dSDimitry Andric   return false;
20381ad6265SDimitry Andric }
204