| //===-- CSKYRegisterInfo.h - CSKY Register Information Impl ---*- C++ -*---===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains the CSKY implementation of the TargetRegisterInfo class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "CSKYRegisterInfo.h" | |
| #include "CSKY.h" | |
| #include "CSKYSubtarget.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/RegisterScavenging.h" | |
| #include "llvm/MC/MCContext.h" | |
| #define GET_REGINFO_TARGET_DESC | |
| #include "CSKYGenRegisterInfo.inc" | |
| using namespace llvm; | |
| CSKYRegisterInfo::CSKYRegisterInfo() | |
| : CSKYGenRegisterInfo(CSKY::R15, 0, 0, 0) {} | |
| const uint32_t * | |
| CSKYRegisterInfo::getCallPreservedMask(const MachineFunction &MF, | |
| CallingConv::ID Id) const { | |
| const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); | |
| if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) | |
| return CSR_GPR_FPR64_RegMask; | |
| if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) | |
| return CSR_GPR_FPR32_RegMask; | |
| return CSR_I32_RegMask; | |
| } | |
| Register CSKYRegisterInfo::getFrameRegister(const MachineFunction &MF) const { | |
| const TargetFrameLowering *TFI = getFrameLowering(MF); | |
| return TFI->hasFP(MF) ? CSKY::R8 : CSKY::R14; | |
| } | |
| BitVector CSKYRegisterInfo::getReservedRegs(const MachineFunction &MF) const { | |
| const CSKYFrameLowering *TFI = getFrameLowering(MF); | |
| const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); | |
| BitVector Reserved(getNumRegs()); | |
| // Reserve the base register if we need to allocate | |
| // variable-sized objects at runtime. | |
| if (TFI->hasBP(MF)) | |
| markSuperRegs(Reserved, CSKY::R7); // bp | |
| if (TFI->hasFP(MF)) | |
| markSuperRegs(Reserved, CSKY::R8); // fp | |
| if (!STI.hasE2()) { | |
| for (unsigned i = 0; i < 6; i++) | |
| markSuperRegs(Reserved, CSKY::R8 + i); // R8 - R13 | |
| } | |
| markSuperRegs(Reserved, CSKY::R14); // sp | |
| markSuperRegs(Reserved, CSKY::R15); // lr | |
| if (!STI.hasHighRegisters()) { | |
| for (unsigned i = 0; i < 10; i++) | |
| markSuperRegs(Reserved, CSKY::R16 + i); // R16 - R25 | |
| } | |
| markSuperRegs(Reserved, CSKY::R26); | |
| markSuperRegs(Reserved, CSKY::R27); | |
| markSuperRegs(Reserved, CSKY::R28); // gp | |
| markSuperRegs(Reserved, CSKY::R29); | |
| markSuperRegs(Reserved, CSKY::R30); | |
| markSuperRegs(Reserved, CSKY::R31); // tp | |
| assert(checkAllSuperRegsMarked(Reserved)); | |
| return Reserved; | |
| } | |
| const uint32_t *CSKYRegisterInfo::getNoPreservedMask() const { | |
| return CSR_NoRegs_RegMask; | |
| } | |
| const MCPhysReg * | |
| CSKYRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { | |
| const CSKYSubtarget &STI = MF->getSubtarget<CSKYSubtarget>(); | |
| if (MF->getFunction().hasFnAttribute("interrupt")) { | |
| if (STI.hasFPUv3DoubleFloat()) | |
| return CSR_GPR_FPR64v3_ISR_SaveList; | |
| if (STI.hasFPUv3SingleFloat()) | |
| return CSR_GPR_FPR32v3_ISR_SaveList; | |
| if (STI.hasFPUv2DoubleFloat()) | |
| return CSR_GPR_FPR64_ISR_SaveList; | |
| if (STI.hasFPUv2SingleFloat()) | |
| return CSR_GPR_FPR32_ISR_SaveList; | |
| return CSR_GPR_ISR_SaveList; | |
| } | |
| if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) | |
| return CSR_GPR_FPR64_SaveList; | |
| if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) | |
| return CSR_GPR_FPR32_SaveList; | |
| return CSR_I32_SaveList; | |
| } | |
| static bool IsLegalOffset(const CSKYInstrInfo *TII, MachineInstr *MI, | |
| int &Offset) { | |
| const MCInstrDesc &Desc = MI->getDesc(); | |
| unsigned AddrMode = (Desc.TSFlags & CSKYII::AddrModeMask); | |
| unsigned i = 0; | |
| for (; !MI->getOperand(i).isFI(); ++i) { | |
| assert(i + 1 < MI->getNumOperands() && | |
| "Instr doesn't have FrameIndex operand!"); | |
| } | |
| if (MI->getOpcode() == CSKY::ADDI32) { | |
| if (!isUInt<12>(std::abs(Offset) - 1)) | |
| return false; | |
| if (Offset < 0) { | |
| MI->setDesc(TII->get(CSKY::SUBI32)); | |
| Offset = -Offset; | |
| } | |
| return true; | |
| } | |
| if (MI->getOpcode() == CSKY::ADDI16XZ) | |
| return false; | |
| if (Offset < 0) | |
| return false; | |
| unsigned NumBits = 0; | |
| unsigned Scale = 1; | |
| switch (AddrMode) { | |
| case CSKYII::AddrMode32B: | |
| Scale = 1; | |
| NumBits = 12; | |
| break; | |
| case CSKYII::AddrMode32H: | |
| Scale = 2; | |
| NumBits = 12; | |
| break; | |
| case CSKYII::AddrMode32WD: | |
| Scale = 4; | |
| NumBits = 12; | |
| break; | |
| case CSKYII::AddrMode16B: | |
| Scale = 1; | |
| NumBits = 5; | |
| break; | |
| case CSKYII::AddrMode16H: | |
| Scale = 2; | |
| NumBits = 5; | |
| break; | |
| case CSKYII::AddrMode16W: | |
| Scale = 4; | |
| NumBits = 5; | |
| break; | |
| case CSKYII::AddrMode32SDF: | |
| Scale = 4; | |
| NumBits = 8; | |
| break; | |
| default: | |
| llvm_unreachable("Unsupported addressing mode!"); | |
| } | |
| // Cannot encode offset. | |
| if ((Offset & (Scale - 1)) != 0) | |
| return false; | |
| unsigned Mask = (1 << NumBits) - 1; | |
| if ((unsigned)Offset <= Mask * Scale) | |
| return true; | |
| // Offset out of range. | |
| return false; | |
| } | |
| bool CSKYRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, | |
| int SPAdj, unsigned FIOperandNum, | |
| RegScavenger *RS) const { | |
| assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); | |
| MachineInstr *MI = &*II; | |
| MachineBasicBlock &MBB = *MI->getParent(); | |
| MachineFunction &MF = *MI->getParent()->getParent(); | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const CSKYInstrInfo *TII = MF.getSubtarget<CSKYSubtarget>().getInstrInfo(); | |
| DebugLoc DL = MI->getDebugLoc(); | |
| const CSKYSubtarget &STI = MF.getSubtarget<CSKYSubtarget>(); | |
| switch (MI->getOpcode()) { | |
| default: | |
| break; | |
| case CSKY::RESTORE_CARRY: { | |
| Register NewReg = STI.hasE2() | |
| ? MRI.createVirtualRegister(&CSKY::GPRRegClass) | |
| : MRI.createVirtualRegister(&CSKY::mGPRRegClass); | |
| auto *Temp = BuildMI(MBB, II, DL, TII->get(CSKY::LD32W), NewReg) | |
| .add(MI->getOperand(1)) | |
| .add(MI->getOperand(2)) | |
| .getInstr(); | |
| BuildMI(MBB, II, DL, TII->get(STI.hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16), | |
| MI->getOperand(0).getReg()) | |
| .addReg(NewReg, getKillRegState(true)) | |
| .addImm(0); | |
| MI = Temp; | |
| MBB.erase(II); | |
| break; | |
| } | |
| case CSKY::SPILL_CARRY: { | |
| Register NewReg; | |
| if (STI.hasE2()) { | |
| NewReg = MRI.createVirtualRegister(&CSKY::GPRRegClass); | |
| BuildMI(MBB, II, DL, TII->get(CSKY::MVC32), NewReg) | |
| .add(MI->getOperand(0)); | |
| } else { | |
| NewReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass); | |
| BuildMI(MBB, II, DL, TII->get(CSKY::MOVI16), NewReg).addImm(0); | |
| BuildMI(MBB, II, DL, TII->get(CSKY::ADDC16)) | |
| .addReg(NewReg, RegState::Define) | |
| .addReg(MI->getOperand(0).getReg(), RegState::Define) | |
| .addReg(NewReg, getKillRegState(true)) | |
| .addReg(NewReg, getKillRegState(true)) | |
| .addReg(MI->getOperand(0).getReg()); | |
| BuildMI(MBB, II, DL, TII->get(CSKY::BTSTI16), MI->getOperand(0).getReg()) | |
| .addReg(NewReg) | |
| .addImm(0); | |
| } | |
| MI = BuildMI(MBB, II, DL, TII->get(CSKY::ST32W)) | |
| .addReg(NewReg, getKillRegState(true)) | |
| .add(MI->getOperand(1)) | |
| .add(MI->getOperand(2)) | |
| .getInstr(); | |
| MBB.erase(II); | |
| break; | |
| } | |
| } | |
| int FrameIndex = MI->getOperand(FIOperandNum).getIndex(); | |
| Register FrameReg; | |
| int Offset = getFrameLowering(MF) | |
| ->getFrameIndexReference(MF, FrameIndex, FrameReg) | |
| .getFixed() + | |
| MI->getOperand(FIOperandNum + 1).getImm(); | |
| if (!isInt<32>(Offset)) | |
| report_fatal_error( | |
| "Frame offsets outside of the signed 32-bit range not supported"); | |
| bool FrameRegIsKill = false; | |
| MachineBasicBlock::iterator NewII(MI); | |
| if (!IsLegalOffset(TII, MI, Offset)) { | |
| assert(isInt<32>(Offset) && "Int32 expected"); | |
| // The offset won't fit in an immediate, so use a scratch register instead | |
| // Modify Offset and FrameReg appropriately | |
| Register ScratchReg = TII->movImm(MBB, NewII, DL, Offset); | |
| BuildMI(MBB, NewII, DL, | |
| TII->get(STI.hasE2() ? CSKY::ADDU32 : CSKY::ADDU16XZ), ScratchReg) | |
| .addReg(ScratchReg, RegState::Kill) | |
| .addReg(FrameReg); | |
| Offset = 0; | |
| FrameReg = ScratchReg; | |
| FrameRegIsKill = true; | |
| } | |
| if (Offset == 0 && | |
| (MI->getOpcode() == CSKY::ADDI32 || MI->getOpcode() == CSKY::ADDI16XZ)) { | |
| MI->setDesc(TII->get(TargetOpcode::COPY)); | |
| MI->getOperand(FIOperandNum) | |
| .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); | |
| MI->removeOperand(FIOperandNum + 1); | |
| } else { | |
| MI->getOperand(FIOperandNum) | |
| .ChangeToRegister(FrameReg, false, false, FrameRegIsKill); | |
| MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); | |
| } | |
| return false; | |
| } |