//===-- VERegisterInfo.cpp - VE Register Information ----------------------===// // // 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 VE implementation of the TargetRegisterInfo class. // //===----------------------------------------------------------------------===// #include "VERegisterInfo.h" #include "VE.h" #include "VESubtarget.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; #define DEBUG_TYPE "ve-register-info" #define GET_REGINFO_TARGET_DESC #include "VEGenRegisterInfo.inc" // VE uses %s10 == %lp to keep return address VERegisterInfo::VERegisterInfo() : VEGenRegisterInfo(VE::SX10) {} const MCPhysReg * VERegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { switch (MF->getFunction().getCallingConv()) { case CallingConv::Fast: // Being explicit (same as standard CC). default: return CSR_SaveList; case CallingConv::PreserveAll: return CSR_preserve_all_SaveList; } } const uint32_t *VERegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID CC) const { switch (CC) { case CallingConv::Fast: // Being explicit (same as standard CC). default: return CSR_RegMask; case CallingConv::PreserveAll: return CSR_preserve_all_RegMask; } } const uint32_t *VERegisterInfo::getNoPreservedMask() const { return CSR_NoRegs_RegMask; } BitVector VERegisterInfo::getReservedRegs(const MachineFunction &MF) const { BitVector Reserved(getNumRegs()); const Register ReservedRegs[] = { VE::SX8, // Stack limit VE::SX9, // Frame pointer VE::SX10, // Link register (return address) VE::SX11, // Stack pointer // FIXME: maybe not need to be reserved VE::SX12, // Outer register VE::SX13, // Id register for dynamic linker VE::SX14, // Thread pointer VE::SX15, // Global offset table register VE::SX16, // Procedure linkage table register VE::SX17, // Linkage-area register // sx18-sx33 are callee-saved registers // sx34-sx63 are temporary registers }; for (auto R : ReservedRegs) for (MCRegAliasIterator ItAlias(R, this, true); ItAlias.isValid(); ++ItAlias) Reserved.set(*ItAlias); // Reserve constant registers. Reserved.set(VE::VM0); Reserved.set(VE::VMP0); return Reserved; } const TargetRegisterClass * VERegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind) const { return &VE::I64RegClass; } static unsigned offsetToDisp(MachineInstr &MI) { // Default offset in instruction's operands (reg+reg+imm). unsigned OffDisp = 2; #define RRCAS_multi_cases(NAME) NAME##rir : case NAME##rii { using namespace llvm::VE; switch (MI.getOpcode()) { case INLINEASM: case RRCAS_multi_cases(TS1AML): case RRCAS_multi_cases(TS1AMW): case RRCAS_multi_cases(CASL): case RRCAS_multi_cases(CASW): // These instructions use AS format (reg+imm). OffDisp = 1; break; } } #undef RRCAS_multi_cases return OffDisp; } namespace { class EliminateFrameIndex { const TargetInstrInfo &TII; const TargetRegisterInfo &TRI; const DebugLoc &DL; MachineBasicBlock &MBB; MachineBasicBlock::iterator II; Register clobber; // Some helper functions for the ease of instruction building. MachineFunction &getFunc() const { return *MBB.getParent(); } inline MCRegister getSubReg(MCRegister Reg, unsigned Idx) const { return TRI.getSubReg(Reg, Idx); } inline const MCInstrDesc &get(unsigned Opcode) const { return TII.get(Opcode); } inline MachineInstrBuilder build(const MCInstrDesc &MCID, Register DestReg) { return BuildMI(MBB, II, DL, MCID, DestReg); } inline MachineInstrBuilder build(unsigned InstOpc, Register DestReg) { return build(get(InstOpc), DestReg); } inline MachineInstrBuilder build(const MCInstrDesc &MCID) { return BuildMI(MBB, II, DL, MCID); } inline MachineInstrBuilder build(unsigned InstOpc) { return build(get(InstOpc)); } // Calculate an address of frame index from a frame register and a given // offset if the offset doesn't fit in the immediate field. Use a clobber // register to hold calculated address. void prepareReplaceFI(MachineInstr &MI, Register &FrameReg, int64_t &Offset, int64_t Bytes = 0); // Replace the frame index in \p MI with a frame register and a given offset // if it fits in the immediate field. Otherwise, use pre-calculated address // in a clobber regsiter. void replaceFI(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); // Expand and eliminate Frame Index of pseudo STQrii and LDQrii. void processSTQ(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); void processLDQ(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); // Expand and eliminate Frame Index of pseudo STVMrii and LDVMrii. void processSTVM(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); void processLDVM(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); // Expand and eliminate Frame Index of pseudo STVM512rii and LDVM512rii. void processSTVM512(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); void processLDVM512(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); public: EliminateFrameIndex(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const DebugLoc &DL, MachineBasicBlock &MBB, MachineBasicBlock::iterator II) : TII(TII), TRI(TRI), DL(DL), MBB(MBB), II(II), clobber(VE::SX13) {} // Expand and eliminate Frame Index from MI void processMI(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum); }; } // namespace // Prepare the frame index if it doesn't fit in the immediate field. Use // clobber register to hold calculated address. void EliminateFrameIndex::prepareReplaceFI(MachineInstr &MI, Register &FrameReg, int64_t &Offset, int64_t Bytes) { if (isInt<32>(Offset) && isInt<32>(Offset + Bytes)) { // If the offset is small enough to fit in the immediate field, directly // encode it. So, nothing to prepare here. return; } // If the offset doesn't fit, emit following codes. This clobbers SX13 // which we always know is available here. // lea %clobber, Offset@lo // and %clobber, %clobber, (32)0 // lea.sl %clobber, Offset@hi(FrameReg, %clobber) build(VE::LEAzii, clobber).addImm(0).addImm(0).addImm(Lo_32(Offset)); build(VE::ANDrm, clobber).addReg(clobber).addImm(M0(32)); build(VE::LEASLrri, clobber) .addReg(clobber) .addReg(FrameReg) .addImm(Hi_32(Offset)); // Use clobber register as a frame register and 0 offset FrameReg = clobber; Offset = 0; } // Replace the frame index in \p MI with a proper byte and framereg offset. void EliminateFrameIndex::replaceFI(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(isInt<32>(Offset)); // The offset must be small enough to fit in the immediate field after // call of prepareReplaceFI. Therefore, we directly encode it. MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); MI.getOperand(FIOperandNum + offsetToDisp(MI)).ChangeToImmediate(Offset); } void EliminateFrameIndex::processSTQ(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::STQrii); LLVM_DEBUG(dbgs() << "processSTQ: "; MI.dump()); prepareReplaceFI(MI, FrameReg, Offset, 8); Register SrcReg = MI.getOperand(3).getReg(); Register SrcHiReg = getSubReg(SrcReg, VE::sub_even); Register SrcLoReg = getSubReg(SrcReg, VE::sub_odd); // VE stores HiReg to 8(addr) and LoReg to 0(addr) MachineInstr *StMI = build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg(SrcLoReg); replaceFI(*StMI, FrameReg, Offset, 0); // Mutate to 'hi' store. MI.setDesc(get(VE::STrii)); MI.getOperand(3).setReg(SrcHiReg); Offset += 8; replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processLDQ(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::LDQrii); LLVM_DEBUG(dbgs() << "processLDQ: "; MI.dump()); prepareReplaceFI(MI, FrameReg, Offset, 8); Register DestReg = MI.getOperand(0).getReg(); Register DestHiReg = getSubReg(DestReg, VE::sub_even); Register DestLoReg = getSubReg(DestReg, VE::sub_odd); // VE loads HiReg from 8(addr) and LoReg from 0(addr) MachineInstr *StMI = build(VE::LDrii, DestLoReg).addReg(FrameReg).addImm(0).addImm(0); replaceFI(*StMI, FrameReg, Offset, 1); MI.setDesc(get(VE::LDrii)); MI.getOperand(0).setReg(DestHiReg); Offset += 8; replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processSTVM(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::STVMrii); LLVM_DEBUG(dbgs() << "processSTVM: "; MI.dump()); // Original MI is: // STVMrii frame-index, 0, offset, reg (, memory operand) // Convert it to: // SVMi tmp-reg, reg, 0 // STrii frame-reg, 0, offset, tmp-reg // SVMi tmp-reg, reg, 1 // STrii frame-reg, 0, offset+8, tmp-reg // SVMi tmp-reg, reg, 2 // STrii frame-reg, 0, offset+16, tmp-reg // SVMi tmp-reg, reg, 3 // STrii frame-reg, 0, offset+24, tmp-reg prepareReplaceFI(MI, FrameReg, Offset, 24); Register SrcReg = MI.getOperand(3).getReg(); bool isKill = MI.getOperand(3).isKill(); // FIXME: it would be better to scavenge a register here instead of // reserving SX16 all of the time. Register TmpReg = VE::SX16; for (int i = 0; i < 3; ++i) { build(VE::SVMmr, TmpReg).addReg(SrcReg).addImm(i); MachineInstr *StMI = build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg( TmpReg, getKillRegState(true)); replaceFI(*StMI, FrameReg, Offset, 0); Offset += 8; } build(VE::SVMmr, TmpReg).addReg(SrcReg, getKillRegState(isKill)).addImm(3); MI.setDesc(get(VE::STrii)); MI.getOperand(3).ChangeToRegister(TmpReg, false, false, true); replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processLDVM(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::LDVMrii); LLVM_DEBUG(dbgs() << "processLDVM: "; MI.dump()); // Original MI is: // LDVMri reg, frame-index, 0, offset (, memory operand) // Convert it to: // LDrii tmp-reg, frame-reg, 0, offset // LVMir vm, 0, tmp-reg // LDrii tmp-reg, frame-reg, 0, offset+8 // LVMir_m vm, 1, tmp-reg, vm // LDrii tmp-reg, frame-reg, 0, offset+16 // LVMir_m vm, 2, tmp-reg, vm // LDrii tmp-reg, frame-reg, 0, offset+24 // LVMir_m vm, 3, tmp-reg, vm prepareReplaceFI(MI, FrameReg, Offset, 24); Register DestReg = MI.getOperand(0).getReg(); // FIXME: it would be better to scavenge a register here instead of // reserving SX16 all of the time. unsigned TmpReg = VE::SX16; for (int i = 0; i < 4; ++i) { if (i != 3) { MachineInstr *StMI = build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0); replaceFI(*StMI, FrameReg, Offset, 1); Offset += 8; } else { // Last LDrii replace the target instruction. MI.setDesc(get(VE::LDrii)); MI.getOperand(0).ChangeToRegister(TmpReg, true); } // First LVM is LVMir. Others are LVMir_m. Last LVM places at the // next of the target instruction. if (i == 0) build(VE::LVMir, DestReg).addImm(i).addReg(TmpReg, getKillRegState(true)); else if (i != 3) build(VE::LVMir_m, DestReg) .addImm(i) .addReg(TmpReg, getKillRegState(true)) .addReg(DestReg); else BuildMI(*MI.getParent(), std::next(II), DL, get(VE::LVMir_m), DestReg) .addImm(3) .addReg(TmpReg, getKillRegState(true)) .addReg(DestReg); } replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processSTVM512(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::STVM512rii); LLVM_DEBUG(dbgs() << "processSTVM512: "; MI.dump()); prepareReplaceFI(MI, FrameReg, Offset, 56); Register SrcReg = MI.getOperand(3).getReg(); Register SrcLoReg = getSubReg(SrcReg, VE::sub_vm_odd); Register SrcHiReg = getSubReg(SrcReg, VE::sub_vm_even); bool isKill = MI.getOperand(3).isKill(); // FIXME: it would be better to scavenge a register here instead of // reserving SX16 all of the time. Register TmpReg = VE::SX16; // store low part of VMP MachineInstr *LastMI = nullptr; for (int i = 0; i < 4; ++i) { LastMI = build(VE::SVMmr, TmpReg).addReg(SrcLoReg).addImm(i); MachineInstr *StMI = build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg( TmpReg, getKillRegState(true)); replaceFI(*StMI, FrameReg, Offset, 0); Offset += 8; } if (isKill) LastMI->addRegisterKilled(SrcLoReg, &TRI, true); // store high part of VMP for (int i = 0; i < 3; ++i) { build(VE::SVMmr, TmpReg).addReg(SrcHiReg).addImm(i); MachineInstr *StMI = build(VE::STrii).addReg(FrameReg).addImm(0).addImm(0).addReg( TmpReg, getKillRegState(true)); replaceFI(*StMI, FrameReg, Offset, 0); Offset += 8; } LastMI = build(VE::SVMmr, TmpReg).addReg(SrcHiReg).addImm(3); if (isKill) { LastMI->addRegisterKilled(SrcHiReg, &TRI, true); // Add implicit super-register kills to the particular MI. LastMI->addRegisterKilled(SrcReg, &TRI, true); } MI.setDesc(get(VE::STrii)); MI.getOperand(3).ChangeToRegister(TmpReg, false, false, true); replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processLDVM512(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { assert(MI.getOpcode() == VE::LDVM512rii); LLVM_DEBUG(dbgs() << "processLDVM512: "; MI.dump()); prepareReplaceFI(MI, FrameReg, Offset, 56); Register DestReg = MI.getOperand(0).getReg(); Register DestLoReg = getSubReg(DestReg, VE::sub_vm_odd); Register DestHiReg = getSubReg(DestReg, VE::sub_vm_even); // FIXME: it would be better to scavenge a register here instead of // reserving SX16 all of the time. Register TmpReg = VE::SX16; build(VE::IMPLICIT_DEF, DestReg); for (int i = 0; i < 4; ++i) { MachineInstr *LdMI = build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0); replaceFI(*LdMI, FrameReg, Offset, 1); build(VE::LVMir_m, DestLoReg) .addImm(i) .addReg(TmpReg, getKillRegState(true)) .addReg(DestLoReg); Offset += 8; } for (int i = 0; i < 3; ++i) { MachineInstr *LdMI = build(VE::LDrii, TmpReg).addReg(FrameReg).addImm(0).addImm(0); replaceFI(*LdMI, FrameReg, Offset, 1); build(VE::LVMir_m, DestHiReg) .addImm(i) .addReg(TmpReg, getKillRegState(true)) .addReg(DestHiReg); Offset += 8; } MI.setDesc(get(VE::LDrii)); MI.getOperand(0).ChangeToRegister(TmpReg, true); BuildMI(*MI.getParent(), std::next(II), DL, get(VE::LVMir_m), DestHiReg) .addImm(3) .addReg(TmpReg, getKillRegState(true)) .addReg(DestHiReg); replaceFI(MI, FrameReg, Offset, FIOperandNum); } void EliminateFrameIndex::processMI(MachineInstr &MI, Register FrameReg, int64_t Offset, int FIOperandNum) { switch (MI.getOpcode()) { case VE::STQrii: processSTQ(MI, FrameReg, Offset, FIOperandNum); return; case VE::LDQrii: processLDQ(MI, FrameReg, Offset, FIOperandNum); return; case VE::STVMrii: processSTVM(MI, FrameReg, Offset, FIOperandNum); return; case VE::LDVMrii: processLDVM(MI, FrameReg, Offset, FIOperandNum); return; case VE::STVM512rii: processSTVM512(MI, FrameReg, Offset, FIOperandNum); return; case VE::LDVM512rii: processLDVM512(MI, FrameReg, Offset, FIOperandNum); return; } prepareReplaceFI(MI, FrameReg, Offset); replaceFI(MI, FrameReg, Offset, FIOperandNum); } bool VERegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); MachineInstr &MI = *II; int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); MachineFunction &MF = *MI.getParent()->getParent(); const VESubtarget &Subtarget = MF.getSubtarget(); const VEFrameLowering &TFI = *getFrameLowering(MF); const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); const VERegisterInfo &TRI = *Subtarget.getRegisterInfo(); DebugLoc DL = MI.getDebugLoc(); EliminateFrameIndex EFI(TII, TRI, DL, *MI.getParent(), II); // Retrieve FrameReg and byte offset for stack slot. Register FrameReg; int64_t Offset = TFI.getFrameIndexReference(MF, FrameIndex, FrameReg).getFixed(); Offset += MI.getOperand(FIOperandNum + offsetToDisp(MI)).getImm(); EFI.processMI(MI, FrameReg, Offset, FIOperandNum); return false; } Register VERegisterInfo::getFrameRegister(const MachineFunction &MF) const { return VE::SX9; }