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 containsSamplers() const;
136
137 bool equals(const TStructure &other) const;
138
setUniqueId(int uniqueId)139 void setUniqueId(int uniqueId)
140 {
141 mUniqueId = uniqueId;
142 }
143
uniqueId()144 int uniqueId() const
145 {
146 ASSERT(mUniqueId != 0);
147 return mUniqueId;
148 }
149
setAtGlobalScope(bool atGlobalScope)150 void setAtGlobalScope(bool atGlobalScope)
151 {
152 mAtGlobalScope = atGlobalScope;
153 }
154
atGlobalScope()155 bool atGlobalScope() const
156 {
157 return mAtGlobalScope;
158 }
159
160 private:
161 // TODO(zmo): Find a way to get rid of the const_cast in function
162 // setName(). At the moment keep this function private so only
163 // friend class RegenerateStructNames may call it.
164 friend class RegenerateStructNames;
setName(const TString & name)165 void setName(const TString &name)
166 {
167 TString *mutableName = const_cast<TString *>(mName);
168 *mutableName = name;
169 }
170
mangledNamePrefix()171 virtual TString mangledNamePrefix() const
172 {
173 return "struct-";
174 }
175 int calculateDeepestNesting() const;
176
177 mutable int mDeepestNesting;
178 int mUniqueId;
179 bool mAtGlobalScope;
180 };
181
182 class TInterfaceBlock : public TFieldListCollection
183 {
184 public:
185 POOL_ALLOCATOR_NEW_DELETE();
TInterfaceBlock(const TString * name,TFieldList * fields,const TString * instanceName,int arraySize,const TLayoutQualifier & layoutQualifier)186 TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName,
187 int arraySize, const TLayoutQualifier &layoutQualifier)
188 : TFieldListCollection(name, fields),
189 mInstanceName(instanceName),
190 mArraySize(arraySize),
191 mBlockStorage(layoutQualifier.blockStorage),
192 mMatrixPacking(layoutQualifier.matrixPacking)
193 {
194 }
195
instanceName()196 const TString &instanceName() const
197 {
198 return *mInstanceName;
199 }
hasInstanceName()200 bool hasInstanceName() const
201 {
202 return mInstanceName != nullptr;
203 }
isArray()204 bool isArray() const
205 {
206 return mArraySize > 0;
207 }
arraySize()208 int arraySize() const
209 {
210 return mArraySize;
211 }
blockStorage()212 TLayoutBlockStorage blockStorage() const
213 {
214 return mBlockStorage;
215 }
matrixPacking()216 TLayoutMatrixPacking matrixPacking() const
217 {
218 return mMatrixPacking;
219 }
220
221 private:
mangledNamePrefix()222 virtual TString mangledNamePrefix() const
223 {
224 return "iblock-";
225 }
226
227 const TString *mInstanceName; // for interface block instance names
228 int mArraySize; // 0 if not an array
229 TLayoutBlockStorage mBlockStorage;
230 TLayoutMatrixPacking mMatrixPacking;
231 };
232
233 //
234 // Base class for things that have a type.
235 //
236 class TType
237 {
238 public:
239 POOL_ALLOCATOR_NEW_DELETE();
TType()240 TType() {}
241 TType(TBasicType t, int s0 = 1, int s1 = 1) :
type(t)242 type(t), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false), layoutQualifier(TLayoutQualifier::create()),
243 primarySize(s0), secondarySize(s1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
244 structure(0), deepestStructNesting(0), mangled(0)
245 {
246 }
247 TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s0 = 1, int s1 = 1, bool a = false) :
type(t)248 type(t), precision(p), qualifier(q), invariant(false), layoutQualifier(TLayoutQualifier::create()),
249 primarySize(s0), secondarySize(s1), array(a), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
250 structure(0), deepestStructNesting(0), mangled(0)
251 {
252 }
253 explicit TType(const TPublicType &p);
254 TType(TStructure* userDef, TPrecision p = EbpUndefined) :
type(EbtStruct)255 type(EbtStruct), precision(p), qualifier(EvqTemporary), invariant(false), layoutQualifier(TLayoutQualifier::create()),
256 primarySize(1), secondarySize(1), array(false), arraySize(0), maxArraySize(0), arrayInformationType(0), interfaceBlock(0),
257 structure(userDef), deepestStructNesting(0), mangled(0)
258 {
259 }
260
TType(TInterfaceBlock * interfaceBlockIn,TQualifier qualifierIn,TLayoutQualifier layoutQualifierIn,int arraySizeIn)261 TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
262 TLayoutQualifier layoutQualifierIn, int arraySizeIn)
263 : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
264 invariant(false), layoutQualifier(layoutQualifierIn),
265 primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), maxArraySize(0), arrayInformationType(0),
266 interfaceBlock(interfaceBlockIn), structure(0), deepestStructNesting(0), mangled(0)
267 {
268 }
269
getBasicType()270 TBasicType getBasicType() const { return type; }
setBasicType(TBasicType t)271 void setBasicType(TBasicType t) { type = t; }
272
getPrecision()273 TPrecision getPrecision() const { return precision; }
setPrecision(TPrecision p)274 void setPrecision(TPrecision p) { precision = p; }
275
getQualifier()276 TQualifier getQualifier() const { return qualifier; }
setQualifier(TQualifier q)277 void setQualifier(TQualifier q) { qualifier = q; }
278
isInvariant()279 bool isInvariant() const { return invariant; }
280
getLayoutQualifier()281 TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
setLayoutQualifier(TLayoutQualifier lq)282 void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
283
284 // One-dimensional size of single instance type
getNominalSize()285 int getNominalSize() const { return primarySize; }
setNominalSize(int s)286 void setNominalSize(int s) { primarySize = s; }
287 // Full size of single instance of type
getObjectSize()288 size_t getObjectSize() const
289 {
290 if(isArray())
291 {
292 return getElementSize() * std::max(getArraySize(), getMaxArraySize());
293 }
294 else
295 {
296 return getElementSize();
297 }
298 }
299
getElementSize()300 size_t getElementSize() const
301 {
302 if(getBasicType() == EbtStruct)
303 {
304 return getStructSize();
305 }
306 else if(isInterfaceBlock())
307 {
308 return interfaceBlock->objectSize();
309 }
310 else if(isMatrix())
311 {
312 return primarySize * secondarySize;
313 }
314 else // Vector or scalar
315 {
316 return primarySize;
317 }
318 }
319
elementRegisterCount()320 int elementRegisterCount() const
321 {
322 if(structure || isInterfaceBlock())
323 {
324 int registerCount = 0;
325
326 const TFieldList& fields = isInterfaceBlock() ? interfaceBlock->fields() : structure->fields();
327 for(size_t i = 0; i < fields.size(); i++)
328 {
329 registerCount += fields[i]->type()->totalRegisterCount();
330 }
331
332 return registerCount;
333 }
334 else if(isMatrix())
335 {
336 return getNominalSize();
337 }
338 else
339 {
340 return 1;
341 }
342 }
343
blockRegisterCount()344 int blockRegisterCount() const
345 {
346 // If this TType object is a block member, return the register count of the parent block
347 // Otherwise, return the register count of the current TType object
348 if(interfaceBlock && !isInterfaceBlock())
349 {
350 int registerCount = 0;
351 const TFieldList& fieldList = interfaceBlock->fields();
352 for(size_t i = 0; i < fieldList.size(); i++)
353 {
354 const TType &fieldType = *(fieldList[i]->type());
355 registerCount += fieldType.totalRegisterCount();
356 }
357 return registerCount;
358 }
359 return totalRegisterCount();
360 }
361
totalRegisterCount()362 int totalRegisterCount() const
363 {
364 if(array)
365 {
366 return arraySize * elementRegisterCount();
367 }
368 else
369 {
370 return elementRegisterCount();
371 }
372 }
373
registerSize()374 int registerSize() const
375 {
376 return isMatrix() ? secondarySize : primarySize;
377 }
378
isMatrix()379 bool isMatrix() const { return secondarySize > 1; }
setSecondarySize(int s1)380 void setSecondarySize(int s1) { secondarySize = s1; }
getSecondarySize()381 int getSecondarySize() const { return secondarySize; }
382
isArray()383 bool isArray() const { return array ? true : false; }
getArraySize()384 int getArraySize() const { return arraySize; }
setArraySize(int s)385 void setArraySize(int s) { array = true; arraySize = s; }
getMaxArraySize()386 int getMaxArraySize () const { return maxArraySize; }
setMaxArraySize(int s)387 void setMaxArraySize (int s) { maxArraySize = s; }
clearArrayness()388 void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
setArrayInformationType(TType * t)389 void setArrayInformationType(TType* t) { arrayInformationType = t; }
getArrayInformationType()390 TType* getArrayInformationType() const { return arrayInformationType; }
391
getInterfaceBlock()392 TInterfaceBlock *getInterfaceBlock() const { return interfaceBlock; }
setInterfaceBlock(TInterfaceBlock * interfaceBlockIn)393 void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) { interfaceBlock = interfaceBlockIn; }
isInterfaceBlock()394 bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
getAsInterfaceBlock()395 TInterfaceBlock *getAsInterfaceBlock() const { return isInterfaceBlock() ? getInterfaceBlock() : nullptr; }
396
isVector()397 bool isVector() const { return primarySize > 1 && !isMatrix(); }
isScalar()398 bool isScalar() const { return primarySize == 1 && !isMatrix() && !structure && !isInterfaceBlock(); }
isRegister()399 bool isRegister() const { return !isMatrix() && !structure && !array && !isInterfaceBlock(); } // Fits in a 4-element register
isStruct()400 bool isStruct() const { return structure != 0; }
isScalarInt()401 bool isScalarInt() const { return isScalar() && IsInteger(type); }
402
getStruct()403 TStructure* getStruct() const { return structure; }
setStruct(TStructure * s)404 void setStruct(TStructure* s) { structure = s; computeDeepestStructNesting(); }
405
getMangledName()406 TString& getMangledName() {
407 if (!mangled) {
408 mangled = NewPoolTString("");
409 buildMangledName(*mangled);
410 *mangled += ';' ;
411 }
412
413 return *mangled;
414 }
415
sameElementType(const TType & right)416 bool sameElementType(const TType& right) const {
417 return type == right.type &&
418 primarySize == right.primarySize &&
419 secondarySize == right.secondarySize &&
420 structure == right.structure;
421 }
422 bool operator==(const TType& right) const {
423 return type == right.type &&
424 primarySize == right.primarySize &&
425 secondarySize == right.secondarySize &&
426 array == right.array && (!array || arraySize == right.arraySize) &&
427 structure == right.structure;
428 // don't check the qualifier, it's not ever what's being sought after
429 }
430 bool operator!=(const TType& right) const {
431 return !operator==(right);
432 }
433 bool operator<(const TType& right) const {
434 if (type != right.type) return type < right.type;
435 if(primarySize != right.primarySize) return (primarySize * secondarySize) < (right.primarySize * right.secondarySize);
436 if(secondarySize != right.secondarySize) return secondarySize < right.secondarySize;
437 if (array != right.array) return array < right.array;
438 if (arraySize != right.arraySize) return arraySize < right.arraySize;
439 if (structure != right.structure) return structure < right.structure;
440
441 return false;
442 }
443
getBasicString()444 const char* getBasicString() const { return ::getBasicString(type); }
getPrecisionString()445 const char* getPrecisionString() const { return ::getPrecisionString(precision); }
getQualifierString()446 const char* getQualifierString() const { return ::getQualifierString(qualifier); }
447 TString getCompleteString() const;
448
449 // If this type is a struct, returns the deepest struct nesting of
450 // any field in the struct. For example:
451 // struct nesting1 {
452 // vec4 position;
453 // };
454 // struct nesting2 {
455 // nesting1 field1;
456 // vec4 field2;
457 // };
458 // For type "nesting2", this method would return 2 -- the number
459 // of structures through which indirection must occur to reach the
460 // deepest field (nesting2.field1.position).
getDeepestStructNesting()461 int getDeepestStructNesting() const
462 {
463 return structure ? structure->deepestNesting() : 0;
464 }
465
isStructureContainingArrays()466 bool isStructureContainingArrays() const
467 {
468 return structure ? structure->containsArrays() : false;
469 }
470
isStructureContainingSamplers()471 bool isStructureContainingSamplers() const
472 {
473 return structure ? structure->containsSamplers() : false;
474 }
475
476 protected:
477 void buildMangledName(TString&);
478 size_t getStructSize() const;
479 void computeDeepestStructNesting();
480
481 TBasicType type;
482 TPrecision precision;
483 TQualifier qualifier;
484 bool invariant;
485 TLayoutQualifier layoutQualifier;
486 unsigned char primarySize; // size of vector or matrix, not size of array
487 unsigned char secondarySize; // secondarySize: 1 for vectors, >1 for matrices
488 bool array;
489 int arraySize;
490 int maxArraySize;
491 TType *arrayInformationType;
492
493 // 0 unless this is an interface block, or interface block member variable
494 TInterfaceBlock *interfaceBlock;
495
496 TStructure *structure; // 0 unless this is a struct
497 int deepestStructNesting;
498
499 TString *mangled;
500 };
501
502 //
503 // This is a workaround for a problem with the yacc stack, It can't have
504 // types that it thinks have non-trivial constructors. It should
505 // just be used while recognizing the grammar, not anything else. Pointers
506 // could be used, but also trying to avoid lots of memory management overhead.
507 //
508 // Not as bad as it looks, there is no actual assumption that the fields
509 // match up or are name the same or anything like that.
510 //
511 struct TPublicType
512 {
513 TBasicType type;
514 TLayoutQualifier layoutQualifier;
515 TQualifier qualifier;
516 bool invariant;
517 TPrecision precision;
518 int primarySize; // size of vector or matrix, not size of array
519 int secondarySize; // 1 for scalars/vectors, >1 for matrices
520 bool array;
521 int arraySize;
522 TType* userDef;
523 TSourceLoc line;
524
setBasicTPublicType525 void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
526 {
527 type = bt;
528 layoutQualifier = TLayoutQualifier::create();
529 qualifier = q;
530 invariant = false;
531 precision = EbpUndefined;
532 primarySize = 1;
533 secondarySize = 1;
534 array = false;
535 arraySize = 0;
536 userDef = 0;
537 line = ln;
538 }
539
setAggregateTPublicType540 void setAggregate(int s)
541 {
542 primarySize = s;
543 secondarySize = 1;
544 }
545
setMatrixTPublicType546 void setMatrix(int s0, int s1)
547 {
548 primarySize = s0;
549 secondarySize = s1;
550 }
551
isUnsizedArrayTPublicType552 bool isUnsizedArray() const
553 {
554 return array && arraySize == 0;
555 }
556
557 void setArray(bool a, int s = 0)
558 {
559 array = a;
560 arraySize = s;
561 }
562
clearArraynessTPublicType563 void clearArrayness()
564 {
565 array = false;
566 arraySize = 0;
567 }
568
isStructureContainingArraysTPublicType569 bool isStructureContainingArrays() const
570 {
571 if (!userDef)
572 {
573 return false;
574 }
575
576 return userDef->isStructureContainingArrays();
577 }
578
isMatrixTPublicType579 bool isMatrix() const
580 {
581 return primarySize > 1 && secondarySize > 1;
582 }
583
isVectorTPublicType584 bool isVector() const
585 {
586 return primarySize > 1 && secondarySize == 1;
587 }
588
getColsTPublicType589 int getCols() const
590 {
591 ASSERT(isMatrix());
592 return primarySize;
593 }
594
getRowsTPublicType595 int getRows() const
596 {
597 ASSERT(isMatrix());
598 return secondarySize;
599 }
600
getNominalSizeTPublicType601 int getNominalSize() const
602 {
603 return primarySize;
604 }
605
isAggregateTPublicType606 bool isAggregate() const
607 {
608 return array || isMatrix() || isVector();
609 }
610 };
611
612 #endif // _TYPES_INCLUDED_
613