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
LoongArchRegisterInfo(unsigned HwMode)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 *
getCalleeSavedRegs(const MachineFunction * MF) const3981ad6265SDimitry 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 *
getCallPreservedMask(const MachineFunction & MF,CallingConv::ID CC) const6081ad6265SDimitry 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
getNoPreservedMask() const8181ad6265SDimitry Andric const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const {
8281ad6265SDimitry Andric return CSR_NoRegs_RegMask;
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric
8581ad6265SDimitry Andric BitVector
getReservedRegs(const MachineFunction & MF) const8681ad6265SDimitry 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
getFrameRegister(const MachineFunction & MF) const10781ad6265SDimitry 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
eliminateFrameIndex(MachineBasicBlock::iterator II,int SPAdj,unsigned FIOperandNum,RegScavenger * RS) const112bdd1243dSDimitry 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
canRealignStack(const MachineFunction & MF) const199*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