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