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_INLINES_H__
24#define __NV50_IR_INLINES_H__
25
26static inline CondCode reverseCondCode(CondCode cc)
27{
28   static const uint8_t ccRev[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
29
30   return static_cast<CondCode>(ccRev[cc & 7] | (cc & ~7));
31}
32
33static inline CondCode inverseCondCode(CondCode cc)
34{
35   return static_cast<CondCode>(cc ^ 7);
36}
37
38static inline bool isMemoryFile(DataFile f)
39{
40   return (f >= FILE_MEMORY_CONST && f <= FILE_MEMORY_LOCAL);
41}
42
43// contrary to asTex(), this will never include SULD/SUST
44static inline bool isTextureOp(operation op)
45{
46   return (op >= OP_TEX && op <= OP_TEXPREP);
47}
48
49static inline bool isSurfaceOp(operation op)
50{
51   return (op >= OP_SULDB && op <= OP_SULEA) || (op == OP_SUQ);
52}
53
54static inline unsigned int typeSizeof(DataType ty)
55{
56   switch (ty) {
57   case TYPE_U8:
58   case TYPE_S8:
59      return 1;
60   case TYPE_F16:
61   case TYPE_U16:
62   case TYPE_S16:
63      return 2;
64   case TYPE_F32:
65   case TYPE_U32:
66   case TYPE_S32:
67      return 4;
68   case TYPE_F64:
69   case TYPE_U64:
70   case TYPE_S64:
71      return 8;
72   case TYPE_B96:
73      return 12;
74   case TYPE_B128:
75      return 16;
76   default:
77      return 0;
78   }
79}
80
81static inline unsigned int typeSizeofLog2(DataType ty)
82{
83   switch (ty) {
84   case TYPE_F16:
85   case TYPE_U16:
86   case TYPE_S16:
87      return 1;
88   case TYPE_F32:
89   case TYPE_U32:
90   case TYPE_S32:
91      return 2;
92   case TYPE_F64:
93   case TYPE_U64:
94   case TYPE_S64:
95      return 3;
96   case TYPE_B96:
97   case TYPE_B128:
98      return 4;
99   case TYPE_U8:
100   case TYPE_S8:
101   default:
102      return 0;
103   }
104}
105
106static inline DataType typeOfSize(unsigned int size,
107                                  bool flt = false, bool sgn = false)
108{
109   switch (size) {
110   case 1: return sgn ? TYPE_S8 : TYPE_U8;
111   case 2: return flt ? TYPE_F16 : (sgn ? TYPE_S16 : TYPE_U16);
112   case 8: return flt ? TYPE_F64 : (sgn ? TYPE_S64 : TYPE_U64);
113   case 12: return TYPE_B96;
114   case 16: return TYPE_B128;
115   case 4:
116      return flt ? TYPE_F32 : (sgn ? TYPE_S32 : TYPE_U32);
117   default:
118      return TYPE_NONE;
119   }
120}
121
122static inline bool isFloatType(DataType ty)
123{
124   return (ty >= TYPE_F16 && ty <= TYPE_F64);
125}
126
127static inline bool isSignedIntType(DataType ty)
128{
129   return (ty == TYPE_S8 || ty == TYPE_S16 || ty == TYPE_S32 || ty == TYPE_S64);
130}
131
132static inline bool isSignedType(DataType ty)
133{
134   switch (ty) {
135   case TYPE_NONE:
136   case TYPE_U8:
137   case TYPE_U16:
138   case TYPE_U32:
139   case TYPE_U64:
140   case TYPE_B96:
141   case TYPE_B128:
142      return false;
143   default:
144      return true;
145   }
146}
147
148static inline DataType intTypeToSigned(DataType ty)
149{
150   switch (ty) {
151   case TYPE_U64: return TYPE_S64;
152   case TYPE_U32: return TYPE_S32;
153   case TYPE_U16: return TYPE_S16;
154   case TYPE_U8: return TYPE_S8;
155   default:
156      return ty;
157   }
158}
159
160const ValueRef *ValueRef::getIndirect(int dim) const
161{
162   return isIndirect(dim) ? &insn->src(indirect[dim]) : NULL;
163}
164
165DataFile ValueRef::getFile() const
166{
167   return value ? value->reg.file : FILE_NULL;
168}
169
170unsigned int ValueRef::getSize() const
171{
172   return value ? value->reg.size : 0;
173}
174
175Value *ValueRef::rep() const
176{
177   assert(value);
178   return value->join;
179}
180
181Value *ValueDef::rep() const
182{
183   assert(value);
184   return value->join;
185}
186
187DataFile ValueDef::getFile() const
188{
189   return value ? value->reg.file : FILE_NULL;
190}
191
192unsigned int ValueDef::getSize() const
193{
194   return value ? value->reg.size : 0;
195}
196
197void ValueDef::setSSA(LValue *lval)
198{
199   origin = value->asLValue();
200   set(lval);
201}
202
203const LValue *ValueDef::preSSA() const
204{
205   return origin;
206}
207
208Instruction *Value::getInsn() const
209{
210   return defs.empty() ? NULL : defs.front()->getInsn();
211}
212
213Instruction *Value::getUniqueInsn() const
214{
215   if (defs.empty())
216      return NULL;
217
218   // after regalloc, the definitions of coalesced values are linked
219   if (join != this) {
220      for (DefCIterator it = defs.begin(); it != defs.end(); ++it)
221         if ((*it)->get() == this)
222            return (*it)->getInsn();
223      // should be unreachable and trigger assertion at the end
224   }
225#ifdef DEBUG
226   if (reg.data.id < 0) {
227      int n = 0;
228      for (DefCIterator it = defs.begin(); n < 2 && it != defs.end(); ++it)
229         if ((*it)->get() == this) // don't count joined values
230            ++n;
231      if (n > 1)
232         WARN("value %%%i not uniquely defined\n", id); // return NULL ?
233   }
234#endif
235   assert(defs.front()->get() == this);
236   return defs.front()->getInsn();
237}
238
239inline bool Instruction::constrainedDefs() const
240{
241   return defExists(1) || op == OP_UNION;
242}
243
244Value *Instruction::getIndirect(int s, int dim) const
245{
246   return srcs[s].isIndirect(dim) ? getSrc(srcs[s].indirect[dim]) : NULL;
247}
248
249Value *Instruction::getPredicate() const
250{
251   return (predSrc >= 0) ? getSrc(predSrc) : NULL;
252}
253
254void Instruction::setFlagsDef(int d, Value *val)
255{
256   if (val) {
257      if (flagsDef < 0)
258         flagsDef = d;
259      setDef(flagsDef, val);
260   } else {
261      if (flagsDef >= 0) {
262         setDef(flagsDef, NULL);
263         flagsDef = -1;
264      }
265   }
266}
267
268void Instruction::setFlagsSrc(int s, Value *val)
269{
270   flagsSrc = s;
271   setSrc(flagsSrc, val);
272}
273
274Value *TexInstruction::getIndirectR() const
275{
276   return tex.rIndirectSrc >= 0 ? getSrc(tex.rIndirectSrc) : NULL;
277}
278
279Value *TexInstruction::getIndirectS() const
280{
281   return tex.rIndirectSrc >= 0 ? getSrc(tex.rIndirectSrc) : NULL;
282}
283
284CmpInstruction *Instruction::asCmp()
285{
286   if (op >= OP_SET_AND && op <= OP_SLCT && op != OP_SELP)
287      return static_cast<CmpInstruction *>(this);
288   return NULL;
289}
290
291const CmpInstruction *Instruction::asCmp() const
292{
293   if (op >= OP_SET_AND && op <= OP_SLCT && op != OP_SELP)
294      return static_cast<const CmpInstruction *>(this);
295   return NULL;
296}
297
298FlowInstruction *Instruction::asFlow()
299{
300   if (op >= OP_BRA && op <= OP_JOIN)
301      return static_cast<FlowInstruction *>(this);
302   return NULL;
303}
304
305const FlowInstruction *Instruction::asFlow() const
306{
307   if (op >= OP_BRA && op <= OP_JOIN)
308      return static_cast<const FlowInstruction *>(this);
309   return NULL;
310}
311
312TexInstruction *Instruction::asTex()
313{
314   if ((op >= OP_TEX && op <= OP_SULEA) || op == OP_SUQ)
315      return static_cast<TexInstruction *>(this);
316   return NULL;
317}
318
319const TexInstruction *Instruction::asTex() const
320{
321   if ((op >= OP_TEX && op <= OP_SULEA) || op == OP_SUQ)
322      return static_cast<const TexInstruction *>(this);
323   return NULL;
324}
325
326static inline Instruction *cloneForward(Function *ctx, Instruction *obj)
327{
328   DeepClonePolicy<Function> pol(ctx);
329
330   for (int i = 0; obj->srcExists(i); ++i)
331      pol.set(obj->getSrc(i), obj->getSrc(i));
332
333   return obj->clone(pol);
334}
335
336// XXX: use a virtual function so we're really really safe ?
337LValue *Value::asLValue()
338{
339   if (reg.file >= FILE_GPR && reg.file <= FILE_ADDRESS)
340      return static_cast<LValue *>(this);
341   return NULL;
342}
343
344Symbol *Value::asSym()
345{
346   if (reg.file >= FILE_MEMORY_CONST)
347      return static_cast<Symbol *>(this);
348   return NULL;
349}
350
351const Symbol *Value::asSym() const
352{
353   if (reg.file >= FILE_MEMORY_CONST)
354      return static_cast<const Symbol *>(this);
355   return NULL;
356}
357
358void Symbol::setOffset(int32_t offset)
359{
360   reg.data.offset = offset;
361}
362
363void Symbol::setAddress(Symbol *base, int32_t offset)
364{
365   baseSym = base;
366   reg.data.offset = offset;
367}
368
369void Symbol::setSV(SVSemantic sv, uint32_t index)
370{
371   reg.data.sv.sv = sv;
372   reg.data.sv.index = index;
373}
374
375ImmediateValue *Value::asImm()
376{
377   if (reg.file == FILE_IMMEDIATE)
378      return static_cast<ImmediateValue *>(this);
379   return NULL;
380}
381
382const ImmediateValue *Value::asImm() const
383{
384   if (reg.file == FILE_IMMEDIATE)
385      return static_cast<const ImmediateValue *>(this);
386   return NULL;
387}
388
389Value *Value::get(Iterator &it)
390{
391   return reinterpret_cast<Value *>(it.get());
392}
393
394bool BasicBlock::reachableBy(const BasicBlock *by, const BasicBlock *term)
395{
396   return cfg.reachableBy(&by->cfg, &term->cfg);
397}
398
399BasicBlock *BasicBlock::get(Iterator &iter)
400{
401   return reinterpret_cast<BasicBlock *>(iter.get());
402}
403
404BasicBlock *BasicBlock::get(Graph::Node *node)
405{
406   assert(node);
407   return reinterpret_cast<BasicBlock *>(node->data);
408}
409
410Function *Function::get(Graph::Node *node)
411{
412   assert(node);
413   return reinterpret_cast<Function *>(node->data);
414}
415
416LValue *Function::getLValue(int id)
417{
418   assert((unsigned int)id < (unsigned int)allLValues.getSize());
419   return reinterpret_cast<LValue *>(allLValues.get(id));
420}
421
422#endif // __NV50_IR_INLINES_H__
423