Restrict sin/cos optimization to 64-bit only for now. 32-bit is a bit messy and less...
[oota-llvm.git] / lib / Target / R600 / SIAssignInterpRegs.cpp
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 /// \file
11 /// \brief This pass maps the pseudo interpolation registers to the correct physical
12 /// registers.
13 //
14 /// Prior to executing a fragment shader, the GPU loads interpolation
15 /// parameters into physical registers.  The specific physical register that each
16 /// interpolation parameter ends up in depends on the type of the interpolation
17 /// parameter as well as how many interpolation parameters are used by the
18 /// shader.
19 //
20 //===----------------------------------------------------------------------===//
21
22
23
24 #include "AMDGPU.h"
25 #include "AMDIL.h"
26 #include "SIMachineFunctionInfo.h"
27 #include "llvm/CodeGen/MachineFunctionPass.h"
28 #include "llvm/CodeGen/MachineInstrBuilder.h"
29 #include "llvm/CodeGen/MachineRegisterInfo.h"
30
31 using namespace llvm;
32
33 namespace {
34
35 class SIAssignInterpRegsPass : public MachineFunctionPass {
36
37 private:
38   static char ID;
39   TargetMachine &TM;
40
41   void addLiveIn(MachineFunction * MF,  MachineRegisterInfo & MRI,
42                  unsigned physReg, unsigned virtReg);
43
44 public:
45   SIAssignInterpRegsPass(TargetMachine &tm) :
46     MachineFunctionPass(ID), TM(tm) { }
47
48   virtual bool runOnMachineFunction(MachineFunction &MF);
49
50   const char *getPassName() const { return "SI Assign intrpolation registers"; }
51 };
52
53 } // End anonymous namespace
54
55 char SIAssignInterpRegsPass::ID = 0;
56
57 #define INTERP_VALUES 16
58 #define REQUIRED_VALUE_MAX_INDEX 7
59
60 struct InterpInfo {
61   bool Enabled;
62   unsigned Regs[3];
63   unsigned RegCount;
64 };
65
66
67 FunctionPass *llvm::createSIAssignInterpRegsPass(TargetMachine &tm) {
68   return new SIAssignInterpRegsPass(tm);
69 }
70
71 bool SIAssignInterpRegsPass::runOnMachineFunction(MachineFunction &MF) {
72
73   struct InterpInfo InterpUse[INTERP_VALUES] = {
74     {false, {AMDGPU::PERSP_SAMPLE_I, AMDGPU::PERSP_SAMPLE_J}, 2},
75     {false, {AMDGPU::PERSP_CENTER_I, AMDGPU::PERSP_CENTER_J}, 2},
76     {false, {AMDGPU::PERSP_CENTROID_I, AMDGPU::PERSP_CENTROID_J}, 2},
77     {false, {AMDGPU::PERSP_I_W, AMDGPU::PERSP_J_W, AMDGPU::PERSP_1_W}, 3},
78     {false, {AMDGPU::LINEAR_SAMPLE_I, AMDGPU::LINEAR_SAMPLE_J}, 2},
79     {false, {AMDGPU::LINEAR_CENTER_I, AMDGPU::LINEAR_CENTER_J}, 2},
80     {false, {AMDGPU::LINEAR_CENTROID_I, AMDGPU::LINEAR_CENTROID_J}, 2},
81     {false, {AMDGPU::LINE_STIPPLE_TEX_COORD}, 1},
82     {false, {AMDGPU::POS_X_FLOAT}, 1},
83     {false, {AMDGPU::POS_Y_FLOAT}, 1},
84     {false, {AMDGPU::POS_Z_FLOAT}, 1},
85     {false, {AMDGPU::POS_W_FLOAT}, 1},
86     {false, {AMDGPU::FRONT_FACE}, 1},
87     {false, {AMDGPU::ANCILLARY}, 1},
88     {false, {AMDGPU::SAMPLE_COVERAGE}, 1},
89     {false, {AMDGPU::POS_FIXED_PT}, 1}
90   };
91
92   SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
93   // This pass is only needed for pixel shaders.
94   if (MFI->ShaderType != ShaderType::PIXEL) {
95     return false;
96   }
97   MachineRegisterInfo &MRI = MF.getRegInfo();
98   bool ForceEnable = true;
99
100   // First pass, mark the interpolation values that are used.
101   for (unsigned InterpIdx = 0; InterpIdx < INTERP_VALUES; InterpIdx++) {
102     for (unsigned RegIdx = 0; RegIdx < InterpUse[InterpIdx].RegCount;
103                                                                RegIdx++) {
104       InterpUse[InterpIdx].Enabled = InterpUse[InterpIdx].Enabled ||
105                             !MRI.use_empty(InterpUse[InterpIdx].Regs[RegIdx]);
106       if (InterpUse[InterpIdx].Enabled &&
107           InterpIdx <= REQUIRED_VALUE_MAX_INDEX) {
108         ForceEnable = false;
109       }
110     }
111   }
112
113   // At least one interpolation mode must be enabled or else the GPU will hang.
114   if (ForceEnable) {
115     InterpUse[0].Enabled = true;
116   }
117
118   unsigned UsedVgprs = 0;
119
120   // Second pass, replace with VGPRs.
121   for (unsigned InterpIdx = 0; InterpIdx < INTERP_VALUES; InterpIdx++) {
122     if (!InterpUse[InterpIdx].Enabled) {
123       continue;
124     }
125     MFI->SPIPSInputAddr |= (1 << InterpIdx);
126
127     for (unsigned RegIdx = 0; RegIdx < InterpUse[InterpIdx].RegCount;
128                                                   RegIdx++, UsedVgprs++) {
129       unsigned NewReg = AMDGPU::VReg_32RegClass.getRegister(UsedVgprs);
130       unsigned VirtReg = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass);
131       MRI.replaceRegWith(InterpUse[InterpIdx].Regs[RegIdx], VirtReg);
132       addLiveIn(&MF, MRI, NewReg, VirtReg);
133     }
134   }
135
136   return false;
137 }
138
139 void SIAssignInterpRegsPass::addLiveIn(MachineFunction * MF,
140                            MachineRegisterInfo & MRI,
141                            unsigned physReg, unsigned virtReg) {
142     const TargetInstrInfo * TII = TM.getInstrInfo();
143     if (!MRI.isLiveIn(physReg)) {
144       MRI.addLiveIn(physReg, virtReg);
145       MF->front().addLiveIn(physReg);
146       BuildMI(MF->front(), MF->front().begin(), DebugLoc(),
147               TII->get(TargetOpcode::COPY), virtReg)
148                 .addReg(physReg);
149     } else {
150       MRI.replaceRegWith(virtReg, MRI.getLiveInVirtReg(physReg));
151     }
152 }