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