| //===-- 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; |
| } |