Implement atomic ops, bit conversions, fix fwidth stage mask, fix saturate dest modifier.
[platform/upstream/glslang.git] / hlsl / hlslParseables.cpp
1 //
2 //Copyright (C) 2016 LunarG, Inc.
3 //
4 //All rights reserved.
5 //
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
8 //are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //POSSIBILITY OF SUCH DAMAGE.
34 //
35
36 //
37 // Create strings that declare built-in definitions, add built-ins programmatically 
38 // that cannot be expressed in the strings, and establish mappings between
39 // built-in functions and operators.
40 //
41 // Where to put a built-in:
42 //   TBuiltInParseablesHlsl::initialize(version,profile) context-independent textual built-ins; add them to the right string
43 //   TBuiltInParseablesHlsl::initialize(resources,...)   context-dependent textual built-ins; add them to the right string
44 //   TBuiltInParseablesHlsl::identifyBuiltIns(...,symbolTable) context-independent programmatic additions/mappings to the symbol table,
45 //                                                including identifying what extensions are needed if a version does not allow a symbol
46 //   TBuiltInParseablesHlsl::identifyBuiltIns(...,symbolTable, resources) context-dependent programmatic additions/mappings to the
47 //                                                symbol table, including identifying what extensions are needed if a version does
48 //                                                not allow a symbol
49 //
50
51 #include "hlslParseables.h"
52 #include <cctype>
53 #include <utility>
54
55 namespace {  // anonymous namespace functions
56
57 const char* BaseTypeName(const char* argOrder, const char* scalarName, const char* vecName, const char* matName)
58 {
59     switch (*argOrder) {
60     case 'S': return scalarName;
61     case 'V': return vecName;
62     case 'M': return matName;
63     default:  return "UNKNOWN_TYPE";
64     }
65 }
66     
67 // Create and return a type name.  This is done in GLSL, not HLSL conventions, until such
68 // time as builtins are parsed using the HLSL parser.
69 //
70 //    order:   S = scalar, V = vector, M = matrix
71 //    argType: F = float, D = double, I = int, U = uint, B = bool, S = sampler
72 //    dim0 = vector dimension, or matrix 1st dimension
73 //    dim1 = matrix 2nd dimension
74 glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, const char* argType, int dim0, int dim1)
75 {
76     const bool transpose = (argOrder[0] == '^');
77
78     // Take transpose of matrix dimensions
79     if (transpose) {
80         std::swap(dim0, dim1);
81         ++argOrder;
82     }
83
84     switch (*argType) {
85     case '-': s += "void"; break;
86     case 'F': s += BaseTypeName(argOrder, "float",   "vec",     "mat");  break;
87     case 'D': s += BaseTypeName(argOrder, "double",  "dvec",    "dmat"); break;
88     case 'I': s += BaseTypeName(argOrder, "int",     "ivec",    "imat"); break;
89     case 'U': s += BaseTypeName(argOrder, "uint",    "uvec",    "umat"); break;
90     case 'B': s += BaseTypeName(argOrder, "bool",    "bvec",    "bmat"); break;
91     case 'S': s += BaseTypeName(argOrder, "sampler", "sampler", "sampler"); break; // TODO: 
92     default:  s += "UNKNOWN_TYPE"; break;
93     }
94
95     // handle fixed vector sizes, such as float3, and only ever 3.
96     const int fixedVecSize = isdigit(argOrder[1]) ? (argOrder[1] - '0') : 0;
97     if (fixedVecSize != 0)
98         dim0 = dim1 = fixedVecSize;
99
100     // Add sampler dimensions
101     if (*argType == 'S') {
102         switch (dim0) {
103         case 1: s += "1D";   break;
104         case 2: s += "2D";   break;
105         case 3: s += "3D";   break;
106         case 4: s += "Cube"; break;
107         default: s += "UNKNOWN_SAMPLER"; break;
108         }
109     }
110
111     // verify dimensions
112     if ((*argOrder == 'V' || *argOrder == 'M') && (dim0 < 1 || dim0 > 4) ||
113         (*argOrder == 'M' && (dim1 < 1 || dim1 > 4))) {
114         s += "UNKNOWN_DIMENSION";
115         return s;
116     }
117
118     switch (*argOrder) {
119     case '-': break;  // no dimensions for voids
120     case 'S': break;  // no dimensions on scalars
121     case 'V': s += ('0' + dim0); break;
122     case 'M': s += ('0' + dim0); s += 'x'; s += ('0' + dim1); break;
123     }
124
125     return s;
126 }
127
128 // TODO: the GLSL parser is currently used to parse HLSL prototypes.  However, many valid HLSL prototypes
129 // are not valid GLSL prototypes.  This rejects the invalid ones.  Thus, there is a single switch below
130 // to enable creation of the entire HLSL space.
131 inline bool IsValidGlsl(const char* cname, char retOrder, char retType, char argOrder, char argType,
132                         int dim0, int dim1, int dim0Max, int dim1Max)
133 {
134     const bool isVec = dim0Max > 1 || argType == 'V';
135     const bool isMat = dim1Max > 1 || argType == 'M';
136
137     if (argType == 'D'                  ||  // avoid double args
138         retType == 'D'                  ||  // avoid double return
139         (isVec && dim0 == 1)            ||  // avoid vec1
140         (isMat && dim0 == 1 && dim1 == 1))  // avoid mat1x1
141         return false;
142
143     const std::string name(cname);  // for ease of comparison. slow, but temporary, until HLSL parser is online.
144                                 
145     if (isMat && dim0 != dim1)  // TODO: avoid mats until we find the right GLSL profile
146         return false;
147
148     if (isMat && (argType == 'I' || argType == 'U' || argType == 'B') ||
149         retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B'))
150         return false;
151
152     if (name == "GetRenderTargetSamplePosition" ||
153         name == "tex1D" ||
154         name == "tex1Dgrad")
155         return false;
156
157     return true;
158 }
159
160
161 // Return true for the end of a single argument key, which can be the end of the string, or
162 // the comma separator.
163 inline bool IsEndOfArg(const char* arg)
164 {
165     return arg == nullptr || *arg == '\0' || *arg == ',';
166 }
167
168
169 // return position of end of argument specifier
170 inline const char* FindEndOfArg(const char* arg)
171 {
172     while (!IsEndOfArg(arg))
173         ++arg;
174
175     return *arg == '\0' ? nullptr : arg;
176 }
177
178
179 // Return pointer to beginning of Nth argument specifier in the string.
180 inline const char* NthArg(const char* arg, int n)
181 {
182     for (int x=0; x<n && arg; ++x)
183         if ((arg = FindEndOfArg(arg)) != nullptr)
184             ++arg;  // skip arg separator
185
186     return arg;
187 }
188
189 inline void FindVectorMatrixBounds(const char* argOrder, int fixedVecSize, int& dim0Min, int& dim0Max, int& dim1Min, int& dim1Max)
190 {
191     for (int arg = 0; ; ++arg) {
192         const char* nthArgOrder(NthArg(argOrder, arg));
193         if (nthArgOrder == nullptr)
194             break;
195         else if (*nthArgOrder == 'V')
196             dim0Max = 4;
197         else if (*nthArgOrder == 'M')
198             dim0Max = dim1Max = 4;
199     }
200
201     if (fixedVecSize > 0) // handle fixed sized vectors
202         dim0Min = dim0Max = fixedVecSize;
203 }
204     
205 } // end anonymous namespace
206
207 namespace glslang {
208
209 TBuiltInParseablesHlsl::TBuiltInParseablesHlsl()
210 {
211 }
212
213 //
214 // Add all context-independent built-in functions and variables that are present
215 // for the given version and profile.  Share common ones across stages, otherwise
216 // make stage-specific entries.
217 //
218 // Most built-ins variables can be added as simple text strings.  Some need to
219 // be added programmatically, which is done later in IdentifyBuiltIns() below.
220 //
221 void TBuiltInParseablesHlsl::initialize(int version, EProfile profile, int spv, int vulkan)
222 {
223     static const EShLanguageMask EShLangAll = EShLanguageMask(EShLangCount - 1);
224
225     // This structure encodes the prototype information for each HLSL intrinsic.
226     // Because explicit enumeration would be cumbersome, it's procedurally generated.
227     // orderKey can be:
228     //   S = scalar, V = vector, M = matrix, - = void
229     // typekey can be:
230     //   D = double, F = float, U = uint, I = int, B = bool, S = sampler, - = void
231     // An empty order or type key repeats the first one.  E.g: SVM,, means 3 args each of SVM.
232     // '>' as first letter of order creates an output paremeter
233     // '<' as first letter of order creates an input paremeter
234     // '^' as first letter of order takes transpose dimensions
235
236     static const struct {
237         const char*   name;      // intrinsic name
238         const char*   retOrder;  // return type key: empty matches order of 1st argument
239         const char*   retType;   // return type key: empty matches type of 1st argument
240         const char*   argOrder;  // argument order key
241         const char*   argType;   // argument type key
242         unsigned int  stage;     // stage mask
243     } hlslIntrinsics[] = {
244         // name                               retOrd   retType    argOrder      argType   stage mask
245         // -----------------------------------------------------------------------------------------------
246         { "abort",                            nullptr, nullptr,   "-",          "-",      EShLangAll },
247         { "abs",                              nullptr, nullptr,   "SVM",        "DFUI",   EShLangAll },
248         { "acos",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
249         { "all",                              "S",    "B",        "SVM",        "BFI",    EShLangAll },
250         { "AllMemoryBarrier",                 nullptr, nullptr,   "-",          "-",      EShLangComputeMask },
251         { "AllMemoryBarrierWithGroupSync",    nullptr, nullptr,   "-",          "-",      EShLangComputeMask },
252         { "any",                              "S",     "B",       "SVM",        "BFI",    EShLangAll },
253         { "asdouble",                         "S",     "D",       "S,",         "U,",     EShLangAll },
254         { "asdouble",                         "V2",    "D",       "V2,",        "U,",     EShLangAll },
255         { "asfloat",                          nullptr, "F",       "SVM",        "BFIU",   EShLangAll },
256         { "asin",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
257         { "asint",                            nullptr, "I",       "SVM",        "FU",     EShLangAll },
258         { "asuint",                           nullptr, "U",       "SVM",        "FU",     EShLangAll },
259         { "atan",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
260         { "atan2",                            nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
261         { "ceil",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
262         { "CheckAccessFullyMapped",           "S",     "B" ,      "S",          "U",      EShLangFragmentMask | EShLangComputeMask },
263         { "clamp",                            nullptr, nullptr,   "SVM,,",      "FUI,,",  EShLangAll },
264         { "clip",                             "-",     "-",       "SVM",        "F",      EShLangFragmentMask },
265         { "cos",                              nullptr, nullptr,   "SVM",        "F",      EShLangAll },
266         { "cosh",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
267         { "countbits",                        nullptr, nullptr,   "SV",         "U",      EShLangAll },
268         { "cross",                            nullptr, nullptr,   "V3,",        "F,",     EShLangAll },
269         { "D3DCOLORtoUBYTE4",                 "V4",    "I",       "V4",         "F",      EShLangAll },
270         { "ddx",                              nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
271         { "ddx_coarse",                       nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
272         { "ddx_fine",                         nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
273         { "ddy",                              nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
274         { "ddy_coarse",                       nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
275         { "ddy_fine",                         nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
276         { "degrees",                          nullptr, nullptr,   "SVM",        "F",      EShLangAll },
277         { "determinant",                      "S",     "F",       "M",          "F",      EShLangAll },
278         { "DeviceMemoryBarrier",              nullptr, nullptr,   "-",          "-",      EShLangFragmentMask | EShLangComputeMask },
279         { "DeviceMemoryBarrierWithGroupSync", nullptr, nullptr,   "-",          "-",      EShLangComputeMask },
280         { "distance",                         "S",     "F",       "V,",         "F,",     EShLangAll },
281         { "dot",                              "S",     nullptr,   "V,",         "FI,",    EShLangAll },
282         { "dst",                              nullptr, nullptr,   "V4,V4",      "F,",     EShLangAll },
283         // { "errorf",                           "-",     "-",       "",         "",     EShLangAll }, TODO: varargs
284         { "EvaluateAttributeAtCentroid",      nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
285         { "EvaluateAttributeAtSample",        nullptr, nullptr,   "SVM,S",      "F,U",    EShLangFragmentMask },
286         { "EvaluateAttributeSnapped",         nullptr, nullptr,   "SVM,V2",     "F,F",    EShLangFragmentMask },
287         { "exp",                              nullptr, nullptr,   "SVM",        "F",      EShLangAll },
288         { "exp2",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
289         { "f16tof32",                         nullptr, "F",       "SV",         "U",      EShLangAll },
290         { "f32tof16",                         nullptr, "U",       "SV",         "F",      EShLangAll },
291         { "faceforward",                      nullptr, nullptr,   "V,,",        "F,,",    EShLangAll },
292         { "firstbithigh",                     nullptr, nullptr,   "SV",         "UI",     EShLangAll },
293         { "firstbitlow",                      nullptr, nullptr,   "SV",         "UI",     EShLangAll },
294         { "floor",                            nullptr, nullptr,   "SVM",        "F",      EShLangAll },
295         { "fma",                              nullptr, nullptr,   "SVM,,",      "D,,",    EShLangAll },
296         { "fmod",                             nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
297         { "frac",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
298         { "frexp",                            nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
299         { "fwidth",                           nullptr, nullptr,   "SVM",        "F",      EShLangFragmentMask },
300         { "GetRenderTargetSampleCount",       "S",     "U",       "-",          "-",      EShLangAll },
301         { "GetRenderTargetSamplePosition",    "V2",    "F",       "V1",         "I",      EShLangAll },
302         { "GroupMemoryBarrier",               nullptr, nullptr,   "-",          "-",      EShLangComputeMask },
303         { "GroupMemoryBarrierWithGroupSync",  nullptr, nullptr,   "-",          "-",      EShLangComputeMask },
304         { "InterlockedAdd",                   "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
305         { "InterlockedAdd",                   "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
306         { "InterlockedAnd",                   "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
307         { "InterlockedAnd",                   "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
308         { "InterlockedCompareExchange",       "-",     "-",       "SVM,,,>",    "UI,,,",  EShLangFragmentMask | EShLangComputeMask },
309         { "InterlockedCompareStore",          "-",     "-",       "SVM,,",      "UI,,",   EShLangFragmentMask | EShLangComputeMask },
310         { "InterlockedExchange",              "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
311         { "InterlockedMax",                   "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
312         { "InterlockedMax",                   "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
313         { "InterlockedMin",                   "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
314         { "InterlockedMin",                   "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
315         { "InterlockedOr",                    "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
316         { "InterlockedOr",                    "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
317         { "InterlockedXor",                   "-",     "-",       "SVM,,>",     "UI,,",   EShLangFragmentMask | EShLangComputeMask },
318         { "InterlockedXor",                   "-",     "-",       "SVM,",       "UI,",    EShLangFragmentMask | EShLangComputeMask },
319         { "isfinite",                         nullptr, "B" ,      "SVM",        "F",      EShLangAll },
320         { "isinf",                            nullptr, "B" ,      "SVM",        "F",      EShLangAll },
321         { "isnan",                            nullptr, "B" ,      "SVM",        "F",      EShLangAll },
322         { "ldexp",                            nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
323         { "length",                           "S",     "F",       "V",          "F",      EShLangAll },
324         { "lit",                              "V4",    "F",       "S,,",        "F,,",    EShLangAll },
325         { "log",                              nullptr, nullptr,   "SVM",        "F",      EShLangAll },
326         { "log10",                            nullptr, nullptr,   "SVM",        "F",      EShLangAll },
327         { "log2",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
328         { "mad",                              nullptr, nullptr,   "SVM,,",      "DFUI,,", EShLangAll },
329         { "max",                              nullptr, nullptr,   "SVM,",       "FI,",    EShLangAll },
330         { "min",                              nullptr, nullptr,   "SVM,",       "FI,",    EShLangAll },
331         { "modf",                             nullptr, nullptr,   "SVM,>",      "FI,",    EShLangAll },
332         { "msad4",                            "V4",    "U",       "S,V2,V4",    "U,,",    EShLangAll },
333         // TODO: fix matrix return size for non-square mats used with mul opcode
334         { "mul",                              "S",     nullptr,   "S,S",        "FI,",    EShLangAll },
335         { "mul",                              "V",     nullptr,   "S,V",        "FI,",    EShLangAll },
336         { "mul",                              "M",     nullptr,   "S,M",        "FI,",    EShLangAll },
337         { "mul",                              "V",     nullptr,   "V,S",        "FI,",    EShLangAll },
338         { "mul",                              "S",     nullptr,   "V,V",        "FI,",    EShLangAll },
339         { "mul",                              "V",     nullptr,   "V,M",        "FI,",    EShLangAll },
340         { "mul",                              "M",     nullptr,   "M,S",        "FI,",    EShLangAll },
341         { "mul",                              "V",     nullptr,   "M,V",        "FI,",    EShLangAll },
342         { "mul",                              "M",     nullptr,   "M,M",        "FI,",    EShLangAll },
343         { "noise",                            "S",     "F",       "V",          "F",      EShLangFragmentMask },
344         { "normalize",                        nullptr, nullptr,   "V",          "F",      EShLangAll },
345         { "pow",                              nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
346         // { "printf",                           "-",     "-",       "",        "",     EShLangAll }, TODO: varargs
347         { "Process2DQuadTessFactorsAvg",      "-",     "-",       "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask },
348         { "Process2DQuadTessFactorsMax",      "-",     "-",       "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask },
349         { "Process2DQuadTessFactorsMin",      "-",     "-",       "V4,V2,>V4,>V2,>V2", "F,,,,", EShLangTessControlMask },
350         { "ProcessIsolineTessFactors",        "-",     "-",       "S,,>,>",  "F,,,",   EShLangTessControlMask },
351         { "ProcessQuadTessFactorsAvg",        "-",     "-",       "V4,S,>V4,>V2,>V2", "F,,,,",  EShLangTessControlMask },
352         { "ProcessQuadTessFactorsMax",        "-",     "-",       "V4,S,>V4,>V2,>V2", "F,,,,",  EShLangTessControlMask },
353         { "ProcessQuadTessFactorsMin",        "-",     "-",       "V4,S,>V4,>V2,>V2", "F,,,,",  EShLangTessControlMask },
354         { "ProcessTriTessFactorsAvg",         "-",     "-",       "V3,S,>V3,>S,>S",   "F,,,,",  EShLangTessControlMask },
355         { "ProcessTriTessFactorsMax",         "-",     "-",       "V3,S,>V3,>S,>S",   "F,,,,",  EShLangTessControlMask },
356         { "ProcessTriTessFactorsMin",         "-",     "-",       "V3,S,>V3,>S,>S",   "F,,,,",  EShLangTessControlMask },
357         { "radians",                          nullptr, nullptr,   "SVM",        "F",      EShLangAll },
358         { "rcp",                              nullptr, nullptr,   "SVM",        "FD",     EShLangAll },
359         { "reflect",                          nullptr, nullptr,   "V,",         "F,",     EShLangAll },
360         { "refract",                          nullptr, nullptr,   "V,V,S",      "F,,",    EShLangAll },
361         { "reversebits",                      nullptr, nullptr,   "SV",         "U",      EShLangAll },
362         { "round",                            nullptr, nullptr,   "SVM",        "F",      EShLangAll },
363         { "rsqrt",                            nullptr, nullptr,   "SVM",        "F",      EShLangAll },
364         { "saturate",                         nullptr, nullptr ,  "SVM",        "F",      EShLangAll },
365         { "sign",                             nullptr, nullptr,   "SVM",        "FI",     EShLangAll },
366         { "sin",                              nullptr, nullptr,   "SVM",        "F",      EShLangAll },
367         { "sincos",                           "-",     "-",       "SVM,>,>",    "F,,",    EShLangAll },
368         { "sinh",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
369         { "smoothstep",                       nullptr, nullptr,   "SVM,,",      "F,,",    EShLangAll },
370         { "sqrt",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
371         { "step",                             nullptr, nullptr,   "SVM,",       "F,",     EShLangAll },
372         { "tan",                              nullptr, nullptr,   "SVM",        "F",      EShLangAll },
373         { "tanh",                             nullptr, nullptr,   "SVM",        "F",      EShLangAll },
374         { "tex1D",                            "V4",    "F",       "S1,S",       "S,F",    EShLangFragmentMask },
375         { "tex1D",                            "V4",    "F",       "S1,S,V1,V1", "S,F,F,F",EShLangFragmentMask },
376         { "tex1Dbias",                        "V4",    "F",       "S1,V4",      "S,F",    EShLangFragmentMask },
377         { "tex1Dgrad",                        "V4",    "F",       "S1,V1,V1,V1","S,F,F,F",EShLangFragmentMask },
378         { "tex1Dlod",                         "V4",    "F",       "S1,V4",      "S,F",    EShLangFragmentMask },
379         { "tex1Dproj",                        "V4",    "F",       "S1,V4",      "S,F",    EShLangFragmentMask },
380         { "tex2D",                            "V4",    "F",       "S2,V2",      "S,F",    EShLangFragmentMask },
381         { "tex2D",                            "V4",    "F",       "S2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
382         { "tex2Dbias",                        "V4",    "F",       "S2,V4",      "S,F",    EShLangFragmentMask },
383         { "tex2Dgrad",                        "V4",    "F",       "S2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
384         { "tex2Dlod",                         "V4",    "F",       "S2,V4",      "S,F",    EShLangFragmentMask },
385         { "tex2Dproj",                        "V4",    "F",       "S2,V4",      "S,F",    EShLangFragmentMask },
386         { "tex3D",                            "V4",    "F",       "S3,V3",      "S,F",    EShLangFragmentMask },
387         { "tex3D",                            "V4",    "F",       "S3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
388         { "tex3Dbias",                        "V4",    "F",       "S3,V4",      "S,F",    EShLangFragmentMask },
389         { "tex3Dgrad",                        "V4",    "F",       "S3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
390         { "tex3Dlod",                         "V4",    "F",       "S3,V4",      "S,F",    EShLangFragmentMask },
391         { "tex3Dproj",                        "V4",    "F",       "S3,V4",      "S,F",    EShLangFragmentMask },
392         { "texCUBE",                          "V4",    "F",       "S4,V3",      "S,F",    EShLangFragmentMask },
393         { "texCUBE",                          "V4",    "F",       "S4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
394         { "texCUBEbias",                      "V4",    "F",       "S4,V4",      "S,F",    EShLangFragmentMask },
395         { "texCUBEgrad",                      "V4",    "F",       "S4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
396         { "texCUBElod",                       "V4",    "F",       "S4,V4",      "S,F",    EShLangFragmentMask },
397         { "texCUBEproj",                      "V4",    "F",       "S4,V4",      "S,F",    EShLangFragmentMask },
398         { "transpose",                        "^M",    nullptr,   "M",          "F",      EShLangAll },
399         { "trunc",                            nullptr, nullptr,   "SVM",        "F",      EShLangAll },
400
401         // Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
402         { nullptr,                            nullptr, nullptr,   nullptr,      nullptr,  0 },
403     };
404
405     // Set this to true to avoid generating prototypes that will be invalid for the GLSL parser.
406     // TODO: turn it off (and remove the code) when the HLSL parser can be used to parse builtins.
407     static const bool skipInvalidGlsl = true;
408     
409     // Create prototypes for the intrinsics.  TODO: Avoid ranged based for until all compilers can handle it.
410     for (int icount = 0; hlslIntrinsics[icount].name; ++icount) {
411         const auto& intrinsic = hlslIntrinsics[icount];
412
413         for (int stage = 0; stage < EShLangCount; ++stage) {                                // for each stage...
414             if ((intrinsic.stage & (1<<stage)) == 0) // skip inapplicable stages
415                 continue;
416
417             // reference to either the common builtins, or stage specific builtins.
418             TString& s = (intrinsic.stage == EShLangAll) ? commonBuiltins : stageBuiltins[stage];
419
420             for (const char* argOrder = intrinsic.argOrder; !IsEndOfArg(argOrder); ++argOrder) { // for each order...
421                 const int fixedVecSize = isdigit(argOrder[1]) ? (argOrder[1] - '0') : 0;
422
423                 // calculate min and max vector and matrix dimensions
424                 int dim0Min = 1;
425                 int dim0Max = 1;
426                 int dim1Min = 1;
427                 int dim1Max = 1;
428
429                 FindVectorMatrixBounds(argOrder, fixedVecSize, dim0Min, dim0Max, dim1Min, dim1Max);
430
431                 for (const char* argType = intrinsic.argType; !IsEndOfArg(argType); ++argType) { // for each type...
432                     for (int dim0 = dim0Min; dim0 <= dim0Max; ++dim0) {          // for each dim 0...
433                         for (int dim1 = dim1Min; dim1 <= dim1Max; ++dim1) {      // for each dim 1...
434                             const char* retOrder = intrinsic.retOrder ? intrinsic.retOrder : argOrder;
435                             const char* retType  = intrinsic.retType  ? intrinsic.retType  : argType;
436
437                             if (skipInvalidGlsl && !IsValidGlsl(intrinsic.name, *retOrder, *retType, *argOrder, *argType,
438                                                                 dim0, dim1, dim0Max, dim1Max))
439                                 continue;
440
441                             AppendTypeName(s, retOrder, retType, dim0, dim1);  // add return type
442                             s.append(" ");                                     // space between type and name
443                             s.append(intrinsic.name);                          // intrinsic name
444                             s.append("(");                                     // open paren
445
446                             // Append argument types, if any.
447                             for (int arg = 0; ; ++arg) {
448                                 const char* nthArgOrder(NthArg(argOrder, arg));
449                                 const char* nthArgType(NthArg(argType, arg));
450
451                                 if (nthArgOrder == nullptr || nthArgType == nullptr)
452                                     break;
453
454                                 s.append(arg > 0 ? ", ": "");  // comma separator if needed
455                                 
456                                 if (*nthArgOrder == '>') {           // output params
457                                     ++nthArgOrder;
458                                     s.append("out ");
459                                 } else if (*nthArgOrder == '<') {    // input params
460                                     ++nthArgOrder;
461                                     s.append("in ");
462                                 }
463
464                                 // Comma means use the 1st argument order and type.
465                                 if (*nthArgOrder == ',' || *nthArgOrder == '\0') nthArgOrder = argOrder;
466                                 if (*nthArgType == ',' || *nthArgType == '\0') nthArgType = argType;
467
468                                 AppendTypeName(s, nthArgOrder, nthArgType, dim0, dim1); // Add first argument
469                             }
470                             
471                             s.append(");\n");            // close paren and trailing semicolon
472                         }
473                     }
474                 }
475
476                 if (fixedVecSize > 0)  // skip over number for fixed size vectors
477                     ++argOrder;
478             }
479             
480             if (intrinsic.stage == EShLangAll) // common builtins are only added once.
481                 break;
482         }
483     }
484
485     // printf("Common:\n%s\n",   getCommonString().c_str());
486     // printf("Frag:\n%s\n",     getStageString(EShLangFragment).c_str());
487     // printf("Vertex:\n%s\n",   getStageString(EShLangVertex).c_str());
488     // printf("Geo:\n%s\n",      getStageString(EShLangGeometry).c_str());
489     // printf("TessCtrl:\n%s\n", getStageString(EShLangTessControl).c_str());
490     // printf("TessEval:\n%s\n", getStageString(EShLangTessEvaluation).c_str());
491     // printf("Compute:\n%s\n",  getStageString(EShLangCompute).c_str());
492 }
493
494 //
495 // Add context-dependent built-in functions and variables that are present
496 // for the given version and profile.  All the results are put into just the
497 // commonBuiltins, because it is called for just a specific stage.  So,
498 // add stage-specific entries to the commonBuiltins, and only if that stage
499 // was requested.
500 //
501 void TBuiltInParseablesHlsl::initialize(const TBuiltInResource &resources, int version, EProfile profile, int spv,
502                                         int vulkan, EShLanguage language)
503 {
504 }
505
506
507 //
508 // Finish adding/processing context-independent built-in symbols.
509 // 1) Programmatically add symbols that could not be added by simple text strings above.
510 // 2) Map built-in functions to operators, for those that will turn into an operation node
511 //    instead of remaining a function call.
512 // 3) Tag extension-related symbols added to their base version with their extensions, so
513 //    that if an early version has the extension turned off, there is an error reported on use.
514 //
515 void TBuiltInParseablesHlsl::identifyBuiltIns(int version, EProfile profile, int spv, int vulkan, EShLanguage language,
516                                               TSymbolTable& symbolTable)
517 {
518     // symbolTable.relateToOperator("abort",                       EOpAbort);
519     symbolTable.relateToOperator("abs",                         EOpAbs);
520     symbolTable.relateToOperator("acos",                        EOpAcos);
521     symbolTable.relateToOperator("all",                         EOpAll);
522     // symbolTable.relateToOperator("AllMemoryBarrier");
523     // symbolTable.relateToOperator("AllMemoryBarrierWithGroupSync");
524     symbolTable.relateToOperator("any",                         EOpAny);
525     symbolTable.relateToOperator("asdouble",                    EOpUint64BitsToDouble);
526     symbolTable.relateToOperator("asfloat",                     EOpIntBitsToFloat);
527     symbolTable.relateToOperator("asin",                        EOpAsin);
528     symbolTable.relateToOperator("asint",                       EOpFloatBitsToInt);
529     symbolTable.relateToOperator("asuint",                      EOpFloatBitsToUint);
530     symbolTable.relateToOperator("atan",                        EOpAtan);
531     symbolTable.relateToOperator("atan2",                       EOpAtan);
532     symbolTable.relateToOperator("ceil",                        EOpCeil);
533     // symbolTable.relateToOperator("CheckAccessFullyMapped");
534     symbolTable.relateToOperator("clamp",                       EOpClamp);
535     symbolTable.relateToOperator("clip",                        EOpClip);
536     symbolTable.relateToOperator("cos",                         EOpCos);
537     symbolTable.relateToOperator("cosh",                        EOpCosh);
538     symbolTable.relateToOperator("countbits",                   EOpBitCount);
539     symbolTable.relateToOperator("cross",                       EOpCross);
540     // symbolTable.relateToOperator("D3DCOLORtoUBYTE4",            EOpD3DCOLORtoUBYTE4);
541     symbolTable.relateToOperator("ddx",                         EOpDPdx);
542     symbolTable.relateToOperator("ddx_coarse",                  EOpDPdxCoarse);
543     symbolTable.relateToOperator("ddx_fine",                    EOpDPdxFine);
544     symbolTable.relateToOperator("ddy",                         EOpDPdy);
545     symbolTable.relateToOperator("ddy_coarse",                  EOpDPdyCoarse);
546     symbolTable.relateToOperator("ddy_fine",                    EOpDPdyFine);
547     symbolTable.relateToOperator("degrees",                     EOpDegrees);
548     symbolTable.relateToOperator("determinant",                 EOpDeterminant);
549     // symbolTable.relateToOperator("DeviceMemoryBarrier");
550     // symbolTable.relateToOperator("DeviceMemoryBarrierWithGroupSync");
551     symbolTable.relateToOperator("distance",                    EOpDistance);
552     symbolTable.relateToOperator("dot",                         EOpDot);
553     symbolTable.relateToOperator("dst",                         EOpDst);
554     // symbolTable.relateToOperator("errorf");
555     symbolTable.relateToOperator("EvaluateAttributeAtCentroid", EOpInterpolateAtCentroid);
556     symbolTable.relateToOperator("EvaluateAttributeAtSample",   EOpInterpolateAtSample);
557     // symbolTable.relateToOperator("EvaluateAttributeSnapped");  // TODO: hsnflr positions.  new op?
558     symbolTable.relateToOperator("exp",                         EOpExp);
559     symbolTable.relateToOperator("exp2",                        EOpExp2);
560     // symbolTable.relateToOperator("f16tof32");
561     // symbolTable.relateToOperator("f32tof16");
562     symbolTable.relateToOperator("faceforward",                 EOpFaceForward);
563     symbolTable.relateToOperator("firstbithigh",                EOpFindMSB);
564     symbolTable.relateToOperator("firstbitlow",                 EOpFindLSB);
565     symbolTable.relateToOperator("floor",                       EOpFloor);
566     symbolTable.relateToOperator("fma",                         EOpFma);
567     symbolTable.relateToOperator("fmod",                        EOpMod);
568     symbolTable.relateToOperator("frac",                        EOpFract);
569     symbolTable.relateToOperator("frexp",                       EOpFrexp);
570     symbolTable.relateToOperator("fwidth",                      EOpFwidth);
571     // symbolTable.relateToOperator("GetRenderTargetSampleCount");
572     // symbolTable.relateToOperator("GetRenderTargetSamplePosition");
573     // symbolTable.relateToOperator("GroupMemoryBarrier");
574     // symbolTable.relateToOperator("GroupMemoryBarrierWithGroupSync");
575     symbolTable.relateToOperator("InterlockedAdd",              EOpInterlockedAdd);
576     symbolTable.relateToOperator("InterlockedAnd",              EOpInterlockedAnd);
577     symbolTable.relateToOperator("InterlockedCompareExchange",  EOpInterlockedCompareExchange);
578     symbolTable.relateToOperator("InterlockedCompareStore",     EOpInterlockedCompareStore);
579     symbolTable.relateToOperator("InterlockedExchange",         EOpInterlockedExchange);
580     symbolTable.relateToOperator("InterlockedMax",              EOpInterlockedMax);
581     symbolTable.relateToOperator("InterlockedMin",              EOpInterlockedMin);
582     symbolTable.relateToOperator("InterlockedOr",               EOpInterlockedOr);
583     symbolTable.relateToOperator("InterlockedXor",              EOpInterlockedXor);
584     symbolTable.relateToOperator("isfinite",                    EOpIsFinite);
585     symbolTable.relateToOperator("isinf",                       EOpIsInf);
586     symbolTable.relateToOperator("isnan",                       EOpIsNan);
587     symbolTable.relateToOperator("ldexp",                       EOpLdexp);
588     symbolTable.relateToOperator("length",                      EOpLength);
589     // symbolTable.relateToOperator("lit");
590     symbolTable.relateToOperator("log",                         EOpLog);
591     symbolTable.relateToOperator("log10",                       EOpLog10);
592     symbolTable.relateToOperator("log2",                        EOpLog2);
593     // symbolTable.relateToOperator("mad");
594     symbolTable.relateToOperator("max",                         EOpMax);
595     symbolTable.relateToOperator("min",                         EOpMin);
596     symbolTable.relateToOperator("modf",                        EOpModf);
597     // symbolTable.relateToOperator("msad4",                       EOpMsad4);
598     symbolTable.relateToOperator("mul",                         EOpGenMul);
599     // symbolTable.relateToOperator("noise",                    EOpNoise); // TODO: check return type
600     symbolTable.relateToOperator("normalize",                   EOpNormalize);
601     symbolTable.relateToOperator("pow",                         EOpPow);
602     // symbolTable.relateToOperator("printf");
603     // symbolTable.relateToOperator("Process2DQuadTessFactorsAvg");
604     // symbolTable.relateToOperator("Process2DQuadTessFactorsMax");
605     // symbolTable.relateToOperator("Process2DQuadTessFactorsMin");
606     // symbolTable.relateToOperator("ProcessIsolineTessFactors");
607     // symbolTable.relateToOperator("ProcessQuadTessFactorsAvg");
608     // symbolTable.relateToOperator("ProcessQuadTessFactorsMax");
609     // symbolTable.relateToOperator("ProcessQuadTessFactorsMin");
610     // symbolTable.relateToOperator("ProcessTriTessFactorsAvg");
611     // symbolTable.relateToOperator("ProcessTriTessFactorsMax");
612     // symbolTable.relateToOperator("ProcessTriTessFactorsMin");
613     symbolTable.relateToOperator("radians",                     EOpRadians);
614     symbolTable.relateToOperator("rcp",                         EOpRcp);
615     symbolTable.relateToOperator("reflect",                     EOpReflect);
616     symbolTable.relateToOperator("refract",                     EOpRefract);
617     symbolTable.relateToOperator("reversebits",                 EOpBitFieldReverse);
618     symbolTable.relateToOperator("round",                       EOpRoundEven);
619     symbolTable.relateToOperator("rsqrt",                       EOpInverseSqrt);
620     symbolTable.relateToOperator("saturate",                    EOpSaturate);
621     symbolTable.relateToOperator("sign",                        EOpSign);
622     symbolTable.relateToOperator("sin",                         EOpSin);
623     symbolTable.relateToOperator("sincos",                      EOpSinCos);
624     symbolTable.relateToOperator("sinh",                        EOpSinh);
625     symbolTable.relateToOperator("smoothstep",                  EOpSmoothStep);
626     symbolTable.relateToOperator("sqrt",                        EOpSqrt);
627     symbolTable.relateToOperator("step",                        EOpStep);
628     symbolTable.relateToOperator("tan",                         EOpTan);
629     symbolTable.relateToOperator("tanh",                        EOpTanh);
630     symbolTable.relateToOperator("tex1D",                       EOpTexture);
631     // symbolTable.relateToOperator("tex1Dbias",                  // TODO:
632     symbolTable.relateToOperator("tex1Dgrad",                   EOpTextureGrad);
633     symbolTable.relateToOperator("tex1Dlod",                    EOpTextureLod);
634     symbolTable.relateToOperator("tex1Dproj",                   EOpTextureProj);
635     symbolTable.relateToOperator("tex2D",                       EOpTexture);
636     // symbolTable.relateToOperator("tex2Dbias",                  // TODO:
637     symbolTable.relateToOperator("tex2Dgrad",                   EOpTextureGrad);
638     symbolTable.relateToOperator("tex2Dlod",                    EOpTextureLod);
639     // symbolTable.relateToOperator("tex2Dproj",                   EOpTextureProj);
640     symbolTable.relateToOperator("tex3D",                       EOpTexture);
641     // symbolTable.relateToOperator("tex3Dbias");                // TODO
642     symbolTable.relateToOperator("tex3Dgrad",                   EOpTextureGrad);
643     symbolTable.relateToOperator("tex3Dlod",                    EOpTextureLod);
644     // symbolTable.relateToOperator("tex3Dproj",                   EOpTextureProj);
645     symbolTable.relateToOperator("texCUBE",                     EOpTexture);
646     // symbolTable.relateToOperator("texCUBEbias",              // TODO
647     symbolTable.relateToOperator("texCUBEgrad",                 EOpTextureGrad);
648     symbolTable.relateToOperator("texCUBElod",                  EOpTextureLod);
649     // symbolTable.relateToOperator("texCUBEproj",                 EOpTextureProj);
650     symbolTable.relateToOperator("transpose",                   EOpTranspose);
651     symbolTable.relateToOperator("trunc",                       EOpTrunc);
652 }
653
654 //
655 // Add context-dependent (resource-specific) built-ins not handled by the above.  These
656 // would be ones that need to be programmatically added because they cannot 
657 // be added by simple text strings.  For these, also
658 // 1) Map built-in functions to operators, for those that will turn into an operation node
659 //    instead of remaining a function call.
660 // 2) Tag extension-related symbols added to their base version with their extensions, so
661 //    that if an early version has the extension turned off, there is an error reported on use.
662 //
663 void TBuiltInParseablesHlsl::identifyBuiltIns(int version, EProfile profile, int spv, int /*vulkan*/, EShLanguage language,
664                                               TSymbolTable& symbolTable, const TBuiltInResource &resources)
665 {
666 }
667
668
669 } // end namespace glslang