summaryrefslogtreecommitdiff
path: root/lib/Target/AMDGPU/R600AllocateMemoryRegs.cpp
blob: a5b3c688e9afb0605e76a29657df30efccdec2be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//===-- R600AllocateMemoryRegs.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.
//
//===----------------------------------------------------------------------===//
//
// Instruction can use indirect addressing to index the register file as if it
// were memory.  In order to make this work correctly we need add all registers
// that might be used for indirect addressing to the LiveIn lists of basic
// blocks and also add them as implicit uses for instructions that do
// indirect reads.
//
//===----------------------------------------------------------------------===//

#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"

using namespace llvm;

namespace {

class R600AllocateMemoryRegsPass : public MachineFunctionPass {

private:
  static char ID;
  const R600InstrInfo *TII;

public:
  R600AllocateMemoryRegsPass(TargetMachine &tm) :
    MachineFunctionPass(ID),
    TII(static_cast<const R600InstrInfo*>(tm.getInstrInfo()))
    { }

  virtual bool runOnMachineFunction(MachineFunction &MF);

  const char *getPassName() const { return "R600 Handle indirect addressing"; }

};

} // End anonymous namespace

char R600AllocateMemoryRegsPass::ID = 0;

FunctionPass *llvm::createR600AllocateMemoryRegsPass(TargetMachine &tm) {
  return new R600AllocateMemoryRegsPass(tm);
}

bool R600AllocateMemoryRegsPass::runOnMachineFunction(MachineFunction &MF) {

  std::vector<unsigned> IndirectRegs = TII->getIndirectReservedRegs(MF);
  MachineRegisterInfo &MRI = MF.getRegInfo();
  unsigned IndirectRegOffset = TII->getIndirectIndexBegin(MF);

  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
                                                      BB != BB_E; ++BB) {
    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;
      switch (MI.getOpcode()) {
      default: continue;
      case AMDGPU::RegisterStore_i32:
      case AMDGPU::RegisterStore_f32:
        {
          int64_t Offset = (MI.getOperand(2).getImm() * 4) +
                           MI.getOperand(3).getImm() +
                           (IndirectRegOffset * 4);
          unsigned DstReg = AMDGPU::R600_TReg32RegClass.getRegister(Offset);
          R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();

          MFI->IndirectChannels.set(MI.getOperand(3).getImm());

          if (MI.getOperand(1).getReg() == AMDGPU::ZERO) {
            MFI->ReservedRegs.push_back(DstReg);
            TII->buildDefaultInstruction(*BB, I, AMDGPU::MOV, DstReg,
                          MI.getOperand(0).getReg());
          } else {
            MachineInstr *MOVA = TII->buildDefaultInstruction(*BB, I,
                                                        AMDGPU::MOVA_INT_eg,
                                                        AMDGPU::AR_X,
                                                        MI.getOperand(1).getReg());
            TII->setImmOperand(MOVA, R600Operands::WRITE, 0);
            unsigned OffsetReg = AMDGPU::R600_AddrRegClass.getRegister(Offset);
            MachineInstrBuilder MIBuilder = TII->buildDefaultInstruction(*BB, I,
                                        AMDGPU::StackMOV, OffsetReg,
                                        MI.getOperand(0).getReg());
            MachineInstr *NewMI = MIBuilder.addReg(AMDGPU::AR_X, RegState::Implicit);
            TII->setImmOperand(NewMI, R600Operands::DST_REL, 1);
          }
          break;
        }

      case AMDGPU::RegisterLoad_i32:
      case AMDGPU::RegisterLoad_f32:
        {
          unsigned Channel = MI.getOperand(3).getImm();
          unsigned Offset = (MI.getOperand(2).getImm() * 4) + Channel +
                            (IndirectRegOffset * 4);
          unsigned OffsetReg;

          if (MI.getOperand(1).getReg() == AMDGPU::ZERO) {
            OffsetReg = AMDGPU::R600_TReg32RegClass.getRegister(Offset);
            TII->buildDefaultInstruction(MBB, I, AMDGPU::MOV,
                                         MI.getOperand(0).getReg(),
                                         OffsetReg);
          } else {
            R600MachineFunctionInfo * MFI = MF.getInfo<R600MachineFunctionInfo>();
            MachineInstr *MOVA = TII->buildDefaultInstruction(*BB, I,
                                                        AMDGPU::MOVA_INT_eg,
                                                        AMDGPU::AR_X,
                                                        MI.getOperand(1).getReg());
            TII->setImmOperand(MOVA, R600Operands::WRITE, 0);
            OffsetReg = AMDGPU::R600_AddrRegClass.getRegister(Offset);
            MachineInstrBuilder MIBuilder = TII->buildDefaultInstruction(*BB, I,
                                      AMDGPU::MOV, MI.getOperand(0).getReg(),
                                      OffsetReg);
            for (std::vector<unsigned>::iterator RRI = MFI->ReservedRegs.begin(),
                                                 RRE = MFI->ReservedRegs.end();
                                                 RRE != RRI; ++RRI) {
              unsigned Reg = *RRI;
              if (GET_REG_CHAN(Reg) == Channel) {
                MIBuilder.addReg(Reg, RegState::Implicit);
              }
            }
            MachineInstr *NewMI = MIBuilder.addReg(AMDGPU::AR_X, RegState::Implicit);
            TII->setImmOperand(NewMI, R600Operands::SRC0_REL, 1);
          }
          break;
        }
      }
      MI.eraseFromParent();
    }
  }

  return false;
}