1/*
2 * Copyright 2011 Christoph Bumiller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#ifndef __NV50_IR_TARGET_H__
24#define __NV50_IR_TARGET_H__
25
26#include "nv50_ir.h"
27
28namespace nv50_ir {
29
30struct RelocInfo;
31
32struct RelocEntry
33{
34   enum Type
35   {
36      TYPE_CODE,
37      TYPE_BUILTIN,
38      TYPE_DATA
39   };
40
41   uint32_t data;
42   uint32_t mask;
43   uint32_t offset;
44   int8_t bitPos;
45   Type type;
46
47   inline void apply(uint32_t *binary, const RelocInfo *info) const;
48};
49
50struct RelocInfo
51{
52   uint32_t codePos;
53   uint32_t libPos;
54   uint32_t dataPos;
55
56   uint32_t count;
57
58   RelocEntry entry[0];
59};
60
61struct FixupData {
62   FixupData(bool force, bool flat, uint8_t alphatest, bool msaa) :
63      force_persample_interp(force), flatshade(flat), alphatest(alphatest), msaa(msaa) {}
64   bool force_persample_interp;
65   bool flatshade;
66   uint8_t alphatest;
67   bool msaa;
68};
69
70struct FixupEntry;
71typedef void (*FixupApply)(const FixupEntry*, uint32_t*, const FixupData&);
72
73struct FixupEntry
74{
75   FixupEntry(FixupApply apply, int ipa, int reg, int loc) :
76      apply(apply), ipa(ipa), reg(reg), loc(loc) {}
77
78   FixupApply apply;
79   union {
80      struct {
81         uint32_t ipa:4; // SC mode used to identify colors
82         uint32_t reg:8; // The reg used for perspective division
83         uint32_t loc:20; // Let's hope we don't have more than 1M-sized shaders
84      };
85      uint32_t val;
86   };
87};
88
89struct FixupInfo
90{
91   uint32_t count;
92   FixupEntry entry[0];
93};
94
95class CodeEmitter
96{
97public:
98   CodeEmitter(const Target *);
99   virtual ~CodeEmitter() { }
100
101   // returns whether the instruction was encodable and written
102   virtual bool emitInstruction(Instruction *) = 0;
103
104   virtual uint32_t getMinEncodingSize(const Instruction *) const = 0;
105
106   void setCodeLocation(void *, uint32_t size);
107   inline void *getCodeLocation() const { return code; }
108   inline uint32_t getCodeSize() const { return codeSize; }
109
110   bool addReloc(RelocEntry::Type, int w, uint32_t data, uint32_t m,
111                 int s);
112
113   inline void *getRelocInfo() const { return relocInfo; }
114
115   bool addInterp(int ipa, int reg, FixupApply apply);
116   inline void *getFixupInfo() const { return fixupInfo; }
117
118   virtual void prepareEmission(Program *);
119   virtual void prepareEmission(Function *);
120   virtual void prepareEmission(BasicBlock *);
121
122   void printBinary() const;
123
124protected:
125   const Target *targ;
126
127   uint32_t *code;
128   uint32_t codeSize;
129   uint32_t codeSizeLimit;
130
131   RelocInfo *relocInfo;
132   FixupInfo *fixupInfo;
133};
134
135
136enum OpClass
137{
138   OPCLASS_MOVE          = 0,
139   OPCLASS_LOAD          = 1,
140   OPCLASS_STORE         = 2,
141   OPCLASS_ARITH         = 3,
142   OPCLASS_SHIFT         = 4,
143   OPCLASS_SFU           = 5,
144   OPCLASS_LOGIC         = 6,
145   OPCLASS_COMPARE       = 7,
146   OPCLASS_CONVERT       = 8,
147   OPCLASS_ATOMIC        = 9,
148   OPCLASS_TEXTURE       = 10,
149   OPCLASS_SURFACE       = 11,
150   OPCLASS_FLOW          = 12,
151   OPCLASS_PSEUDO        = 14,
152   OPCLASS_VECTOR        = 15,
153   OPCLASS_BITFIELD      = 16,
154   OPCLASS_CONTROL       = 17,
155   OPCLASS_OTHER         = 18
156};
157
158class Target
159{
160public:
161   Target(bool m, bool j, bool s) : hasJoin(m), joinAnterior(j), hasSWSched(s) { }
162   virtual ~Target() { }
163
164   static Target *create(uint32_t chipset);
165   static void destroy(Target *);
166
167   // 0x50 and 0x84 to 0xaf for nv50
168   // 0xc0 to 0xdf for nvc0
169   inline uint32_t getChipset() const { return chipset; }
170
171   virtual CodeEmitter *getCodeEmitter(Program::Type) = 0;
172
173   // Drivers should upload this so we can use it from all programs.
174   // The address chosen is supplied to the relocation routine.
175   virtual void getBuiltinCode(const uint32_t **code, uint32_t *size) const = 0;
176
177   virtual void parseDriverInfo(const struct nv50_ir_prog_info *info,
178                                const struct nv50_ir_prog_info_out *info_out) {
179      if (info_out->type == PIPE_SHADER_COMPUTE) {
180         threads = info->prop.cp.numThreads[0] *
181            info->prop.cp.numThreads[1] *
182            info->prop.cp.numThreads[2];
183         if (threads == 0)
184            threads = info->target >= NVISA_GK104_CHIPSET ? 1024 : 512;
185      } else {
186         threads = 32; // doesn't matter, just not too big.
187      }
188   }
189
190   virtual bool runLegalizePass(Program *, CGStage stage) const = 0;
191
192public:
193   struct OpInfo
194   {
195      OpInfo *variants;
196      operation op;
197      uint16_t srcTypes;
198      uint16_t dstTypes;
199      uint32_t immdBits;
200      uint8_t srcNr;
201      uint8_t srcMods[3];
202      uint8_t dstMods;
203      uint16_t srcFiles[3];
204      uint16_t dstFiles;
205      unsigned int minEncSize  : 5;
206      unsigned int vector      : 1;
207      unsigned int predicate   : 1;
208      unsigned int commutative : 1;
209      unsigned int pseudo      : 1;
210      unsigned int flow        : 1;
211      unsigned int hasDest     : 1;
212      unsigned int terminator  : 1;
213   };
214
215   inline const OpInfo& getOpInfo(const Instruction *) const;
216   inline const OpInfo& getOpInfo(const operation) const;
217
218   inline DataFile nativeFile(DataFile f) const;
219
220   virtual bool insnCanLoad(const Instruction *insn, int s,
221                            const Instruction *ld) const = 0;
222   virtual bool insnCanLoadOffset(const Instruction *insn, int s,
223                                  int offset) const = 0;
224   virtual bool isOpSupported(operation, DataType) const = 0;
225   virtual bool isAccessSupported(DataFile, DataType) const = 0;
226   virtual bool isModSupported(const Instruction *,
227                               int s, Modifier) const = 0;
228   virtual bool isSatSupported(const Instruction *) const = 0;
229   virtual bool isPostMultiplySupported(operation op, float f,
230                                        int& e) const { return false; }
231   virtual bool mayPredicate(const Instruction *,
232                             const Value *) const = 0;
233
234   // whether @insn can be issued together with @next (order matters)
235   virtual bool canDualIssue(const Instruction *insn,
236                             const Instruction *next) const { return false; }
237   virtual int getLatency(const Instruction *) const { return 1; }
238   virtual int getThroughput(const Instruction *) const { return 1; }
239
240   virtual unsigned int getFileSize(DataFile) const = 0;
241   virtual unsigned int getFileUnit(DataFile) const = 0;
242
243   virtual uint32_t getSVAddress(DataFile, const Symbol *) const = 0;
244
245public:
246   const bool hasJoin;      // true if instructions have a join modifier
247   const bool joinAnterior; // true if join is executed before the op
248   const bool hasSWSched;   // true if code should provide scheduling data
249
250   static const uint8_t operationSrcNr[];
251   static const OpClass operationClass[];
252
253   static inline uint8_t getOpSrcNr(operation op)
254   {
255      return operationSrcNr[op];
256   }
257   static inline OpClass getOpClass(operation op)
258   {
259      return operationClass[op];
260   }
261
262protected:
263   uint32_t chipset;
264   uint32_t threads;
265
266   DataFile nativeFileMap[DATA_FILE_COUNT];
267
268   OpInfo opInfo[OP_LAST + 1];
269};
270
271const Target::OpInfo& Target::getOpInfo(const Instruction *insn) const
272{
273   return opInfo[MIN2(insn->op, OP_LAST)];
274}
275
276const Target::OpInfo& Target::getOpInfo(const operation op) const
277{
278   return opInfo[op];
279}
280
281inline DataFile Target::nativeFile(DataFile f) const
282{
283   return nativeFileMap[f];
284}
285
286} // namespace nv50_ir
287
288#endif // __NV50_IR_TARGET_H__
289