1480093f4SDimitry Andric //===-- VERegisterInfo.cpp - VE Register Information ----------------------===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric // 9480093f4SDimitry Andric // This file contains the VE implementation of the TargetRegisterInfo class. 10480093f4SDimitry Andric // 11480093f4SDimitry Andric //===----------------------------------------------------------------------===// 12480093f4SDimitry Andric 13480093f4SDimitry Andric #include "VERegisterInfo.h" 14480093f4SDimitry Andric #include "VE.h" 15480093f4SDimitry Andric #include "VESubtarget.h" 16480093f4SDimitry Andric #include "llvm/ADT/BitVector.h" 17480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h" 18480093f4SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 19480093f4SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 20480093f4SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 21480093f4SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 22480093f4SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 23480093f4SDimitry Andric #include "llvm/IR/Type.h" 24480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 25e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h" 26480093f4SDimitry Andric #include "llvm/Support/ErrorHandling.h" 27480093f4SDimitry Andric 28480093f4SDimitry Andric using namespace llvm; 29480093f4SDimitry Andric 30*753f127fSDimitry Andric #define DEBUG_TYPE "ve-register-info" 31*753f127fSDimitry Andric 32480093f4SDimitry Andric #define GET_REGINFO_TARGET_DESC 33480093f4SDimitry Andric #include "VEGenRegisterInfo.inc" 34480093f4SDimitry Andric 35480093f4SDimitry Andric // VE uses %s10 == %lp to keep return address 36480093f4SDimitry Andric VERegisterInfo::VERegisterInfo() : VEGenRegisterInfo(VE::SX10) {} 37480093f4SDimitry Andric 38480093f4SDimitry Andric const MCPhysReg * 39480093f4SDimitry Andric VERegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { 405ffd83dbSDimitry Andric switch (MF->getFunction().getCallingConv()) { 41e8d8bef9SDimitry Andric case CallingConv::Fast: 42e8d8bef9SDimitry Andric // Being explicit (same as standard CC). 435ffd83dbSDimitry Andric default: 44480093f4SDimitry Andric return CSR_SaveList; 455ffd83dbSDimitry Andric case CallingConv::PreserveAll: 465ffd83dbSDimitry Andric return CSR_preserve_all_SaveList; 475ffd83dbSDimitry Andric } 48480093f4SDimitry Andric } 49480093f4SDimitry Andric 50480093f4SDimitry Andric const uint32_t *VERegisterInfo::getCallPreservedMask(const MachineFunction &MF, 51480093f4SDimitry Andric CallingConv::ID CC) const { 525ffd83dbSDimitry Andric switch (CC) { 53e8d8bef9SDimitry Andric case CallingConv::Fast: 54e8d8bef9SDimitry Andric // Being explicit (same as standard CC). 555ffd83dbSDimitry Andric default: 56480093f4SDimitry Andric return CSR_RegMask; 575ffd83dbSDimitry Andric case CallingConv::PreserveAll: 585ffd83dbSDimitry Andric return CSR_preserve_all_RegMask; 595ffd83dbSDimitry Andric } 60480093f4SDimitry Andric } 61480093f4SDimitry Andric 62480093f4SDimitry Andric const uint32_t *VERegisterInfo::getNoPreservedMask() const { 63480093f4SDimitry Andric return CSR_NoRegs_RegMask; 64480093f4SDimitry Andric } 65480093f4SDimitry Andric 66480093f4SDimitry Andric BitVector VERegisterInfo::getReservedRegs(const MachineFunction &MF) const { 67480093f4SDimitry Andric BitVector Reserved(getNumRegs()); 68480093f4SDimitry Andric 695ffd83dbSDimitry Andric const Register ReservedRegs[] = { 705ffd83dbSDimitry Andric VE::SX8, // Stack limit 715ffd83dbSDimitry Andric VE::SX9, // Frame pointer 725ffd83dbSDimitry Andric VE::SX10, // Link register (return address) 735ffd83dbSDimitry Andric VE::SX11, // Stack pointer 74480093f4SDimitry Andric 755ffd83dbSDimitry Andric // FIXME: maybe not need to be reserved 765ffd83dbSDimitry Andric VE::SX12, // Outer register 775ffd83dbSDimitry Andric VE::SX13, // Id register for dynamic linker 78480093f4SDimitry Andric 795ffd83dbSDimitry Andric VE::SX14, // Thread pointer 805ffd83dbSDimitry Andric VE::SX15, // Global offset table register 815ffd83dbSDimitry Andric VE::SX16, // Procedure linkage table register 825ffd83dbSDimitry Andric VE::SX17, // Linkage-area register 83480093f4SDimitry Andric // sx18-sx33 are callee-saved registers 84480093f4SDimitry Andric // sx34-sx63 are temporary registers 855ffd83dbSDimitry Andric }; 865ffd83dbSDimitry Andric 875ffd83dbSDimitry Andric for (auto R : ReservedRegs) 885ffd83dbSDimitry Andric for (MCRegAliasIterator ItAlias(R, this, true); ItAlias.isValid(); 895ffd83dbSDimitry Andric ++ItAlias) 905ffd83dbSDimitry Andric Reserved.set(*ItAlias); 91480093f4SDimitry Andric 92e8d8bef9SDimitry Andric // Reserve constant registers. 93e8d8bef9SDimitry Andric Reserved.set(VE::VM0); 94e8d8bef9SDimitry Andric Reserved.set(VE::VMP0); 95e8d8bef9SDimitry Andric 96480093f4SDimitry Andric return Reserved; 97480093f4SDimitry Andric } 98480093f4SDimitry Andric 99e8d8bef9SDimitry Andric bool VERegisterInfo::isConstantPhysReg(MCRegister PhysReg) const { 100e8d8bef9SDimitry Andric switch (PhysReg) { 101e8d8bef9SDimitry Andric case VE::VM0: 102e8d8bef9SDimitry Andric case VE::VMP0: 103e8d8bef9SDimitry Andric return true; 104e8d8bef9SDimitry Andric default: 105e8d8bef9SDimitry Andric return false; 106e8d8bef9SDimitry Andric } 107e8d8bef9SDimitry Andric } 108480093f4SDimitry Andric 109480093f4SDimitry Andric const TargetRegisterClass * 110480093f4SDimitry Andric VERegisterInfo::getPointerRegClass(const MachineFunction &MF, 111480093f4SDimitry Andric unsigned Kind) const { 112480093f4SDimitry Andric return &VE::I64RegClass; 113480093f4SDimitry Andric } 114480093f4SDimitry Andric 115e8d8bef9SDimitry Andric static unsigned offsetToDisp(MachineInstr &MI) { 116e8d8bef9SDimitry Andric // Default offset in instruction's operands (reg+reg+imm). 117e8d8bef9SDimitry Andric unsigned OffDisp = 2; 118e8d8bef9SDimitry Andric 119e8d8bef9SDimitry Andric #define RRCAS_multi_cases(NAME) NAME##rir : case NAME##rii 120e8d8bef9SDimitry Andric 121e8d8bef9SDimitry Andric { 122e8d8bef9SDimitry Andric using namespace llvm::VE; 123e8d8bef9SDimitry Andric switch (MI.getOpcode()) { 124e8d8bef9SDimitry Andric case RRCAS_multi_cases(TS1AML): 125e8d8bef9SDimitry Andric case RRCAS_multi_cases(TS1AMW): 126e8d8bef9SDimitry Andric case RRCAS_multi_cases(CASL): 127e8d8bef9SDimitry Andric case RRCAS_multi_cases(CASW): 128e8d8bef9SDimitry Andric // These instructions use AS format (reg+imm). 129e8d8bef9SDimitry Andric OffDisp = 1; 130e8d8bef9SDimitry Andric break; 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric } 133e8d8bef9SDimitry Andric #undef RRCAS_multi_cases 134e8d8bef9SDimitry Andric 135e8d8bef9SDimitry Andric return OffDisp; 136e8d8bef9SDimitry Andric } 137e8d8bef9SDimitry Andric 138*753f127fSDimitry Andric class EliminateFrameIndex { 139*753f127fSDimitry Andric const TargetInstrInfo &TII; 140*753f127fSDimitry Andric const TargetRegisterInfo &TRI; 141*753f127fSDimitry Andric const DebugLoc &DL; 142*753f127fSDimitry Andric MachineBasicBlock &MBB; 143*753f127fSDimitry Andric MachineBasicBlock::iterator II; 144*753f127fSDimitry Andric Register clobber; 145*753f127fSDimitry Andric 146*753f127fSDimitry Andric // Some helper functions for the ease of instruction building. 147*753f127fSDimitry Andric MachineFunction &getFunc() const { return *MBB.getParent(); } 148*753f127fSDimitry Andric inline MCRegister getSubReg(MCRegister Reg, unsigned Idx) const { 149*753f127fSDimitry Andric return TRI.getSubReg(Reg, Idx); 150*753f127fSDimitry Andric } 151*753f127fSDimitry Andric inline const MCInstrDesc &get(unsigned Opcode) const { 152*753f127fSDimitry Andric return TII.get(Opcode); 153*753f127fSDimitry Andric } 154*753f127fSDimitry Andric inline MachineInstrBuilder build(const MCInstrDesc &MCID, Register DestReg) { 155*753f127fSDimitry Andric return BuildMI(MBB, II, DL, MCID, DestReg); 156*753f127fSDimitry Andric } 157*753f127fSDimitry Andric inline MachineInstrBuilder build(unsigned InstOpc, Register DestReg) { 158*753f127fSDimitry Andric return build(get(InstOpc), DestReg); 159*753f127fSDimitry Andric } 160*753f127fSDimitry Andric inline MachineInstrBuilder build(const MCInstrDesc &MCID) { 161*753f127fSDimitry Andric return BuildMI(MBB, II, DL, MCID); 162*753f127fSDimitry Andric } 163*753f127fSDimitry Andric inline MachineInstrBuilder build(unsigned InstOpc) { 164*753f127fSDimitry Andric return build(get(InstOpc)); 165*753f127fSDimitry Andric } 166*753f127fSDimitry Andric 167*753f127fSDimitry Andric // Calculate an address of frame index from a frame register and a given 168*753f127fSDimitry Andric // offset if the offset doesn't fit in the immediate field. Use a clobber 169*753f127fSDimitry Andric // register to hold calculated address. 170*753f127fSDimitry Andric void prepareReplaceFI(MachineInstr &MI, Register &FrameReg, int64_t &Offset, 171*753f127fSDimitry Andric int64_t Bytes = 0); 172*753f127fSDimitry Andric // Replace the frame index in \p MI with a frame register and a given offset 173*753f127fSDimitry Andric // if it fits in the immediate field. Otherwise, use pre-calculated address 174*753f127fSDimitry Andric // in a clobber regsiter. 175*753f127fSDimitry Andric void replaceFI(MachineInstr &MI, Register FrameReg, int64_t Offset, 176*753f127fSDimitry Andric int FIOperandNum); 177*753f127fSDimitry Andric 178*753f127fSDimitry Andric // Expand and eliminate Frame Index of pseudo STQrii and LDQrii. 179*753f127fSDimitry Andric void processSTQ(MachineInstr &MI, Register FrameReg, int64_t Offset, 180*753f127fSDimitry Andric int FIOperandNum); 181*753f127fSDimitry Andric void processLDQ(MachineInstr &MI, Register FrameReg, int64_t Offset, 182*753f127fSDimitry Andric int FIOperandNum); 183*753f127fSDimitry Andric 184*753f127fSDimitry Andric public: 185*753f127fSDimitry Andric EliminateFrameIndex(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, 186*753f127fSDimitry Andric const DebugLoc &DL, MachineBasicBlock &MBB, 187*753f127fSDimitry Andric MachineBasicBlock::iterator II) 188*753f127fSDimitry Andric : TII(TII), TRI(TRI), DL(DL), MBB(MBB), II(II), clobber(VE::SX13) {} 189*753f127fSDimitry Andric 190*753f127fSDimitry Andric // Expand and eliminate Frame Index from MI 191*753f127fSDimitry Andric void processMI(MachineInstr &MI, Register FrameReg, int64_t Offset, 192*753f127fSDimitry Andric int FIOperandNum); 193*753f127fSDimitry Andric }; 194*753f127fSDimitry Andric 195*753f127fSDimitry Andric // Prepare the frame index if it doesn't fit in the immediate field. Use 196*753f127fSDimitry Andric // clobber register to hold calculated address. 197*753f127fSDimitry Andric void EliminateFrameIndex::prepareReplaceFI(MachineInstr &MI, Register &FrameReg, 198*753f127fSDimitry Andric int64_t &Offset, int64_t Bytes) { 199*753f127fSDimitry Andric if (isInt<32>(Offset) && isInt<32>(Offset + Bytes)) { 200*753f127fSDimitry Andric // If the offset is small enough to fit in the immediate field, directly 201*753f127fSDimitry Andric // encode it. So, nothing to prepare here. 202*753f127fSDimitry Andric return; 203*753f127fSDimitry Andric } 204*753f127fSDimitry Andric 205*753f127fSDimitry Andric // If the offset doesn't fit, emit following codes. This clobbers SX13 206*753f127fSDimitry Andric // which we always know is available here. 207*753f127fSDimitry Andric // lea %clobber, Offset@lo 208*753f127fSDimitry Andric // and %clobber, %clobber, (32)0 209*753f127fSDimitry Andric // lea.sl %clobber, Offset@hi(FrameReg, %clobber) 210*753f127fSDimitry Andric build(VE::LEAzii, clobber).addImm(0).addImm(0).addImm(Lo_32(Offset)); 211*753f127fSDimitry Andric build(VE::ANDrm, clobber).addReg(clobber).addImm(M0(32)); 212*753f127fSDimitry Andric build(VE::LEASLrri, clobber) 213*753f127fSDimitry Andric .addReg(clobber) 214*753f127fSDimitry Andric .addReg(FrameReg) 215*753f127fSDimitry Andric .addImm(Hi_32(Offset)); 216*753f127fSDimitry Andric 217*753f127fSDimitry Andric // Use clobber register as a frame register and 0 offset 218*753f127fSDimitry Andric FrameReg = clobber; 219*753f127fSDimitry Andric Offset = 0; 220*753f127fSDimitry Andric } 221*753f127fSDimitry Andric 222*753f127fSDimitry Andric // Replace the frame index in \p MI with a proper byte and framereg offset. 223*753f127fSDimitry Andric void EliminateFrameIndex::replaceFI(MachineInstr &MI, Register FrameReg, 224*753f127fSDimitry Andric int64_t Offset, int FIOperandNum) { 225*753f127fSDimitry Andric assert(isInt<32>(Offset)); 226*753f127fSDimitry Andric 227*753f127fSDimitry Andric // The offset must be small enough to fit in the immediate field after 228*753f127fSDimitry Andric // call of prepareReplaceFI. Therefore, we directly encode it. 2295ffd83dbSDimitry Andric MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); 230e8d8bef9SDimitry Andric MI.getOperand(FIOperandNum + offsetToDisp(MI)).ChangeToImmediate(Offset); 231480093f4SDimitry Andric } 232480093f4SDimitry Andric 233*753f127fSDimitry Andric void EliminateFrameIndex::processSTQ(MachineInstr &MI, Register FrameReg, 234*753f127fSDimitry Andric int64_t Offset, int FIOperandNum) { 235*753f127fSDimitry Andric assert(MI.getOpcode() == VE::STQrii); 236*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "processSTQ: "; MI.dump()); 237*753f127fSDimitry Andric 238*753f127fSDimitry Andric prepareReplaceFI(MI, FrameReg, Offset, 8); 239*753f127fSDimitry Andric 240*753f127fSDimitry Andric Register SrcReg = MI.getOperand(3).getReg(); 241*753f127fSDimitry Andric Register SrcHiReg = getSubReg(SrcReg, VE::sub_even); 242*753f127fSDimitry Andric Register SrcLoReg = getSubReg(SrcReg, VE::sub_odd); 243*753f127fSDimitry Andric // VE stores HiReg to 8(addr) and LoReg to 0(addr) 244*753f127fSDimitry Andric MachineInstr *StMI = 245*753f127fSDimitry Andric build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(SrcLoReg); 246*753f127fSDimitry Andric replaceFI(*StMI, FrameReg, Offset, 0); 247*753f127fSDimitry Andric // Mutate to 'hi' store. 248*753f127fSDimitry Andric MI.setDesc(get(VE::STrii)); 249*753f127fSDimitry Andric MI.getOperand(3).setReg(SrcHiReg); 250*753f127fSDimitry Andric Offset += 8; 251*753f127fSDimitry Andric replaceFI(MI, FrameReg, Offset, FIOperandNum); 252*753f127fSDimitry Andric } 253*753f127fSDimitry Andric 254*753f127fSDimitry Andric void EliminateFrameIndex::processLDQ(MachineInstr &MI, Register FrameReg, 255*753f127fSDimitry Andric int64_t Offset, int FIOperandNum) { 256*753f127fSDimitry Andric assert(MI.getOpcode() == VE::LDQrii); 257*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "processLDQ: "; MI.dump()); 258*753f127fSDimitry Andric 259*753f127fSDimitry Andric prepareReplaceFI(MI, FrameReg, Offset, 8); 260*753f127fSDimitry Andric 261*753f127fSDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 262*753f127fSDimitry Andric Register DestHiReg = getSubReg(DestReg, VE::sub_even); 263*753f127fSDimitry Andric Register DestLoReg = getSubReg(DestReg, VE::sub_odd); 264*753f127fSDimitry Andric // VE loads HiReg from 8(addr) and LoReg from 0(addr) 265*753f127fSDimitry Andric MachineInstr *StMI = 266*753f127fSDimitry Andric build(VE::LDrii, DestLoReg).addReg(FrameReg).addImm(0).addImm(0); 267*753f127fSDimitry Andric replaceFI(*StMI, FrameReg, Offset, 1); 268*753f127fSDimitry Andric MI.setDesc(get(VE::LDrii)); 269*753f127fSDimitry Andric MI.getOperand(0).setReg(DestHiReg); 270*753f127fSDimitry Andric Offset += 8; 271*753f127fSDimitry Andric replaceFI(MI, FrameReg, Offset, FIOperandNum); 272*753f127fSDimitry Andric } 273*753f127fSDimitry Andric 274*753f127fSDimitry Andric void EliminateFrameIndex::processMI(MachineInstr &MI, Register FrameReg, 275*753f127fSDimitry Andric int64_t Offset, int FIOperandNum) { 276*753f127fSDimitry Andric switch (MI.getOpcode()) { 277*753f127fSDimitry Andric case VE::STQrii: 278*753f127fSDimitry Andric processSTQ(MI, FrameReg, Offset, FIOperandNum); 279*753f127fSDimitry Andric return; 280*753f127fSDimitry Andric case VE::LDQrii: 281*753f127fSDimitry Andric processLDQ(MI, FrameReg, Offset, FIOperandNum); 282*753f127fSDimitry Andric return; 283*753f127fSDimitry Andric } 284*753f127fSDimitry Andric prepareReplaceFI(MI, FrameReg, Offset); 285*753f127fSDimitry Andric replaceFI(MI, FrameReg, Offset, FIOperandNum); 286*753f127fSDimitry Andric } 287*753f127fSDimitry Andric 288480093f4SDimitry Andric void VERegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, 289480093f4SDimitry Andric int SPAdj, unsigned FIOperandNum, 290480093f4SDimitry Andric RegScavenger *RS) const { 291480093f4SDimitry Andric assert(SPAdj == 0 && "Unexpected"); 292480093f4SDimitry Andric 293480093f4SDimitry Andric MachineInstr &MI = *II; 294480093f4SDimitry Andric int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); 295*753f127fSDimitry Andric 296480093f4SDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 297*753f127fSDimitry Andric const VESubtarget &Subtarget = MF.getSubtarget<VESubtarget>(); 298*753f127fSDimitry Andric const VEFrameLowering &TFI = *getFrameLowering(MF); 299*753f127fSDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); 300*753f127fSDimitry Andric const VERegisterInfo &TRI = *Subtarget.getRegisterInfo(); 301*753f127fSDimitry Andric DebugLoc DL = MI.getDebugLoc(); 302*753f127fSDimitry Andric EliminateFrameIndex EFI(TII, TRI, DL, *MI.getParent(), II); 303480093f4SDimitry Andric 304*753f127fSDimitry Andric // Retrieve FrameReg and byte offset for stack slot. 3055ffd83dbSDimitry Andric Register FrameReg; 306*753f127fSDimitry Andric int64_t Offset = 307*753f127fSDimitry Andric TFI.getFrameIndexReference(MF, FrameIndex, FrameReg).getFixed(); 308e8d8bef9SDimitry Andric Offset += MI.getOperand(FIOperandNum + offsetToDisp(MI)).getImm(); 309e8d8bef9SDimitry Andric 310*753f127fSDimitry Andric EFI.processMI(MI, FrameReg, Offset, FIOperandNum); 311480093f4SDimitry Andric } 312480093f4SDimitry Andric 313480093f4SDimitry Andric Register VERegisterInfo::getFrameRegister(const MachineFunction &MF) const { 314480093f4SDimitry Andric return VE::SX9; 315480093f4SDimitry Andric } 316