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