1 //
2 // Copyright 2020 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_TRANSLATORMETALDIRECT_SYMBOLENV_H_
8 #define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
9 
10 #include <unordered_set>
11 
12 #include "compiler/translator/Compiler.h"
13 #include "compiler/translator/TranslatorMetalDirect/Name.h"
14 #include "compiler/translator/TranslatorMetalDirect/Reference.h"
15 #include "compiler/translator/Types.h"
16 
17 namespace sh
18 {
19 
20 enum class AddressSpace
21 {
22     Constant,
23     Device,
24     Thread,
25 };
26 
27 char const *toString(AddressSpace space);
28 
29 class VarField
30 {
31   public:
VarField(const TVariable & var)32     VarField(const TVariable &var) : mVariable(&var) {}
VarField(const TField & field)33     VarField(const TField &field) : mField(&field) {}
34 
variable()35     ANGLE_INLINE const TVariable *variable() const { return mVariable; }
36 
field()37     ANGLE_INLINE const TField *field() const { return mField; }
38 
39     ANGLE_INLINE bool operator==(const VarField &other) const
40     {
41         return mVariable == other.mVariable && mField == other.mField;
42     }
43 
44   private:
45     const TVariable *mVariable = nullptr;
46     const TField *mField       = nullptr;
47 };
48 
49 }  // namespace sh
50 
51 namespace std
52 {
53 
54 template <>
55 struct hash<sh::VarField>
56 {
57     size_t operator()(const sh::VarField &x) const
58     {
59         const sh::TVariable *var = x.variable();
60         if (var)
61         {
62             return std::hash<const sh::TVariable *>()(var);
63         }
64         const sh::TField *field = x.field();
65         return std::hash<const sh::TField *>()(field);
66     }
67 };
68 
69 }  // namespace std
70 
71 namespace sh
72 {
73 
74 class TemplateArg
75 {
76   public:
77     enum class Kind
78     {
79         Bool,
80         Int,
81         UInt,
82         Type,
83     };
84 
85     union Value
86     {
87         Value(bool value) : b(value) {}
88         Value(int value) : i(value) {}
89         Value(unsigned value) : u(value) {}
90         Value(const TType &value) : t(&value) {}
91 
92         bool b;
93         int i;
94         unsigned u;
95         const TType *t;
96     };
97 
98     TemplateArg(bool value);
99     TemplateArg(int value);
100     TemplateArg(unsigned value);
101     TemplateArg(const TType &value);
102 
103     bool operator==(const TemplateArg &other) const;
104     bool operator<(const TemplateArg &other) const;
105 
106     Kind kind() const { return mKind; }
107     Value value() const { return mValue; }
108 
109   public:
110     Kind mKind;
111     Value mValue;
112 };
113 
114 // An environment for creating and uniquely sharing TSymbol objects.
115 class SymbolEnv
116 {
117     class TemplateName
118     {
119         Name baseName;
120         std::vector<TemplateArg> templateArgs;
121 
122       public:
123         bool operator==(const TemplateName &other) const;
124         bool operator<(const TemplateName &other) const;
125 
126         bool empty() const;
127         void clear();
128 
129         Name fullName(std::string &buffer) const;
130 
131         void assign(const Name &name, size_t argCount, const TemplateArg *args);
132     };
133 
134     using TypeRef        = CRef<TType>;
135     using Sig            = std::vector<TypeRef>;  // Param0, Param1, ... ParamN, Return
136     using SigToFunc      = std::map<Sig, TFunction *>;
137     using Overloads      = std::map<TemplateName, SigToFunc>;
138     using AngleStructs   = std::map<ImmutableString, TStructure *>;
139     using TextureStructs = std::map<TBasicType, TStructure *>;
140 
141   public:
142     SymbolEnv(TCompiler &compiler, TIntermBlock &root);
143 
144     TSymbolTable &symbolTable() { return mSymbolTable; }
145 
146     // There exist Angle rewrites that can lead to incoherent structs
147     //
148     // Example
149     //    struct A { ... }
150     //    struct B { A' a; } // A' has same name as A but is not identical.
151     // becomes
152     //    struct A { ... }
153     //    struct B { A a; }
154     //
155     // This notably happens when A contains a sampler in the original GLSL code but is rewritten to
156     // not have a sampler, yet the A' struct field still contains the sampler field.
157     const TStructure &remap(const TStructure &s) const;
158 
159     // Like `TStructure &remap(const TStructure &s)` but additionally maps null to null.
160     const TStructure *remap(const TStructure *s) const;
161 
162     const TFunction &getFunctionOverload(const Name &name,
163                                          const TType &returnType,
164                                          size_t paramCount,
165                                          const TType **paramTypes,
166                                          size_t templateArgCount         = 0,
167                                          const TemplateArg *templateArgs = nullptr);
168 
169     TIntermAggregate &callFunctionOverload(const Name &name,
170                                            const TType &returnType,
171                                            TIntermSequence &args,
172                                            size_t templateArgCount         = 0,
173                                            const TemplateArg *templateArgs = nullptr);
174 
175     const TStructure &newStructure(const Name &name, TFieldList &fields);
176 
177     const TStructure &getTextureEnv(TBasicType samplerType);
178     const TStructure &getSamplerStruct();
179 
180     void markAsPointer(VarField x, AddressSpace space);
181     void removePointer(VarField x);
182     const AddressSpace *isPointer(VarField x) const;
183 
184     void markAsReference(VarField x, AddressSpace space);
185     void removeAsReference(VarField x);
186     const AddressSpace *isReference(VarField x) const;
187 
188     void markAsPacked(const TField &field);
189     bool isPacked(const TField &field) const;
190 
191     void markAsUBO(VarField x);
192     bool isUBO(VarField x) const;
193 
194   private:
195     const TFunction &getFunctionOverloadImpl();
196 
197     void markSpace(VarField x, AddressSpace space, std::unordered_map<VarField, AddressSpace> &map);
198     void removeSpace(VarField x, std::unordered_map<VarField, AddressSpace> &map);
199     const AddressSpace *isSpace(VarField x,
200                                 const std::unordered_map<VarField, AddressSpace> &map) const;
201 
202   private:
203     TSymbolTable &mSymbolTable;
204 
205     std::map<Name, const TStructure *> mNameToStruct;
206     Overloads mOverloads;
207     Sig mReusableSigBuffer;
208     TemplateName mReusableTemplateNameBuffer;
209     std::string mReusableStringBuffer;
210 
211     AngleStructs mAngleStructs;
212     std::unordered_map<TBasicType, const TStructure *> mTextureEnvs;
213     const TStructure *mSampler = nullptr;
214 
215     std::unordered_map<VarField, AddressSpace> mPointers;
216     std::unordered_map<VarField, AddressSpace> mReferences;
217     std::unordered_set<const TField *> mPackedFields;
218     std::unordered_set<VarField> mUboFields;
219 };
220 
221 Name GetTextureTypeName(TBasicType samplerType);
222 
223 }  // namespace sh
224 
225 #endif  // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_SYMBOLENV_H_
226