1 //===- SIMachineFunctionInfo.h - SIMachineFunctionInfo interface -*- C++ -*-==//
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 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H
15 #define LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H
16 
17 #include "AMDGPUMachineFunction.h"
18 #include "SIRegisterInfo.h"
19 #include "llvm/CodeGen/PseudoSourceValue.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include <array>
23 #include <cassert>
24 #include <map>
25 #include <utility>
26 
27 namespace llvm {
28 
29 class AMDGPUImagePseudoSourceValue : public PseudoSourceValue {
30 public:
31   explicit AMDGPUImagePseudoSourceValue() :
32     PseudoSourceValue(PseudoSourceValue::TargetCustom) { }
33 
34   bool isConstant(const MachineFrameInfo *) const override {
35     // This should probably be true for most images, but we will start by being
36     // conservative.
37     return false;
38   }
39 
40   bool isAliased(const MachineFrameInfo *) const override {
41     // FIXME: If we ever change image intrinsics to accept fat pointers, then
42     // this could be true for some cases.
43     return false;
44   }
45 
46   bool mayAlias(const MachineFrameInfo*) const override {
47     // FIXME: If we ever change image intrinsics to accept fat pointers, then
48     // this could be true for some cases.
49     return false;
50   }
51 };
52 
53 class AMDGPUBufferPseudoSourceValue : public PseudoSourceValue {
54 public:
55   explicit AMDGPUBufferPseudoSourceValue() :
56     PseudoSourceValue(PseudoSourceValue::TargetCustom) { }
57 
58   bool isConstant(const MachineFrameInfo *) const override {
59     // This should probably be true for most images, but we will start by being
60     // conservative.
61     return false;
62   }
63 
64   bool isAliased(const MachineFrameInfo *) const override {
65     // FIXME: If we ever change image intrinsics to accept fat pointers, then
66     // this could be true for some cases.
67     return false;
68   }
69 
70   bool mayAlias(const MachineFrameInfo*) const override {
71     // FIXME: If we ever change image intrinsics to accept fat pointers, then
72     // this could be true for some cases.
73     return false;
74   }
75 };
76 
77 /// This class keeps track of the SPI_SP_INPUT_ADDR config register, which
78 /// tells the hardware which interpolation parameters to load.
79 class SIMachineFunctionInfo final : public AMDGPUMachineFunction {
80   // FIXME: This should be removed and getPreloadedValue moved here.
81   friend class SIRegisterInfo;
82 
83   unsigned TIDReg;
84 
85   // Registers that may be reserved for spilling purposes. These may be the same
86   // as the input registers.
87   unsigned ScratchRSrcReg;
88   unsigned ScratchWaveOffsetReg;
89 
90   // Input registers setup for the HSA ABI.
91   // User SGPRs in allocation order.
92   unsigned PrivateSegmentBufferUserSGPR;
93   unsigned DispatchPtrUserSGPR;
94   unsigned QueuePtrUserSGPR;
95   unsigned KernargSegmentPtrUserSGPR;
96   unsigned DispatchIDUserSGPR;
97   unsigned FlatScratchInitUserSGPR;
98   unsigned PrivateSegmentSizeUserSGPR;
99   unsigned GridWorkGroupCountXUserSGPR;
100   unsigned GridWorkGroupCountYUserSGPR;
101   unsigned GridWorkGroupCountZUserSGPR;
102 
103   // System SGPRs in allocation order.
104   unsigned WorkGroupIDXSystemSGPR;
105   unsigned WorkGroupIDYSystemSGPR;
106   unsigned WorkGroupIDZSystemSGPR;
107   unsigned WorkGroupInfoSystemSGPR;
108   unsigned PrivateSegmentWaveByteOffsetSystemSGPR;
109 
110   // Graphics info.
111   unsigned PSInputAddr;
112   bool ReturnsVoid;
113 
114   // A pair of default/requested minimum/maximum flat work group sizes.
115   // Minimum - first, maximum - second.
116   std::pair<unsigned, unsigned> FlatWorkGroupSizes;
117 
118   // A pair of default/requested minimum/maximum number of waves per execution
119   // unit. Minimum - first, maximum - second.
120   std::pair<unsigned, unsigned> WavesPerEU;
121 
122   // Stack object indices for work group IDs.
123   std::array<int, 3> DebuggerWorkGroupIDStackObjectIndices;
124   // Stack object indices for work item IDs.
125   std::array<int, 3> DebuggerWorkItemIDStackObjectIndices;
126 
127   AMDGPUBufferPseudoSourceValue BufferPSV;
128   AMDGPUImagePseudoSourceValue ImagePSV;
129 
130 public:
131   // FIXME: Make private
132   unsigned LDSWaveSpillSize;
133   unsigned PSInputEna;
134   std::map<unsigned, unsigned> LaneVGPRs;
135   unsigned ScratchOffsetReg;
136   unsigned NumUserSGPRs;
137   unsigned NumSystemSGPRs;
138 
139 private:
140   bool HasSpilledSGPRs;
141   bool HasSpilledVGPRs;
142   bool HasNonSpillStackObjects;
143 
144   unsigned NumSpilledSGPRs;
145   unsigned NumSpilledVGPRs;
146 
147   // Feature bits required for inputs passed in user SGPRs.
148   bool PrivateSegmentBuffer : 1;
149   bool DispatchPtr : 1;
150   bool QueuePtr : 1;
151   bool KernargSegmentPtr : 1;
152   bool DispatchID : 1;
153   bool FlatScratchInit : 1;
154   bool GridWorkgroupCountX : 1;
155   bool GridWorkgroupCountY : 1;
156   bool GridWorkgroupCountZ : 1;
157 
158   // Feature bits required for inputs passed in system SGPRs.
159   bool WorkGroupIDX : 1; // Always initialized.
160   bool WorkGroupIDY : 1;
161   bool WorkGroupIDZ : 1;
162   bool WorkGroupInfo : 1;
163   bool PrivateSegmentWaveByteOffset : 1;
164 
165   bool WorkItemIDX : 1; // Always initialized.
166   bool WorkItemIDY : 1;
167   bool WorkItemIDZ : 1;
168 
169   MCPhysReg getNextUserSGPR() const {
170     assert(NumSystemSGPRs == 0 && "System SGPRs must be added after user SGPRs");
171     return AMDGPU::SGPR0 + NumUserSGPRs;
172   }
173 
174   MCPhysReg getNextSystemSGPR() const {
175     return AMDGPU::SGPR0 + NumUserSGPRs + NumSystemSGPRs;
176   }
177 
178 public:
179   struct SpilledReg {
180     unsigned VGPR = AMDGPU::NoRegister;
181     int Lane = -1;
182 
183     SpilledReg() = default;
184     SpilledReg(unsigned R, int L) : VGPR (R), Lane (L) { }
185 
186     bool hasLane() { return Lane != -1;}
187     bool hasReg() { return VGPR != AMDGPU::NoRegister;}
188   };
189 
190   // SIMachineFunctionInfo definition
191 
192   SIMachineFunctionInfo(const MachineFunction &MF);
193 
194   SpilledReg getSpilledReg(MachineFunction *MF, unsigned FrameIndex,
195                            unsigned SubIdx);
196   bool hasCalculatedTID() const { return TIDReg != AMDGPU::NoRegister; };
197   unsigned getTIDReg() const { return TIDReg; };
198   void setTIDReg(unsigned Reg) { TIDReg = Reg; }
199 
200   // Add user SGPRs.
201   unsigned addPrivateSegmentBuffer(const SIRegisterInfo &TRI);
202   unsigned addDispatchPtr(const SIRegisterInfo &TRI);
203   unsigned addQueuePtr(const SIRegisterInfo &TRI);
204   unsigned addKernargSegmentPtr(const SIRegisterInfo &TRI);
205   unsigned addDispatchID(const SIRegisterInfo &TRI);
206   unsigned addFlatScratchInit(const SIRegisterInfo &TRI);
207 
208   // Add system SGPRs.
209   unsigned addWorkGroupIDX() {
210     WorkGroupIDXSystemSGPR = getNextSystemSGPR();
211     NumSystemSGPRs += 1;
212     return WorkGroupIDXSystemSGPR;
213   }
214 
215   unsigned addWorkGroupIDY() {
216     WorkGroupIDYSystemSGPR = getNextSystemSGPR();
217     NumSystemSGPRs += 1;
218     return WorkGroupIDYSystemSGPR;
219   }
220 
221   unsigned addWorkGroupIDZ() {
222     WorkGroupIDZSystemSGPR = getNextSystemSGPR();
223     NumSystemSGPRs += 1;
224     return WorkGroupIDZSystemSGPR;
225   }
226 
227   unsigned addWorkGroupInfo() {
228     WorkGroupInfoSystemSGPR = getNextSystemSGPR();
229     NumSystemSGPRs += 1;
230     return WorkGroupInfoSystemSGPR;
231   }
232 
233   unsigned addPrivateSegmentWaveByteOffset() {
234     PrivateSegmentWaveByteOffsetSystemSGPR = getNextSystemSGPR();
235     NumSystemSGPRs += 1;
236     return PrivateSegmentWaveByteOffsetSystemSGPR;
237   }
238 
239   void setPrivateSegmentWaveByteOffset(unsigned Reg) {
240     PrivateSegmentWaveByteOffsetSystemSGPR = Reg;
241   }
242 
243   bool hasPrivateSegmentBuffer() const {
244     return PrivateSegmentBuffer;
245   }
246 
247   bool hasDispatchPtr() const {
248     return DispatchPtr;
249   }
250 
251   bool hasQueuePtr() const {
252     return QueuePtr;
253   }
254 
255   bool hasKernargSegmentPtr() const {
256     return KernargSegmentPtr;
257   }
258 
259   bool hasDispatchID() const {
260     return DispatchID;
261   }
262 
263   bool hasFlatScratchInit() const {
264     return FlatScratchInit;
265   }
266 
267   bool hasGridWorkgroupCountX() const {
268     return GridWorkgroupCountX;
269   }
270 
271   bool hasGridWorkgroupCountY() const {
272     return GridWorkgroupCountY;
273   }
274 
275   bool hasGridWorkgroupCountZ() const {
276     return GridWorkgroupCountZ;
277   }
278 
279   bool hasWorkGroupIDX() const {
280     return WorkGroupIDX;
281   }
282 
283   bool hasWorkGroupIDY() const {
284     return WorkGroupIDY;
285   }
286 
287   bool hasWorkGroupIDZ() const {
288     return WorkGroupIDZ;
289   }
290 
291   bool hasWorkGroupInfo() const {
292     return WorkGroupInfo;
293   }
294 
295   bool hasPrivateSegmentWaveByteOffset() const {
296     return PrivateSegmentWaveByteOffset;
297   }
298 
299   bool hasWorkItemIDX() const {
300     return WorkItemIDX;
301   }
302 
303   bool hasWorkItemIDY() const {
304     return WorkItemIDY;
305   }
306 
307   bool hasWorkItemIDZ() const {
308     return WorkItemIDZ;
309   }
310 
311   unsigned getNumUserSGPRs() const {
312     return NumUserSGPRs;
313   }
314 
315   unsigned getNumPreloadedSGPRs() const {
316     return NumUserSGPRs + NumSystemSGPRs;
317   }
318 
319   unsigned getPrivateSegmentWaveByteOffsetSystemSGPR() const {
320     return PrivateSegmentWaveByteOffsetSystemSGPR;
321   }
322 
323   /// \brief Returns the physical register reserved for use as the resource
324   /// descriptor for scratch accesses.
325   unsigned getScratchRSrcReg() const {
326     return ScratchRSrcReg;
327   }
328 
329   void setScratchRSrcReg(unsigned Reg) {
330     assert(Reg != AMDGPU::NoRegister && "Should never be unset");
331     ScratchRSrcReg = Reg;
332   }
333 
334   unsigned getScratchWaveOffsetReg() const {
335     return ScratchWaveOffsetReg;
336   }
337 
338   void setScratchWaveOffsetReg(unsigned Reg) {
339     assert(Reg != AMDGPU::NoRegister && "Should never be unset");
340     ScratchWaveOffsetReg = Reg;
341   }
342 
343   unsigned getQueuePtrUserSGPR() const {
344     return QueuePtrUserSGPR;
345   }
346 
347   bool hasSpilledSGPRs() const {
348     return HasSpilledSGPRs;
349   }
350 
351   void setHasSpilledSGPRs(bool Spill = true) {
352     HasSpilledSGPRs = Spill;
353   }
354 
355   bool hasSpilledVGPRs() const {
356     return HasSpilledVGPRs;
357   }
358 
359   void setHasSpilledVGPRs(bool Spill = true) {
360     HasSpilledVGPRs = Spill;
361   }
362 
363   bool hasNonSpillStackObjects() const {
364     return HasNonSpillStackObjects;
365   }
366 
367   void setHasNonSpillStackObjects(bool StackObject = true) {
368     HasNonSpillStackObjects = StackObject;
369   }
370 
371   unsigned getNumSpilledSGPRs() const {
372     return NumSpilledSGPRs;
373   }
374 
375   unsigned getNumSpilledVGPRs() const {
376     return NumSpilledVGPRs;
377   }
378 
379   void addToSpilledSGPRs(unsigned num) {
380     NumSpilledSGPRs += num;
381   }
382 
383   void addToSpilledVGPRs(unsigned num) {
384     NumSpilledVGPRs += num;
385   }
386 
387   unsigned getPSInputAddr() const {
388     return PSInputAddr;
389   }
390 
391   bool isPSInputAllocated(unsigned Index) const {
392     return PSInputAddr & (1 << Index);
393   }
394 
395   void markPSInputAllocated(unsigned Index) {
396     PSInputAddr |= 1 << Index;
397   }
398 
399   bool returnsVoid() const {
400     return ReturnsVoid;
401   }
402 
403   void setIfReturnsVoid(bool Value) {
404     ReturnsVoid = Value;
405   }
406 
407   /// \returns A pair of default/requested minimum/maximum flat work group sizes
408   /// for this function.
409   std::pair<unsigned, unsigned> getFlatWorkGroupSizes() const {
410     return FlatWorkGroupSizes;
411   }
412 
413   /// \returns Default/requested minimum flat work group size for this function.
414   unsigned getMinFlatWorkGroupSize() const {
415     return FlatWorkGroupSizes.first;
416   }
417 
418   /// \returns Default/requested maximum flat work group size for this function.
419   unsigned getMaxFlatWorkGroupSize() const {
420     return FlatWorkGroupSizes.second;
421   }
422 
423   /// \returns A pair of default/requested minimum/maximum number of waves per
424   /// execution unit.
425   std::pair<unsigned, unsigned> getWavesPerEU() const {
426     return WavesPerEU;
427   }
428 
429   /// \returns Default/requested minimum number of waves per execution unit.
430   unsigned getMinWavesPerEU() const {
431     return WavesPerEU.first;
432   }
433 
434   /// \returns Default/requested maximum number of waves per execution unit.
435   unsigned getMaxWavesPerEU() const {
436     return WavesPerEU.second;
437   }
438 
439   /// \returns Stack object index for \p Dim's work group ID.
440   int getDebuggerWorkGroupIDStackObjectIndex(unsigned Dim) const {
441     assert(Dim < 3);
442     return DebuggerWorkGroupIDStackObjectIndices[Dim];
443   }
444 
445   /// \brief Sets stack object index for \p Dim's work group ID to \p ObjectIdx.
446   void setDebuggerWorkGroupIDStackObjectIndex(unsigned Dim, int ObjectIdx) {
447     assert(Dim < 3);
448     DebuggerWorkGroupIDStackObjectIndices[Dim] = ObjectIdx;
449   }
450 
451   /// \returns Stack object index for \p Dim's work item ID.
452   int getDebuggerWorkItemIDStackObjectIndex(unsigned Dim) const {
453     assert(Dim < 3);
454     return DebuggerWorkItemIDStackObjectIndices[Dim];
455   }
456 
457   /// \brief Sets stack object index for \p Dim's work item ID to \p ObjectIdx.
458   void setDebuggerWorkItemIDStackObjectIndex(unsigned Dim, int ObjectIdx) {
459     assert(Dim < 3);
460     DebuggerWorkItemIDStackObjectIndices[Dim] = ObjectIdx;
461   }
462 
463   /// \returns SGPR used for \p Dim's work group ID.
464   unsigned getWorkGroupIDSGPR(unsigned Dim) const {
465     switch (Dim) {
466     case 0:
467       assert(hasWorkGroupIDX());
468       return WorkGroupIDXSystemSGPR;
469     case 1:
470       assert(hasWorkGroupIDY());
471       return WorkGroupIDYSystemSGPR;
472     case 2:
473       assert(hasWorkGroupIDZ());
474       return WorkGroupIDZSystemSGPR;
475     }
476     llvm_unreachable("unexpected dimension");
477   }
478 
479   /// \returns VGPR used for \p Dim' work item ID.
480   unsigned getWorkItemIDVGPR(unsigned Dim) const {
481     switch (Dim) {
482     case 0:
483       assert(hasWorkItemIDX());
484       return AMDGPU::VGPR0;
485     case 1:
486       assert(hasWorkItemIDY());
487       return AMDGPU::VGPR1;
488     case 2:
489       assert(hasWorkItemIDZ());
490       return AMDGPU::VGPR2;
491     }
492     llvm_unreachable("unexpected dimension");
493   }
494 
495   const AMDGPUBufferPseudoSourceValue *getBufferPSV() const {
496     return &BufferPSV;
497   }
498 
499   const AMDGPUImagePseudoSourceValue *getImagePSV() const {
500     return &ImagePSV;
501   }
502 };
503 
504 } // end namespace llvm
505 
506 #endif // LLVM_LIB_TARGET_AMDGPU_SIMACHINEFUNCTIONINFO_H
507