mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-28 06:29:45 +00:00
Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Tom Stellard <thomas.stellard@amd.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176620 91177308-0d34-0410-b5e6-96231b3b80d8
344 lines
13 KiB
C++
344 lines
13 KiB
C++
//===-- 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<const AMDGPUInstrInfo*>(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<unsigned, unsigned> 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<unsigned, unsigned> 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<unsigned, unsigned>::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<unsigned, unsigned> LiveAddressRegisterMap;
|
|
MachineBasicBlock &MBB = *BB;
|
|
|
|
MachineBasicBlock::livein_iterator LI = MBB.livein_begin();
|
|
while (LI != MBB.livein_end()) {
|
|
std::vector<unsigned> 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<unsigned>::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;
|
|
}
|