10b57cec5SDimitry Andric //===- ARCRegisterInfo.cpp - ARC Register Information -----------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains the ARC implementation of the MRegisterInfo class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "ARCRegisterInfo.h" 140b57cec5SDimitry Andric #include "ARC.h" 150b57cec5SDimitry Andric #include "ARCInstrInfo.h" 160b57cec5SDimitry Andric #include "ARCMachineFunctionInfo.h" 170b57cec5SDimitry Andric #include "ARCSubtarget.h" 180b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 25fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h" 260b57cec5SDimitry Andric #include "llvm/IR/Function.h" 270b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 280b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 290b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #define DEBUG_TYPE "arc-reg-info" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric #define GET_REGINFO_TARGET_DESC 360b57cec5SDimitry Andric #include "ARCGenRegisterInfo.inc" 370b57cec5SDimitry Andric 38349cc55cSDimitry Andric static void replaceFrameIndex(MachineBasicBlock::iterator II, 390b57cec5SDimitry Andric const ARCInstrInfo &TII, unsigned Reg, 400b57cec5SDimitry Andric unsigned FrameReg, int Offset, int StackSize, 410b57cec5SDimitry Andric int ObjSize, RegScavenger *RS, int SPAdj) { 420b57cec5SDimitry Andric assert(RS && "Need register scavenger."); 430b57cec5SDimitry Andric MachineInstr &MI = *II; 440b57cec5SDimitry Andric MachineBasicBlock &MBB = *MI.getParent(); 45349cc55cSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 460b57cec5SDimitry Andric unsigned BaseReg = FrameReg; 470b57cec5SDimitry Andric unsigned KillState = 0; 480b57cec5SDimitry Andric if (MI.getOpcode() == ARC::LD_rs9 && (Offset >= 256 || Offset < -256)) { 490b57cec5SDimitry Andric // Loads can always be reached with LD_rlimm. 50349cc55cSDimitry Andric BuildMI(MBB, II, DL, TII.get(ARC::LD_rlimm), Reg) 510b57cec5SDimitry Andric .addReg(BaseReg) 520b57cec5SDimitry Andric .addImm(Offset) 530b57cec5SDimitry Andric .addMemOperand(*MI.memoperands_begin()); 540b57cec5SDimitry Andric MBB.erase(II); 550b57cec5SDimitry Andric return; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric if (MI.getOpcode() != ARC::GETFI && (Offset >= 256 || Offset < -256)) { 590b57cec5SDimitry Andric // We need to use a scratch register to reach the far-away frame indexes. 600b57cec5SDimitry Andric BaseReg = RS->FindUnusedReg(&ARC::GPR32RegClass); 610b57cec5SDimitry Andric if (!BaseReg) { 620b57cec5SDimitry Andric // We can be sure that the scavenged-register slot is within the range 630b57cec5SDimitry Andric // of the load offset. 640b57cec5SDimitry Andric const TargetRegisterInfo *TRI = 650b57cec5SDimitry Andric MBB.getParent()->getSubtarget().getRegisterInfo(); 660b57cec5SDimitry Andric BaseReg = RS->scavengeRegister(&ARC::GPR32RegClass, II, SPAdj); 670b57cec5SDimitry Andric assert(BaseReg && "Register scavenging failed."); 680b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scavenged register " << printReg(BaseReg, TRI) 690b57cec5SDimitry Andric << " for FrameReg=" << printReg(FrameReg, TRI) 700b57cec5SDimitry Andric << "+Offset=" << Offset << "\n"); 710b57cec5SDimitry Andric (void)TRI; 720b57cec5SDimitry Andric RS->setRegUsed(BaseReg); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric unsigned AddOpc = isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm; 75349cc55cSDimitry Andric BuildMI(MBB, II, DL, TII.get(AddOpc)) 760b57cec5SDimitry Andric .addReg(BaseReg, RegState::Define) 770b57cec5SDimitry Andric .addReg(FrameReg) 780b57cec5SDimitry Andric .addImm(Offset); 790b57cec5SDimitry Andric Offset = 0; 800b57cec5SDimitry Andric KillState = RegState::Kill; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric switch (MI.getOpcode()) { 830b57cec5SDimitry Andric case ARC::LD_rs9: 840b57cec5SDimitry Andric assert((Offset % 4 == 0) && "LD needs 4 byte alignment."); 85*bdd1243dSDimitry Andric [[fallthrough]]; 860b57cec5SDimitry Andric case ARC::LDH_rs9: 870b57cec5SDimitry Andric case ARC::LDH_X_rs9: 880b57cec5SDimitry Andric assert((Offset % 2 == 0) && "LDH needs 2 byte alignment."); 89*bdd1243dSDimitry Andric [[fallthrough]]; 900b57cec5SDimitry Andric case ARC::LDB_rs9: 910b57cec5SDimitry Andric case ARC::LDB_X_rs9: 920b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Building LDFI\n"); 93349cc55cSDimitry Andric BuildMI(MBB, II, DL, TII.get(MI.getOpcode()), Reg) 940b57cec5SDimitry Andric .addReg(BaseReg, KillState) 950b57cec5SDimitry Andric .addImm(Offset) 960b57cec5SDimitry Andric .addMemOperand(*MI.memoperands_begin()); 970b57cec5SDimitry Andric break; 980b57cec5SDimitry Andric case ARC::ST_rs9: 990b57cec5SDimitry Andric assert((Offset % 4 == 0) && "ST needs 4 byte alignment."); 100*bdd1243dSDimitry Andric [[fallthrough]]; 1010b57cec5SDimitry Andric case ARC::STH_rs9: 1020b57cec5SDimitry Andric assert((Offset % 2 == 0) && "STH needs 2 byte alignment."); 103*bdd1243dSDimitry Andric [[fallthrough]]; 1040b57cec5SDimitry Andric case ARC::STB_rs9: 1050b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Building STFI\n"); 106349cc55cSDimitry Andric BuildMI(MBB, II, DL, TII.get(MI.getOpcode())) 1070b57cec5SDimitry Andric .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) 1080b57cec5SDimitry Andric .addReg(BaseReg, KillState) 1090b57cec5SDimitry Andric .addImm(Offset) 1100b57cec5SDimitry Andric .addMemOperand(*MI.memoperands_begin()); 1110b57cec5SDimitry Andric break; 1120b57cec5SDimitry Andric case ARC::GETFI: 1130b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Building GETFI\n"); 114349cc55cSDimitry Andric BuildMI(MBB, II, DL, 1150b57cec5SDimitry Andric TII.get(isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm)) 1160b57cec5SDimitry Andric .addReg(Reg, RegState::Define) 1170b57cec5SDimitry Andric .addReg(FrameReg) 1180b57cec5SDimitry Andric .addImm(Offset); 1190b57cec5SDimitry Andric break; 1200b57cec5SDimitry Andric default: 1210b57cec5SDimitry Andric llvm_unreachable("Unhandled opcode."); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Erase old instruction. 1250b57cec5SDimitry Andric MBB.erase(II); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 128349cc55cSDimitry Andric ARCRegisterInfo::ARCRegisterInfo(const ARCSubtarget &ST) 129349cc55cSDimitry Andric : ARCGenRegisterInfo(ARC::BLINK), ST(ST) {} 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric bool ARCRegisterInfo::needsFrameMoves(const MachineFunction &MF) { 132480093f4SDimitry Andric return MF.needsFrameMoves(); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric const MCPhysReg * 1360b57cec5SDimitry Andric ARCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { 1370b57cec5SDimitry Andric return CSR_ARC_SaveList; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric BitVector ARCRegisterInfo::getReservedRegs(const MachineFunction &MF) const { 1410b57cec5SDimitry Andric BitVector Reserved(getNumRegs()); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric Reserved.set(ARC::ILINK); 1440b57cec5SDimitry Andric Reserved.set(ARC::SP); 1450b57cec5SDimitry Andric Reserved.set(ARC::GP); 1460b57cec5SDimitry Andric Reserved.set(ARC::R25); 1470b57cec5SDimitry Andric Reserved.set(ARC::BLINK); 1480b57cec5SDimitry Andric Reserved.set(ARC::FP); 149349cc55cSDimitry Andric 1500b57cec5SDimitry Andric return Reserved; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric bool ARCRegisterInfo::requiresRegisterScavenging( 1540b57cec5SDimitry Andric const MachineFunction &MF) const { 1550b57cec5SDimitry Andric return true; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ARCRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const { 1590b57cec5SDimitry Andric return true; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 162*bdd1243dSDimitry Andric bool ARCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, 1630b57cec5SDimitry Andric int SPAdj, unsigned FIOperandNum, 1640b57cec5SDimitry Andric RegScavenger *RS) const { 1650b57cec5SDimitry Andric assert(SPAdj == 0 && "Unexpected"); 1660b57cec5SDimitry Andric MachineInstr &MI = *II; 1670b57cec5SDimitry Andric MachineOperand &FrameOp = MI.getOperand(FIOperandNum); 1680b57cec5SDimitry Andric int FrameIndex = FrameOp.getIndex(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 1710b57cec5SDimitry Andric const ARCInstrInfo &TII = *MF.getSubtarget<ARCSubtarget>().getInstrInfo(); 1720b57cec5SDimitry Andric const ARCFrameLowering *TFI = getFrameLowering(MF); 1730b57cec5SDimitry Andric int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex); 1740b57cec5SDimitry Andric int ObjSize = MF.getFrameInfo().getObjectSize(FrameIndex); 1750b57cec5SDimitry Andric int StackSize = MF.getFrameInfo().getStackSize(); 1760b57cec5SDimitry Andric int LocalFrameSize = MF.getFrameInfo().getLocalFrameSize(); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\nFunction : " << MF.getName() << "\n"); 1790b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "<--------->\n"); 1800b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MI << "\n"); 1810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "FrameIndex : " << FrameIndex << "\n"); 1820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ObjSize : " << ObjSize << "\n"); 1830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "FrameOffset : " << Offset << "\n"); 1840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "StackSize : " << StackSize << "\n"); 1850b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "LocalFrameSize : " << LocalFrameSize << "\n"); 1860b57cec5SDimitry Andric (void)LocalFrameSize; 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // Special handling of DBG_VALUE instructions. 1890b57cec5SDimitry Andric if (MI.isDebugValue()) { 1900b57cec5SDimitry Andric Register FrameReg = getFrameRegister(MF); 1910b57cec5SDimitry Andric MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/); 1920b57cec5SDimitry Andric MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); 193*bdd1243dSDimitry Andric return false; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // fold constant into offset. 1970b57cec5SDimitry Andric Offset += MI.getOperand(FIOperandNum + 1).getImm(); 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric // TODO: assert based on the load type: 2000b57cec5SDimitry Andric // ldb needs no alignment, 2010b57cec5SDimitry Andric // ldh needs 2 byte alignment 2020b57cec5SDimitry Andric // ld needs 4 byte alignment 2030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Offset : " << Offset << "\n" 2040b57cec5SDimitry Andric << "<--------->\n"); 2050b57cec5SDimitry Andric 2068bcb0991SDimitry Andric Register Reg = MI.getOperand(0).getReg(); 2070b57cec5SDimitry Andric assert(ARC::GPR32RegClass.contains(Reg) && "Unexpected register operand"); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric if (!TFI->hasFP(MF)) { 2100b57cec5SDimitry Andric Offset = StackSize + Offset; 2110b57cec5SDimitry Andric if (FrameIndex >= 0) 2120b57cec5SDimitry Andric assert((Offset >= 0 && Offset < StackSize) && "SP Offset not in bounds."); 2130b57cec5SDimitry Andric } else { 2140b57cec5SDimitry Andric if (FrameIndex >= 0) { 2150b57cec5SDimitry Andric assert((Offset < 0 && -Offset <= StackSize) && 2160b57cec5SDimitry Andric "FP Offset not in bounds."); 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric } 219349cc55cSDimitry Andric replaceFrameIndex(II, TII, Reg, getFrameRegister(MF), Offset, StackSize, 2200b57cec5SDimitry Andric ObjSize, RS, SPAdj); 221*bdd1243dSDimitry Andric return true; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric Register ARCRegisterInfo::getFrameRegister(const MachineFunction &MF) const { 2250b57cec5SDimitry Andric const ARCFrameLowering *TFI = getFrameLowering(MF); 2260b57cec5SDimitry Andric return TFI->hasFP(MF) ? ARC::FP : ARC::SP; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric const uint32_t * 2300b57cec5SDimitry Andric ARCRegisterInfo::getCallPreservedMask(const MachineFunction &MF, 2310b57cec5SDimitry Andric CallingConv::ID CC) const { 2320b57cec5SDimitry Andric return CSR_ARC_RegMask; 2330b57cec5SDimitry Andric } 234