2 //Copyright (C) 2016 LunarG, Inc.
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
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.
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
51 #include "hlslParseables.h"
55 namespace { // anonymous namespace functions
57 const char* BaseTypeName(const char* argOrder, const char* scalarName, const char* vecName, const char* matName)
60 case 'S': return scalarName;
61 case 'V': return vecName;
62 case 'M': return matName;
63 default: return "UNKNOWN_TYPE";
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.
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)
76 const bool transpose = (argOrder[0] == '^');
78 // Take transpose of matrix dimensions
80 std::swap(dim0, dim1);
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;
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;
100 // Add sampler dimensions
101 if (*argType == 'S') {
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;
112 if ((*argOrder == 'V' || *argOrder == 'M') && (dim0 < 1 || dim0 > 4) ||
113 (*argOrder == 'M' && (dim1 < 1 || dim1 > 4))) {
114 s += "UNKNOWN_DIMENSION";
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;
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)
134 const bool isVec = dim0Max > 1 || argType == 'V';
135 const bool isMat = dim1Max > 1 || argType == 'M';
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
143 const std::string name(cname); // for ease of comparison. slow, but temporary, until HLSL parser is online.
145 if (isMat && dim0 != dim1) // TODO: avoid mats until we find the right GLSL profile
148 if (isMat && (argType == 'I' || argType == 'U' || argType == 'B') ||
149 retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B'))
152 if (name == "GetRenderTargetSamplePosition" ||
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)
165 return arg == nullptr || *arg == '\0' || *arg == ',';
169 // return position of end of argument specifier
170 inline const char* FindEndOfArg(const char* arg)
172 while (!IsEndOfArg(arg))
175 return *arg == '\0' ? nullptr : arg;
179 // Return pointer to beginning of Nth argument specifier in the string.
180 inline const char* NthArg(const char* arg, int n)
182 for (int x=0; x<n && arg; ++x)
183 if ((arg = FindEndOfArg(arg)) != nullptr)
184 ++arg; // skip arg separator
189 inline void FindVectorMatrixBounds(const char* argOrder, int fixedVecSize, int& dim0Min, int& dim0Max, int& dim1Min, int& dim1Max)
191 for (int arg = 0; ; ++arg) {
192 const char* nthArgOrder(NthArg(argOrder, arg));
193 if (nthArgOrder == nullptr)
195 else if (*nthArgOrder == 'V')
197 else if (*nthArgOrder == 'M')
198 dim0Max = dim1Max = 4;
201 if (fixedVecSize > 0) // handle fixed sized vectors
202 dim0Min = dim0Max = fixedVecSize;
205 } // end anonymous namespace
209 TBuiltInParseablesHlsl::TBuiltInParseablesHlsl()
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.
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.
221 void TBuiltInParseablesHlsl::initialize(int version, EProfile profile, int spv, int vulkan)
223 static const EShLanguageMask EShLangAll = EShLanguageMask(EShLangCount - 1);
225 // This structure encodes the prototype information for each HLSL intrinsic.
226 // Because explicit enumeration would be cumbersome, it's procedurally generated.
228 // S = scalar, V = vector, M = matrix, - = void
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
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 },
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 },
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;
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];
413 for (int stage = 0; stage < EShLangCount; ++stage) { // for each stage...
414 if ((intrinsic.stage & (1<<stage)) == 0) // skip inapplicable stages
417 // reference to either the common builtins, or stage specific builtins.
418 TString& s = (intrinsic.stage == EShLangAll) ? commonBuiltins : stageBuiltins[stage];
420 for (const char* argOrder = intrinsic.argOrder; !IsEndOfArg(argOrder); ++argOrder) { // for each order...
421 const int fixedVecSize = isdigit(argOrder[1]) ? (argOrder[1] - '0') : 0;
423 // calculate min and max vector and matrix dimensions
429 FindVectorMatrixBounds(argOrder, fixedVecSize, dim0Min, dim0Max, dim1Min, dim1Max);
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;
437 if (skipInvalidGlsl && !IsValidGlsl(intrinsic.name, *retOrder, *retType, *argOrder, *argType,
438 dim0, dim1, dim0Max, dim1Max))
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
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));
451 if (nthArgOrder == nullptr || nthArgType == nullptr)
454 s.append(arg > 0 ? ", ": ""); // comma separator if needed
456 if (*nthArgOrder == '>') { // output params
459 } else if (*nthArgOrder == '<') { // input params
464 // Comma means use the 1st argument order and type.
465 if (*nthArgOrder == ',' || *nthArgOrder == '\0') nthArgOrder = argOrder;
466 if (*nthArgType == ',' || *nthArgType == '\0') nthArgType = argType;
468 AppendTypeName(s, nthArgOrder, nthArgType, dim0, dim1); // Add first argument
471 s.append(");\n"); // close paren and trailing semicolon
476 if (fixedVecSize > 0) // skip over number for fixed size vectors
480 if (intrinsic.stage == EShLangAll) // common builtins are only added once.
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());
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
501 void TBuiltInParseablesHlsl::initialize(const TBuiltInResource &resources, int version, EProfile profile, int spv,
502 int vulkan, EShLanguage language)
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.
515 void TBuiltInParseablesHlsl::identifyBuiltIns(int version, EProfile profile, int spv, int vulkan, EShLanguage language,
516 TSymbolTable& symbolTable)
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);
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.
663 void TBuiltInParseablesHlsl::identifyBuiltIns(int version, EProfile profile, int spv, int /*vulkan*/, EShLanguage language,
664 TSymbolTable& symbolTable, const TBuiltInResource &resources)
669 } // end namespace glslang