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 enum class Spec : uint8_t
72 {
73 GLSL,
74 ESSL
75 };
76
77 constexpr uint16_t kESSL1Only = 100;
78 // Some built-ins from Vulkan GLSL are made available to ESSL for use in tree transformations. This
79 // (invalid) shader version is used to select those built-ins. This value needs to be larger than
80 // all other shader versions.
81 constexpr uint16_t kESSLVulkanOnly = 0x3FFF;
82
83 // The version assigned to |kESSLVulkanOnly| should be good until OpenGL 20.0!
84 static_assert(kESSLVulkanOnly > 2000, "Accidentally exposing Vulkan built-ins in OpenGL");
85
86 static_assert(offsetof(ShBuiltInResources, OES_standard_derivatives) != 0,
87 "Update SymbolTable extension logic");
88
89 #define EXT_INDEX(Ext) (offsetof(ShBuiltInResources, Ext) / sizeof(int))
90
91 class SymbolRule
92 {
93 public:
94 const TSymbol *get(ShShaderSpec shaderSpec,
95 int shaderVersion,
96 sh::GLenum shaderType,
97 const ShBuiltInResources &resources,
98 const TSymbolTableBase &symbolTable) const;
99
100 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
101 constexpr static SymbolRule Get(T value);
102
103 private:
104 constexpr SymbolRule(Spec spec,
105 int version,
106 Shader shaders,
107 size_t extensionIndex,
108 const TSymbol *symbol);
109
110 constexpr SymbolRule(Spec spec,
111 int version,
112 Shader shaders,
113 size_t extensionIndex,
114 VarPointer resourceVar);
115
116 union SymbolOrVar
117 {
SymbolOrVar(const TSymbol * symbolIn)118 constexpr SymbolOrVar(const TSymbol *symbolIn) : symbol(symbolIn) {}
SymbolOrVar(VarPointer varIn)119 constexpr SymbolOrVar(VarPointer varIn) : var(varIn) {}
120
121 const TSymbol *symbol;
122 VarPointer var;
123 };
124
125 uint16_t mIsDesktop : 1;
126 uint16_t mIsVar : 1;
127 uint16_t mVersion : 14;
128 uint8_t mShaders;
129 uint8_t mExtensionIndex;
130 SymbolOrVar mSymbolOrVar;
131 };
132
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,const TSymbol * symbol)133 constexpr SymbolRule::SymbolRule(Spec spec,
134 int version,
135 Shader shaders,
136 size_t extensionIndex,
137 const TSymbol *symbol)
138 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
139 mIsVar(0u),
140 mVersion(static_cast<uint16_t>(version)),
141 mShaders(static_cast<uint8_t>(shaders)),
142 mExtensionIndex(extensionIndex),
143 mSymbolOrVar(symbol)
144 {}
145
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,VarPointer resourceVar)146 constexpr SymbolRule::SymbolRule(Spec spec,
147 int version,
148 Shader shaders,
149 size_t extensionIndex,
150 VarPointer resourceVar)
151 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
152 mIsVar(1u),
153 mVersion(static_cast<uint16_t>(version)),
154 mShaders(static_cast<uint8_t>(shaders)),
155 mExtensionIndex(extensionIndex),
156 mSymbolOrVar(resourceVar)
157 {}
158
159 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
160 // static
Get(T value)161 constexpr SymbolRule SymbolRule::Get(T value)
162 {
163 static_assert(version < 0x4000u, "version OOR");
164 static_assert(static_cast<uint8_t>(shaders) < 0xFFu, "shaders OOR");
165 static_assert(static_cast<uint8_t>(extensionIndex) < 0xFF, "extensionIndex OOR");
166 return SymbolRule(spec, version, shaders, extensionIndex, value);
167 }
168
169 const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
170 int shaderVersion,
171 sh::GLenum shaderType,
172 const ShBuiltInResources &resources,
173 const TSymbolTableBase &symbolTable,
174 const SymbolRule *rules,
175 uint16_t startIndex,
176 uint16_t endIndex);
177
178 class UnmangledEntry
179 {
180 public:
181 template <size_t ESSLExtCount>
182 constexpr UnmangledEntry(const char *name,
183 const std::array<TExtension, ESSLExtCount> &esslExtensions,
184 TExtension glslExtension,
185 int esslVersion,
186 int glslVersion,
187 Shader shaderType);
188
189 bool matches(const ImmutableString &name,
190 ShShaderSpec shaderSpec,
191 int shaderVersion,
192 sh::GLenum shaderType,
193 const TExtensionBehavior &extensions) const;
194
195 private:
196 const char *mName;
197 std::array<TExtension, 2u> mESSLExtensions;
198 TExtension mGLSLExtension;
199 uint8_t mShaderType;
200 uint16_t mESSLVersion;
201 uint16_t mGLSLVersion;
202 };
203
204 template <>
UnmangledEntry(const char * name,const std::array<TExtension,1> & esslExtensions,TExtension glslExtension,int esslVersion,int glslVersion,Shader shaderType)205 constexpr UnmangledEntry::UnmangledEntry(const char *name,
206 const std::array<TExtension, 1> &esslExtensions,
207 TExtension glslExtension,
208 int esslVersion,
209 int glslVersion,
210 Shader shaderType)
211 : mName(name),
212 mESSLExtensions{esslExtensions[0], TExtension::UNDEFINED},
213 mGLSLExtension(glslExtension),
214 mShaderType(static_cast<uint8_t>(shaderType)),
215 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
216 : static_cast<uint16_t>(esslVersion)),
217 mGLSLVersion(glslVersion < 0 ? std::numeric_limits<uint16_t>::max()
218 : static_cast<uint16_t>(glslVersion))
219 {}
220
221 // Note: Until C++17, std::array functions are not constexpr, so the constructor is necessarily
222 // duplicated.
223 template <>
UnmangledEntry(const char * name,const std::array<TExtension,2> & esslExtensions,TExtension glslExtension,int esslVersion,int glslVersion,Shader shaderType)224 constexpr UnmangledEntry::UnmangledEntry(const char *name,
225 const std::array<TExtension, 2> &esslExtensions,
226 TExtension glslExtension,
227 int esslVersion,
228 int glslVersion,
229 Shader shaderType)
230 : mName(name),
231 mESSLExtensions{esslExtensions[0], esslExtensions[1]},
232 mGLSLExtension(glslExtension),
233 mShaderType(static_cast<uint8_t>(shaderType)),
234 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
235 : static_cast<uint16_t>(esslVersion)),
236 mGLSLVersion(glslVersion < 0 ? std::numeric_limits<uint16_t>::max()
237 : static_cast<uint16_t>(glslVersion))
238 {}
239
240 class TSymbolTable : angle::NonCopyable, TSymbolTableBase
241 {
242 public:
243 TSymbolTable();
244 // To start using the symbol table after construction:
245 // * initializeBuiltIns() needs to be called.
246 // * push() needs to be called to push the global level.
247
248 ~TSymbolTable();
249
250 bool isEmpty() const;
251 bool atGlobalLevel() const;
252
253 void push();
254 void pop();
255
256 // Declare a non-function symbol at the current scope. Return true in case the declaration was
257 // successful, and false if the declaration failed due to redefinition.
258 bool declare(TSymbol *symbol);
259
260 // Only used to declare internal variables.
261 bool declareInternal(TSymbol *symbol);
262
263 // Functions are always declared at global scope.
264 void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
265
266 // These return the TFunction pointer to keep using to refer to this function.
267 const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
268 bool *hadPrototypeDeclarationOut) const;
269 const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
270 bool *wasDefinedOut) const;
271
272 // Return false if the gl_in array size has already been initialized with a mismatching value.
273 bool setGlInArraySize(unsigned int inputArraySize);
274 TVariable *getGlInVariableWithArraySize() const;
275
276 const TVariable *gl_FragData() const;
277 const TVariable *gl_SecondaryFragDataEXT() const;
278
279 void markStaticRead(const TVariable &variable);
280 void markStaticWrite(const TVariable &variable);
281
282 // Note: Should not call this for constant variables.
283 bool isStaticallyUsed(const TVariable &variable) const;
284
285 // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
286 // with a reference to a short-lived char * is fine to pass here.
287 const TSymbol *find(const ImmutableString &name, int shaderVersion) const;
288
289 const TSymbol *findUserDefined(const ImmutableString &name) const;
290
291 TFunction *findUserDefinedFunction(const ImmutableString &name) const;
292
293 const TSymbol *findGlobal(const ImmutableString &name) const;
294 const TSymbol *findGlobalWithConversion(const std::vector<ImmutableString> &names) const;
295
296 const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const;
297 const TSymbol *findBuiltInWithConversion(const std::vector<ImmutableString> &names,
298 int shaderVersion) const;
299
300 void setDefaultPrecision(TBasicType type, TPrecision prec);
301
302 // Searches down the precisionStack for a precision qualifier
303 // for the specified TBasicType
304 TPrecision getDefaultPrecision(TBasicType type) const;
305
306 // This records invariant varyings declared through "invariant varying_name;".
307 void addInvariantVarying(const TVariable &variable);
308
309 // If this returns false, the varying could still be invariant if it is set as invariant during
310 // the varying variable declaration - this piece of information is stored in the variable's
311 // type, not here.
312 bool isVaryingInvariant(const TVariable &variable) const;
313
314 void setGlobalInvariant(bool invariant);
315
nextUniqueId()316 const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
317
318 // Gets the built-in accessible by a shader with the specified version, if any.
319 bool isUnmangledBuiltInName(const ImmutableString &name,
320 int shaderVersion,
321 const TExtensionBehavior &extensions) const;
322
323 void initializeBuiltIns(sh::GLenum type,
324 ShShaderSpec spec,
325 const ShBuiltInResources &resources);
326 void clearCompilationResults();
327
getDefaultUniformsBindingIndex()328 int getDefaultUniformsBindingIndex() const { return mResources.DefaultUniformsBindingIndex; }
getDriverUniformsBindingIndex()329 int getDriverUniformsBindingIndex() const { return mResources.DriverUniformsBindingIndex; }
getUBOArgumentBufferBindingIndex()330 int getUBOArgumentBufferBindingIndex() const
331 {
332 return mResources.UBOArgumentBufferBindingIndex;
333 }
334
335 private:
336 friend class TSymbolUniqueId;
337
338 struct VariableMetadata
339 {
340 VariableMetadata();
341 bool staticRead;
342 bool staticWrite;
343 bool invariant;
344 };
345
346 int nextUniqueIdValue();
347
348 class TSymbolTableLevel;
349
350 void initSamplerDefaultPrecision(TBasicType samplerType);
351
352 void initializeBuiltInVariables(sh::GLenum shaderType,
353 ShShaderSpec spec,
354 const ShBuiltInResources &resources);
355
356 VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable);
357
358 std::vector<std::unique_ptr<TSymbolTableLevel>> mTable;
359
360 // There's one precision stack level for predefined precisions and then one level for each scope
361 // in table.
362 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
363 std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack;
364
365 bool mGlobalInvariant;
366
367 int mUniqueIdCounter;
368
369 static const int kLastBuiltInId;
370
371 sh::GLenum mShaderType;
372 ShShaderSpec mShaderSpec;
373 ShBuiltInResources mResources;
374
375 // Indexed by unique id. Map instead of vector since the variables are fairly sparse.
376 std::map<int, VariableMetadata> mVariableMetadata;
377
378 // Store gl_in variable with its array size once the array size can be determined. The array
379 // size can also be checked against latter input primitive type declaration.
380 TVariable *mGlInVariableWithArraySize;
381 };
382
383 } // namespace sh
384
385 #endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
386