1//===-- SIAssignInterpRegs.cpp - Assign interpolation registers -----------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass maps the pseudo interpolation registers to the correct physical
11// registers.  Prior to executing a fragment shader, the GPU loads interpolation
12// parameters into physical registers.  The specific physical register that each
13// interpolation parameter ends up in depends on the type of the interpolation
14// parameter as well as how many interpolation parameters are used by the
15// shader.
16//
17//===----------------------------------------------------------------------===//
18
19
20
21#include "AMDGPU.h"
22#include "AMDIL.h"
23#include "SIMachineFunctionInfo.h"
24#include "llvm/CodeGen/MachineFunctionPass.h"
25#include "llvm/CodeGen/MachineInstrBuilder.h"
26#include "llvm/CodeGen/MachineRegisterInfo.h"
27
28using namespace llvm;
29
30namespace {
31
32class SIAssignInterpRegsPass : public MachineFunctionPass {
33
34private:
35  static char ID;
36  TargetMachine &TM;
37
38  void AddLiveIn(MachineFunction * MF,  MachineRegisterInfo & MRI,
39                 unsigned physReg, unsigned virtReg);
40
41public:
42  SIAssignInterpRegsPass(TargetMachine &tm) :
43    MachineFunctionPass(ID), TM(tm) { }
44
45  virtual bool runOnMachineFunction(MachineFunction &MF);
46
47  const char *getPassName() const { return "SI Assign intrpolation registers"; }
48};
49
50} // End anonymous namespace
51
52char SIAssignInterpRegsPass::ID = 0;
53
54#define INTERP_VALUES 16
55
56struct interp_info {
57  bool enabled;
58  unsigned regs[3];
59  unsigned reg_count;
60};
61
62
63FunctionPass *llvm::createSIAssignInterpRegsPass(TargetMachine &tm) {
64  return new SIAssignInterpRegsPass(tm);
65}
66
67bool SIAssignInterpRegsPass::runOnMachineFunction(MachineFunction &MF)
68{
69
70  struct interp_info InterpUse[INTERP_VALUES] = {
71    {false, {AMDGPU::PERSP_SAMPLE_I, AMDGPU::PERSP_SAMPLE_J}, 2},
72    {false, {AMDGPU::PERSP_CENTER_I, AMDGPU::PERSP_CENTER_J}, 2},
73    {false, {AMDGPU::PERSP_CENTROID_I, AMDGPU::PERSP_CENTROID_J}, 2},
74    {false, {AMDGPU::PERSP_I_W, AMDGPU::PERSP_J_W, AMDGPU::PERSP_1_W}, 3},
75    {false, {AMDGPU::LINEAR_SAMPLE_I, AMDGPU::LINEAR_SAMPLE_J}, 2},
76    {false, {AMDGPU::LINEAR_CENTER_I, AMDGPU::LINEAR_CENTER_J}, 2},
77    {false, {AMDGPU::LINEAR_CENTROID_I, AMDGPU::LINEAR_CENTROID_J}, 2},
78    {false, {AMDGPU::LINE_STIPPLE_TEX_COORD}, 1},
79    {false, {AMDGPU::POS_X_FLOAT}, 1},
80    {false, {AMDGPU::POS_Y_FLOAT}, 1},
81    {false, {AMDGPU::POS_Z_FLOAT}, 1},
82    {false, {AMDGPU::POS_W_FLOAT}, 1},
83    {false, {AMDGPU::FRONT_FACE}, 1},
84    {false, {AMDGPU::ANCILLARY}, 1},
85    {false, {AMDGPU::SAMPLE_COVERAGE}, 1},
86    {false, {AMDGPU::POS_FIXED_PT}, 1}
87  };
88
89  SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
90  MachineRegisterInfo &MRI = MF.getRegInfo();
91
92  /* First pass, mark the interpolation values that are used. */
93  for (unsigned interp_idx = 0; interp_idx < INTERP_VALUES; interp_idx++) {
94    for (unsigned reg_idx = 0; reg_idx < InterpUse[interp_idx].reg_count;
95                                                               reg_idx++) {
96      InterpUse[interp_idx].enabled =
97                            !MRI.use_empty(InterpUse[interp_idx].regs[reg_idx]);
98    }
99  }
100
101  unsigned used_vgprs = 0;
102
103  /* Second pass, replace with VGPRs. */
104  for (unsigned interp_idx = 0; interp_idx < INTERP_VALUES; interp_idx++) {
105    if (!InterpUse[interp_idx].enabled) {
106      continue;
107    }
108    MFI->spi_ps_input_addr |= (1 << interp_idx);
109
110    for (unsigned reg_idx = 0; reg_idx < InterpUse[interp_idx].reg_count;
111                                                  reg_idx++, used_vgprs++) {
112      unsigned new_reg = AMDGPU::VReg_32RegClass.getRegister(used_vgprs);
113      unsigned virt_reg = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass);
114      MRI.replaceRegWith(InterpUse[interp_idx].regs[reg_idx], virt_reg);
115      AddLiveIn(&MF, MRI, new_reg, virt_reg);
116    }
117  }
118
119  return false;
120}
121
122void SIAssignInterpRegsPass::AddLiveIn(MachineFunction * MF,
123                           MachineRegisterInfo & MRI,
124                           unsigned physReg, unsigned virtReg)
125{
126    const TargetInstrInfo * TII = TM.getInstrInfo();
127    if (!MRI.isLiveIn(physReg)) {
128      MRI.addLiveIn(physReg, virtReg);
129      MF->front().addLiveIn(physReg);
130      BuildMI(MF->front(), MF->front().begin(), DebugLoc(),
131              TII->get(TargetOpcode::COPY), virtReg)
132                .addReg(physReg);
133    } else {
134      MRI.replaceRegWith(virtReg, MRI.getLiveInVirtReg(physReg));
135    }
136}
137