1 //
2 // Copyright 2002 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
7 #ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_
8 #define COMPILER_TRANSLATOR_SYMBOLTABLE_H_
9
10 //
11 // Symbol table for parsing. Has these design characteristics:
12 //
13 // * Same symbol table can be used to compile many shaders, to preserve
14 // effort of creating and loading with the large numbers of built-in
15 // symbols.
16 //
17 // * Name mangling will be used to give each function a unique name
18 // so that symbol table lookups are never ambiguous. This allows
19 // a simpler symbol table structure.
20 //
21 // * Pushing and popping of scope, so symbol table will really be a stack
22 // of symbol tables. Searched from the top, with new inserts going into
23 // the top.
24 //
25 // * Constants: Compile time constant symbols will keep their values
26 // in the symbol table. The parser can substitute constants at parse
27 // time, including doing constant folding and constant propagation.
28 //
29 // * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
30 // are tracked in the intermediate representation, not the symbol table.
31 //
32
33 #include <limits>
34 #include <memory>
35 #include <set>
36
37 #include "common/angleutils.h"
38 #include "compiler/translator/ExtensionBehavior.h"
39 #include "compiler/translator/ImmutableString.h"
40 #include "compiler/translator/InfoSink.h"
41 #include "compiler/translator/IntermNode.h"
42 #include "compiler/translator/Symbol.h"
43 #include "compiler/translator/SymbolTable_autogen.h"
44
45 enum class Shader : uint8_t
46 {
47 ALL,
48 FRAGMENT, // GL_FRAGMENT_SHADER
49 VERTEX, // GL_VERTEX_SHADER
50 COMPUTE, // GL_COMPUTE_SHADER
51 GEOMETRY, // GL_GEOMETRY_SHADER
52 GEOMETRY_EXT, // GL_GEOMETRY_SHADER_EXT
53 TESS_CONTROL_EXT, // GL_TESS_CONTROL_SHADER_EXT
54 TESS_EVALUATION_EXT, // GL_TESS_EVALUATION_SHADER_EXT
55 NOT_COMPUTE
56 };
57
58 namespace sh
59 {
60
61 struct UnmangledBuiltIn
62 {
UnmangledBuiltInUnmangledBuiltIn63 constexpr UnmangledBuiltIn(TExtension extension) : extension(extension) {}
64
65 TExtension extension;
66 };
67
68 using VarPointer = TSymbol *(TSymbolTableBase::*);
69 using ValidateExtension = int ShBuiltInResources::*;
70
71 constexpr uint16_t kESSL1Only = 100;
72 // Some built-ins from backend shader languages are made available internally to ESSL for use in
73 // tree transformations. This (invalid) shader version is used to select those built-ins. This
74 // value needs to be larger than all other shader versions.
75 constexpr uint16_t kESSLInternalBackendBuiltIns = 0x3FFF;
76
77 // The version assigned to |kESSLInternalBackendBuiltIns| should be good until OpenGL 20.0!
78 static_assert(kESSLInternalBackendBuiltIns > 2000,
79 "Accidentally exposing internal backend built-ins in OpenGL");
80
81 static_assert(offsetof(ShBuiltInResources, OES_standard_derivatives) != 0,
82 "Update SymbolTable extension logic");
83
84 #define EXT_INDEX(Ext) (offsetof(ShBuiltInResources, Ext) / sizeof(int))
85
86 class SymbolRule
87 {
88 public:
89 const TSymbol *get(ShShaderSpec shaderSpec,
90 int shaderVersion,
91 sh::GLenum shaderType,
92 const ShBuiltInResources &resources,
93 const TSymbolTableBase &symbolTable) const;
94
95 template <int version, Shader shaders, size_t extensionIndex, typename T>
96 constexpr static SymbolRule Get(T value);
97
98 private:
99 constexpr SymbolRule(int version, Shader shaders, size_t extensionIndex, const TSymbol *symbol);
100
101 constexpr SymbolRule(int version,
102 Shader shaders,
103 size_t extensionIndex,
104 VarPointer resourceVar);
105
106 union SymbolOrVar
107 {
SymbolOrVar(const TSymbol * symbolIn)108 constexpr SymbolOrVar(const TSymbol *symbolIn) : symbol(symbolIn) {}
SymbolOrVar(VarPointer varIn)109 constexpr SymbolOrVar(VarPointer varIn) : var(varIn) {}
110
111 const TSymbol *symbol;
112 VarPointer var;
113 };
114
115 uint16_t mIsVar : 1;
116 uint16_t mVersion : 14;
117 uint8_t mShaders;
118 uint8_t mExtensionIndex;
119 SymbolOrVar mSymbolOrVar;
120 };
121
SymbolRule(int version,Shader shaders,size_t extensionIndex,const TSymbol * symbol)122 constexpr SymbolRule::SymbolRule(int version,
123 Shader shaders,
124 size_t extensionIndex,
125 const TSymbol *symbol)
126 : mIsVar(0u),
127 mVersion(static_cast<uint16_t>(version)),
128 mShaders(static_cast<uint8_t>(shaders)),
129 mExtensionIndex(extensionIndex),
130 mSymbolOrVar(symbol)
131 {}
132
SymbolRule(int version,Shader shaders,size_t extensionIndex,VarPointer resourceVar)133 constexpr SymbolRule::SymbolRule(int version,
134 Shader shaders,
135 size_t extensionIndex,
136 VarPointer resourceVar)
137 : mIsVar(1u),
138 mVersion(static_cast<uint16_t>(version)),
139 mShaders(static_cast<uint8_t>(shaders)),
140 mExtensionIndex(extensionIndex),
141 mSymbolOrVar(resourceVar)
142 {}
143
144 template <int version, Shader shaders, size_t extensionIndex, typename T>
145 // static
Get(T value)146 constexpr SymbolRule SymbolRule::Get(T value)
147 {
148 static_assert(version < 0x4000u, "version OOR");
149 static_assert(static_cast<uint8_t>(shaders) < 0xFFu, "shaders OOR");
150 static_assert(static_cast<uint8_t>(extensionIndex) < 0xFF, "extensionIndex OOR");
151 return SymbolRule(version, shaders, extensionIndex, value);
152 }
153
154 const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
155 int shaderVersion,
156 sh::GLenum shaderType,
157 const ShBuiltInResources &resources,
158 const TSymbolTableBase &symbolTable,
159 const SymbolRule *rules,
160 uint16_t startIndex,
161 uint16_t endIndex);
162
163 class UnmangledEntry
164 {
165 public:
166 template <size_t ESSLExtCount>
167 constexpr UnmangledEntry(const char *name,
168 const std::array<TExtension, ESSLExtCount> &esslExtensions,
169 int esslVersion,
170 Shader shaderType);
171
172 bool matches(const ImmutableString &name,
173 ShShaderSpec shaderSpec,
174 int shaderVersion,
175 sh::GLenum shaderType,
176 const TExtensionBehavior &extensions) const;
177
178 private:
179 const char *mName;
180 std::array<TExtension, 2u> mESSLExtensions;
181 uint8_t mShaderType;
182 uint16_t mESSLVersion;
183 };
184
185 template <size_t ESSLExtCount>
UnmangledEntry(const char * name,const std::array<TExtension,ESSLExtCount> & esslExtensions,int esslVersion,Shader shaderType)186 constexpr UnmangledEntry::UnmangledEntry(const char *name,
187 const std::array<TExtension, ESSLExtCount> &esslExtensions,
188 int esslVersion,
189 Shader shaderType)
190 : mName(name),
191 mESSLExtensions{(ESSLExtCount >= 1) ? esslExtensions[0] : TExtension::UNDEFINED,
192 (ESSLExtCount >= 2) ? esslExtensions[1] : TExtension::UNDEFINED},
193 mShaderType(static_cast<uint8_t>(shaderType)),
194 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
195 : static_cast<uint16_t>(esslVersion))
196 {}
197
198 class TSymbolTable : angle::NonCopyable, TSymbolTableBase
199 {
200 public:
201 TSymbolTable();
202 // To start using the symbol table after construction:
203 // * initializeBuiltIns() needs to be called.
204 // * push() needs to be called to push the global level.
205
206 ~TSymbolTable();
207
208 bool isEmpty() const;
209 bool atGlobalLevel() const;
210
211 void push();
212 void pop();
213
214 // Declare a non-function symbol at the current scope. Return true in case the declaration was
215 // successful, and false if the declaration failed due to redefinition.
216 bool declare(TSymbol *symbol);
217
218 // Only used to declare internal variables.
219 bool declareInternal(TSymbol *symbol);
220
221 // Functions are always declared at global scope.
222 void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
223
224 // These return the TFunction pointer to keep using to refer to this function.
225 const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
226 bool *hadPrototypeDeclarationOut) const;
227 const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
228 bool *wasDefinedOut) const;
229
230 // Return false if the gl_in array size has already been initialized with a mismatching value.
231 bool setGlInArraySize(unsigned int inputArraySize);
232 TVariable *getGlInVariableWithArraySize() const;
233
234 const TVariable *gl_FragData() const;
235 const TVariable *gl_SecondaryFragDataEXT() const;
236
237 void markStaticRead(const TVariable &variable);
238 void markStaticWrite(const TVariable &variable);
239
240 // Note: Should not call this for constant variables.
241 bool isStaticallyUsed(const TVariable &variable) const;
242
243 // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
244 // with a reference to a short-lived char * is fine to pass here.
245 const TSymbol *find(const ImmutableString &name, int shaderVersion) const;
246
247 const TSymbol *findUserDefined(const ImmutableString &name) const;
248
249 TFunction *findUserDefinedFunction(const ImmutableString &name) const;
250
251 const TSymbol *findGlobal(const ImmutableString &name) const;
252
253 const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const;
254
255 void setDefaultPrecision(TBasicType type, TPrecision prec);
256
257 // Searches down the precisionStack for a precision qualifier
258 // for the specified TBasicType
259 TPrecision getDefaultPrecision(TBasicType type) const;
260
261 // This records invariant varyings declared through "invariant varying_name;".
262 void addInvariantVarying(const TVariable &variable);
263
264 // If this returns false, the varying could still be invariant if it is set as invariant during
265 // the varying variable declaration - this piece of information is stored in the variable's
266 // type, not here.
267 bool isVaryingInvariant(const TVariable &variable) const;
268
269 void setGlobalInvariant(bool invariant);
270
nextUniqueId()271 const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
272
273 // Gets the built-in accessible by a shader with the specified version, if any.
274 bool isUnmangledBuiltInName(const ImmutableString &name,
275 int shaderVersion,
276 const TExtensionBehavior &extensions) const;
277
278 void initializeBuiltIns(sh::GLenum type,
279 ShShaderSpec spec,
280 const ShBuiltInResources &resources);
281 void clearCompilationResults();
282
getShaderSpec()283 ShShaderSpec getShaderSpec() const { return mShaderSpec; }
284
285 private:
286 friend class TSymbolUniqueId;
287
288 struct VariableMetadata
289 {
290 VariableMetadata();
291 bool staticRead;
292 bool staticWrite;
293 bool invariant;
294 };
295
296 int nextUniqueIdValue();
297
298 class TSymbolTableLevel;
299
300 void initSamplerDefaultPrecision(TBasicType samplerType);
301
302 void initializeBuiltInVariables(sh::GLenum shaderType,
303 ShShaderSpec spec,
304 const ShBuiltInResources &resources);
305
306 VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable);
307
308 std::vector<std::unique_ptr<TSymbolTableLevel>> mTable;
309
310 // There's one precision stack level for predefined precisions and then one level for each scope
311 // in table.
312 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
313 std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack;
314
315 bool mGlobalInvariant;
316
317 int mUniqueIdCounter;
318
319 static constexpr int kFirstUserDefinedSymbolId = 3000;
320
321 sh::GLenum mShaderType;
322 ShShaderSpec mShaderSpec;
323 ShBuiltInResources mResources;
324
325 // Indexed by unique id. Map instead of vector since the variables are fairly sparse.
326 std::map<int, VariableMetadata> mVariableMetadata;
327
328 // Store gl_in variable with its array size once the array size can be determined. The array
329 // size can also be checked against latter input primitive type declaration.
330 TVariable *mGlInVariableWithArraySize;
331 friend struct SymbolIdChecker;
332 };
333
334 } // namespace sh
335
336 #endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
337