1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Compile-time instances of many common TType values. These are looked up
7 // (statically or dynamically) through the methods defined in the namespace.
8 //
9 
10 #ifndef COMPILER_TRANSLATOR_STATIC_TYPE_H_
11 #define COMPILER_TRANSLATOR_STATIC_TYPE_H_
12 
13 #include "compiler/translator/Types.h"
14 
15 namespace sh
16 {
17 
18 namespace StaticType
19 {
20 
21 namespace Helpers
22 {
23 
24 //
25 // Generation and static allocation of type mangled name values.
26 //
27 
28 // Size of the constexpr-generated mangled name.
29 // If this value is too small, the compiler will produce errors.
30 static constexpr size_t kStaticMangledNameLength = TBasicMangledName::mangledNameSize + 1;
31 
32 // Type which holds the mangled names for constexpr-generated TTypes.
33 // This simple struct is needed so that a char array can be returned by value.
34 struct StaticMangledName
35 {
36     // If this array is too small, the compiler will produce errors.
37     char name[kStaticMangledNameLength + 1] = {};
38 };
39 
40 // Generates a mangled name for a TType given its parameters.
BuildStaticMangledName(TBasicType basicType,TPrecision precision,TQualifier qualifier,unsigned char primarySize,unsigned char secondarySize)41 constexpr StaticMangledName BuildStaticMangledName(TBasicType basicType,
42                                                    TPrecision precision,
43                                                    TQualifier qualifier,
44                                                    unsigned char primarySize,
45                                                    unsigned char secondarySize)
46 {
47     StaticMangledName name = {};
48     name.name[0]           = TType::GetSizeMangledName(primarySize, secondarySize);
49     TBasicMangledName typeName(basicType);
50     char *mangledName = typeName.getName();
51     static_assert(TBasicMangledName::mangledNameSize == 2, "Mangled name size is not 2");
52     name.name[1] = mangledName[0];
53     name.name[2] = mangledName[1];
54     name.name[3] = '\0';
55     return name;
56 }
57 
58 // Similar mangled name builder but for array types.  Currently, only single-dimension arrays of
59 // single-digit size are necessary and supported.
60 static constexpr size_t kStaticArrayMangledNameLength = kStaticMangledNameLength + 2;
61 struct StaticArrayMangledName
62 {
63     char name[kStaticArrayMangledNameLength + 1] = {};
64 };
BuildStaticArrayMangledName(TBasicType basicType,TPrecision precision,TQualifier qualifier,unsigned char primarySize,unsigned char secondarySize,const unsigned int * arraySizes,size_t numArraySizes)65 constexpr StaticArrayMangledName BuildStaticArrayMangledName(TBasicType basicType,
66                                                              TPrecision precision,
67                                                              TQualifier qualifier,
68                                                              unsigned char primarySize,
69                                                              unsigned char secondarySize,
70                                                              const unsigned int *arraySizes,
71                                                              size_t numArraySizes)
72 {
73     StaticMangledName nonArrayName =
74         BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
75 
76     StaticArrayMangledName arrayName = {};
77     static_assert(kStaticMangledNameLength == 3, "Static mangled name size is not 3");
78 
79     arrayName.name[0] = nonArrayName.name[0];
80     arrayName.name[1] = nonArrayName.name[1];
81     arrayName.name[2] = nonArrayName.name[2];
82     arrayName.name[3] = 'x';
83     arrayName.name[4] = static_cast<char>('0' + arraySizes[0]);
84     arrayName.name[5] = '\0';
85     return arrayName;
86 }
87 
88 // This "variable" contains the mangled names for every constexpr-generated TType.
89 // If kMangledNameInstance<B, P, Q, PS, SS> is used anywhere (specifally
90 // in instance, below), this is where the appropriate type will be stored.
91 template <TBasicType basicType,
92           TPrecision precision,
93           TQualifier qualifier,
94           unsigned char primarySize,
95           unsigned char secondarySize>
96 static constexpr StaticMangledName kMangledNameInstance =
97     BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
98 
99 // Same as kMangledNameInstance, but for array types.
100 template <TBasicType basicType,
101           TPrecision precision,
102           TQualifier qualifier,
103           unsigned char primarySize,
104           unsigned char secondarySize,
105           const unsigned int *arraySizes,
106           size_t numArraySizes>
107 static constexpr StaticArrayMangledName kMangledNameArrayInstance =
108     BuildStaticArrayMangledName(basicType,
109                                 precision,
110                                 qualifier,
111                                 primarySize,
112                                 secondarySize,
113                                 arraySizes,
114                                 numArraySizes);
115 
116 //
117 // Generation and static allocation of TType values.
118 //
119 
120 // This "variable" contains every constexpr-generated TType.
121 // If instance<B, P, Q, PS, SS> is used anywhere (specifally
122 // in Get, below), this is where the appropriate type will be stored.
123 //
124 // TODO(crbug.com/981610): This is constexpr but doesn't follow the kConstant naming convention
125 // because TType has a mutable member that prevents it from being in .data.rel.ro and makes the
126 // Android Binary Size builder complain when ANGLE is rolled in Chromium.
127 template <TBasicType basicType,
128           TPrecision precision,
129           TQualifier qualifier,
130           unsigned char primarySize,
131           unsigned char secondarySize>
132 static constexpr TType instance =
133     TType(basicType,
134           precision,
135           qualifier,
136           primarySize,
137           secondarySize,
138           TSpan<const unsigned int>(),
139           kMangledNameInstance<basicType, precision, qualifier, primarySize, secondarySize>.name);
140 
141 // Same as instance, but for array types.
142 template <TBasicType basicType,
143           TPrecision precision,
144           TQualifier qualifier,
145           unsigned char primarySize,
146           unsigned char secondarySize,
147           const unsigned int *arraySizes,
148           size_t numArraySizes>
149 static constexpr TType arrayInstance =
150     TType(basicType,
151           precision,
152           qualifier,
153           primarySize,
154           secondarySize,
155           TSpan<const unsigned int>(arraySizes, numArraySizes),
156           kMangledNameArrayInstance<basicType, precision, qualifier, primarySize, secondarySize, arraySizes, numArraySizes>.name);
157 
158 }  // namespace Helpers
159 
160 //
161 // Fully-qualified type lookup.
162 //
163 
164 template <TBasicType basicType,
165           TPrecision precision,
166           TQualifier qualifier,
167           unsigned char primarySize,
168           unsigned char secondarySize>
Get()169 constexpr const TType *Get()
170 {
171     static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds");
172     static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds");
173     return &Helpers::instance<basicType, precision, qualifier, primarySize, secondarySize>;
174 }
175 
176 template <TBasicType basicType,
177           TPrecision precision,
178           TQualifier qualifier,
179           unsigned char primarySize,
180           unsigned char secondarySize,
181           const unsigned int *arraySizes,
182           size_t numArraySizes>
GetArray()183 constexpr const TType *GetArray()
184 {
185     static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds");
186     static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds");
187     static_assert(numArraySizes == 1, "only single-dimension static types are supported");
188     static_assert(arraySizes[0] < 10, "only single-digit dimensions are supported in static types");
189     return &Helpers::arrayInstance<basicType, precision, qualifier, primarySize, secondarySize,
190                                    arraySizes, numArraySizes>;
191 }
192 
193 //
194 // Overloads
195 //
196 
197 template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1>
GetBasic()198 constexpr const TType *GetBasic()
199 {
200     return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>();
201 }
202 
203 template <TBasicType basicType,
204           TQualifier qualifier,
205           unsigned char primarySize   = 1,
206           unsigned char secondarySize = 1>
GetQualified()207 const TType *GetQualified()
208 {
209     return Get<basicType, EbpUndefined, qualifier, primarySize, secondarySize>();
210 }
211 
212 // Dynamic lookup methods (convert runtime values to template args)
213 
214 namespace Helpers
215 {
216 
217 // Helper which takes secondarySize statically but primarySize dynamically.
218 template <TBasicType basicType,
219           TPrecision precision,
220           TQualifier qualifier,
221           unsigned char secondarySize>
GetForVecMatHelper(unsigned char primarySize)222 constexpr const TType *GetForVecMatHelper(unsigned char primarySize)
223 {
224     static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
225                       basicType == EbtBool,
226                   "unsupported basicType");
227     switch (primarySize)
228     {
229         case 1:
230             return Get<basicType, precision, qualifier, 1, secondarySize>();
231         case 2:
232             return Get<basicType, precision, qualifier, 2, secondarySize>();
233         case 3:
234             return Get<basicType, precision, qualifier, 3, secondarySize>();
235         case 4:
236             return Get<basicType, precision, qualifier, 4, secondarySize>();
237         default:
238             UNREACHABLE();
239             return GetBasic<EbtVoid>();
240     }
241 }
242 
243 }  // namespace Helpers
244 
245 template <TBasicType basicType,
246           TPrecision precision = EbpUndefined,
247           TQualifier qualifier = EvqGlobal>
248 constexpr const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1)
249 {
250     static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
251                       basicType == EbtBool,
252                   "unsupported basicType");
253     switch (secondarySize)
254     {
255         case 1:
256             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 1>(primarySize);
257         case 2:
258             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 2>(primarySize);
259         case 3:
260             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 3>(primarySize);
261         case 4:
262             return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 4>(primarySize);
263         default:
264             UNREACHABLE();
265             return GetBasic<EbtVoid>();
266     }
267 }
268 
269 template <TBasicType basicType, TPrecision precision = EbpUndefined>
GetForVec(TQualifier qualifier,unsigned char size)270 constexpr const TType *GetForVec(TQualifier qualifier, unsigned char size)
271 {
272     switch (qualifier)
273     {
274         case EvqGlobal:
275             return Helpers::GetForVecMatHelper<basicType, precision, EvqGlobal, 1>(size);
276         case EvqOut:
277             return Helpers::GetForVecMatHelper<basicType, precision, EvqOut, 1>(size);
278         default:
279             UNREACHABLE();
280             return GetBasic<EbtVoid>();
281     }
282 }
283 
284 }  // namespace StaticType
285 
286 }  // namespace sh
287 
288 #endif  // COMPILER_TRANSLATOR_STATIC_TYPE_H_
289