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