1 //===- LoongArchRegisterInfo.cpp - LoongArch Register Information -*- C++ -*-=// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains the LoongArch implementation of the TargetRegisterInfo 10 // class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "LoongArchRegisterInfo.h" 15 #include "LoongArch.h" 16 #include "LoongArchInstrInfo.h" 17 #include "LoongArchSubtarget.h" 18 #include "MCTargetDesc/LoongArchMCTargetDesc.h" 19 #include "llvm/CodeGen/MachineFrameInfo.h" 20 #include "llvm/CodeGen/MachineFunction.h" 21 #include "llvm/CodeGen/MachineInstrBuilder.h" 22 #include "llvm/CodeGen/RegisterScavenging.h" 23 #include "llvm/CodeGen/TargetFrameLowering.h" 24 #include "llvm/CodeGen/TargetInstrInfo.h" 25 #include "llvm/Support/ErrorHandling.h" 26 27 using namespace llvm; 28 29 #define GET_REGINFO_TARGET_DESC 30 #include "LoongArchGenRegisterInfo.inc" 31 32 LoongArchRegisterInfo::LoongArchRegisterInfo(unsigned HwMode) 33 : LoongArchGenRegisterInfo(LoongArch::R1, /*DwarfFlavour*/ 0, 34 /*EHFlavor*/ 0, 35 /*PC*/ 0, HwMode) {} 36 37 const MCPhysReg * 38 LoongArchRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { 39 auto &Subtarget = MF->getSubtarget<LoongArchSubtarget>(); 40 41 if (MF->getFunction().getCallingConv() == CallingConv::GHC) 42 return CSR_NoRegs_SaveList; 43 switch (Subtarget.getTargetABI()) { 44 default: 45 llvm_unreachable("Unrecognized ABI"); 46 case LoongArchABI::ABI_ILP32S: 47 case LoongArchABI::ABI_LP64S: 48 return CSR_ILP32S_LP64S_SaveList; 49 case LoongArchABI::ABI_ILP32F: 50 case LoongArchABI::ABI_LP64F: 51 return CSR_ILP32F_LP64F_SaveList; 52 case LoongArchABI::ABI_ILP32D: 53 case LoongArchABI::ABI_LP64D: 54 return CSR_ILP32D_LP64D_SaveList; 55 } 56 } 57 58 const uint32_t * 59 LoongArchRegisterInfo::getCallPreservedMask(const MachineFunction &MF, 60 CallingConv::ID CC) const { 61 auto &Subtarget = MF.getSubtarget<LoongArchSubtarget>(); 62 63 if (CC == CallingConv::GHC) 64 return CSR_NoRegs_RegMask; 65 switch (Subtarget.getTargetABI()) { 66 default: 67 llvm_unreachable("Unrecognized ABI"); 68 case LoongArchABI::ABI_ILP32S: 69 case LoongArchABI::ABI_LP64S: 70 return CSR_ILP32S_LP64S_RegMask; 71 case LoongArchABI::ABI_ILP32F: 72 case LoongArchABI::ABI_LP64F: 73 return CSR_ILP32F_LP64F_RegMask; 74 case LoongArchABI::ABI_ILP32D: 75 case LoongArchABI::ABI_LP64D: 76 return CSR_ILP32D_LP64D_RegMask; 77 } 78 } 79 80 const uint32_t *LoongArchRegisterInfo::getNoPreservedMask() const { 81 return CSR_NoRegs_RegMask; 82 } 83 84 BitVector 85 LoongArchRegisterInfo::getReservedRegs(const MachineFunction &MF) const { 86 const LoongArchFrameLowering *TFI = getFrameLowering(MF); 87 BitVector Reserved(getNumRegs()); 88 89 // Use markSuperRegs to ensure any register aliases are also reserved 90 markSuperRegs(Reserved, LoongArch::R0); // zero 91 markSuperRegs(Reserved, LoongArch::R2); // tp 92 markSuperRegs(Reserved, LoongArch::R3); // sp 93 markSuperRegs(Reserved, LoongArch::R21); // non-allocatable 94 if (TFI->hasFP(MF)) 95 markSuperRegs(Reserved, LoongArch::R22); // fp 96 // Reserve the base register if we need to realign the stack and allocate 97 // variable-sized objects at runtime. 98 if (TFI->hasBP(MF)) 99 markSuperRegs(Reserved, LoongArchABI::getBPReg()); // bp 100 101 // FIXME: To avoid generating COPY instructions between CFRs, only use $fcc0. 102 // This is required to work around the fact that COPY instruction between CFRs 103 // is not provided in LoongArch. 104 if (MF.getSubtarget<LoongArchSubtarget>().hasBasicF()) 105 for (size_t Reg = LoongArch::FCC1; Reg <= LoongArch::FCC7; ++Reg) 106 markSuperRegs(Reserved, Reg); 107 108 assert(checkAllSuperRegsMarked(Reserved)); 109 return Reserved; 110 } 111 112 Register 113 LoongArchRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 114 const TargetFrameLowering *TFI = getFrameLowering(MF); 115 return TFI->hasFP(MF) ? LoongArch::R22 : LoongArch::R3; 116 } 117 118 bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, 119 int SPAdj, 120 unsigned FIOperandNum, 121 RegScavenger *RS) const { 122 // TODO: this implementation is a temporary placeholder which does just 123 // enough to allow other aspects of code generation to be tested. 124 125 assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); 126 127 MachineInstr &MI = *II; 128 assert(MI.getOperand(FIOperandNum + 1).isImm() && 129 "Unexpected FI-consuming insn"); 130 131 MachineBasicBlock &MBB = *MI.getParent(); 132 MachineFunction &MF = *MI.getParent()->getParent(); 133 MachineRegisterInfo &MRI = MF.getRegInfo(); 134 const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>(); 135 const LoongArchInstrInfo *TII = STI.getInstrInfo(); 136 const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); 137 DebugLoc DL = MI.getDebugLoc(); 138 bool IsLA64 = STI.is64Bit(); 139 unsigned MIOpc = MI.getOpcode(); 140 141 int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); 142 Register FrameReg; 143 StackOffset Offset = 144 TFI->getFrameIndexReference(MF, FrameIndex, FrameReg) + 145 StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm()); 146 147 bool FrameRegIsKill = false; 148 149 if (!isInt<12>(Offset.getFixed())) { 150 unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W; 151 unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W; 152 153 // The offset won't fit in an immediate, so use a scratch register instead. 154 // Modify Offset and FrameReg appropriately. 155 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 156 TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed()); 157 if (MIOpc == Addi) { 158 BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg()) 159 .addReg(FrameReg) 160 .addReg(ScratchReg, RegState::Kill); 161 MI.eraseFromParent(); 162 return true; 163 } 164 BuildMI(MBB, II, DL, TII->get(Add), ScratchReg) 165 .addReg(FrameReg) 166 .addReg(ScratchReg, RegState::Kill); 167 Offset = StackOffset::getFixed(0); 168 FrameReg = ScratchReg; 169 FrameRegIsKill = true; 170 } 171 172 // Spill CFRs. 173 if (MIOpc == LoongArch::PseudoST_CFR) { 174 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 175 BuildMI(MBB, II, DL, TII->get(LoongArch::MOVCF2GR), ScratchReg) 176 .add(MI.getOperand(0)); 177 BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W)) 178 .addReg(ScratchReg, RegState::Kill) 179 .addReg(FrameReg) 180 .addImm(Offset.getFixed()); 181 MI.eraseFromParent(); 182 return true; 183 } 184 185 // Reload CFRs. 186 if (MIOpc == LoongArch::PseudoLD_CFR) { 187 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 188 BuildMI(MBB, II, DL, TII->get(IsLA64 ? LoongArch::LD_D : LoongArch::LD_W), 189 ScratchReg) 190 .addReg(FrameReg) 191 .addImm(Offset.getFixed()); 192 BuildMI(MBB, II, DL, TII->get(LoongArch::MOVGR2CF)) 193 .add(MI.getOperand(0)) 194 .addReg(ScratchReg, RegState::Kill); 195 MI.eraseFromParent(); 196 return true; 197 } 198 199 MI.getOperand(FIOperandNum) 200 .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); 201 MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed()); 202 return false; 203 } 204