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