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