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