1// Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#ifndef _TYPES_INCLUDED 16#define _TYPES_INCLUDED 17 18#include "BaseTypes.h" 19#include "Common.h" 20#include "debug.h" 21 22#include <algorithm> 23 24class TType; 25struct TPublicType; 26 27class TField 28{ 29public: 30 POOL_ALLOCATOR_NEW_DELETE(); 31 TField(TType *type, TString *name, const TSourceLoc &line) 32 : mType(type), 33 mName(name), 34 mLine(line) 35 { 36 } 37 38 // TODO(alokp): We should only return const type. 39 // Fix it by tweaking grammar. 40 TType *type() 41 { 42 return mType; 43 } 44 const TType *type() const 45 { 46 return mType; 47 } 48 49 const TString &name() const 50 { 51 return *mName; 52 } 53 const TSourceLoc &line() const 54 { 55 return mLine; 56 } 57 58private: 59 TType *mType; 60 TString *mName; 61 TSourceLoc mLine; 62}; 63 64typedef TVector<TField *> TFieldList; 65inline TFieldList *NewPoolTFieldList() 66{ 67 void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList)); 68 return new(memory)TFieldList; 69} 70 71class TFieldListCollection 72{ 73public: 74 virtual ~TFieldListCollection() { } 75 const TString &name() const 76 { 77 return *mName; 78 } 79 const TFieldList &fields() const 80 { 81 return *mFields; 82 } 83 84 const TString &mangledName() const 85 { 86 if(mMangledName.empty()) 87 mMangledName = buildMangledName(); 88 return mMangledName; 89 } 90 size_t objectSize() const 91 { 92 if(mObjectSize == 0) 93 mObjectSize = calculateObjectSize(); 94 return mObjectSize; 95 }; 96 97protected: 98 TFieldListCollection(const TString *name, TFieldList *fields) 99 : mName(name), 100 mFields(fields), 101 mObjectSize(0) 102 { 103 } 104 TString buildMangledName() const; 105 size_t calculateObjectSize() const; 106 virtual TString mangledNamePrefix() const = 0; 107 108 const TString *mName; 109 TFieldList *mFields; 110 111 mutable TString mMangledName; 112 mutable size_t mObjectSize; 113}; 114 115// May also represent interface blocks 116class TStructure : public TFieldListCollection 117{ 118public: 119 POOL_ALLOCATOR_NEW_DELETE(); 120 TStructure(const TString *name, TFieldList *fields) 121 : TFieldListCollection(name, fields), 122 mDeepestNesting(0), 123 mUniqueId(0), 124 mAtGlobalScope(false) 125 { 126 } 127 128 int deepestNesting() const 129 { 130 if(mDeepestNesting == 0) 131 mDeepestNesting = calculateDeepestNesting(); 132 return mDeepestNesting; 133 } 134 bool containsArrays() const; 135 bool containsType(TBasicType type) const; 136 bool containsSamplers() const; 137 138 bool equals(const TStructure &other) const; 139 140 void setUniqueId(int uniqueId) 141 { 142 mUniqueId = uniqueId; 143 } 144 145 int uniqueId() const 146 { 147 ASSERT(mUniqueId != 0); 148 return mUniqueId; 149 } 150 151 void setAtGlobalScope(bool atGlobalScope) 152 { 153 mAtGlobalScope = atGlobalScope; 154 } 155 156 bool atGlobalScope() const 157 { 158 return mAtGlobalScope; 159 } 160 161private: 162 // TODO(zmo): Find a way to get rid of the const_cast in function 163 // setName(). At the moment keep this function private so only 164 // friend class RegenerateStructNames may call it. 165 friend class RegenerateStructNames; 166 void setName(const TString &name) 167 { 168 TString *mutableName = const_cast<TString *>(mName); 169 *mutableName = name; 170 } 171 172 virtual TString mangledNamePrefix() const 173 { 174 return "struct-"; 175 } 176 int calculateDeepestNesting() const; 177 178 mutable int mDeepestNesting; 179 int mUniqueId; 180 bool mAtGlobalScope; 181}; 182 183class TInterfaceBlock : public TFieldListCollection 184{ 185public: 186 POOL_ALLOCATOR_NEW_DELETE(); 187 TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName, 188 int arraySize, const TLayoutQualifier &layoutQualifier) 189 : TFieldListCollection(name, fields), 190 mInstanceName(instanceName), 191 mArraySize(arraySize), 192 mBlockStorage(layoutQualifier.blockStorage), 193 mMatrixPacking(layoutQualifier.matrixPacking) 194 { 195 } 196 197 const TString &instanceName() const 198 { 199 return *mInstanceName; 200 } 201 bool hasInstanceName() const 202 { 203 return mInstanceName != nullptr; 204 } 205 bool isArray() const 206 { 207 return mArraySize > 0; 208 } 209 int arraySize() const 210 { 211 return mArraySize; 212 } 213 TLayoutBlockStorage blockStorage() const 214 { 215 return mBlockStorage; 216 } 217 TLayoutMatrixPacking matrixPacking() const 218 { 219 return mMatrixPacking; 220 } 221 222private: 223 virtual TString mangledNamePrefix() const 224 { 225 return "iblock-"; 226 } 227 228 const TString *mInstanceName; // for interface block instance names 229 int mArraySize; // 0 if not an array 230 TLayoutBlockStorage mBlockStorage; 231 TLayoutMatrixPacking mMatrixPacking; 232}; 233 234// 235// Base class for things that have a type. 236// 237class TType 238{ 239public: 240 POOL_ALLOCATOR_NEW_DELETE(); 241 TType() {} 242 TType(TBasicType t, int s0 = 1, int s1 = 1) : 243 type(t), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false), layoutQualifier(TLayoutQualifier::create()), 244 primarySize(s0), secondarySize(s1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), 245 structure(0), deepestStructNesting(0), mangled(0) 246 { 247 } 248 TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s0 = 1, int s1 = 1, bool a = false) : 249 type(t), precision(p), qualifier(q), invariant(false), layoutQualifier(TLayoutQualifier::create()), 250 primarySize(s0), secondarySize(s1), array(a), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), 251 structure(0), deepestStructNesting(0), mangled(0) 252 { 253 } 254 explicit TType(const TPublicType &p); 255 TType(TStructure* userDef, TPrecision p = EbpUndefined) : 256 type(EbtStruct), precision(p), qualifier(EvqTemporary), invariant(false), layoutQualifier(TLayoutQualifier::create()), 257 primarySize(1), secondarySize(1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0), 258 structure(userDef), deepestStructNesting(0), mangled(0) 259 { 260 } 261 262 TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn, 263 TLayoutQualifier layoutQualifierIn, int arraySizeIn) 264 : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn), 265 invariant(false), layoutQualifier(layoutQualifierIn), 266 primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), maxArraySize(0), arrayInformationType(0), 267 interfaceBlock(interfaceBlockIn), structure(0), deepestStructNesting(0), mangled(0) 268 { 269 } 270 271 TBasicType getBasicType() const { return type; } 272 void setBasicType(TBasicType t) { type = t; } 273 274 TPrecision getPrecision() const { return precision; } 275 void setPrecision(TPrecision p) { precision = p; } 276 277 TQualifier getQualifier() const { return qualifier; } 278 void setQualifier(TQualifier q) { qualifier = q; } 279 280 bool isInvariant() const { return invariant; } 281 282 TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; } 283 void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; } 284 285 // One-dimensional size of single instance type 286 int getNominalSize() const { return primarySize; } 287 void setNominalSize(int s) { primarySize = s; } 288 // Full size of single instance of type 289 size_t getObjectSize() const 290 { 291 if(isArray()) 292 { 293 return getElementSize() * std::max(getArraySize(), getMaxArraySize()); 294 } 295 else 296 { 297 return getElementSize(); 298 } 299 } 300 301 size_t getElementSize() const 302 { 303 if(getBasicType() == EbtStruct) 304 { 305 return getStructSize(); 306 } 307 else if(isInterfaceBlock()) 308 { 309 return interfaceBlock->objectSize(); 310 } 311 else if(isMatrix()) 312 { 313 return primarySize * secondarySize; 314 } 315 else // Vector or scalar 316 { 317 return primarySize; 318 } 319 } 320 321 int elementRegisterCount() const 322 { 323 if(structure || isInterfaceBlock()) 324 { 325 int registerCount = 0; 326 327 const TFieldList& fields = isInterfaceBlock() ? interfaceBlock->fields() : structure->fields(); 328 for(size_t i = 0; i < fields.size(); i++) 329 { 330 registerCount += fields[i]->type()->totalRegisterCount(); 331 } 332 333 return registerCount; 334 } 335 else if(isMatrix()) 336 { 337 return getNominalSize(); 338 } 339 else 340 { 341 return 1; 342 } 343 } 344 345 int blockRegisterCount() const 346 { 347 // If this TType object is a block member, return the register count of the parent block 348 // Otherwise, return the register count of the current TType object 349 if(interfaceBlock && !isInterfaceBlock()) 350 { 351 int registerCount = 0; 352 const TFieldList& fieldList = interfaceBlock->fields(); 353 for(size_t i = 0; i < fieldList.size(); i++) 354 { 355 const TType &fieldType = *(fieldList[i]->type()); 356 registerCount += fieldType.totalRegisterCount(); 357 } 358 return registerCount; 359 } 360 return totalRegisterCount(); 361 } 362 363 int totalRegisterCount() const 364 { 365 if(array) 366 { 367 return arraySize * elementRegisterCount(); 368 } 369 else 370 { 371 return elementRegisterCount(); 372 } 373 } 374 375 int registerSize() const 376 { 377 return isMatrix() ? secondarySize : primarySize; 378 } 379 380 bool isMatrix() const { return secondarySize > 1; } 381 void setSecondarySize(int s1) { secondarySize = s1; } 382 int getSecondarySize() const { return secondarySize; } 383 384 bool isArray() const { return array ? true : false; } 385 bool isUnsizedArray() const { return array && arraySize == 0; } 386 int getArraySize() const { return arraySize; } 387 void setArraySize(int s) { array = true; arraySize = s; } 388 int getMaxArraySize () const { return maxArraySize; } 389 void setMaxArraySize (int s) { maxArraySize = s; } 390 void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; } 391 void setArrayInformationType(TType* t) { arrayInformationType = t; } 392 TType* getArrayInformationType() const { return arrayInformationType; } 393 394 TInterfaceBlock *getInterfaceBlock() const { return interfaceBlock; } 395 void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) { interfaceBlock = interfaceBlockIn; } 396 bool isInterfaceBlock() const { return type == EbtInterfaceBlock; } 397 TInterfaceBlock *getAsInterfaceBlock() const { return isInterfaceBlock() ? getInterfaceBlock() : nullptr; } 398 399 bool isVector() const { return primarySize > 1 && !isMatrix(); } 400 bool isScalar() const { return primarySize == 1 && !isMatrix() && !structure && !isInterfaceBlock(); } 401 bool isRegister() const { return !isMatrix() && !structure && !array && !isInterfaceBlock(); } // Fits in a 4-element register 402 bool isStruct() const { return structure != 0; } 403 bool isScalarInt() const { return isScalar() && IsInteger(type); } 404 405 TStructure* getStruct() const { return structure; } 406 void setStruct(TStructure* s) { structure = s; computeDeepestStructNesting(); } 407 408 TString& getMangledName() { 409 if (!mangled) { 410 mangled = NewPoolTString(""); 411 buildMangledName(*mangled); 412 *mangled += ';' ; 413 } 414 415 return *mangled; 416 } 417 418 bool sameElementType(const TType& right) const { 419 return type == right.type && 420 primarySize == right.primarySize && 421 secondarySize == right.secondarySize && 422 structure == right.structure; 423 } 424 bool operator==(const TType& right) const { 425 return type == right.type && 426 primarySize == right.primarySize && 427 secondarySize == right.secondarySize && 428 array == right.array && (!array || arraySize == right.arraySize) && 429 structure == right.structure; 430 // don't check the qualifier, it's not ever what's being sought after 431 } 432 bool operator!=(const TType& right) const { 433 return !operator==(right); 434 } 435 bool operator<(const TType& right) const { 436 if (type != right.type) return type < right.type; 437 if(primarySize != right.primarySize) return (primarySize * secondarySize) < (right.primarySize * right.secondarySize); 438 if(secondarySize != right.secondarySize) return secondarySize < right.secondarySize; 439 if (array != right.array) return array < right.array; 440 if (arraySize != right.arraySize) return arraySize < right.arraySize; 441 if (structure != right.structure) return structure < right.structure; 442 443 return false; 444 } 445 446 const char* getBasicString() const { return ::getBasicString(type); } 447 const char* getPrecisionString() const { return ::getPrecisionString(precision); } 448 const char* getQualifierString() const { return ::getQualifierString(qualifier); } 449 TString getCompleteString() const; 450 451 // If this type is a struct, returns the deepest struct nesting of 452 // any field in the struct. For example: 453 // struct nesting1 { 454 // vec4 position; 455 // }; 456 // struct nesting2 { 457 // nesting1 field1; 458 // vec4 field2; 459 // }; 460 // For type "nesting2", this method would return 2 -- the number 461 // of structures through which indirection must occur to reach the 462 // deepest field (nesting2.field1.position). 463 int getDeepestStructNesting() const 464 { 465 return structure ? structure->deepestNesting() : 0; 466 } 467 468 bool isStructureContainingArrays() const 469 { 470 return structure ? structure->containsArrays() : false; 471 } 472 473 bool isStructureContainingType(TBasicType t) const 474 { 475 return structure ? structure->containsType(t) : false; 476 } 477 478 bool isStructureContainingSamplers() const 479 { 480 return structure ? structure->containsSamplers() : false; 481 } 482 483protected: 484 void buildMangledName(TString&); 485 size_t getStructSize() const; 486 void computeDeepestStructNesting(); 487 488 TBasicType type; 489 TPrecision precision; 490 TQualifier qualifier; 491 bool invariant; 492 TLayoutQualifier layoutQualifier; 493 unsigned char primarySize; // size of vector or matrix, not size of array 494 unsigned char secondarySize; // secondarySize: 1 for vectors, >1 for matrices 495 bool array; 496 int arraySize; 497 int maxArraySize; 498 TType *arrayInformationType; 499 500 // 0 unless this is an interface block, or interface block member variable 501 TInterfaceBlock *interfaceBlock; 502 503 TStructure *structure; // 0 unless this is a struct 504 int deepestStructNesting; 505 506 TString *mangled; 507}; 508 509// 510// This is a workaround for a problem with the yacc stack, It can't have 511// types that it thinks have non-trivial constructors. It should 512// just be used while recognizing the grammar, not anything else. Pointers 513// could be used, but also trying to avoid lots of memory management overhead. 514// 515// Not as bad as it looks, there is no actual assumption that the fields 516// match up or are name the same or anything like that. 517// 518struct TPublicType 519{ 520 TBasicType type; 521 TLayoutQualifier layoutQualifier; 522 TQualifier qualifier; 523 bool invariant; 524 TPrecision precision; 525 int primarySize; // size of vector or matrix, not size of array 526 int secondarySize; // 1 for scalars/vectors, >1 for matrices 527 bool array; 528 int arraySize; 529 TType* userDef; 530 TSourceLoc line; 531 532 void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln) 533 { 534 type = bt; 535 layoutQualifier = TLayoutQualifier::create(); 536 qualifier = q; 537 invariant = false; 538 precision = EbpUndefined; 539 primarySize = 1; 540 secondarySize = 1; 541 array = false; 542 arraySize = 0; 543 userDef = 0; 544 line = ln; 545 } 546 547 void setAggregate(int s) 548 { 549 primarySize = s; 550 secondarySize = 1; 551 } 552 553 void setMatrix(int s0, int s1) 554 { 555 primarySize = s0; 556 secondarySize = s1; 557 } 558 559 bool isUnsizedArray() const 560 { 561 return array && arraySize == 0; 562 } 563 564 void setArray(bool a, int s = 0) 565 { 566 array = a; 567 arraySize = s; 568 } 569 570 void clearArrayness() 571 { 572 array = false; 573 arraySize = 0; 574 } 575 576 bool isStructureContainingArrays() const 577 { 578 if (!userDef) 579 { 580 return false; 581 } 582 583 return userDef->isStructureContainingArrays(); 584 } 585 586 bool isStructureContainingType(TBasicType t) const 587 { 588 if(!userDef) 589 { 590 return false; 591 } 592 593 return userDef->isStructureContainingType(t); 594 } 595 596 bool isMatrix() const 597 { 598 return primarySize > 1 && secondarySize > 1; 599 } 600 601 bool isVector() const 602 { 603 return primarySize > 1 && secondarySize == 1; 604 } 605 606 int getCols() const 607 { 608 ASSERT(isMatrix()); 609 return primarySize; 610 } 611 612 int getRows() const 613 { 614 ASSERT(isMatrix()); 615 return secondarySize; 616 } 617 618 int getNominalSize() const 619 { 620 return primarySize; 621 } 622 623 bool isAggregate() const 624 { 625 return array || isMatrix() || isVector(); 626 } 627}; 628 629#endif // _TYPES_INCLUDED_ 630