//===-- AMDGPUIndirectAddressing.cpp - Indirect Adressing Support ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// /// Instructions can use indirect addressing to index the register file as if it /// were memory. This pass lowers RegisterLoad and RegisterStore instructions /// to either a COPY or a MOV that uses indirect addressing. // //===----------------------------------------------------------------------===// #include "AMDGPU.h" #include "R600InstrInfo.h" #include "R600MachineFunctionInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" using namespace llvm; namespace { class AMDGPUIndirectAddressingPass : public MachineFunctionPass { private: static char ID; const AMDGPUInstrInfo *TII; bool regHasExplicitDef(MachineRegisterInfo &MRI, unsigned Reg) const; public: AMDGPUIndirectAddressingPass(TargetMachine &tm) : MachineFunctionPass(ID), TII(static_cast(tm.getInstrInfo())) { } virtual bool runOnMachineFunction(MachineFunction &MF); const char *getPassName() const { return "R600 Handle indirect addressing"; } }; } // End anonymous namespace char AMDGPUIndirectAddressingPass::ID = 0; FunctionPass *llvm::createAMDGPUIndirectAddressingPass(TargetMachine &tm) { return new AMDGPUIndirectAddressingPass(tm); } bool AMDGPUIndirectAddressingPass::runOnMachineFunction(MachineFunction &MF) { MachineRegisterInfo &MRI = MF.getRegInfo(); int IndirectBegin = TII->getIndirectIndexBegin(MF); int IndirectEnd = TII->getIndirectIndexEnd(MF); if (IndirectBegin == -1) { // No indirect addressing, we can skip this pass assert(IndirectEnd == -1); return false; } // The map keeps track of the indirect address that is represented by // each virtual register. The key is the register and the value is the // indirect address it uses. std::map RegisterAddressMap; // First pass - Lower all of the RegisterStore instructions and track which // registers are live. for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); BB != BB_E; ++BB) { // This map keeps track of the current live indirect registers. // The key is the address and the value is the register std::map LiveAddressRegisterMap; MachineBasicBlock &MBB = *BB; for (MachineBasicBlock::iterator I = MBB.begin(), Next = llvm::next(I); I != MBB.end(); I = Next) { Next = llvm::next(I); MachineInstr &MI = *I; if (!TII->isRegisterStore(MI)) { continue; } // Lower RegisterStore unsigned RegIndex = MI.getOperand(2).getImm(); unsigned Channel = MI.getOperand(3).getImm(); unsigned Address = TII->calculateIndirectAddress(RegIndex, Channel); const TargetRegisterClass *IndirectStoreRegClass = TII->getIndirectAddrStoreRegClass(MI.getOperand(0).getReg()); if (MI.getOperand(1).getReg() == AMDGPU::INDIRECT_BASE_ADDR) { // Direct register access. unsigned DstReg = MRI.createVirtualRegister(IndirectStoreRegClass); BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(AMDGPU::COPY), DstReg) .addOperand(MI.getOperand(0)); RegisterAddressMap[DstReg] = Address; LiveAddressRegisterMap[Address] = DstReg; } else { // Indirect register access. MachineInstrBuilder MOV = TII->buildIndirectWrite(BB, I, MI.getOperand(0).getReg(), // Value Address, MI.getOperand(1).getReg()); // Offset for (int i = IndirectBegin; i <= IndirectEnd; ++i) { unsigned Addr = TII->calculateIndirectAddress(i, Channel); unsigned DstReg = MRI.createVirtualRegister(IndirectStoreRegClass); MOV.addReg(DstReg, RegState::Define | RegState::Implicit); RegisterAddressMap[DstReg] = Addr; LiveAddressRegisterMap[Addr] = DstReg; } } MI.eraseFromParent(); } // Update the live-ins of the succesor blocks for (MachineBasicBlock::succ_iterator Succ = MBB.succ_begin(), SuccEnd = MBB.succ_end(); SuccEnd != Succ; ++Succ) { std::map::const_iterator Key, KeyEnd; for (Key = LiveAddressRegisterMap.begin(), KeyEnd = LiveAddressRegisterMap.end(); KeyEnd != Key; ++Key) { (*Succ)->addLiveIn(Key->second); } } } // Second pass - Lower the RegisterLoad instructions for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); BB != BB_E; ++BB) { // Key is the address and the value is the register std::map LiveAddressRegisterMap; MachineBasicBlock &MBB = *BB; MachineBasicBlock::livein_iterator LI = MBB.livein_begin(); while (LI != MBB.livein_end()) { std::vector PhiRegisters; // Make sure this live in is used for indirect addressing if (RegisterAddressMap.find(*LI) == RegisterAddressMap.end()) { ++LI; continue; } unsigned Address = RegisterAddressMap[*LI]; LiveAddressRegisterMap[Address] = *LI; PhiRegisters.push_back(*LI); // Check if there are other live in registers which map to the same // indirect address. for (MachineBasicBlock::livein_iterator LJ = llvm::next(LI), LE = MBB.livein_end(); LJ != LE; ++LJ) { unsigned Reg = *LJ; if (RegisterAddressMap.find(Reg) == RegisterAddressMap.end()) { continue; } if (RegisterAddressMap[Reg] == Address) { PhiRegisters.push_back(Reg); } } if (PhiRegisters.size() == 1) { // We don't need to insert a Phi instruction, so we can just add the // registers to the live list for the block. LiveAddressRegisterMap[Address] = *LI; MBB.removeLiveIn(*LI); } else { // We need to insert a PHI, because we have the same address being // written in multiple predecessor blocks. const TargetRegisterClass *PhiDstClass = TII->getIndirectAddrStoreRegClass(*(PhiRegisters.begin())); unsigned PhiDstReg = MRI.createVirtualRegister(PhiDstClass); MachineInstrBuilder Phi = BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), TII->get(AMDGPU::PHI), PhiDstReg); for (std::vector::const_iterator RI = PhiRegisters.begin(), RE = PhiRegisters.end(); RI != RE; ++RI) { unsigned Reg = *RI; MachineInstr *DefInst = MRI.getVRegDef(Reg); assert(DefInst); MachineBasicBlock *RegBlock = DefInst->getParent(); Phi.addReg(Reg); Phi.addMBB(RegBlock); MBB.removeLiveIn(Reg); } RegisterAddressMap[PhiDstReg] = Address; LiveAddressRegisterMap[Address] = PhiDstReg; } LI = MBB.livein_begin(); } for (MachineBasicBlock::iterator I = MBB.begin(), Next = llvm::next(I); I != MBB.end(); I = Next) { Next = llvm::next(I); MachineInstr &MI = *I; if (!TII->isRegisterLoad(MI)) { if (MI.getOpcode() == AMDGPU::PHI) { continue; } // Check for indirect register defs for (unsigned OpIdx = 0, NumOperands = MI.getNumOperands(); OpIdx < NumOperands; ++OpIdx) { MachineOperand &MO = MI.getOperand(OpIdx); if (MO.isReg() && MO.isDef() && RegisterAddressMap.find(MO.getReg()) != RegisterAddressMap.end()) { unsigned Reg = MO.getReg(); unsigned LiveAddress = RegisterAddressMap[Reg]; // Chain the live-ins if (LiveAddressRegisterMap.find(LiveAddress) != RegisterAddressMap.end()) { MI.addOperand(MachineOperand::CreateReg( LiveAddressRegisterMap[LiveAddress], false, // isDef true, // isImp true)); // isKill } LiveAddressRegisterMap[LiveAddress] = Reg; } } continue; } const TargetRegisterClass *SuperIndirectRegClass = TII->getSuperIndirectRegClass(); const TargetRegisterClass *IndirectLoadRegClass = TII->getIndirectAddrLoadRegClass(); unsigned IndirectReg = MRI.createVirtualRegister(SuperIndirectRegClass); unsigned RegIndex = MI.getOperand(2).getImm(); unsigned Channel = MI.getOperand(3).getImm(); unsigned Address = TII->calculateIndirectAddress(RegIndex, Channel); if (MI.getOperand(1).getReg() == AMDGPU::INDIRECT_BASE_ADDR) { // Direct register access unsigned Reg = LiveAddressRegisterMap[Address]; unsigned AddrReg = IndirectLoadRegClass->getRegister(Address); if (regHasExplicitDef(MRI, Reg)) { // If the register we are reading from has an explicit def, then that // means it was written via a direct register access (i.e. COPY // or other instruction that doesn't use indirect addressing). In // this case we know where the value has been stored, so we can just // issue a copy. BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(AMDGPU::COPY), MI.getOperand(0).getReg()) .addReg(Reg); } else { // If the register we are reading has an implicit def, then that // means it was written by an indirect register access (i.e. An // instruction that uses indirect addressing. BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(AMDGPU::COPY), MI.getOperand(0).getReg()) .addReg(AddrReg) .addReg(Reg, RegState::Implicit); } } else { // Indirect register access // Note on REQ_SEQUENCE instructons: You can't actually use the register // it defines unless you have an instruction that takes the defined // register class as an operand. MachineInstrBuilder Sequence = BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(AMDGPU::REG_SEQUENCE), IndirectReg); for (int i = IndirectBegin; i <= IndirectEnd; ++i) { unsigned Addr = TII->calculateIndirectAddress(i, Channel); if (LiveAddressRegisterMap.find(Addr) == LiveAddressRegisterMap.end()) { continue; } unsigned Reg = LiveAddressRegisterMap[Addr]; // We only need to use REG_SEQUENCE for explicit defs, since the // register coalescer won't do anything with the implicit defs. if (!regHasExplicitDef(MRI, Reg)) { continue; } // Insert a REQ_SEQUENCE instruction to force the register allocator // to allocate the virtual register to the correct physical register. Sequence.addReg(LiveAddressRegisterMap[Addr]); Sequence.addImm(TII->getRegisterInfo().getIndirectSubReg(Addr)); } MachineInstrBuilder Mov = TII->buildIndirectRead(BB, I, MI.getOperand(0).getReg(), // Value Address, MI.getOperand(1).getReg()); // Offset Mov.addReg(IndirectReg, RegState::Implicit | RegState::Kill); Mov.addReg(LiveAddressRegisterMap[Address], RegState::Implicit); } MI.eraseFromParent(); } } return false; } bool AMDGPUIndirectAddressingPass::regHasExplicitDef(MachineRegisterInfo &MRI, unsigned Reg) const { MachineInstr *DefInstr = MRI.getVRegDef(Reg); if (!DefInstr) { return false; } if (DefInstr->getOpcode() == AMDGPU::PHI) { bool Explicit = false; for (MachineInstr::const_mop_iterator I = DefInstr->operands_begin(), E = DefInstr->operands_end(); I != E; ++I) { const MachineOperand &MO = *I; if (!MO.isReg() || MO.isDef()) { continue; } Explicit = Explicit || regHasExplicitDef(MRI, MO.getReg()); } return Explicit; } return DefInstr->getOperand(0).isReg() && DefInstr->getOperand(0).getReg() == Reg; }