Coverage Report

Created: 2025-07-18 06:47

/src/glslang/glslang/MachineIndependent/ParseHelper.cpp
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3
// Copyright (C) 2012-2015 LunarG, Inc.
4
// Copyright (C) 2015-2018 Google, Inc.
5
// Copyright (C) 2017, 2019 ARM Limited.
6
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
7
// Modifications Copyright (C) 2024 Ravi Prakash Singh.
8
//
9
// All rights reserved.
10
//
11
// Redistribution and use in source and binary forms, with or without
12
// modification, are permitted provided that the following conditions
13
// are met:
14
//
15
//    Redistributions of source code must retain the above copyright
16
//    notice, this list of conditions and the following disclaimer.
17
//
18
//    Redistributions in binary form must reproduce the above
19
//    copyright notice, this list of conditions and the following
20
//    disclaimer in the documentation and/or other materials provided
21
//    with the distribution.
22
//
23
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
24
//    contributors may be used to endorse or promote products derived
25
//    from this software without specific prior written permission.
26
//
27
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
// POSSIBILITY OF SUCH DAMAGE.
39
//
40
41
#include "ParseHelper.h"
42
#include "Initialize.h"
43
#include "Scan.h"
44
45
#include <algorithm>
46
47
#include "Versions.h"
48
#include "preprocessor/PpContext.h"
49
50
extern int yyparse(glslang::TParseContext*);
51
52
namespace glslang {
53
54
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
55
                             int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
56
                             TInfoSink& infoSink, bool forwardCompatible, EShMessages messages,
57
                             const TString* entryPoint) :
58
5.09k
            TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language,
59
5.09k
                              infoSink, forwardCompatible, messages, entryPoint),
60
5.09k
            inMain(false),
61
5.09k
            blockName(nullptr),
62
5.09k
            limits(resources.limits),
63
5.09k
            atomicUintOffsets(nullptr), anyIndexLimits(false)
64
5.09k
{
65
    // decide whether precision qualifiers should be ignored or respected
66
5.09k
    if (isEsProfile() || spvVersion.vulkan > 0) {
67
4.65k
        precisionManager.respectPrecisionQualifiers();
68
4.65k
        if (! parsingBuiltins && language == EShLangFragment && !isEsProfile() && spvVersion.vulkan > 0)
69
0
            precisionManager.warnAboutDefaults();
70
4.65k
    }
71
72
5.09k
    setPrecisionDefaults();
73
74
5.09k
    globalUniformDefaults.clear();
75
5.09k
    globalUniformDefaults.layoutMatrix = ElmColumnMajor;
76
5.09k
    globalUniformDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd140 : ElpShared;
77
78
5.09k
    globalBufferDefaults.clear();
79
5.09k
    globalBufferDefaults.layoutMatrix = ElmColumnMajor;
80
5.09k
    globalBufferDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd430 : ElpShared;
81
82
5.09k
    globalInputDefaults.clear();
83
5.09k
    globalOutputDefaults.clear();
84
85
5.09k
    globalSharedDefaults.clear();
86
5.09k
    globalSharedDefaults.layoutMatrix = ElmColumnMajor;
87
5.09k
    globalSharedDefaults.layoutPacking = ElpStd430;
88
89
    // "Shaders in the transform
90
    // feedback capturing mode have an initial global default of
91
    //     layout(xfb_buffer = 0) out;"
92
5.09k
    if (language == EShLangVertex ||
93
5.09k
        language == EShLangTessControl ||
94
5.09k
        language == EShLangTessEvaluation ||
95
5.09k
        language == EShLangGeometry)
96
2.17k
        globalOutputDefaults.layoutXfbBuffer = 0;
97
98
5.09k
    if (language == EShLangGeometry)
99
218
        globalOutputDefaults.layoutStream = 0;
100
101
5.09k
    if (entryPoint != nullptr && entryPoint->size() > 0 && *entryPoint != "main")
102
0
        infoSink.info.message(EPrefixError, "Source entry point must be \"main\"");
103
5.09k
}
104
105
TParseContext::~TParseContext()
106
5.09k
{
107
5.09k
    delete [] atomicUintOffsets;
108
5.09k
}
109
110
// Set up all default precisions as needed by the current environment.
111
// Intended just as a TParseContext constructor helper.
112
void TParseContext::setPrecisionDefaults()
113
5.09k
{
114
    // Set all precision defaults to EpqNone, which is correct for all types
115
    // when not obeying precision qualifiers, and correct for types that don't
116
    // have defaults (thus getting an error on use) when obeying precision
117
    // qualifiers.
118
119
168k
    for (int type = 0; type < EbtNumTypes; ++type)
120
162k
        defaultPrecision[type] = EpqNone;
121
122
46.9M
    for (int type = 0; type < maxSamplerIndex; ++type)
123
46.9M
        defaultSamplerPrecision[type] = EpqNone;
124
125
    // replace with real precision defaults for those that have them
126
5.09k
    if (obeyPrecisionQualifiers()) {
127
4.65k
        if (isEsProfile()) {
128
            // Most don't have defaults, a few default to lowp.
129
1.87k
            TSampler sampler;
130
1.87k
            sampler.set(EbtFloat, Esd2D);
131
1.87k
            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
132
1.87k
            sampler.set(EbtFloat, EsdCube);
133
1.87k
            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
134
1.87k
            sampler.set(EbtFloat, Esd2D);
135
1.87k
            sampler.setExternal(true);
136
1.87k
            defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
137
1.87k
        }
138
139
        // If we are parsing built-in computational variables/functions, it is meaningful to record
140
        // whether the built-in has no precision qualifier, as that ambiguity
141
        // is used to resolve the precision from the supplied arguments/operands instead.
142
        // So, we don't actually want to replace EpqNone with a default precision for built-ins.
143
4.65k
        if (! parsingBuiltins) {
144
68
            if (isEsProfile() && language == EShLangFragment) {
145
0
                defaultPrecision[EbtInt] = EpqMedium;
146
0
                defaultPrecision[EbtUint] = EpqMedium;
147
68
            } else {
148
68
                defaultPrecision[EbtInt] = EpqHigh;
149
68
                defaultPrecision[EbtUint] = EpqHigh;
150
68
                defaultPrecision[EbtFloat] = EpqHigh;
151
68
            }
152
153
68
            if (!isEsProfile()) {
154
                // Non-ES profile
155
                // All sampler precisions default to highp.
156
0
                for (int type = 0; type < maxSamplerIndex; ++type)
157
0
                    defaultSamplerPrecision[type] = EpqHigh;
158
0
            }
159
68
        }
160
161
4.65k
        defaultPrecision[EbtSampler] = EpqLow;
162
4.65k
        defaultPrecision[EbtAtomicUint] = EpqHigh;
163
4.65k
    }
164
5.09k
}
165
166
void TParseContext::setLimits(const TBuiltInResource& r)
167
96
{
168
96
    resources = r;
169
96
    intermediate.setLimits(r);
170
171
96
    anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
172
96
                     ! limits.generalConstantMatrixVectorIndexing ||
173
96
                     ! limits.generalSamplerIndexing ||
174
96
                     ! limits.generalUniformIndexing ||
175
96
                     ! limits.generalVariableIndexing ||
176
96
                     ! limits.generalVaryingIndexing;
177
178
179
    // "Each binding point tracks its own current default offset for
180
    // inheritance of subsequent variables using the same binding. The initial state of compilation is that all
181
    // binding points have an offset of 0."
182
96
    atomicUintOffsets = new int[resources.maxAtomicCounterBindings];
183
192
    for (int b = 0; b < resources.maxAtomicCounterBindings; ++b)
184
96
        atomicUintOffsets[b] = 0;
185
96
}
186
187
//
188
// Parse an array of strings using yyparse, going through the
189
// preprocessor to tokenize the shader strings, then through
190
// the GLSL scanner.
191
//
192
// Returns true for successful acceptance of the shader, false if any errors.
193
//
194
bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& input, bool versionWillBeError)
195
5.09k
{
196
5.09k
    currentScanner = &input;
197
5.09k
    ppContext.setInput(input, versionWillBeError);
198
5.09k
    yyparse(this);
199
200
5.09k
    finish();
201
202
5.09k
    return numErrors == 0;
203
5.09k
}
204
205
// This is called from bison when it has a parse (syntax) error
206
// Note though that to stop cascading errors, we set EOF, which
207
// will usually cause a syntax error, so be more accurate that
208
// compilation is terminating.
209
void TParseContext::parserError(const char* s)
210
1.39k
{
211
1.39k
    if (! getScanner()->atEndOfInput() || numErrors == 0)
212
1.33k
        error(getCurrentLoc(), "", "", s, "");
213
57
    else
214
57
        error(getCurrentLoc(), "compilation terminated", "", "");
215
1.39k
}
216
217
void TParseContext::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList)
218
0
{
219
0
    bool createBlock = globalUniformBlock == nullptr;
220
221
0
    if (createBlock) {
222
0
        globalUniformBinding = intermediate.getGlobalUniformBinding();
223
0
        globalUniformSet = intermediate.getGlobalUniformSet();
224
0
    }
225
226
    // use base class function to create/expand block
227
0
    TParseContextBase::growGlobalUniformBlock(loc, memberType, memberName, typeList);
228
229
0
    if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) {
230
        // check for a block storage override
231
0
        TBlockStorageClass storageOverride = intermediate.getBlockStorageOverride(getGlobalUniformBlockName());
232
0
        TQualifier& qualifier = globalUniformBlock->getWritableType().getQualifier();
233
0
        qualifier.defaultBlock = true;
234
235
0
        if (storageOverride != EbsNone) {
236
0
            if (createBlock) {
237
                // Remap block storage
238
0
                qualifier.setBlockStorage(storageOverride);
239
240
                // check that the change didn't create errors
241
0
                blockQualifierCheck(loc, qualifier, false);
242
0
            }
243
244
            // remap meber storage as well
245
0
            memberType.getQualifier().setBlockStorage(storageOverride);
246
0
        }
247
0
    }
248
0
}
249
250
void TParseContext::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList)
251
0
{
252
0
    bool createBlock = atomicCounterBuffers.find(binding) == atomicCounterBuffers.end();
253
254
0
    if (createBlock) {
255
0
        atomicCounterBlockSet = intermediate.getAtomicCounterBlockSet();
256
0
    }
257
258
    // use base class function to create/expand block
259
0
    TParseContextBase::growAtomicCounterBlock(binding, loc, memberType, memberName, typeList);
260
0
    TQualifier& qualifier = atomicCounterBuffers[binding]->getWritableType().getQualifier();
261
0
    qualifier.defaultBlock = true;
262
263
0
    if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) {
264
        // check for a Block storage override
265
0
        TBlockStorageClass storageOverride = intermediate.getBlockStorageOverride(getAtomicCounterBlockName());
266
267
0
        if (storageOverride != EbsNone) {
268
0
            if (createBlock) {
269
                // Remap block storage
270
271
0
                qualifier.setBlockStorage(storageOverride);
272
273
                // check that the change didn't create errors
274
0
                blockQualifierCheck(loc, qualifier, false);
275
0
            }
276
277
            // remap meber storage as well
278
0
            memberType.getQualifier().setBlockStorage(storageOverride);
279
0
        }
280
0
    }
281
0
}
282
283
const char* TParseContext::getGlobalUniformBlockName() const
284
0
{
285
0
    const char* name = intermediate.getGlobalUniformBlockName();
286
0
    if (std::string(name) == "")
287
0
        return "gl_DefaultUniformBlock";
288
0
    else
289
0
        return name;
290
0
}
291
void TParseContext::finalizeGlobalUniformBlockLayout(TVariable&)
292
0
{
293
0
}
294
void TParseContext::setUniformBlockDefaults(TType& block) const
295
0
{
296
0
    block.getQualifier().layoutPacking = ElpStd140;
297
0
    block.getQualifier().layoutMatrix = ElmColumnMajor;
298
0
}
299
300
301
const char* TParseContext::getAtomicCounterBlockName() const
302
0
{
303
0
    const char* name = intermediate.getAtomicCounterBlockName();
304
0
    if (std::string(name) == "")
305
0
        return "gl_AtomicCounterBlock";
306
0
    else
307
0
        return name;
308
0
}
309
void TParseContext::finalizeAtomicCounterBlockLayout(TVariable&)
310
0
{
311
0
}
312
313
void TParseContext::setAtomicCounterBlockDefaults(TType& block) const
314
0
{
315
0
    block.getQualifier().layoutPacking = ElpStd430;
316
0
    block.getQualifier().layoutMatrix = ElmRowMajor;
317
0
}
318
319
0
void TParseContext::setInvariant(const TSourceLoc& loc, const char* builtin) {
320
0
    TSymbol* symbol = symbolTable.find(builtin);
321
0
    if (symbol && symbol->getType().getQualifier().isPipeOutput()) {
322
0
        if (intermediate.inIoAccessed(builtin))
323
0
            warn(loc, "changing qualification after use", "invariant", builtin);
324
0
        TSymbol* csymbol = symbolTable.copyUp(symbol);
325
0
        csymbol->getWritableType().getQualifier().invariant = true;
326
0
    }
327
0
}
328
329
void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
330
2
{
331
2
    if (pragmaCallback)
332
0
        pragmaCallback(loc.line, tokens);
333
334
2
    if (tokens.size() == 0)
335
0
        return;
336
337
2
    if (tokens[0].compare("optimize") == 0) {
338
0
        if (tokens.size() != 4) {
339
0
            error(loc, "optimize pragma syntax is incorrect", "#pragma", "");
340
0
            return;
341
0
        }
342
343
0
        if (tokens[1].compare("(") != 0) {
344
0
            error(loc, "\"(\" expected after 'optimize' keyword", "#pragma", "");
345
0
            return;
346
0
        }
347
348
0
        if (tokens[2].compare("on") == 0)
349
0
            contextPragma.optimize = true;
350
0
        else if (tokens[2].compare("off") == 0)
351
0
            contextPragma.optimize = false;
352
0
        else {
353
0
            if(relaxedErrors())
354
                //  If an implementation does not recognize the tokens following #pragma, then it will ignore that pragma.
355
0
                warn(loc, "\"on\" or \"off\" expected after '(' for 'optimize' pragma", "#pragma", "");
356
0
            return;
357
0
        }
358
359
0
        if (tokens[3].compare(")") != 0) {
360
0
            error(loc, "\")\" expected to end 'optimize' pragma", "#pragma", "");
361
0
            return;
362
0
        }
363
2
    } else if (tokens[0].compare("debug") == 0) {
364
0
        if (tokens.size() != 4) {
365
0
            error(loc, "debug pragma syntax is incorrect", "#pragma", "");
366
0
            return;
367
0
        }
368
369
0
        if (tokens[1].compare("(") != 0) {
370
0
            error(loc, "\"(\" expected after 'debug' keyword", "#pragma", "");
371
0
            return;
372
0
        }
373
374
0
        if (tokens[2].compare("on") == 0)
375
0
            contextPragma.debug = true;
376
0
        else if (tokens[2].compare("off") == 0)
377
0
            contextPragma.debug = false;
378
0
        else {
379
0
            if(relaxedErrors())
380
                //  If an implementation does not recognize the tokens following #pragma, then it will ignore that pragma.
381
0
                warn(loc, "\"on\" or \"off\" expected after '(' for 'debug' pragma", "#pragma", "");
382
0
            return;
383
0
        }
384
385
0
        if (tokens[3].compare(")") != 0) {
386
0
            error(loc, "\")\" expected to end 'debug' pragma", "#pragma", "");
387
0
            return;
388
0
        }
389
2
    } else if (spvVersion.spv > 0 && tokens[0].compare("use_storage_buffer") == 0) {
390
0
        if (tokens.size() != 1)
391
0
            error(loc, "extra tokens", "#pragma", "");
392
0
        intermediate.setUseStorageBuffer();
393
2
    } else if (spvVersion.spv > 0 && tokens[0].compare("use_vulkan_memory_model") == 0) {
394
0
        if (tokens.size() != 1)
395
0
            error(loc, "extra tokens", "#pragma", "");
396
0
        intermediate.setUseVulkanMemoryModel();
397
2
    } else if (spvVersion.spv > 0 && tokens[0].compare("use_variable_pointers") == 0) {
398
0
        if (tokens.size() != 1)
399
0
            error(loc, "extra tokens", "#pragma", "");
400
0
        if (spvVersion.spv < glslang::EShTargetSpv_1_3)
401
0
            error(loc, "requires SPIR-V 1.3", "#pragma use_variable_pointers", "");
402
0
        intermediate.setUseVariablePointers();
403
2
    } else if (spvVersion.spv > 0 && tokens[0].compare("use_replicated_composites") == 0) {
404
0
        if (tokens.size() != 1)
405
0
            error(loc, "extra tokens", "#pragma", "");
406
0
        intermediate.setReplicatedComposites();
407
2
    } else if (tokens[0].compare("once") == 0) {
408
0
        warn(loc, "not implemented", "#pragma once", "");
409
2
    } else if (tokens[0].compare("glslang_binary_double_output") == 0) {
410
0
        intermediate.setBinaryDoubleOutput();
411
2
    } else if (spvVersion.spv > 0 && tokens[0].compare("STDGL") == 0 &&
412
2
               tokens[1].compare("invariant") == 0 && tokens[3].compare("all") == 0) {
413
0
        intermediate.setInvariantAll();
414
        // Set all builtin out variables invariant if declared
415
0
        setInvariant(loc, "gl_Position");
416
0
        setInvariant(loc, "gl_PointSize");
417
0
        setInvariant(loc, "gl_ClipDistance");
418
0
        setInvariant(loc, "gl_CullDistance");
419
0
        setInvariant(loc, "gl_TessLevelOuter");
420
0
        setInvariant(loc, "gl_TessLevelInner");
421
0
        setInvariant(loc, "gl_PrimitiveID");
422
0
        setInvariant(loc, "gl_Layer");
423
0
        setInvariant(loc, "gl_ViewportIndex");
424
0
        setInvariant(loc, "gl_FragDepth");
425
0
        setInvariant(loc, "gl_SampleMask");
426
0
        setInvariant(loc, "gl_ClipVertex");
427
0
        setInvariant(loc, "gl_FrontColor");
428
0
        setInvariant(loc, "gl_BackColor");
429
0
        setInvariant(loc, "gl_FrontSecondaryColor");
430
0
        setInvariant(loc, "gl_BackSecondaryColor");
431
0
        setInvariant(loc, "gl_TexCoord");
432
0
        setInvariant(loc, "gl_FogFragCoord");
433
0
        setInvariant(loc, "gl_FragColor");
434
0
        setInvariant(loc, "gl_FragData");
435
0
    }
436
2
}
437
438
//
439
// Handle seeing a variable identifier in the grammar.
440
//
441
TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string)
442
1.37k
{
443
1.37k
    TIntermTyped* node = nullptr;
444
445
    // Error check for requiring specific extensions present.
446
1.37k
    if (symbol && symbol->getNumExtensions())
447
0
        requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
448
449
1.37k
    if (symbol && symbol->isReadOnly()) {
450
        // All shared things containing an unsized array must be copied up
451
        // on first use, so that all future references will share its array structure,
452
        // so that editing the implicit size will effect all nodes consuming it,
453
        // and so that editing the implicit size won't change the shared one.
454
        //
455
        // If this is a variable or a block, check it and all it contains, but if this
456
        // is a member of an anonymous block, check the whole block, as the whole block
457
        // will need to be copied up if it contains an unsized array.
458
        //
459
        // This check is being done before the block-name check further down, so guard
460
        // for that too.
461
0
        if (!symbol->getType().isUnusableName()) {
462
0
            if (symbol->getType().containsUnsizedArray() ||
463
0
                (symbol->getAsAnonMember() &&
464
0
                 symbol->getAsAnonMember()->getAnonContainer().getType().containsUnsizedArray()))
465
0
                makeEditable(symbol);
466
0
        }
467
0
    }
468
469
1.37k
    const TVariable* variable;
470
1.37k
    const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr;
471
1.37k
    if (anon) {
472
        // It was a member of an anonymous container.
473
474
        // Create a subtree for its dereference.
475
0
        variable = anon->getAnonContainer().getAsVariable();
476
0
        TIntermTyped* container = intermediate.addSymbol(*variable, loc);
477
0
        TIntermTyped* constNode = intermediate.addConstantUnion(anon->getMemberNumber(), loc);
478
0
        node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc);
479
480
0
        node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
481
0
        if (node->getType().hiddenMember())
482
0
            error(loc, "member of nameless block was not redeclared", string->c_str(), "");
483
1.37k
    } else {
484
        // Not a member of an anonymous container.
485
486
        // The symbol table search was done in the lexical phase.
487
        // See if it was a variable.
488
1.37k
        variable = symbol ? symbol->getAsVariable() : nullptr;
489
1.37k
        if (variable) {
490
839
            if (variable->getType().isUnusableName()) {
491
0
                error(loc, "cannot be used (maybe an instance name is needed)", string->c_str(), "");
492
0
                variable = nullptr;
493
0
            }
494
495
839
            if (language == EShLangMesh && variable) {
496
0
                TLayoutGeometry primitiveType = intermediate.getOutputPrimitive();
497
0
                if ((variable->getMangledName() == "gl_PrimitiveTriangleIndicesEXT" && primitiveType != ElgTriangles) ||
498
0
                    (variable->getMangledName() == "gl_PrimitiveLineIndicesEXT" && primitiveType != ElgLines) ||
499
0
                    (variable->getMangledName() == "gl_PrimitivePointIndicesEXT" && primitiveType != ElgPoints)) {
500
0
                    error(loc, "cannot be used (output primitive type mismatch)", string->c_str(), "");
501
0
                    variable = nullptr;
502
0
                }
503
0
            }
504
839
        } else {
505
533
            if (symbol)
506
0
                error(loc, "variable name expected", string->c_str(), "");
507
533
        }
508
509
        // Recovery, if it wasn't found or was not a variable.
510
1.37k
        if (! variable) {
511
533
            bool builtIn = false;
512
533
            TVector<const TFunction*> candidateList;
513
533
            symbolTable.findFunctionNameList(*string + "(", candidateList, builtIn);
514
515
            // If it's a function, pass the name/mangledName
516
533
            if (!candidateList.empty() && !builtIn) {
517
0
                variable = new TVariable(&candidateList[0]->getName(), &candidateList[0]->getMangledName(), TType(EbtFunction));
518
533
            } else {
519
533
                variable = new TVariable(string, TType(EbtVoid));
520
533
            }
521
533
        }
522
523
1.37k
        if (variable->getType().getQualifier().isFrontEndConstant())
524
51
            node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
525
1.32k
        else
526
1.32k
            node = intermediate.addSymbol(*variable, loc);
527
1.37k
    }
528
529
1.37k
    if (variable->getType().getQualifier().isIo())
530
0
        intermediate.addIoAccessed(*string);
531
532
1.37k
    if (variable->getType().isReference() &&
533
1.37k
        variable->getType().getQualifier().bufferReferenceNeedsVulkanMemoryModel()) {
534
0
        intermediate.setUseVulkanMemoryModel();
535
0
    }
536
537
1.37k
    return node;
538
1.37k
}
539
540
//
541
// Handle seeing a base[index] dereference in the grammar.
542
//
543
TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index)
544
3
{
545
3
    int indexValue = 0;
546
3
    if (index->getQualifier().isFrontEndConstant())
547
2
        indexValue = index->getAsConstantUnion()->getConstArray()[0].getIConst();
548
549
    // basic type checks...
550
3
    variableCheck(base);
551
552
3
    if (! base->isArray() && ! base->isMatrix() && ! base->isVector() && ! base->getType().isCoopMat() &&
553
3
        ! base->isReference() && ! base->getType().isCoopVecNV()) {
554
1
        if (base->getAsSymbolNode())
555
1
            error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
556
0
        else
557
0
            error(loc, " left of '[' is not of type array, matrix, or vector ", "expression", "");
558
559
        // Insert dummy error-recovery result
560
1
        return intermediate.addConstantUnion(0.0, EbtFloat, loc);
561
1
    }
562
563
2
    if (!base->isArray() && base->isVector()) {
564
0
        if (base->getType().contains16BitFloat())
565
0
            requireFloat16Arithmetic(loc, "[", "does not operate on types containing float16");
566
0
        if (base->getType().contains16BitInt())
567
0
            requireInt16Arithmetic(loc, "[", "does not operate on types containing (u)int16");
568
0
        if (base->getType().contains8BitInt())
569
0
            requireInt8Arithmetic(loc, "[", "does not operate on types containing (u)int8");
570
0
    }
571
572
    // check for constant folding
573
2
    if (base->getType().getQualifier().isFrontEndConstant() && index->getQualifier().isFrontEndConstant()) {
574
        // both base and index are front-end constants
575
0
        checkIndex(loc, base->getType(), indexValue);
576
0
        return intermediate.foldDereference(base, indexValue, loc);
577
0
    }
578
579
    // at least one of base and index is not a front-end constant variable...
580
2
    TIntermTyped* result = nullptr;
581
582
2
    if (base->isReference() && ! base->isArray()) {
583
0
        requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing");
584
0
        if (base->getType().getReferentType()->containsUnsizedArray()) {
585
0
            error(loc, "cannot index reference to buffer containing an unsized array", "", "");
586
0
            result = nullptr;
587
0
        } else {
588
0
            result = intermediate.addBinaryMath(EOpAdd, base, index, loc);
589
0
            if (result != nullptr)
590
0
                result->setType(base->getType());
591
0
        }
592
0
        if (result == nullptr) {
593
0
            error(loc, "cannot index buffer reference", "", "");
594
0
            result = intermediate.addConstantUnion(0.0, EbtFloat, loc);
595
0
        }
596
0
        return result;
597
0
    }
598
2
    if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
599
0
        handleIoResizeArrayAccess(loc, base);
600
601
2
    if (index->getQualifier().isFrontEndConstant())
602
1
        checkIndex(loc, base->getType(), indexValue);
603
604
2
    if (index->getQualifier().isFrontEndConstant()) {
605
1
        if (base->getType().isUnsizedArray()) {
606
0
            base->getWritableType().updateImplicitArraySize(indexValue + 1);
607
0
            base->getWritableType().setImplicitlySized(true);
608
0
            if (base->getQualifier().builtIn == EbvClipDistance &&
609
0
                indexValue >= resources.maxClipDistances) {
610
0
                error(loc, "gl_ClipDistance", "[", "array index out of range '%d'", indexValue);
611
0
            }
612
0
            else if (base->getQualifier().builtIn == EbvCullDistance &&
613
0
                indexValue >= resources.maxCullDistances) {
614
0
                error(loc, "gl_CullDistance", "[", "array index out of range '%d'", indexValue);
615
0
            }
616
0
            else if (base->getQualifier().builtIn == EbvSampleMask &&
617
0
                indexValue >= (resources.maxSamples + 31) / 32) {
618
0
                error(loc, "gl_SampleMask", "[", "array index out of range '%d'", indexValue);
619
0
            }
620
            // For 2D per-view builtin arrays, update the inner dimension size in parent type
621
0
            if (base->getQualifier().isPerView() && base->getQualifier().builtIn != EbvNone) {
622
0
                TIntermBinary* binaryNode = base->getAsBinaryNode();
623
0
                if (binaryNode) {
624
0
                    TType& leftType = binaryNode->getLeft()->getWritableType();
625
0
                    TArraySizes& arraySizes = *leftType.getArraySizes();
626
0
                    assert(arraySizes.getNumDims() == 2);
627
0
                    arraySizes.setDimSize(1, std::max(arraySizes.getDimSize(1), indexValue + 1));
628
0
                }
629
0
            }
630
0
        } else
631
1
            checkIndex(loc, base->getType(), indexValue);
632
1
        result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
633
1
    } else {
634
1
        if (base->getType().isUnsizedArray()) {
635
            // we have a variable index into an unsized array, which is okay,
636
            // depending on the situation
637
0
            if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
638
0
                error(loc, "", "[", "array must be sized by a redeclaration or layout qualifier before being indexed with a variable");
639
0
            else {
640
                // it is okay for a run-time sized array
641
0
                checkRuntimeSizable(loc, *base);
642
0
            }
643
0
            base->getWritableType().setArrayVariablyIndexed();
644
0
        }
645
1
        if (base->getBasicType() == EbtBlock) {
646
0
            if (base->getQualifier().storage == EvqBuffer)
647
0
                requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array");
648
0
            else if (base->getQualifier().storage == EvqUniform) {
649
0
                profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
650
0
                                "variable indexing uniform block array");
651
0
                profileRequires(base->getLoc(), ECoreProfile, 400, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5,
652
0
                                "variable indexing uniform block array");
653
654
0
            }
655
0
            else {
656
                // input/output blocks either don't exist or can't be variably indexed
657
0
            }
658
1
        } else if (language == EShLangFragment && base->getQualifier().isPipeOutput() && base->getQualifier().builtIn != EbvSampleMask)
659
0
            requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader output array");
660
1
        else if (base->getBasicType() == EbtSampler && version >= 130) {
661
0
            const char* explanation = "variable indexing sampler array";
662
0
            requireProfile(base->getLoc(), EEsProfile | ECoreProfile | ECompatibilityProfile, explanation);
663
0
            profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation);
664
0
            profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, Num_AEP_core_gpu_shader5,
665
0
                            AEP_core_gpu_shader5, explanation);
666
0
        }
667
668
1
        result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
669
1
    }
670
671
    // Insert valid dereferenced result type
672
2
    TType newType(base->getType(), 0);
673
2
    if (base->getType().getQualifier().isConstant() && index->getQualifier().isConstant()) {
674
0
        newType.getQualifier().storage = EvqConst;
675
        // If base or index is a specialization constant, the result should also be a specialization constant.
676
0
        if (base->getType().getQualifier().isSpecConstant() || index->getQualifier().isSpecConstant()) {
677
0
            newType.getQualifier().makeSpecConstant();
678
0
        }
679
2
    } else {
680
2
        newType.getQualifier().storage = EvqTemporary;
681
2
        newType.getQualifier().specConstant = false;
682
2
    }
683
2
    result->setType(newType);
684
685
2
    inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier());
686
687
    // Propagate nonuniform
688
2
    if (base->getQualifier().isNonUniform() || index->getQualifier().isNonUniform())
689
0
        result->getWritableType().getQualifier().nonUniform = true;
690
691
2
    if (anyIndexLimits)
692
0
        handleIndexLimits(loc, base, index);
693
694
2
    return result;
695
2
}
696
697
// for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
698
void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* base, TIntermTyped* index)
699
0
{
700
0
    if ((! limits.generalSamplerIndexing && base->getBasicType() == EbtSampler) ||
701
0
        (! limits.generalUniformIndexing && base->getQualifier().isUniformOrBuffer() && language != EShLangVertex) ||
702
0
        (! limits.generalAttributeMatrixVectorIndexing && base->getQualifier().isPipeInput() && language == EShLangVertex && (base->getType().isMatrix() || base->getType().isVector())) ||
703
0
        (! limits.generalConstantMatrixVectorIndexing && base->getAsConstantUnion()) ||
704
0
        (! limits.generalVariableIndexing && ! base->getType().getQualifier().isUniformOrBuffer() &&
705
0
                                             ! base->getType().getQualifier().isPipeInput() &&
706
0
                                             ! base->getType().getQualifier().isPipeOutput() &&
707
0
                                             ! base->getType().getQualifier().isConstant()) ||
708
0
        (! limits.generalVaryingIndexing && (base->getType().getQualifier().isPipeInput() ||
709
0
                                                base->getType().getQualifier().isPipeOutput()))) {
710
        // it's too early to know what the inductive variables are, save it for post processing
711
0
        needsIndexLimitationChecking.push_back(index);
712
0
    }
713
0
}
714
715
// Make a shared symbol have a non-shared version that can be edited by the current
716
// compile, such that editing its type will not change the shared version and will
717
// effect all nodes sharing it.
718
void TParseContext::makeEditable(TSymbol*& symbol)
719
0
{
720
0
    TParseContextBase::makeEditable(symbol);
721
722
    // See if it's tied to IO resizing
723
0
    if (isIoResizeArray(symbol->getType()))
724
0
        ioArraySymbolResizeList.push_back(symbol);
725
0
}
726
727
// Return true if this is a geometry shader input array or tessellation control output array
728
// or mesh shader output array.
729
bool TParseContext::isIoResizeArray(const TType& type) const
730
1.94k
{
731
1.94k
    return type.isArray() &&
732
1.94k
           ((language == EShLangGeometry    && type.getQualifier().storage == EvqVaryingIn) ||
733
1.29k
            (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut &&
734
1.07k
                ! type.getQualifier().patch) ||
735
1.29k
            (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn &&
736
859
                (type.getQualifier().pervertexNV || type.getQualifier().pervertexEXT)) ||
737
1.29k
            (language == EShLangMesh && type.getQualifier().storage == EvqVaryingOut &&
738
859
                !type.getQualifier().perTaskNV));
739
1.94k
}
740
741
// If an array is not isIoResizeArray() but is an io array, make sure it has the right size
742
void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type)
743
685
{
744
685
    if (! type.isArray() || type.getQualifier().patch || symbolTable.atBuiltInLevel())
745
654
        return;
746
747
31
    assert(! isIoResizeArray(type));
748
749
31
    if (type.getQualifier().storage != EvqVaryingIn || type.getQualifier().patch)
750
31
        return;
751
752
0
    if (language == EShLangTessControl || language == EShLangTessEvaluation) {
753
0
        if (type.getOuterArraySize() != resources.maxPatchVertices) {
754
0
            if (type.isSizedArray())
755
0
                error(loc, "tessellation input array size must be gl_MaxPatchVertices or implicitly sized", "[]", "");
756
0
            type.changeOuterArraySize(resources.maxPatchVertices);
757
0
        }
758
0
    }
759
0
}
760
761
// Issue any errors if the non-array object is missing arrayness WRT
762
// shader I/O that has array requirements.
763
// All arrayness checking is handled in array paths, this is for
764
void TParseContext::ioArrayCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
765
108k
{
766
108k
    if (! type.isArray() && ! symbolTable.atBuiltInLevel()) {
767
1.16k
        if (type.getQualifier().isArrayedIo(language) && !type.getQualifier().layoutPassthrough)
768
0
            error(loc, "type must be an array:", type.getStorageQualifierString(), identifier.c_str());
769
1.16k
    }
770
108k
}
771
772
// Handle a dereference of a geometry shader input array or tessellation control output array.
773
// See ioArraySymbolResizeList comment in ParseHelper.h.
774
//
775
void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TIntermTyped* base)
776
0
{
777
0
    TIntermSymbol* symbolNode = base->getAsSymbolNode();
778
0
    assert(symbolNode);
779
0
    if (! symbolNode)
780
0
        return;
781
782
    // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing)
783
0
    if (symbolNode->getType().isUnsizedArray()) {
784
0
        int newSize = getIoArrayImplicitSize(symbolNode->getType().getQualifier());
785
0
        if (newSize > 0)
786
0
            symbolNode->getWritableType().changeOuterArraySize(newSize);
787
0
    }
788
0
}
789
790
// If there has been an input primitive declaration (geometry shader) or an output
791
// number of vertices declaration(tessellation shader), make sure all input array types
792
// match it in size.  Types come either from nodes in the AST or symbols in the
793
// symbol table.
794
//
795
// Types without an array size will be given one.
796
// Types already having a size that is wrong will get an error.
797
//
798
void TParseContext::checkIoArraysConsistency(const TSourceLoc &loc, bool tailOnly)
799
1.25k
{
800
1.25k
    int requiredSize = 0;
801
1.25k
    TString featureString;
802
1.25k
    size_t listSize = ioArraySymbolResizeList.size();
803
1.25k
    size_t i = 0;
804
805
    // If tailOnly = true, only check the last array symbol in the list.
806
1.25k
    if (tailOnly) {
807
1.25k
        i = listSize - 1;
808
1.25k
    }
809
1.25k
    for (bool firstIteration = true; i < listSize; ++i) {
810
1.25k
        TType &type = ioArraySymbolResizeList[i]->getWritableType();
811
812
        // As I/O array sizes don't change, fetch requiredSize only once,
813
        // except for mesh shaders which could have different I/O array sizes based on type qualifiers.
814
1.25k
        if (firstIteration || (language == EShLangMesh)) {
815
1.25k
            requiredSize = getIoArrayImplicitSize(type.getQualifier(), &featureString);
816
1.25k
            if (requiredSize == 0)
817
1.25k
                break;
818
0
            firstIteration = false;
819
0
        }
820
821
0
        checkIoArrayConsistency(loc, requiredSize, featureString.c_str(), type,
822
0
                                ioArraySymbolResizeList[i]->getName());
823
0
    }
824
1.25k
}
825
826
int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString *featureString) const
827
1.25k
{
828
1.25k
    int expectedSize = 0;
829
1.25k
    TString str = "unknown";
830
1.25k
    unsigned int maxVertices = intermediate.getVertices() != TQualifier::layoutNotSet ? intermediate.getVertices() : 0;
831
832
1.25k
    if (language == EShLangGeometry) {
833
218
        expectedSize = TQualifier::mapGeometryToSize(intermediate.getInputPrimitive());
834
218
        str = TQualifier::getGeometryString(intermediate.getInputPrimitive());
835
218
    }
836
1.03k
    else if (language == EShLangTessControl) {
837
218
        expectedSize = maxVertices;
838
218
        str = "vertices";
839
820
    } else if (language == EShLangFragment) {
840
        // Number of vertices for Fragment shader is always three.
841
0
        expectedSize = 3;
842
0
        str = "vertices";
843
820
    } else if (language == EShLangMesh) {
844
820
        unsigned int maxPrimitives =
845
820
            intermediate.getPrimitives() != TQualifier::layoutNotSet ? intermediate.getPrimitives() : 0;
846
820
        if (qualifier.builtIn == EbvPrimitiveIndicesNV) {
847
0
            expectedSize = maxPrimitives * TQualifier::mapGeometryToSize(intermediate.getOutputPrimitive());
848
0
            str = "max_primitives*";
849
0
            str += TQualifier::getGeometryString(intermediate.getOutputPrimitive());
850
0
        }
851
820
        else if (qualifier.builtIn == EbvPrimitiveTriangleIndicesEXT || qualifier.builtIn == EbvPrimitiveLineIndicesEXT ||
852
820
                 qualifier.builtIn == EbvPrimitivePointIndicesEXT) {
853
0
            expectedSize = maxPrimitives;
854
0
            str = "max_primitives";
855
0
        }
856
820
        else if (qualifier.isPerPrimitive()) {
857
410
            expectedSize = maxPrimitives;
858
410
            str = "max_primitives";
859
410
        }
860
410
        else {
861
410
            expectedSize = maxVertices;
862
410
            str = "max_vertices";
863
410
        }
864
820
    }
865
1.25k
    if (featureString)
866
1.25k
        *featureString = str;
867
1.25k
    return expectedSize;
868
1.25k
}
869
870
void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredSize, const char* feature, TType& type, const TString& name)
871
0
{
872
0
    if (type.isUnsizedArray())
873
0
        type.changeOuterArraySize(requiredSize);
874
0
    else if (type.getOuterArraySize() != requiredSize) {
875
0
        if (language == EShLangGeometry)
876
0
            error(loc, "inconsistent input primitive for array size of", feature, name.c_str());
877
0
        else if (language == EShLangTessControl)
878
0
            error(loc, "inconsistent output number of vertices for array size of", feature, name.c_str());
879
0
        else if (language == EShLangFragment) {
880
0
            if (type.getOuterArraySize() > requiredSize)
881
0
                error(loc, " cannot be greater than 3 for pervertexEXT", feature, name.c_str());
882
0
        }
883
0
        else if (language == EShLangMesh)
884
0
            error(loc, "inconsistent output array size of", feature, name.c_str());
885
0
        else
886
0
            assert(0);
887
0
    }
888
0
}
889
890
// Handle seeing a binary node with a math operation.
891
// Returns nullptr if not semantically allowed.
892
TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right)
893
872
{
894
872
    rValueErrorCheck(loc, str, left->getAsTyped());
895
872
    rValueErrorCheck(loc, str, right->getAsTyped());
896
897
872
    bool allowed = true;
898
872
    switch (op) {
899
    // TODO: Bring more source language-specific checks up from intermediate.cpp
900
    // to the specific parse helpers for that source language.
901
373
    case EOpLessThan:
902
373
    case EOpGreaterThan:
903
373
    case EOpLessThanEqual:
904
373
    case EOpGreaterThanEqual:
905
373
        if (! left->isScalar() || ! right->isScalar())
906
0
            allowed = false;
907
373
        break;
908
499
    default:
909
499
        break;
910
872
    }
911
912
872
    if (((left->getType().contains16BitFloat() || right->getType().contains16BitFloat()) && !float16Arithmetic()) ||
913
872
        ((left->getType().contains16BitInt() || right->getType().contains16BitInt()) && !int16Arithmetic()) ||
914
872
        ((left->getType().contains8BitInt() || right->getType().contains8BitInt()) && !int8Arithmetic()) ||
915
872
        (left->getType().containsBFloat16() || right->getType().containsBFloat16()) ||
916
872
        (left->getType().contains8BitFloat() || right->getType().contains8BitFloat())) {
917
0
        allowed = false;
918
0
    }
919
920
872
    TIntermTyped* result = nullptr;
921
872
    if (allowed) {
922
872
        if ((left->isReference() || right->isReference()))
923
0
            requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference math");
924
872
        result = intermediate.addBinaryMath(op, left, right, loc);
925
872
    }
926
927
872
    if (result == nullptr) {
928
16
        bool enhanced = intermediate.getEnhancedMsgs();
929
16
        binaryOpError(loc, str, left->getCompleteString(enhanced), right->getCompleteString(enhanced));
930
16
    }
931
932
872
    return result;
933
872
}
934
935
// Handle seeing a unary node with a math operation.
936
TIntermTyped* TParseContext::handleUnaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* childNode)
937
1.24k
{
938
1.24k
    rValueErrorCheck(loc, str, childNode);
939
940
1.24k
    bool allowed = true;
941
1.24k
    if ((childNode->getType().contains16BitFloat() && !float16Arithmetic()) ||
942
1.24k
        (childNode->getType().contains16BitInt() && !int16Arithmetic()) ||
943
1.24k
        (childNode->getType().contains8BitInt() && !int8Arithmetic()) ||
944
1.24k
        (childNode->getType().containsBFloat16()) ||
945
1.24k
        (childNode->getType().contains8BitFloat())) {
946
0
        allowed = false;
947
0
    }
948
949
1.24k
    TIntermTyped* result = nullptr;
950
1.24k
    if (allowed)
951
1.24k
        result = intermediate.addUnaryMath(op, childNode, loc);
952
953
1.24k
    if (result)
954
411
        return result;
955
837
    else {
956
837
        bool enhanced = intermediate.getEnhancedMsgs();
957
837
        unaryOpError(loc, str, childNode->getCompleteString(enhanced));
958
837
    }
959
960
837
    return childNode;
961
1.24k
}
962
963
//
964
// Handle seeing a base.field dereference in the grammar.
965
//
966
TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TIntermTyped* base, const TString& field)
967
339
{
968
339
    variableCheck(base);
969
970
    //
971
    // .length() can't be resolved until we later see the function-calling syntax.
972
    // Save away the name in the AST for now.  Processing is completed in
973
    // handleLengthMethod().
974
    //
975
339
    if (field == "length") {
976
0
        if (base->isArray()) {
977
0
            profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, ".length");
978
0
            profileRequires(loc, EEsProfile, 300, nullptr, ".length");
979
0
        } else if (base->isVector() || base->isMatrix()) {
980
0
            const char* feature = ".length() on vectors and matrices";
981
0
            requireProfile(loc, ~EEsProfile, feature);
982
0
            profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, feature);
983
0
        } else if (!base->getType().isCoopMat() && !base->getType().isCoopVecNV()) {
984
0
            bool enhanced = intermediate.getEnhancedMsgs();
985
0
            error(loc, "does not operate on this type:", field.c_str(), base->getType().getCompleteString(enhanced).c_str());
986
0
            return base;
987
0
        }
988
989
0
        return intermediate.addMethod(base, TType(EbtInt), &field, loc);
990
0
    }
991
992
    // It's not .length() if we get to here.
993
994
339
    if (base->isArray()) {
995
0
        error(loc, "cannot apply to an array:", ".", field.c_str());
996
997
0
        return base;
998
0
    }
999
1000
339
    if (base->getType().isCoopMat()) {
1001
0
        error(loc, "cannot apply to a cooperative matrix type:", ".", field.c_str());
1002
0
        return base;
1003
0
    }
1004
1005
    // It's neither an array nor .length() if we get here,
1006
    // leaving swizzles and struct/block dereferences.
1007
1008
339
    TIntermTyped* result = base;
1009
339
    if ((base->isVector() || base->isScalar()) &&
1010
339
        (base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) {
1011
339
        result = handleDotSwizzle(loc, base, field);
1012
339
    } else if (base->isStruct() || base->isReference()) {
1013
0
        const TTypeList* fields = base->isReference() ?
1014
0
                                  base->getType().getReferentType()->getStruct() :
1015
0
                                  base->getType().getStruct();
1016
0
        bool fieldFound = false;
1017
0
        int member;
1018
0
        for (member = 0; member < (int)fields->size(); ++member) {
1019
0
            if ((*fields)[member].type->getFieldName() == field) {
1020
0
                fieldFound = true;
1021
0
                break;
1022
0
            }
1023
0
        }
1024
1025
0
        if (fieldFound) {
1026
0
            if (spvVersion.vulkan != 0 && spvVersion.vulkanRelaxed)
1027
0
                result = vkRelaxedRemapDotDereference(loc, *base, *(*fields)[member].type, field);
1028
1029
0
            if (result == base)
1030
0
            {
1031
0
                if (base->getType().getQualifier().isFrontEndConstant())
1032
0
                    result = intermediate.foldDereference(base, member, loc);
1033
0
                else {
1034
0
                    blockMemberExtensionCheck(loc, base, member, field);
1035
0
                    TIntermTyped* index = intermediate.addConstantUnion(member, loc);
1036
0
                    result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
1037
0
                    result->setType(*(*fields)[member].type);
1038
0
                    if ((*fields)[member].type->getQualifier().isIo())
1039
0
                        intermediate.addIoAccessed(field);
1040
0
                }
1041
0
            }
1042
1043
0
            inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier());
1044
0
        } else {
1045
0
            auto baseSymbol = base;
1046
0
            while (baseSymbol->getAsSymbolNode() == nullptr) {
1047
0
                auto binaryNode = baseSymbol->getAsBinaryNode();
1048
0
                if (binaryNode == nullptr) break;
1049
0
                baseSymbol = binaryNode->getLeft();
1050
0
            }
1051
0
            if (baseSymbol->getAsSymbolNode() != nullptr) {
1052
0
                TString structName;
1053
0
                structName.append("\'").append(baseSymbol->getAsSymbolNode()->getName().c_str()).append("\'");
1054
0
                error(loc, "no such field in structure", field.c_str(), structName.c_str());
1055
0
            } else {
1056
0
                error(loc, "no such field in structure", field.c_str(), "");
1057
0
            }
1058
0
        }
1059
0
    } else
1060
0
        error(loc, "does not apply to this type:", field.c_str(),
1061
0
          base->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str());
1062
1063
    // Propagate noContraction up the dereference chain
1064
339
    if (base->getQualifier().isNoContraction())
1065
0
        result->getWritableType().getQualifier().setNoContraction();
1066
1067
    // Propagate nonuniform
1068
339
    if (base->getQualifier().isNonUniform())
1069
0
        result->getWritableType().getQualifier().nonUniform = true;
1070
1071
339
    return result;
1072
339
}
1073
1074
//
1075
// Handle seeing a base.swizzle, a subset of base.identifier in the grammar.
1076
//
1077
TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermTyped* base, const TString& field)
1078
339
{
1079
339
    TIntermTyped* result = base;
1080
339
    if (base->isScalar()) {
1081
339
        const char* dotFeature = "scalar swizzle";
1082
339
        requireProfile(loc, ~EEsProfile, dotFeature);
1083
339
        profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature);
1084
339
    }
1085
1086
339
    TSwizzleSelectors<TVectorSelector> selectors;
1087
339
    parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
1088
1089
339
    if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
1090
0
        requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
1091
339
    if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt())
1092
0
        requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16");
1093
339
    if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt())
1094
0
        requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
1095
1096
339
    if (base->isScalar()) {
1097
339
        if (selectors.size() == 1)
1098
0
            return result;
1099
339
        else {
1100
339
            TType type(base->getBasicType(), EvqTemporary, selectors.size());
1101
            // Swizzle operations propagate specialization-constantness
1102
339
            if (base->getQualifier().isSpecConstant())
1103
0
                type.getQualifier().makeSpecConstant();
1104
339
            return addConstructor(loc, base, type);
1105
339
        }
1106
339
    }
1107
1108
0
    if (base->getType().getQualifier().isFrontEndConstant())
1109
0
        result = intermediate.foldSwizzle(base, selectors, loc);
1110
0
    else {
1111
0
        if (selectors.size() == 1) {
1112
0
            TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc);
1113
0
            result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
1114
0
            result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision));
1115
0
        } else {
1116
0
            TIntermTyped* index = intermediate.addSwizzle(selectors, loc);
1117
0
            result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
1118
0
            result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size()));
1119
0
        }
1120
        // Swizzle operations propagate specialization-constantness
1121
0
        if (base->getType().getQualifier().isSpecConstant())
1122
0
            result->getWritableType().getQualifier().makeSpecConstant();
1123
0
    }
1124
1125
0
    return result;
1126
339
}
1127
1128
void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
1129
0
{
1130
    // a block that needs extension checking is either 'base', or if arrayed,
1131
    // one level removed to the left
1132
0
    const TIntermSymbol* baseSymbol = nullptr;
1133
0
    if (base->getAsBinaryNode() == nullptr)
1134
0
        baseSymbol = base->getAsSymbolNode();
1135
0
    else
1136
0
        baseSymbol = base->getAsBinaryNode()->getLeft()->getAsSymbolNode();
1137
0
    if (baseSymbol == nullptr)
1138
0
        return;
1139
0
    const TSymbol* symbol = symbolTable.find(baseSymbol->getName());
1140
0
    if (symbol == nullptr)
1141
0
        return;
1142
0
    const TVariable* variable = symbol->getAsVariable();
1143
0
    if (variable == nullptr)
1144
0
        return;
1145
0
    if (!variable->hasMemberExtensions())
1146
0
        return;
1147
1148
    // We now have a variable that is the base of a dot reference
1149
    // with members that need extension checking.
1150
0
    if (variable->getNumMemberExtensions(member) > 0)
1151
0
        requireExtensions(loc, variable->getNumMemberExtensions(member), variable->getMemberExtensions(member), memberName.c_str());
1152
0
}
1153
1154
//
1155
// Handle seeing a function declarator in the grammar.  This is the precursor
1156
// to recognizing a function prototype or function definition.
1157
//
1158
TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunction& function, bool prototype)
1159
2.33M
{
1160
    // ES can't declare prototypes inside functions
1161
2.33M
    if (! symbolTable.atGlobalLevel())
1162
0
        requireProfile(loc, ~EEsProfile, "local function declaration");
1163
1164
    //
1165
    // Multiple declarations of the same function name are allowed.
1166
    //
1167
    // If this is a definition, the definition production code will check for redefinitions
1168
    // (we don't know at this point if it's a definition or not).
1169
    //
1170
    // Redeclarations (full signature match) are allowed.  But, return types and parameter qualifiers must also match.
1171
    //  - except ES 100, which only allows a single prototype
1172
    //
1173
    // ES 100 does not allow redefining, but does allow overloading of built-in functions.
1174
    // ES 300 does not allow redefining or overloading of built-in functions.
1175
    //
1176
2.33M
    bool builtIn;
1177
2.33M
    TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn);
1178
2.33M
    if (symbol && symbol->getAsFunction() && builtIn)
1179
11.1k
        requireProfile(loc, ~EEsProfile, "redefinition of built-in function");
1180
    // Check the validity of using spirv_literal qualifier
1181
8.75M
    for (int i = 0; i < function.getParamCount(); ++i) {
1182
6.41M
        if (function[i].type->getQualifier().isSpirvLiteral() && function.getBuiltInOp() != EOpSpirvInst)
1183
0
            error(loc, "'spirv_literal' can only be used on functions defined with 'spirv_instruction' for argument",
1184
0
                  function.getName().c_str(), "%d", i + 1);
1185
6.41M
    }
1186
1187
    // For function declaration with SPIR-V instruction qualifier, always ignore the built-in function and
1188
    // respect this redeclared one.
1189
2.33M
    if (symbol && builtIn && function.getBuiltInOp() == EOpSpirvInst)
1190
0
        symbol = nullptr;
1191
2.33M
    const TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr;
1192
2.33M
    if (prevDec) {
1193
11.1k
        if (prevDec->isPrototyped() && prototype)
1194
0
            profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function");
1195
11.1k
        if (prevDec->getSpirvInstruction() != function.getSpirvInstruction()) {
1196
0
            error(loc, "overloaded functions must have the same qualifiers", function.getName().c_str(),
1197
0
                  "spirv_instruction");
1198
0
        }
1199
11.1k
        bool parameterTypesDiffer = false;
1200
50.7k
        for (int i = 0; i < prevDec->getParamCount(); ++i) {
1201
39.5k
            if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
1202
0
                error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1);
1203
1204
39.5k
            if ((*prevDec)[i].type->getQualifier().precision != function[i].type->getQualifier().precision)
1205
0
                error(loc, "overloaded functions must have the same parameter precision qualifiers for argument", function[i].type->getPrecisionQualifierString(), "%d", i+1);
1206
1207
39.5k
            if (*(*prevDec)[i].type != *function[i].type)
1208
0
                parameterTypesDiffer = true;
1209
39.5k
        }
1210
11.1k
        if (!parameterTypesDiffer && prevDec->getType() != function.getType())
1211
0
            error(loc, "overloaded functions must have the same return type", function.getName().c_str(), "");
1212
11.1k
    }
1213
1214
2.33M
    arrayObjectCheck(loc, function.getType(), "array in function return type");
1215
1216
2.33M
    if (prototype) {
1217
        // All built-in functions are defined, even though they don't have a body.
1218
        // Count their prototype as a definition instead.
1219
2.33M
        if (symbolTable.atBuiltInLevel())
1220
2.33M
            function.setDefined();
1221
0
        else {
1222
0
            if (prevDec && ! builtIn)
1223
0
                symbol->getAsFunction()->setPrototyped();  // need a writable one, but like having prevDec as a const
1224
0
            function.setPrototyped();
1225
0
        }
1226
2.33M
    }
1227
1228
    // This insert won't actually insert it if it's a duplicate signature, but it will still check for
1229
    // other forms of name collisions.
1230
2.33M
    if (! symbolTable.insert(function))
1231
0
        error(loc, "function name is redeclaration of existing name", function.getName().c_str(), "");
1232
1233
    //
1234
    // If this is a redeclaration, it could also be a definition,
1235
    // in which case, we need to use the parameter names from this one, and not the one that's
1236
    // being redeclared.  So, pass back this declaration, not the one in the symbol table.
1237
    //
1238
2.33M
    return &function;
1239
2.33M
}
1240
1241
//
1242
// Handle seeing the function prototype in front of a function definition in the grammar.
1243
// The body is handled after this function returns.
1244
//
1245
TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function)
1246
19
{
1247
19
    currentCaller = function.getMangledName();
1248
19
    TSymbol* symbol = symbolTable.find(function.getMangledName());
1249
19
    TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr;
1250
1251
19
    if (! prevDec)
1252
0
        error(loc, "can't find function", function.getName().c_str(), "");
1253
    // Note:  'prevDec' could be 'function' if this is the first time we've seen function
1254
    // as it would have just been put in the symbol table.  Otherwise, we're looking up
1255
    // an earlier occurrence.
1256
1257
19
    if (prevDec && prevDec->isDefined()) {
1258
        // Then this function already has a body.
1259
0
        error(loc, "function already has a body", function.getName().c_str(), "");
1260
0
    }
1261
19
    if (prevDec && ! prevDec->isDefined()) {
1262
19
        prevDec->setDefined();
1263
1264
        // Remember the return type for later checking for RETURN statements.
1265
19
        currentFunctionType = &(prevDec->getType());
1266
19
    } else
1267
0
        currentFunctionType = new TType(EbtVoid);
1268
19
    functionReturnsValue = false;
1269
1270
    // Check for entry point
1271
19
    if (function.getName().compare(intermediate.getEntryPointName().c_str()) == 0) {
1272
3
        intermediate.setEntryPointMangledName(function.getMangledName().c_str());
1273
3
        intermediate.incrementEntryPointCount();
1274
3
        inMain = true;
1275
3
    } else
1276
16
        inMain = false;
1277
1278
    //
1279
    // Raise error message if main function takes any parameters or returns anything other than void
1280
    //
1281
19
    if (inMain) {
1282
3
        if (function.getParamCount() > 0)
1283
0
            error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
1284
3
        if (function.getType().getBasicType() != EbtVoid)
1285
0
            error(loc, "", function.getType().getBasicTypeString().c_str(), "entry point cannot return a value");
1286
3
        if (function.getLinkType() != ELinkNone)
1287
0
            error(loc, "main function cannot be exported", "", "");
1288
3
    }
1289
1290
    //
1291
    // New symbol table scope for body of function plus its arguments
1292
    //
1293
19
    symbolTable.push();
1294
1295
    //
1296
    // Insert parameters into the symbol table.
1297
    // If the parameter has no name, it's not an error, just don't insert it
1298
    // (could be used for unused args).
1299
    //
1300
    // Also, accumulate the list of parameters into the HIL, so lower level code
1301
    // knows where to find parameters.
1302
    //
1303
19
    TIntermAggregate* paramNodes = new TIntermAggregate;
1304
19
    for (int i = 0; i < function.getParamCount(); i++) {
1305
0
        TParameter& param = function[i];
1306
0
        if (param.name != nullptr) {
1307
0
            TVariable *variable = new TVariable(param.name, *param.type);
1308
1309
            // Insert the parameters with name in the symbol table.
1310
0
            if (! symbolTable.insert(*variable))
1311
0
                error(loc, "redefinition", variable->getName().c_str(), "");
1312
0
            else {
1313
                // Transfer ownership of name pointer to symbol table.
1314
0
                param.name = nullptr;
1315
1316
                // Add the parameter to the HIL
1317
0
                paramNodes = intermediate.growAggregate(paramNodes,
1318
0
                                                        intermediate.addSymbol(*variable, loc),
1319
0
                                                        loc);
1320
0
            }
1321
0
        } else
1322
0
            paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc);
1323
0
    }
1324
19
    paramNodes->setLinkType(function.getLinkType());
1325
19
    intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
1326
19
    loopNestingLevel = 0;
1327
19
    statementNestingLevel = 0;
1328
19
    controlFlowNestingLevel = 0;
1329
19
    postEntryPointReturn = false;
1330
1331
19
    return paramNodes;
1332
19
}
1333
1334
//
1335
// Handle seeing function call syntax in the grammar, which could be any of
1336
//  - .length() method
1337
//  - constructor
1338
//  - a call to a built-in function mapped to an operator
1339
//  - a call to a built-in function that will remain a function call (e.g., texturing)
1340
//  - user function
1341
//  - subroutine call (not implemented yet)
1342
//
1343
TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments)
1344
1.01k
{
1345
1.01k
    TIntermTyped* result = nullptr;
1346
1347
1.01k
    if (spvVersion.vulkan != 0 && spvVersion.vulkanRelaxed) {
1348
        // allow calls that are invalid in Vulkan Semantics to be invisibily
1349
        // remapped to equivalent valid functions
1350
0
        result = vkRelaxedRemapFunctionCall(loc, function, arguments);
1351
0
        if (result)
1352
0
            return result;
1353
0
    }
1354
1355
1.01k
    if (function->getBuiltInOp() == EOpArrayLength)
1356
0
        result = handleLengthMethod(loc, function, arguments);
1357
1.01k
    else if (function->getBuiltInOp() != EOpNull) {
1358
        //
1359
        // Then this should be a constructor.
1360
        // Don't go through the symbol table for constructors.
1361
        // Their parameters will be verified algorithmically.
1362
        //
1363
924
        TType type(EbtVoid);  // use this to get the type back
1364
924
        if (! constructorError(loc, arguments, *function, function->getBuiltInOp(), type)) {
1365
            //
1366
            // It's a constructor, of type 'type'.
1367
            //
1368
918
            result = addConstructor(loc, arguments, type);
1369
918
            if (result == nullptr)
1370
32
                error(loc, "cannot construct with these arguments", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str(), "");
1371
918
        }
1372
924
    } else {
1373
        //
1374
        // Find it in the symbol table.
1375
        //
1376
89
        const TFunction* fnCandidate;
1377
89
        bool builtIn {false};
1378
89
        fnCandidate = findFunction(loc, *function, builtIn);
1379
89
        if (fnCandidate) {
1380
            // This is a declared function that might map to
1381
            //  - a built-in operator,
1382
            //  - a built-in function not mapped to an operator, or
1383
            //  - a user function.
1384
1385
            // Error check for a function requiring specific extensions present.
1386
0
            if (builtIn &&
1387
0
                (fnCandidate->getBuiltInOp() == EOpSubgroupQuadAll || fnCandidate->getBuiltInOp() == EOpSubgroupQuadAny))
1388
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_quad_control, fnCandidate->getName().c_str());
1389
1390
0
            if (builtIn && fnCandidate->getNumExtensions())
1391
0
                requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
1392
1393
0
            if (builtIn && fnCandidate->getType().contains16BitFloat())
1394
0
                requireFloat16Arithmetic(loc, "built-in function", "float16 types can only be in uniform block or buffer storage");
1395
0
            if (builtIn && fnCandidate->getType().contains16BitInt())
1396
0
                requireInt16Arithmetic(loc, "built-in function", "(u)int16 types can only be in uniform block or buffer storage");
1397
0
            if (builtIn && fnCandidate->getType().contains8BitInt())
1398
0
                requireInt8Arithmetic(loc, "built-in function", "(u)int8 types can only be in uniform block or buffer storage");
1399
0
            if (builtIn && (fnCandidate->getBuiltInOp() == EOpTextureFetch || fnCandidate->getBuiltInOp() == EOpTextureQuerySize)) {
1400
0
                if ((*fnCandidate)[0].type->getSampler().isMultiSample() && version <= 140)
1401
0
                    requireExtensions(loc, 1, &E_GL_ARB_texture_multisample, fnCandidate->getName().c_str());
1402
0
            }
1403
0
            if (arguments != nullptr) {
1404
                // Make sure qualifications work for these arguments.
1405
0
                TIntermAggregate* aggregate = arguments->getAsAggregate();
1406
0
                for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
1407
                    // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
1408
                    // is the single argument itself or its children are the arguments.  Only one argument
1409
                    // means take 'arguments' itself as the one argument.
1410
0
                    if ((*fnCandidate)[i].defaultValue) {
1411
0
                        if (!aggregate) {
1412
                            // Only one argument was passed (rest are default arguments) so arguments isn't a TIntermAggregate.
1413
                            // But the function takes at least one more argument, so a TIntermAggregate is needed.
1414
0
                            aggregate = new TIntermAggregate;
1415
0
                            aggregate->getSequence().push_back(arguments);
1416
0
                            arguments = aggregate;
1417
0
                        }
1418
0
                        if (i >= static_cast<int>(aggregate->getSequence().size())) {
1419
                            // Append the default value if there are no more arguments left in the aggregate.
1420
0
                            TIntermConstantUnion *defaultValue = nullptr;
1421
0
                            if (const auto *constUnion = (*fnCandidate)[i].defaultValue->getAsConstantUnion()) {
1422
0
                                defaultValue = new TIntermConstantUnion(constUnion->getConstArray(), constUnion->getType());
1423
0
                            }
1424
0
                            assert(defaultValue && "unsupported default value construct");
1425
0
                            aggregate->getSequence().push_back(defaultValue);
1426
0
                        }
1427
0
                    }
1428
0
                    TIntermNode* arg = fnCandidate->getParamCount() == 1 ? arguments : (aggregate ? aggregate->getSequence()[i] : arguments);
1429
0
                    TQualifier& formalQualifier = (*fnCandidate)[i].type->getQualifier();
1430
0
                    if (formalQualifier.isParamOutput()) {
1431
0
                        if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
1432
0
                            error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
1433
0
                    }
1434
0
                    if (formalQualifier.isSpirvLiteral()) {
1435
0
                        if (!arg->getAsTyped()->getQualifier().isFrontEndConstant()) {
1436
0
                            error(arguments->getLoc(),
1437
0
                                  "Non front-end constant expressions cannot be passed for 'spirv_literal' parameters.",
1438
0
                                  "spirv_literal", "");
1439
0
                        }
1440
0
                    }
1441
0
                    const TType& argType = arg->getAsTyped()->getType();
1442
0
                    const TQualifier& argQualifier = argType.getQualifier();
1443
0
                    bool containsBindlessSampler = intermediate.getBindlessMode() && argType.containsSampler();
1444
0
                    if (argQualifier.isMemory() && !containsBindlessSampler && (argType.containsOpaque() || argType.isReference())) {
1445
0
                        const char* message = "argument cannot drop memory qualifier when passed to formal parameter";
1446
0
                        if (argQualifier.volatil && ! formalQualifier.volatil)
1447
0
                            error(arguments->getLoc(), message, "volatile", "");
1448
0
                        if (argQualifier.coherent && ! (formalQualifier.devicecoherent || formalQualifier.coherent))
1449
0
                            error(arguments->getLoc(), message, "coherent", "");
1450
0
                        if (argQualifier.devicecoherent && ! (formalQualifier.devicecoherent || formalQualifier.coherent))
1451
0
                            error(arguments->getLoc(), message, "devicecoherent", "");
1452
0
                        if (argQualifier.queuefamilycoherent && ! (formalQualifier.queuefamilycoherent || formalQualifier.devicecoherent || formalQualifier.coherent))
1453
0
                            error(arguments->getLoc(), message, "queuefamilycoherent", "");
1454
0
                        if (argQualifier.workgroupcoherent && ! (formalQualifier.workgroupcoherent || formalQualifier.queuefamilycoherent || formalQualifier.devicecoherent || formalQualifier.coherent))
1455
0
                            error(arguments->getLoc(), message, "workgroupcoherent", "");
1456
0
                        if (argQualifier.subgroupcoherent && ! (formalQualifier.subgroupcoherent || formalQualifier.workgroupcoherent || formalQualifier.queuefamilycoherent || formalQualifier.devicecoherent || formalQualifier.coherent))
1457
0
                            error(arguments->getLoc(), message, "subgroupcoherent", "");
1458
0
                        if (argQualifier.readonly && ! formalQualifier.readonly)
1459
0
                            error(arguments->getLoc(), message, "readonly", "");
1460
0
                        if (argQualifier.writeonly && ! formalQualifier.writeonly)
1461
0
                            error(arguments->getLoc(), message, "writeonly", "");
1462
0
                        if (argQualifier.nontemporal && ! formalQualifier.nontemporal)
1463
0
                            error(arguments->getLoc(), message, "nontemporal", "");
1464
                        // Don't check 'restrict', it is different than the rest:
1465
                        // "...but only restrict can be taken away from a calling argument, by a formal parameter that
1466
                        // lacks the restrict qualifier..."
1467
0
                    }
1468
0
                    if (!builtIn && argQualifier.getFormat() != formalQualifier.getFormat()) {
1469
                        // we have mismatched formats, which should only be allowed if writeonly
1470
                        // and at least one format is unknown
1471
0
                        if (!formalQualifier.isWriteOnly() || (formalQualifier.getFormat() != ElfNone &&
1472
0
                                                                  argQualifier.getFormat() != ElfNone))
1473
0
                            error(arguments->getLoc(), "image formats must match", "format", "");
1474
0
                    }
1475
0
                    if (builtIn && arg->getAsTyped()->getType().contains16BitFloat())
1476
0
                        requireFloat16Arithmetic(arguments->getLoc(), "built-in function", "float16 types can only be in uniform block or buffer storage");
1477
0
                    if (builtIn && arg->getAsTyped()->getType().contains16BitInt())
1478
0
                        requireInt16Arithmetic(arguments->getLoc(), "built-in function", "(u)int16 types can only be in uniform block or buffer storage");
1479
0
                    if (builtIn && arg->getAsTyped()->getType().contains8BitInt())
1480
0
                        requireInt8Arithmetic(arguments->getLoc(), "built-in function", "(u)int8 types can only be in uniform block or buffer storage");
1481
1482
                    // Check that coopVecOuterProductAccumulateNV vector component types match
1483
0
                    if (builtIn && fnCandidate->getBuiltInOp() == EOpCooperativeVectorOuterProductAccumulateNV &&
1484
0
                        i == 1 && arg->getAsTyped()->getType().getBasicType() != aggregate->getSequence()[0]->getAsTyped()->getType().getBasicType())
1485
0
                        error(arguments->getLoc(), "cooperative vector basic types must match", fnCandidate->getName().c_str(), "");
1486
1487
                    // TODO 4.5 functionality:  A shader will fail to compile
1488
                    // if the value passed to the memargument of an atomic memory function does not correspond to a buffer or
1489
                    // shared variable. It is acceptable to pass an element of an array or a single component of a vector to the
1490
                    // memargument of an atomic memory function, as long as the underlying array or vector is a buffer or
1491
                    // shared variable.
1492
0
                }
1493
1494
                // Convert 'in' arguments
1495
0
                addInputArgumentConversions(*fnCandidate, arguments);  // arguments may be modified if it's just a single argument node
1496
0
            }
1497
1498
0
            if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) {
1499
                // A function call mapped to a built-in operation.
1500
0
                result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate);
1501
0
            } else if (fnCandidate->getBuiltInOp() == EOpSpirvInst) {
1502
                // When SPIR-V instruction qualifier is specified, the function call is still mapped to a built-in operation.
1503
0
                result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate);
1504
0
            } else {
1505
                // This is a function call not mapped to built-in operator.
1506
                // It could still be a built-in function, but only if PureOperatorBuiltins == false.
1507
0
                result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc);
1508
0
                TIntermAggregate* call = result->getAsAggregate();
1509
0
                call->setName(fnCandidate->getMangledName());
1510
1511
                // this is how we know whether the given function is a built-in function or a user-defined function
1512
                // if builtIn == false, it's a userDefined -> could be an overloaded built-in function also
1513
                // if builtIn == true, it's definitely a built-in function with EOpNull
1514
0
                if (! builtIn) {
1515
0
                    call->setUserDefined();
1516
0
                    if (symbolTable.atGlobalLevel()) {
1517
0
                        requireProfile(loc, ~EEsProfile, "calling user function from global scope");
1518
0
                        intermediate.addToCallGraph(infoSink, "main(", fnCandidate->getMangledName());
1519
0
                    } else
1520
0
                        intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
1521
0
                }
1522
1523
0
                if (builtIn)
1524
0
                    nonOpBuiltInCheck(loc, *fnCandidate, *call);
1525
0
                else
1526
0
                    userFunctionCallCheck(loc, *call);
1527
0
            }
1528
1529
            // Convert 'out' arguments.  If it was a constant folded built-in, it won't be an aggregate anymore.
1530
            // Built-ins with a single argument aren't called with an aggregate, but they also don't have an output.
1531
            // Also, build the qualifier list for user function calls, which are always called with an aggregate.
1532
0
            if (result->getAsAggregate()) {
1533
0
                TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
1534
0
                for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
1535
0
                    TStorageQualifier qual = (*fnCandidate)[i].type->getQualifier().storage;
1536
0
                    qualifierList.push_back(qual);
1537
0
                }
1538
0
                result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
1539
0
            }
1540
1541
0
            handleCoopMat2FunctionCall(loc, fnCandidate, result, arguments);
1542
1543
0
            if (result->getAsTyped()->getType().isCoopVecNV() &&
1544
0
               !result->getAsTyped()->getType().isParameterized()) {
1545
0
                if (auto unaryNode = result->getAsUnaryNode())
1546
0
                    result->setType(unaryNode->getOperand()->getAsTyped()->getType());
1547
0
                else
1548
0
                    result->setType(result->getAsAggregate()->getSequence()[0]->getAsTyped()->getType());
1549
0
            }
1550
1551
0
            if (fnCandidate->getBuiltInOp() == EOpConstructSaturated) {
1552
                // result type is taken from the first parameter
1553
0
                result->setType(result->getAsAggregate()->getSequence()[0]->getAsTyped()->getType());
1554
0
            }
1555
0
        }
1556
89
    }
1557
1558
    // generic error recovery
1559
    // TODO: simplification: localize all the error recoveries that look like this, and taking type into account to reduce cascades
1560
1.01k
    if (result == nullptr)
1561
127
        result = intermediate.addConstantUnion(0.0, EbtFloat, loc);
1562
1563
1.01k
    return result;
1564
1.01k
}
1565
1566
void TParseContext::handleCoopMat2FunctionCall(const TSourceLoc& loc, const TFunction* fnCandidate, TIntermTyped* result, TIntermNode* arguments)
1567
0
{
1568
0
    if (arguments && arguments->getAsAggregate()) {
1569
0
        auto &sequence = arguments->getAsAggregate()->getSequence();
1570
0
        for (uint32_t i = 0; i < sequence.size(); ++i) {
1571
0
            auto param = sequence[i];
1572
0
            if (param->getAsTyped()->getBasicType() == EbtFunction) {
1573
                // Add the function to the callgraph
1574
0
                intermediate.addToCallGraph(infoSink, currentCaller, param->getAsSymbolNode()->getMangledName());
1575
1576
                // error checking that all parameters are 'const in'
1577
0
                if (fnCandidate->getBuiltInOp() == EOpCooperativeMatrixLoadTensorNV ||
1578
0
                    fnCandidate->getBuiltInOp() == EOpCooperativeMatrixReduceNV ||
1579
0
                    fnCandidate->getBuiltInOp() == EOpCooperativeMatrixPerElementOpNV) {
1580
0
                    const TFunction* func = symbolTable.find(param->getAsSymbolNode()->getMangledName())->getAsFunction();
1581
0
                    for (int i = 0; i < func->getParamCount(); ++i) {
1582
0
                        const TParameter& arg = (*func)[i];
1583
0
                        const TQualifier& formalQualifier = arg.type->getQualifier();
1584
0
                        if (formalQualifier.storage != EvqConstReadOnly) {
1585
0
                            error(loc, "function parameters must all be qualified 'const in'", param->getAsSymbolNode()->getMangledName().c_str(), "");
1586
0
                        }
1587
0
                    }
1588
0
                }
1589
1590
                // error checking decodeFunc parameters are (reference, uint32_t[], uint32_t[])
1591
0
                if (fnCandidate->getBuiltInOp() == EOpCooperativeMatrixLoadTensorNV) {
1592
0
                    const TFunction* decodeFunc = symbolTable.find(param->getAsSymbolNode()->getMangledName())->getAsFunction();
1593
1594
0
                    if (decodeFunc->getParamCount() != 3) {
1595
0
                        error(loc, "must have three parameters", param->getAsSymbolNode()->getMangledName().c_str(), "");
1596
0
                    }
1597
1598
0
                    if ((*decodeFunc)[0].type->getBasicType() != EbtReference) {
1599
0
                        error(loc, "first parameter must be buffer reference type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1600
0
                    }
1601
0
                    if ((*decodeFunc)[1].type->getBasicType() != EbtUint || (*decodeFunc)[2].type->getBasicType() != EbtUint) {
1602
0
                        error(loc, "coordinate parameters must be uint32_t", param->getAsSymbolNode()->getMangledName().c_str(), "");
1603
0
                    }
1604
0
                    if (!(*decodeFunc)[1].type->isArray() || !(*decodeFunc)[2].type->isArray()) {
1605
0
                        error(loc, "coordinate parameters must be uint32_t", param->getAsSymbolNode()->getMangledName().c_str(), "");
1606
0
                    }
1607
0
                }
1608
1609
                // error checking reduce function has matching parameters
1610
0
                if (fnCandidate->getBuiltInOp() == EOpCooperativeMatrixReduceNV) {
1611
0
                    const TFunction* combineOp = symbolTable.find(param->getAsSymbolNode()->getMangledName())->getAsFunction();
1612
1613
0
                    if (combineOp->getParamCount() != 2) {
1614
0
                        error(loc, "must have two parameters", param->getAsSymbolNode()->getMangledName().c_str(), "");
1615
0
                    }
1616
1617
0
                    for (int i = 0; i < combineOp->getParamCount(); ++i) {
1618
0
                        const TParameter& arg = (*combineOp)[i];
1619
0
                        if (sequence[1]->getAsTyped()->getType().getBasicType() != arg.type->getBasicType()) {
1620
0
                            error(loc, "parameter types must match cooperative matrix component type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1621
0
                        }
1622
0
                    }
1623
0
                    if (sequence[1]->getAsTyped()->getType().getBasicType() != combineOp->getType().getBasicType()) {
1624
0
                        error(loc, "return type must match cooperative matrix component type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1625
0
                    }
1626
0
                }
1627
1628
                // error checking perelement op has correct parameters
1629
0
                if (fnCandidate->getBuiltInOp() == EOpCooperativeMatrixPerElementOpNV) {
1630
0
                    const TFunction* elemOp = symbolTable.find(param->getAsSymbolNode()->getMangledName())->getAsFunction();
1631
1632
0
                    if (sequence[1]->getAsTyped()->getType() != sequence[0]->getAsTyped()->getType()) {
1633
0
                        error(loc, "cooperative matrix input and result types must match", "", "");
1634
0
                    }
1635
1636
0
                    if (elemOp->getParamCount() < 3) {
1637
0
                        error(loc, "not enough parameters", param->getAsSymbolNode()->getMangledName().c_str(), "");
1638
0
                    } else if (elemOp->getParamCount() != (int)sequence.size()) {
1639
0
                        error(loc, "number of parameters must match call to coopMatPerElementNV", param->getAsSymbolNode()->getMangledName().c_str(), "");
1640
0
                    } else {
1641
0
                        if ((*elemOp)[0].type->getBasicType() != EbtUint || (*elemOp)[1].type->getBasicType() != EbtUint) {
1642
0
                            error(loc, "row/column parameters must be uint32_t", param->getAsSymbolNode()->getMangledName().c_str(), "");
1643
0
                        }
1644
1645
0
                        const TParameter& matArg = (*elemOp)[2];
1646
0
                        if (sequence[1]->getAsTyped()->getType().getBasicType() != matArg.type->getBasicType()) {
1647
0
                            error(loc, "third parameter must match cooperative matrix component type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1648
0
                        }
1649
1650
0
                        for (int i = 3; i < elemOp->getParamCount(); ++i) {
1651
0
                            const TParameter& arg = (*elemOp)[i];
1652
0
                            if (sequence[i]->getAsTyped()->getType().getBasicType() != arg.type->getBasicType()) {
1653
0
                                error(loc, "parameter types must match or be cooperative matrix component type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1654
0
                            }
1655
0
                        }
1656
0
                        if (sequence[1]->getAsTyped()->getType().getBasicType() != elemOp->getType().getBasicType()) {
1657
0
                            error(loc, "return type must match cooperative matrix component type", param->getAsSymbolNode()->getMangledName().c_str(), "");
1658
0
                        }
1659
0
                    }
1660
0
                }
1661
0
            }
1662
0
        }
1663
0
    }
1664
0
    if ((result->getAsTyped()->getType().isCoopMat() ||
1665
0
         result->getAsTyped()->getType().isTensorLayoutNV() ||
1666
0
         result->getAsTyped()->getType().isTensorViewNV()) &&
1667
0
       !result->getAsTyped()->getType().isParameterized()) {
1668
0
        assert(fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAdd ||
1669
0
               fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAddNV ||
1670
0
               fnCandidate->getBuiltInOp() == EOpCooperativeMatrixReduceNV ||
1671
0
               fnCandidate->getBuiltInOp() == EOpCooperativeMatrixPerElementOpNV ||
1672
0
               fnCandidate->getBuiltInOp() == EOpCooperativeMatrixTransposeNV ||
1673
0
               fnCandidate->getBuiltInOp() == EOpCreateTensorLayoutNV ||
1674
0
               fnCandidate->getBuiltInOp() == EOpTensorLayoutSetDimensionNV ||
1675
0
               fnCandidate->getBuiltInOp() == EOpTensorLayoutSetBlockSizeNV ||
1676
0
               fnCandidate->getBuiltInOp() == EOpTensorLayoutSetStrideNV ||
1677
0
               fnCandidate->getBuiltInOp() == EOpTensorLayoutSliceNV ||
1678
0
               fnCandidate->getBuiltInOp() == EOpTensorLayoutSetClampValueNV ||
1679
0
               fnCandidate->getBuiltInOp() == EOpCreateTensorViewNV ||
1680
0
               fnCandidate->getBuiltInOp() == EOpTensorViewSetDimensionNV ||
1681
0
               fnCandidate->getBuiltInOp() == EOpTensorViewSetStrideNV ||
1682
0
               fnCandidate->getBuiltInOp() == EOpTensorViewSetClipNV);
1683
1684
0
        if (fnCandidate->getBuiltInOp() == EOpCreateTensorLayoutNV) {
1685
1686
            // Convert template parameters to arraySizes/typeParameters
1687
0
            TArraySizes *arraySizes = new TArraySizes;
1688
0
            for (uint32_t i = 0; i < 2; ++i) {
1689
0
                TIntermNode *param {};
1690
0
                if (arguments->getAsConstantUnion()) {
1691
0
                    if (i == 0) {
1692
0
                        param = arguments;
1693
0
                    }
1694
0
                } else {
1695
0
                    assert(arguments->getAsAggregate());
1696
0
                    auto &sequence = arguments->getAsAggregate()->getSequence();
1697
0
                    if (i < sequence.size()) {
1698
0
                        param = sequence[i];
1699
0
                    }
1700
0
                }
1701
0
                if (param) {
1702
0
                    if (param->getAsTyped()->getType().getQualifier().isSpecConstant()) {
1703
0
                        uint32_t value = param->getAsSymbolNode()->getConstArray()[0].getIConst();
1704
0
                        arraySizes->addInnerSize(value, param->getAsTyped());
1705
0
                    } else {
1706
0
                        uint32_t value = param->getAsConstantUnion()->getConstArray()[0].getIConst();
1707
0
                        arraySizes->addInnerSize(value);
1708
0
                    }
1709
0
                } else {
1710
                    // gl_CooperativeMatrixClampModeUndefined
1711
0
                    arraySizes->addInnerSize(0);
1712
0
                }
1713
0
            }
1714
0
            TTypeParameters typeParameters;
1715
0
            typeParameters.arraySizes = arraySizes;
1716
1717
0
            TType resultType;
1718
0
            resultType.deepCopy(result->getAsTyped()->getType());
1719
1720
0
            resultType.copyTypeParameters(typeParameters);
1721
0
            result->setType(resultType);
1722
0
        } else if (fnCandidate->getBuiltInOp() == EOpCreateTensorViewNV) {
1723
1724
            // Convert template parameters to arraySizes/typeParameters
1725
0
            TArraySizes *arraySizes = new TArraySizes;
1726
0
            for (uint32_t i = 0; i < 7; ++i) {
1727
0
                TIntermNode *param {};
1728
0
                if (arguments->getAsConstantUnion()) {
1729
0
                    if (i == 0) {
1730
0
                        param = arguments;
1731
0
                    }
1732
0
                } else {
1733
0
                    assert(arguments->getAsAggregate());
1734
0
                    auto &sequence = arguments->getAsAggregate()->getSequence();
1735
0
                    if (i < sequence.size()) {
1736
0
                        param = sequence[i];
1737
0
                    }
1738
0
                }
1739
0
                if (param) {
1740
0
                    if (param->getAsTyped()->getType().getQualifier().isSpecConstant()) {
1741
0
                        uint32_t value = param->getAsSymbolNode()->getConstArray()[0].getIConst();
1742
0
                        arraySizes->addInnerSize(value, param->getAsTyped());
1743
0
                    } else {
1744
0
                        uint32_t value = param->getAsConstantUnion()->getConstArray()[0].getIConst();
1745
0
                        arraySizes->addInnerSize(value);
1746
0
                    }
1747
0
                } else {
1748
0
                    uint32_t value = 0;
1749
0
                    if (i >= 2) {
1750
                        // default permutation values are an increasing sequence
1751
0
                        value = i - 2;
1752
0
                    }
1753
0
                    arraySizes->addInnerSize(value);
1754
0
                }
1755
0
            }
1756
0
            TTypeParameters typeParameters;
1757
0
            typeParameters.arraySizes = arraySizes;
1758
1759
0
            TType resultType;
1760
0
            resultType.deepCopy(result->getAsTyped()->getType());
1761
1762
0
            resultType.copyTypeParameters(typeParameters);
1763
0
            result->setType(resultType);
1764
0
        } else if (fnCandidate->getBuiltInOp() == EOpCooperativeMatrixReduceNV ||
1765
0
                   fnCandidate->getBuiltInOp() == EOpCooperativeMatrixPerElementOpNV ||
1766
0
                   fnCandidate->getBuiltInOp() == EOpCooperativeMatrixTransposeNV ||
1767
0
                   fnCandidate->getBuiltInOp() == EOpTensorLayoutSetDimensionNV ||
1768
0
                   fnCandidate->getBuiltInOp() == EOpTensorLayoutSetBlockSizeNV ||
1769
0
                   fnCandidate->getBuiltInOp() == EOpTensorLayoutSetStrideNV ||
1770
0
                   fnCandidate->getBuiltInOp() == EOpTensorLayoutSliceNV ||
1771
0
                   fnCandidate->getBuiltInOp() == EOpTensorLayoutSetClampValueNV ||
1772
0
                   fnCandidate->getBuiltInOp() == EOpTensorViewSetDimensionNV ||
1773
0
                   fnCandidate->getBuiltInOp() == EOpTensorViewSetStrideNV ||
1774
0
                   fnCandidate->getBuiltInOp() == EOpTensorViewSetClipNV) {
1775
            // Set result type to match type of first parameter
1776
0
            result->setType(result->getAsAggregate()->getSequence()[0]->getAsTyped()->getType());
1777
0
        } else {
1778
            // For MulAdd, set result type to match type of C parameter
1779
0
            result->setType(result->getAsAggregate()->getSequence()[2]->getAsTyped()->getType());
1780
0
        }
1781
0
    }
1782
0
}
1783
1784
TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNode* arguments,
1785
                                                       const TFunction& function)
1786
0
{
1787
0
    checkLocation(loc, function.getBuiltInOp());
1788
0
    TIntermTyped *result = intermediate.addBuiltInFunctionCall(loc, function.getBuiltInOp(),
1789
0
                                                               function.getParamCount() == 1,
1790
0
                                                               arguments, function.getType());
1791
0
    if (result != nullptr && obeyPrecisionQualifiers())
1792
0
        computeBuiltinPrecisions(*result, function);
1793
1794
0
    if (result == nullptr) {
1795
0
        if (arguments == nullptr)
1796
0
            error(loc, " wrong operand type", "Internal Error",
1797
0
                                      "built in unary operator function.  Type: %s", "");
1798
0
        else
1799
0
            error(arguments->getLoc(), " wrong operand type", "Internal Error",
1800
0
                                      "built in unary operator function.  Type: %s",
1801
0
                                      static_cast<TIntermTyped*>(arguments)->getCompleteString(intermediate.getEnhancedMsgs()).c_str());
1802
0
    } else if (result->getAsOperator())
1803
0
        builtInOpCheck(loc, function, *result->getAsOperator());
1804
1805
    // Special handling for function call with SPIR-V instruction qualifier specified
1806
0
    if (function.getBuiltInOp() == EOpSpirvInst) {
1807
0
        if (auto agg = result->getAsAggregate()) {
1808
            // Propogate spirv_by_reference/spirv_literal from parameters to arguments
1809
0
            auto& sequence = agg->getSequence();
1810
0
            for (unsigned i = 0; i < sequence.size(); ++i) {
1811
0
                if (function[i].type->getQualifier().isSpirvByReference())
1812
0
                    sequence[i]->getAsTyped()->getQualifier().setSpirvByReference();
1813
0
                if (function[i].type->getQualifier().isSpirvLiteral())
1814
0
                    sequence[i]->getAsTyped()->getQualifier().setSpirvLiteral();
1815
0
            }
1816
1817
            // Attach the function call to SPIR-V intruction
1818
0
            agg->setSpirvInstruction(function.getSpirvInstruction());
1819
0
        } else if (auto unaryNode = result->getAsUnaryNode()) {
1820
            // Propogate spirv_by_reference/spirv_literal from parameters to arguments
1821
0
            if (function[0].type->getQualifier().isSpirvByReference())
1822
0
                unaryNode->getOperand()->getQualifier().setSpirvByReference();
1823
0
            if (function[0].type->getQualifier().isSpirvLiteral())
1824
0
                unaryNode->getOperand()->getQualifier().setSpirvLiteral();
1825
1826
            // Attach the function call to SPIR-V intruction
1827
0
            unaryNode->setSpirvInstruction(function.getSpirvInstruction());
1828
0
        } else
1829
0
            assert(0);
1830
0
    }
1831
1832
0
    return result;
1833
0
}
1834
1835
// "The operation of a built-in function can have a different precision
1836
// qualification than the precision qualification of the resulting value.
1837
// These two precision qualifications are established as follows.
1838
//
1839
// The precision qualification of the operation of a built-in function is
1840
// based on the precision qualification of its input arguments and formal
1841
// parameters:  When a formal parameter specifies a precision qualifier,
1842
// that is used, otherwise, the precision qualification of the calling
1843
// argument is used.  The highest precision of these will be the precision
1844
// qualification of the operation of the built-in function. Generally,
1845
// this is applied across all arguments to a built-in function, with the
1846
// exceptions being:
1847
//   - bitfieldExtract and bitfieldInsert ignore the 'offset' and 'bits'
1848
//     arguments.
1849
//   - interpolateAt* functions only look at the 'interpolant' argument.
1850
//
1851
// The precision qualification of the result of a built-in function is
1852
// determined in one of the following ways:
1853
//
1854
//   - For the texture sampling, image load, and image store functions,
1855
//     the precision of the return type matches the precision of the
1856
//     sampler type
1857
//
1858
//   Otherwise:
1859
//
1860
//   - For prototypes that do not specify a resulting precision qualifier,
1861
//     the precision will be the same as the precision of the operation.
1862
//
1863
//   - For prototypes that do specify a resulting precision qualifier,
1864
//     the specified precision qualifier is the precision qualification of
1865
//     the result."
1866
//
1867
void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction& function)
1868
0
{
1869
0
    TPrecisionQualifier operationPrecision = EpqNone;
1870
0
    TPrecisionQualifier resultPrecision = EpqNone;
1871
1872
0
    TIntermOperator* opNode = node.getAsOperator();
1873
0
    if (opNode == nullptr)
1874
0
        return;
1875
1876
0
    if (TIntermUnary* unaryNode = node.getAsUnaryNode()) {
1877
0
        operationPrecision = std::max(function[0].type->getQualifier().precision,
1878
0
                                      unaryNode->getOperand()->getType().getQualifier().precision);
1879
0
        if (function.getType().getBasicType() != EbtBool)
1880
0
            resultPrecision = function.getType().getQualifier().precision == EpqNone ?
1881
0
                                        operationPrecision :
1882
0
                                        function.getType().getQualifier().precision;
1883
0
    } else if (TIntermAggregate* agg = node.getAsAggregate()) {
1884
0
        TIntermSequence& sequence = agg->getSequence();
1885
0
        unsigned int numArgs = (unsigned int)sequence.size();
1886
0
        switch (agg->getOp()) {
1887
0
        case EOpBitfieldExtract:
1888
0
            numArgs = 1;
1889
0
            break;
1890
0
        case EOpBitfieldInsert:
1891
0
            numArgs = 2;
1892
0
            break;
1893
0
        case EOpInterpolateAtCentroid:
1894
0
        case EOpInterpolateAtOffset:
1895
0
        case EOpInterpolateAtSample:
1896
0
            numArgs = 1;
1897
0
            break;
1898
0
        case EOpDebugPrintf:
1899
0
        case EOpCooperativeMatrixPerElementOpNV:
1900
0
        case EOpCooperativeMatrixReduceNV:
1901
0
        case EOpConstructSaturated:
1902
0
            numArgs = 0;
1903
0
            break;
1904
0
        default:
1905
0
            break;
1906
0
        }
1907
        // find the maximum precision from the arguments and parameters
1908
0
        for (unsigned int arg = 0; arg < numArgs; ++arg) {
1909
0
            operationPrecision = std::max(operationPrecision, sequence[arg]->getAsTyped()->getQualifier().precision);
1910
0
        }
1911
0
        for (int arg = 0; arg < function.getParamCount(); ++arg) {
1912
0
            operationPrecision = std::max(operationPrecision, function[arg].type->getQualifier().precision);
1913
0
        }
1914
        // compute the result precision
1915
0
        if (agg->isSampling() ||
1916
0
            agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore ||
1917
0
            agg->getOp() == EOpImageLoadLod || agg->getOp() == EOpImageStoreLod)
1918
0
            resultPrecision = sequence[0]->getAsTyped()->getQualifier().precision;
1919
0
        else if (function.getType().getBasicType() != EbtBool)
1920
0
            resultPrecision = function.getType().getQualifier().precision == EpqNone ?
1921
0
                                        operationPrecision :
1922
0
                                        function.getType().getQualifier().precision;
1923
0
    }
1924
1925
    // Propagate precision through this node and its children. That algorithm stops
1926
    // when a precision is found, so start by clearing this subroot precision
1927
0
    opNode->getQualifier().precision = EpqNone;
1928
0
    if (operationPrecision != EpqNone) {
1929
0
        opNode->propagatePrecision(operationPrecision);
1930
0
        opNode->setOperationPrecision(operationPrecision);
1931
0
    }
1932
    // Now, set the result precision, which might not match
1933
0
    opNode->getQualifier().precision = resultPrecision;
1934
0
}
1935
1936
TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value)
1937
0
{
1938
0
    storage16BitAssignmentCheck(loc, value->getType(), "return");
1939
1940
0
    functionReturnsValue = true;
1941
0
    TIntermBranch* branch = nullptr;
1942
0
    if (currentFunctionType->getBasicType() == EbtVoid) {
1943
0
        error(loc, "void function cannot return a value", "return", "");
1944
0
        branch = intermediate.addBranch(EOpReturn, loc);
1945
0
    } else if (*currentFunctionType != value->getType()) {
1946
0
        TIntermTyped* converted = intermediate.addConversion(EOpReturn, *currentFunctionType, value);
1947
0
        if (converted) {
1948
0
            if (*currentFunctionType != converted->getType())
1949
0
                error(loc, "cannot convert return value to function return type", "return", "");
1950
0
            if (version < 420)
1951
0
                warn(loc, "type conversion on return values was not explicitly allowed until version 420",
1952
0
                     "return", "");
1953
0
            branch = intermediate.addBranch(EOpReturn, converted, loc);
1954
0
        } else {
1955
0
            error(loc, "type does not match, or is not convertible to, the function's return type", "return", "");
1956
0
            branch = intermediate.addBranch(EOpReturn, value, loc);
1957
0
        }
1958
0
    } else {
1959
0
        if (value->getType().isTexture() || value->getType().isImage()) {
1960
0
            if (spvVersion.spv != 0)
1961
0
                error(loc, "sampler or image cannot be used as return type when generating SPIR-V", "return", "");
1962
0
            else if (!extensionTurnedOn(E_GL_ARB_bindless_texture))
1963
0
                error(loc, "sampler or image can be used as return type only when the extension GL_ARB_bindless_texture enabled", "return", "");
1964
0
        }
1965
0
        branch = intermediate.addBranch(EOpReturn, value, loc);
1966
0
    }
1967
0
    branch->updatePrecision(currentFunctionType->getQualifier().precision);
1968
0
    return branch;
1969
0
}
1970
1971
// See if the operation is being done in an illegal location.
1972
void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op)
1973
0
{
1974
0
    switch (op) {
1975
0
    case EOpBarrier:
1976
0
        if (language == EShLangTessControl) {
1977
0
            if (controlFlowNestingLevel > 0)
1978
0
                error(loc, "tessellation control barrier() cannot be placed within flow control", "", "");
1979
0
            if (! inMain)
1980
0
                error(loc, "tessellation control barrier() must be in main()", "", "");
1981
0
            else if (postEntryPointReturn)
1982
0
                error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", "");
1983
0
        }
1984
0
        break;
1985
0
    case EOpBeginInvocationInterlock:
1986
0
        if (language != EShLangFragment)
1987
0
            error(loc, "beginInvocationInterlockARB() must be in a fragment shader", "", "");
1988
0
        if (! inMain)
1989
0
            error(loc, "beginInvocationInterlockARB() must be in main()", "", "");
1990
0
        else if (postEntryPointReturn)
1991
0
            error(loc, "beginInvocationInterlockARB() cannot be placed after a return from main()", "", "");
1992
0
        if (controlFlowNestingLevel > 0)
1993
0
            error(loc, "beginInvocationInterlockARB() cannot be placed within flow control", "", "");
1994
1995
0
        if (beginInvocationInterlockCount > 0)
1996
0
            error(loc, "beginInvocationInterlockARB() must only be called once", "", "");
1997
0
        if (endInvocationInterlockCount > 0)
1998
0
            error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", "");
1999
2000
0
        beginInvocationInterlockCount++;
2001
2002
        // default to pixel_interlock_ordered
2003
0
        if (intermediate.getInterlockOrdering() == EioNone)
2004
0
            intermediate.setInterlockOrdering(EioPixelInterlockOrdered);
2005
0
        break;
2006
0
    case EOpEndInvocationInterlock:
2007
0
        if (language != EShLangFragment)
2008
0
            error(loc, "endInvocationInterlockARB() must be in a fragment shader", "", "");
2009
0
        if (! inMain)
2010
0
            error(loc, "endInvocationInterlockARB() must be in main()", "", "");
2011
0
        else if (postEntryPointReturn)
2012
0
            error(loc, "endInvocationInterlockARB() cannot be placed after a return from main()", "", "");
2013
0
        if (controlFlowNestingLevel > 0)
2014
0
            error(loc, "endInvocationInterlockARB() cannot be placed within flow control", "", "");
2015
2016
0
        if (endInvocationInterlockCount > 0)
2017
0
            error(loc, "endInvocationInterlockARB() must only be called once", "", "");
2018
0
        if (beginInvocationInterlockCount == 0)
2019
0
            error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", "");
2020
2021
0
        endInvocationInterlockCount++;
2022
0
        break;
2023
0
    default:
2024
0
        break;
2025
0
    }
2026
0
}
2027
2028
// Finish processing object.length(). This started earlier in handleDotDereference(), where
2029
// the ".length" part was recognized and semantically checked, and finished here where the
2030
// function syntax "()" is recognized.
2031
//
2032
// Return resulting tree node.
2033
TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction* function, TIntermNode* intermNode)
2034
0
{
2035
0
    int length = 0;
2036
2037
0
    if (function->getParamCount() > 0)
2038
0
        error(loc, "method does not accept any arguments", function->getName().c_str(), "");
2039
0
    else {
2040
0
        const TType& type = intermNode->getAsTyped()->getType();
2041
0
        if (type.isArray()) {
2042
0
            if (type.isUnsizedArray()) {
2043
0
                if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) {
2044
                    // We could be between a layout declaration that gives a built-in io array implicit size and
2045
                    // a user redeclaration of that array, meaning we have to substitute its implicit size here
2046
                    // without actually redeclaring the array.  (It is an error to use a member before the
2047
                    // redeclaration, but not an error to use the array name itself.)
2048
0
                    const TString& name = intermNode->getAsSymbolNode()->getName();
2049
0
                    if (name == "gl_in" || name == "gl_out" || name == "gl_MeshVerticesNV" ||
2050
0
                        name == "gl_MeshPrimitivesNV") {
2051
0
                        length = getIoArrayImplicitSize(type.getQualifier());
2052
0
                    }
2053
0
                } else if (const auto typed = intermNode->getAsTyped()) {
2054
0
                    if (typed->getQualifier().builtIn == EbvSampleMask) {
2055
0
                        requireProfile(loc, EEsProfile, "the array size of gl_SampleMask and gl_SampleMaskIn is ceil(gl_MaxSamples/32)");
2056
0
                        length = (resources.maxSamples + 31) / 32;
2057
0
                    }
2058
0
                }
2059
0
                if (length == 0) {
2060
0
                    if (intermNode->getAsSymbolNode() && isIoResizeArray(type))
2061
0
                        error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
2062
0
                    else if (isRuntimeLength(*intermNode->getAsTyped())) {
2063
                        // Create a unary op and let the back end handle it
2064
0
                        return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
2065
0
                    } else
2066
0
                        error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
2067
0
                }
2068
0
            } else if (type.getOuterArrayNode()) {
2069
                // If the array's outer size is specified by an intermediate node, it means the array's length
2070
                // was specified by a specialization constant. In such a case, we should return the node of the
2071
                // specialization constants to represent the length.
2072
0
                return type.getOuterArrayNode();
2073
0
            } else
2074
0
                length = type.getOuterArraySize();
2075
0
        } else if (type.isMatrix())
2076
0
            length = type.getMatrixCols();
2077
0
        else if (type.isVector())
2078
0
            length = type.getVectorSize();
2079
0
        else if (type.isCoopMat() || type.isCoopVecNV())
2080
0
            return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
2081
0
        else {
2082
            // we should not get here, because earlier semantic checking should have prevented this path
2083
0
            error(loc, ".length()", "unexpected use of .length()", "");
2084
0
        }
2085
0
    }
2086
2087
0
    if (length == 0)
2088
0
        length = 1;
2089
2090
0
    return intermediate.addConstantUnion(length, loc);
2091
0
}
2092
2093
//
2094
// Add any needed implicit conversions for function-call arguments to input parameters.
2095
//
2096
void TParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const
2097
0
{
2098
0
    TIntermAggregate* aggregate = arguments->getAsAggregate();
2099
2100
    // Process each argument's conversion
2101
0
    for (int i = 0; i < function.getParamCount(); ++i) {
2102
        // At this early point there is a slight ambiguity between whether an aggregate 'arguments'
2103
        // is the single argument itself or its children are the arguments.  Only one argument
2104
        // means take 'arguments' itself as the one argument.
2105
0
        TIntermTyped* arg = function.getParamCount() == 1 ? arguments->getAsTyped() : (aggregate ? aggregate->getSequence()[i]->getAsTyped() : arguments->getAsTyped());
2106
0
        if (*function[i].type != arg->getType()) {
2107
0
            if (function[i].type->getQualifier().isParamInput() &&
2108
0
               !function[i].type->isCoopMat() && !function[i].type->isTensorARM()) {
2109
                // In-qualified arguments just need an extra node added above the argument to
2110
                // convert to the correct type.
2111
0
                arg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg);
2112
0
                if (arg) {
2113
0
                    if (function.getParamCount() == 1)
2114
0
                        arguments = arg;
2115
0
                    else {
2116
0
                        if (aggregate)
2117
0
                            aggregate->getSequence()[i] = arg;
2118
0
                        else
2119
0
                            arguments = arg;
2120
0
                    }
2121
0
                }
2122
0
            }
2123
0
        }
2124
0
    }
2125
0
}
2126
2127
//
2128
// Add any needed implicit output conversions for function-call arguments.  This
2129
// can require a new tree topology, complicated further by whether the function
2130
// has a return value.
2131
//
2132
// Returns a node of a subtree that evaluates to the return value of the function.
2133
//
2134
TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const
2135
0
{
2136
0
    TIntermSequence& arguments = intermNode.getSequence();
2137
2138
    // Will there be any output conversions?
2139
0
    bool outputConversions = false;
2140
0
    for (int i = 0; i < function.getParamCount(); ++i) {
2141
0
        if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().isParamOutput() &&
2142
0
            !function[i].type->isCoopMat()) {
2143
0
            outputConversions = true;
2144
0
            break;
2145
0
        }
2146
0
    }
2147
2148
0
    if (! outputConversions)
2149
0
        return &intermNode;
2150
2151
    // Setup for the new tree, if needed:
2152
    //
2153
    // Output conversions need a different tree topology.
2154
    // Out-qualified arguments need a temporary of the correct type, with the call
2155
    // followed by an assignment of the temporary to the original argument:
2156
    //     void: function(arg, ...)  ->        (          function(tempArg, ...), arg = tempArg, ...)
2157
    //     ret = function(arg, ...)  ->  ret = (tempRet = function(tempArg, ...), arg = tempArg, ..., tempRet)
2158
    // Where the "tempArg" type needs no conversion as an argument, but will convert on assignment.
2159
0
    TIntermTyped* conversionTree = nullptr;
2160
0
    TVariable* tempRet = nullptr;
2161
0
    if (intermNode.getBasicType() != EbtVoid) {
2162
        // do the "tempRet = function(...), " bit from above
2163
0
        tempRet = makeInternalVariable("tempReturn", intermNode.getType());
2164
0
        TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
2165
0
        conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, intermNode.getLoc());
2166
0
    } else
2167
0
        conversionTree = &intermNode;
2168
2169
0
    conversionTree = intermediate.makeAggregate(conversionTree);
2170
2171
    // Process each argument's conversion
2172
0
    for (int i = 0; i < function.getParamCount(); ++i) {
2173
0
        if (*function[i].type != arguments[i]->getAsTyped()->getType()) {
2174
0
            if (function[i].type->getQualifier().isParamOutput()) {
2175
                // Out-qualified arguments need to use the topology set up above.
2176
                // do the " ...(tempArg, ...), arg = tempArg" bit from above
2177
0
                TType paramType;
2178
0
                paramType.shallowCopy(*function[i].type);
2179
0
                if (arguments[i]->getAsTyped()->getType().isParameterized() &&
2180
0
                    !paramType.isParameterized()) {
2181
0
                    paramType.shallowCopy(arguments[i]->getAsTyped()->getType());
2182
0
                    paramType.copyTypeParameters(*arguments[i]->getAsTyped()->getType().getTypeParameters());
2183
0
                }
2184
0
                TVariable* tempArg = makeInternalVariable("tempArg", paramType);
2185
0
                tempArg->getWritableType().getQualifier().makeTemporary();
2186
0
                TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc());
2187
0
                TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc());
2188
0
                conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc());
2189
                // replace the argument with another node for the same tempArg variable
2190
0
                arguments[i] = intermediate.addSymbol(*tempArg, intermNode.getLoc());
2191
0
            }
2192
0
        }
2193
0
    }
2194
2195
    // Finalize the tree topology (see bigger comment above).
2196
0
    if (tempRet) {
2197
        // do the "..., tempRet" bit from above
2198
0
        TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
2199
0
        conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, intermNode.getLoc());
2200
0
    }
2201
0
    conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc());
2202
2203
0
    return conversionTree;
2204
0
}
2205
2206
TIntermTyped* TParseContext::addAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right)
2207
6
{
2208
6
    if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference())
2209
0
        requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "+= and -= on a buffer reference");
2210
2211
6
    if (op == EOpAssign && left->getBasicType() == EbtSampler && right->getBasicType() == EbtSampler)
2212
0
        requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler assignment for bindless texture");
2213
2214
6
    return intermediate.addAssign(op, left, right, loc);
2215
6
}
2216
2217
void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& fnCandidate, const TIntermOperator& callNode)
2218
0
{
2219
0
    const TIntermSequence* argp = &callNode.getAsAggregate()->getSequence();
2220
2221
    //const int gl_SemanticsRelaxed         = 0x0;
2222
0
    const int gl_SemanticsAcquire         = 0x2;
2223
0
    const int gl_SemanticsRelease         = 0x4;
2224
0
    const int gl_SemanticsAcquireRelease  = 0x8;
2225
0
    const int gl_SemanticsMakeAvailable   = 0x2000;
2226
0
    const int gl_SemanticsMakeVisible     = 0x4000;
2227
0
    const int gl_SemanticsVolatile        = 0x8000;
2228
2229
    //const int gl_StorageSemanticsNone     = 0x0;
2230
0
    const int gl_StorageSemanticsBuffer   = 0x40;
2231
0
    const int gl_StorageSemanticsShared   = 0x100;
2232
0
    const int gl_StorageSemanticsImage    = 0x800;
2233
0
    const int gl_StorageSemanticsOutput   = 0x1000;
2234
2235
2236
0
    unsigned int semantics = 0, storageClassSemantics = 0;
2237
0
    unsigned int semantics2 = 0, storageClassSemantics2 = 0;
2238
2239
0
    const TIntermTyped* arg0 = (*argp)[0]->getAsTyped();
2240
0
    const bool isMS = arg0->getBasicType() == EbtSampler && arg0->getType().getSampler().isMultiSample();
2241
2242
    // Grab the semantics and storage class semantics from the operands, based on opcode
2243
0
    switch (callNode.getOp()) {
2244
0
    case EOpAtomicAdd:
2245
0
    case EOpAtomicSubtract:
2246
0
    case EOpAtomicMin:
2247
0
    case EOpAtomicMax:
2248
0
    case EOpAtomicAnd:
2249
0
    case EOpAtomicOr:
2250
0
    case EOpAtomicXor:
2251
0
    case EOpAtomicExchange:
2252
0
    case EOpAtomicStore:
2253
0
        storageClassSemantics = (*argp)[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
2254
0
        semantics = (*argp)[4]->getAsConstantUnion()->getConstArray()[0].getIConst();
2255
0
        break;
2256
0
    case EOpAtomicLoad:
2257
0
        storageClassSemantics = (*argp)[2]->getAsConstantUnion()->getConstArray()[0].getIConst();
2258
0
        semantics = (*argp)[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
2259
0
        break;
2260
0
    case EOpAtomicCompSwap:
2261
0
        storageClassSemantics = (*argp)[4]->getAsConstantUnion()->getConstArray()[0].getIConst();
2262
0
        semantics = (*argp)[5]->getAsConstantUnion()->getConstArray()[0].getIConst();
2263
0
        storageClassSemantics2 = (*argp)[6]->getAsConstantUnion()->getConstArray()[0].getIConst();
2264
0
        semantics2 = (*argp)[7]->getAsConstantUnion()->getConstArray()[0].getIConst();
2265
0
        break;
2266
2267
0
    case EOpImageAtomicAdd:
2268
0
    case EOpImageAtomicMin:
2269
0
    case EOpImageAtomicMax:
2270
0
    case EOpImageAtomicAnd:
2271
0
    case EOpImageAtomicOr:
2272
0
    case EOpImageAtomicXor:
2273
0
    case EOpImageAtomicExchange:
2274
0
    case EOpImageAtomicStore:
2275
0
        storageClassSemantics = (*argp)[isMS ? 5 : 4]->getAsConstantUnion()->getConstArray()[0].getIConst();
2276
0
        semantics = (*argp)[isMS ? 6 : 5]->getAsConstantUnion()->getConstArray()[0].getIConst();
2277
0
        break;
2278
0
    case EOpImageAtomicLoad:
2279
0
        storageClassSemantics = (*argp)[isMS ? 4 : 3]->getAsConstantUnion()->getConstArray()[0].getIConst();
2280
0
        semantics = (*argp)[isMS ? 5 : 4]->getAsConstantUnion()->getConstArray()[0].getIConst();
2281
0
        break;
2282
0
    case EOpImageAtomicCompSwap:
2283
0
        storageClassSemantics = (*argp)[isMS ? 6 : 5]->getAsConstantUnion()->getConstArray()[0].getIConst();
2284
0
        semantics = (*argp)[isMS ? 7 : 6]->getAsConstantUnion()->getConstArray()[0].getIConst();
2285
0
        storageClassSemantics2 = (*argp)[isMS ? 8 : 7]->getAsConstantUnion()->getConstArray()[0].getIConst();
2286
0
        semantics2 = (*argp)[isMS ? 9 : 8]->getAsConstantUnion()->getConstArray()[0].getIConst();
2287
0
        break;
2288
2289
0
    case EOpBarrier:
2290
0
        storageClassSemantics = (*argp)[2]->getAsConstantUnion()->getConstArray()[0].getIConst();
2291
0
        semantics = (*argp)[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
2292
0
        break;
2293
0
    case EOpMemoryBarrier:
2294
0
        storageClassSemantics = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getIConst();
2295
0
        semantics = (*argp)[2]->getAsConstantUnion()->getConstArray()[0].getIConst();
2296
0
        break;
2297
0
    default:
2298
0
        break;
2299
0
    }
2300
2301
0
    if ((semantics & gl_SemanticsAcquire) &&
2302
0
        (callNode.getOp() == EOpAtomicStore || callNode.getOp() == EOpImageAtomicStore)) {
2303
0
        error(loc, "gl_SemanticsAcquire must not be used with (image) atomic store",
2304
0
              fnCandidate.getName().c_str(), "");
2305
0
    }
2306
0
    if ((semantics & gl_SemanticsRelease) &&
2307
0
        (callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpImageAtomicLoad)) {
2308
0
        error(loc, "gl_SemanticsRelease must not be used with (image) atomic load",
2309
0
              fnCandidate.getName().c_str(), "");
2310
0
    }
2311
0
    if ((semantics & gl_SemanticsAcquireRelease) &&
2312
0
        (callNode.getOp() == EOpAtomicStore || callNode.getOp() == EOpImageAtomicStore ||
2313
0
         callNode.getOp() == EOpAtomicLoad  || callNode.getOp() == EOpImageAtomicLoad)) {
2314
0
        error(loc, "gl_SemanticsAcquireRelease must not be used with (image) atomic load/store",
2315
0
              fnCandidate.getName().c_str(), "");
2316
0
    }
2317
0
    if (((semantics | semantics2) & ~(gl_SemanticsAcquire |
2318
0
                                      gl_SemanticsRelease |
2319
0
                                      gl_SemanticsAcquireRelease |
2320
0
                                      gl_SemanticsMakeAvailable |
2321
0
                                      gl_SemanticsMakeVisible |
2322
0
                                      gl_SemanticsVolatile))) {
2323
0
        error(loc, "Invalid semantics value", fnCandidate.getName().c_str(), "");
2324
0
    }
2325
0
    if (((storageClassSemantics | storageClassSemantics2) & ~(gl_StorageSemanticsBuffer |
2326
0
                                                              gl_StorageSemanticsShared |
2327
0
                                                              gl_StorageSemanticsImage |
2328
0
                                                              gl_StorageSemanticsOutput))) {
2329
0
        error(loc, "Invalid storage class semantics value", fnCandidate.getName().c_str(), "");
2330
0
    }
2331
2332
0
    if (callNode.getOp() == EOpMemoryBarrier) {
2333
0
        if (!IsPow2(semantics & (gl_SemanticsAcquire | gl_SemanticsRelease | gl_SemanticsAcquireRelease))) {
2334
0
            error(loc, "Semantics must include exactly one of gl_SemanticsRelease, gl_SemanticsAcquire, or "
2335
0
                       "gl_SemanticsAcquireRelease", fnCandidate.getName().c_str(), "");
2336
0
        }
2337
0
    } else {
2338
0
        if (semantics & (gl_SemanticsAcquire | gl_SemanticsRelease | gl_SemanticsAcquireRelease)) {
2339
0
            if (!IsPow2(semantics & (gl_SemanticsAcquire | gl_SemanticsRelease | gl_SemanticsAcquireRelease))) {
2340
0
                error(loc, "Semantics must not include multiple of gl_SemanticsRelease, gl_SemanticsAcquire, or "
2341
0
                           "gl_SemanticsAcquireRelease", fnCandidate.getName().c_str(), "");
2342
0
            }
2343
0
        }
2344
0
        if (semantics2 & (gl_SemanticsAcquire | gl_SemanticsRelease | gl_SemanticsAcquireRelease)) {
2345
0
            if (!IsPow2(semantics2 & (gl_SemanticsAcquire | gl_SemanticsRelease | gl_SemanticsAcquireRelease))) {
2346
0
                error(loc, "semUnequal must not include multiple of gl_SemanticsRelease, gl_SemanticsAcquire, or "
2347
0
                           "gl_SemanticsAcquireRelease", fnCandidate.getName().c_str(), "");
2348
0
            }
2349
0
        }
2350
0
    }
2351
0
    if (callNode.getOp() == EOpMemoryBarrier) {
2352
0
        if (storageClassSemantics == 0) {
2353
0
            error(loc, "Storage class semantics must not be zero", fnCandidate.getName().c_str(), "");
2354
0
        }
2355
0
    }
2356
0
    if (callNode.getOp() == EOpBarrier && semantics != 0 && storageClassSemantics == 0) {
2357
0
        error(loc, "Storage class semantics must not be zero", fnCandidate.getName().c_str(), "");
2358
0
    }
2359
0
    if ((callNode.getOp() == EOpAtomicCompSwap || callNode.getOp() == EOpImageAtomicCompSwap) &&
2360
0
        (semantics2 & (gl_SemanticsRelease | gl_SemanticsAcquireRelease))) {
2361
0
        error(loc, "semUnequal must not be gl_SemanticsRelease or gl_SemanticsAcquireRelease",
2362
0
              fnCandidate.getName().c_str(), "");
2363
0
    }
2364
0
    if ((semantics & gl_SemanticsMakeAvailable) &&
2365
0
        !(semantics & (gl_SemanticsRelease | gl_SemanticsAcquireRelease))) {
2366
0
        error(loc, "gl_SemanticsMakeAvailable requires gl_SemanticsRelease or gl_SemanticsAcquireRelease",
2367
0
              fnCandidate.getName().c_str(), "");
2368
0
    }
2369
0
    if ((semantics & gl_SemanticsMakeVisible) &&
2370
0
        !(semantics & (gl_SemanticsAcquire | gl_SemanticsAcquireRelease))) {
2371
0
        error(loc, "gl_SemanticsMakeVisible requires gl_SemanticsAcquire or gl_SemanticsAcquireRelease",
2372
0
              fnCandidate.getName().c_str(), "");
2373
0
    }
2374
0
    if ((semantics & gl_SemanticsVolatile) &&
2375
0
        (callNode.getOp() == EOpMemoryBarrier || callNode.getOp() == EOpBarrier)) {
2376
0
        error(loc, "gl_SemanticsVolatile must not be used with memoryBarrier or controlBarrier",
2377
0
              fnCandidate.getName().c_str(), "");
2378
0
    }
2379
0
    if ((callNode.getOp() == EOpAtomicCompSwap || callNode.getOp() == EOpImageAtomicCompSwap) &&
2380
0
        ((semantics ^ semantics2) & gl_SemanticsVolatile)) {
2381
0
        error(loc, "semEqual and semUnequal must either both include gl_SemanticsVolatile or neither",
2382
0
              fnCandidate.getName().c_str(), "");
2383
0
    }
2384
0
}
2385
2386
//
2387
// Do additional checking of built-in function calls that is not caught
2388
// by normal semantic checks on argument type, extension tagging, etc.
2389
//
2390
// Assumes there has been a semantically correct match to a built-in function prototype.
2391
//
2392
void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermOperator& callNode)
2393
0
{
2394
    // Set up convenience accessors to the argument(s).  There is almost always
2395
    // multiple arguments for the cases below, but when there might be one,
2396
    // check the unaryArg first.
2397
0
    const TIntermSequence* argp = nullptr;   // confusing to use [] syntax on a pointer, so this is to help get a reference
2398
0
    const TIntermTyped* unaryArg = nullptr;
2399
0
    const TIntermTyped* arg0 = nullptr;
2400
0
    if (callNode.getAsAggregate()) {
2401
0
        argp = &callNode.getAsAggregate()->getSequence();
2402
0
        if (argp->size() > 0)
2403
0
            arg0 = (*argp)[0]->getAsTyped();
2404
0
    } else {
2405
0
        assert(callNode.getAsUnaryNode());
2406
0
        unaryArg = callNode.getAsUnaryNode()->getOperand();
2407
0
        arg0 = unaryArg;
2408
0
    }
2409
2410
0
    TString featureString;
2411
0
    const char* feature = nullptr;
2412
0
    switch (callNode.getOp()) {
2413
0
    case EOpTextureGather:
2414
0
    case EOpTextureGatherOffset:
2415
0
    case EOpTextureGatherOffsets:
2416
0
    {
2417
        // Figure out which variants are allowed by what extensions,
2418
        // and what arguments must be constant for which situations.
2419
2420
0
        featureString = fnCandidate.getName();
2421
0
        featureString += "(...)";
2422
0
        feature = featureString.c_str();
2423
0
        profileRequires(loc, EEsProfile, 310, nullptr, feature);
2424
0
        int compArg = -1;  // track which argument, if any, is the constant component argument
2425
0
        const int numTexGatherExts = 3;
2426
0
        const char* texGatherExts[numTexGatherExts] = { E_GL_ARB_texture_gather,
2427
0
                                                        E_GL_ARB_gpu_shader5,
2428
0
                                                        E_GL_NV_gpu_shader5};
2429
0
        switch (callNode.getOp()) {
2430
0
        case EOpTextureGather:
2431
            // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5,
2432
            // otherwise, need GL_ARB_texture_gather.
2433
0
            if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) {
2434
0
                profileRequires(loc, ~EEsProfile, 400, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, feature);
2435
0
                if (! fnCandidate[0].type->getSampler().shadow)
2436
0
                    compArg = 2;
2437
0
            } else
2438
0
                profileRequires(loc, ~EEsProfile, 400, numTexGatherExts, texGatherExts, feature);
2439
0
            break;
2440
0
        case EOpTextureGatherOffset:
2441
            // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument
2442
0
            if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3)
2443
0
                profileRequires(loc, ~EEsProfile, 400, numTexGatherExts, texGatherExts, feature);
2444
0
            else
2445
0
                profileRequires(loc, ~EEsProfile, 400, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, feature);
2446
0
            if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
2447
0
                profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
2448
0
                                "non-constant offset argument");
2449
0
            if (! fnCandidate[0].type->getSampler().shadow)
2450
0
                compArg = 3;
2451
0
            break;
2452
0
        case EOpTextureGatherOffsets:
2453
0
            profileRequires(loc, ~EEsProfile, 400, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, feature);
2454
0
            if (! fnCandidate[0].type->getSampler().shadow)
2455
0
                compArg = 3;
2456
            // check for constant offsets
2457
0
            if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion() 
2458
                // NV_gpu_shader5 relaxes this limitation and allows for non-constant offsets
2459
0
                && !extensionTurnedOn(E_GL_NV_gpu_shader5))
2460
0
                error(loc, "must be a compile-time constant:", feature, "offsets argument");
2461
0
            break;
2462
0
        default:
2463
0
            break;
2464
0
        }
2465
2466
0
        if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
2467
0
            if ((*argp)[compArg]->getAsConstantUnion()) {
2468
0
                int value = (*argp)[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
2469
0
                if (value < 0 || value > 3)
2470
0
                    error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
2471
0
            } else
2472
0
                error(loc, "must be a compile-time constant:", feature, "component argument");
2473
0
        }
2474
2475
0
        bool bias = false;
2476
0
        if (callNode.getOp() == EOpTextureGather)
2477
0
            bias = fnCandidate.getParamCount() > 3;
2478
0
        else if (callNode.getOp() == EOpTextureGatherOffset ||
2479
0
                 callNode.getOp() == EOpTextureGatherOffsets)
2480
0
            bias = fnCandidate.getParamCount() > 4;
2481
2482
0
        if (bias) {
2483
0
            featureString = fnCandidate.getName();
2484
0
            featureString += "with bias argument";
2485
0
            feature = featureString.c_str();
2486
0
            profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
2487
0
            requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
2488
0
        }
2489
0
        break;
2490
0
    }
2491
2492
0
    case EOpTexture:
2493
0
    case EOpTextureLod:
2494
0
    {
2495
0
        if ((fnCandidate.getParamCount() > 2) && ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) &&
2496
0
            ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) && fnCandidate[0].type->getSampler().shadow) {
2497
0
            featureString = fnCandidate.getName();
2498
0
            if (callNode.getOp() == EOpTexture)
2499
0
                featureString += "(..., float bias)";
2500
0
            else
2501
0
                featureString += "(..., float lod)";
2502
0
            feature = featureString.c_str();
2503
2504
0
            if ((fnCandidate[0].type->getSampler().dim == Esd2D && fnCandidate[0].type->getSampler().arrayed) || //2D Array Shadow
2505
0
                (fnCandidate[0].type->getSampler().dim == EsdCube && fnCandidate[0].type->getSampler().arrayed && fnCandidate.getParamCount() > 3) || // Cube Array Shadow
2506
0
                (fnCandidate[0].type->getSampler().dim == EsdCube && callNode.getOp() == EOpTextureLod)) { // Cube Shadow
2507
0
                requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature);
2508
0
                if (isEsProfile()) {
2509
0
                    if (version < 320 &&
2510
0
                        !extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
2511
0
                        error(loc, "GL_EXT_texture_shadow_lod not supported for this ES version", feature, "");
2512
0
                    else
2513
0
                        profileRequires(loc, EEsProfile, 320, nullptr, feature);
2514
0
                } else { // Desktop
2515
0
                    profileRequires(loc, ~EEsProfile, 130, nullptr, feature);
2516
0
                }
2517
0
            }
2518
0
        }
2519
0
        break;
2520
0
    }
2521
2522
0
    case EOpSparseTextureGather:
2523
0
    case EOpSparseTextureGatherOffset:
2524
0
    case EOpSparseTextureGatherOffsets:
2525
0
    {
2526
0
        bool bias = false;
2527
0
        if (callNode.getOp() == EOpSparseTextureGather)
2528
0
            bias = fnCandidate.getParamCount() > 4;
2529
0
        else if (callNode.getOp() == EOpSparseTextureGatherOffset ||
2530
0
                 callNode.getOp() == EOpSparseTextureGatherOffsets)
2531
0
            bias = fnCandidate.getParamCount() > 5;
2532
2533
0
        if (bias) {
2534
0
            featureString = fnCandidate.getName();
2535
0
            featureString += "with bias argument";
2536
0
            feature = featureString.c_str();
2537
0
            profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
2538
0
            requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
2539
0
        }
2540
        // As per GL_ARB_sparse_texture2 extension "Offsets" parameter must be constant integral expression
2541
        // for sparseTextureGatherOffsetsARB just as textureGatherOffsets
2542
0
        if (callNode.getOp() == EOpSparseTextureGatherOffsets) {
2543
0
            int offsetsArg = arg0->getType().getSampler().shadow ? 3 : 2;
2544
0
            if (!(*argp)[offsetsArg]->getAsConstantUnion())
2545
0
                error(loc, "argument must be compile-time constant", "offsets", "");
2546
0
        }
2547
0
        break;
2548
0
    }
2549
2550
0
    case EOpSparseTextureGatherLod:
2551
0
    case EOpSparseTextureGatherLodOffset:
2552
0
    case EOpSparseTextureGatherLodOffsets:
2553
0
    {
2554
0
        requireExtensions(loc, 1, &E_GL_ARB_sparse_texture2, fnCandidate.getName().c_str());
2555
0
        break;
2556
0
    }
2557
2558
0
    case EOpSwizzleInvocations:
2559
0
    {
2560
0
        if (! (*argp)[1]->getAsConstantUnion())
2561
0
            error(loc, "argument must be compile-time constant", "offset", "");
2562
0
        else {
2563
0
            unsigned offset[4] = {};
2564
0
            offset[0] = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst();
2565
0
            offset[1] = (*argp)[1]->getAsConstantUnion()->getConstArray()[1].getUConst();
2566
0
            offset[2] = (*argp)[1]->getAsConstantUnion()->getConstArray()[2].getUConst();
2567
0
            offset[3] = (*argp)[1]->getAsConstantUnion()->getConstArray()[3].getUConst();
2568
0
            if (offset[0] > 3 || offset[1] > 3 || offset[2] > 3 || offset[3] > 3)
2569
0
                error(loc, "components must be in the range [0, 3]", "offset", "");
2570
0
        }
2571
2572
0
        break;
2573
0
    }
2574
2575
0
    case EOpSwizzleInvocationsMasked:
2576
0
    {
2577
0
        if (! (*argp)[1]->getAsConstantUnion())
2578
0
            error(loc, "argument must be compile-time constant", "mask", "");
2579
0
        else {
2580
0
            unsigned mask[3] = {};
2581
0
            mask[0] = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst();
2582
0
            mask[1] = (*argp)[1]->getAsConstantUnion()->getConstArray()[1].getUConst();
2583
0
            mask[2] = (*argp)[1]->getAsConstantUnion()->getConstArray()[2].getUConst();
2584
0
            if (mask[0] > 31 || mask[1] > 31 || mask[2] > 31)
2585
0
                error(loc, "components must be in the range [0, 31]", "mask", "");
2586
0
        }
2587
2588
0
        break;
2589
0
    }
2590
2591
0
    case EOpTextureOffset:
2592
0
    case EOpTextureFetchOffset:
2593
0
    case EOpTextureProjOffset:
2594
0
    case EOpTextureLodOffset:
2595
0
    case EOpTextureProjLodOffset:
2596
0
    case EOpTextureGradOffset:
2597
0
    case EOpTextureProjGradOffset:
2598
0
    case EOpSparseTextureOffset:
2599
0
    case EOpSparseTextureFetchOffset:
2600
0
    case EOpSparseTextureLodOffset:
2601
0
    case EOpSparseTextureGradOffset:
2602
0
    {
2603
        // Handle texture-offset limits checking
2604
        // Pick which argument has to hold constant offsets
2605
0
        int arg = -1;
2606
0
        switch (callNode.getOp()) {
2607
0
        case EOpSparseTextureOffset:
2608
0
        case EOpTextureOffset:
2609
0
        case EOpTextureProjOffset:
2610
0
            arg = 2;
2611
0
            break;
2612
0
        case EOpSparseTextureLodOffset:
2613
0
        case EOpTextureLodOffset:
2614
0
        case EOpTextureProjLodOffset:
2615
0
            arg = 3;
2616
0
            break;
2617
0
        case EOpSparseTextureGradOffset:
2618
0
        case EOpTextureGradOffset:
2619
0
        case EOpTextureProjGradOffset:
2620
0
            arg = 4;
2621
0
            break;
2622
0
        case EOpSparseTextureFetchOffset:
2623
0
        case EOpTextureFetchOffset:
2624
0
            arg = (arg0->getType().getSampler().isRect()) ? 2 : 3;
2625
0
            break;
2626
0
        default:
2627
0
            assert(0);
2628
0
            break;
2629
0
        }
2630
2631
0
        if (arg > 0) {
2632
2633
0
            bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 &&
2634
0
                                    arg0->getType().getSampler().shadow;
2635
0
            if (f16ShadowCompare)
2636
0
                ++arg;
2637
            // Allow non-constant offsets for certain texture ops
2638
0
            bool variableOffsetSupport = extensionTurnedOn(E_GL_NV_gpu_shader5) && 
2639
0
                (callNode.getOp() == EOpTextureOffset || 
2640
0
                 callNode.getOp() == EOpTextureFetchOffset ||
2641
0
                 callNode.getOp() == EOpTextureProjOffset || 
2642
0
                 callNode.getOp() == EOpTextureLodOffset ||
2643
0
                 callNode.getOp() == EOpTextureProjLodOffset);
2644
0
            if (! (*argp)[arg]->getAsTyped()->getQualifier().isConstant()) {
2645
0
        if (!extensionTurnedOn(E_GL_EXT_texture_offset_non_const) && !variableOffsetSupport)
2646
0
                    error(loc, "argument must be compile-time constant", "texel offset", "");
2647
0
            }
2648
0
            else if ((*argp)[arg]->getAsConstantUnion()) {
2649
0
                const TType& type = (*argp)[arg]->getAsTyped()->getType();
2650
0
                for (int c = 0; c < type.getVectorSize(); ++c) {
2651
0
                    int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
2652
0
                    if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
2653
0
                        error(loc, "value is out of range:", "texel offset",
2654
0
                              "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
2655
0
                }
2656
0
            }
2657
2658
            // This check does not apply to sparse because
2659
            // GL_ARB_sparse_texture2 always includes this function.
2660
0
            if (callNode.getOp() == EOpTextureOffset) {
2661
0
                TSampler s = arg0->getType().getSampler();
2662
0
                if (s.is2D() && s.isArrayed() && s.isShadow()) {
2663
0
                    if (
2664
0
                        ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) &&
2665
0
                        ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) &&
2666
0
                        (fnCandidate.getParamCount() == 4)) {
2667
0
                        featureString = fnCandidate.getName() + " for sampler2DArrayShadow";
2668
0
                        feature = featureString.c_str();
2669
0
                        requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature);
2670
0
                        profileRequires(loc, EEsProfile, 300, nullptr, feature);
2671
0
                        profileRequires(loc, ~EEsProfile, 130, nullptr, feature);
2672
0
                    }
2673
0
                    else if (isEsProfile())
2674
0
                        error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "ES Profile");
2675
0
                    else if (version <= 420)
2676
0
                        error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "version <= 420");
2677
0
                }
2678
0
            }
2679
2680
            // This check does not apply to sparse because
2681
            // GL_ARB_sparse_texture2 does not define sparseTextureLodOffsetARB
2682
            // with a sampler2DArrayShadow.
2683
0
            if (callNode.getOp() == EOpTextureLodOffset) {
2684
0
                TSampler s = arg0->getType().getSampler();
2685
0
                if (s.is2D() && s.isArrayed() && s.isShadow() &&
2686
0
                    ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) &&
2687
0
                    ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) &&
2688
0
                    (fnCandidate.getParamCount() == 4)) {
2689
0
                        featureString = fnCandidate.getName() + " for sampler2DArrayShadow";
2690
0
                        feature = featureString.c_str();
2691
0
                        profileRequires(loc, EEsProfile, 300, nullptr, feature);
2692
0
                        profileRequires(loc, ~EEsProfile, 130, nullptr, feature);
2693
0
                        requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature);
2694
0
                }
2695
0
            }
2696
0
        }
2697
2698
0
        break;
2699
0
    }
2700
2701
0
    case EOpTraceNV:
2702
0
        if (!(*argp)[10]->getAsConstantUnion())
2703
0
            error(loc, "argument must be compile-time constant", "payload number", "a");
2704
0
        break;
2705
0
    case EOpTraceRayMotionNV:
2706
0
        if (!(*argp)[11]->getAsConstantUnion())
2707
0
            error(loc, "argument must be compile-time constant", "payload number", "a");
2708
0
        break;
2709
0
    case EOpTraceKHR:
2710
0
        if (!(*argp)[10]->getAsConstantUnion())
2711
0
            error(loc, "argument must be compile-time constant", "payload number", "a");
2712
0
        else {
2713
0
            unsigned int location = (*argp)[10]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2714
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0)
2715
0
                error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location);
2716
0
        }
2717
0
        break;
2718
0
    case EOpExecuteCallableNV:
2719
0
        if (!(*argp)[1]->getAsConstantUnion())
2720
0
            error(loc, "argument must be compile-time constant", "callable data number", "");
2721
0
        break;
2722
0
    case EOpExecuteCallableKHR:
2723
0
        if (!(*argp)[1]->getAsConstantUnion())
2724
0
            error(loc, "argument must be compile-time constant", "callable data number", "");
2725
0
        else {
2726
0
            unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2727
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(1, location) < 0)
2728
0
                error(loc, "with layout(location =", "no callableDataEXT/callableDataInEXT declared", "%d)", location);
2729
0
        }
2730
0
        break;
2731
2732
0
    case EOpHitObjectTraceRayNV:
2733
0
        if (!(*argp)[11]->getAsConstantUnion())
2734
0
            error(loc, "argument must be compile-time constant", "payload number", "");
2735
0
        else {
2736
0
            unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2737
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0)
2738
0
                error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location);
2739
0
        }
2740
0
        break;
2741
0
    case EOpHitObjectTraceRayMotionNV:
2742
0
        if (!(*argp)[12]->getAsConstantUnion())
2743
0
            error(loc, "argument must be compile-time constant", "payload number", "");
2744
0
        else {
2745
0
            unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2746
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0)
2747
0
                error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location);
2748
0
        }
2749
0
        break;
2750
0
    case EOpHitObjectExecuteShaderNV:
2751
0
        if (!(*argp)[1]->getAsConstantUnion())
2752
0
            error(loc, "argument must be compile-time constant", "payload number", "");
2753
0
        else {
2754
0
            unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2755
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0)
2756
0
                error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location);
2757
0
        }
2758
0
        break;
2759
0
    case EOpHitObjectRecordHitNV:
2760
0
        if (!(*argp)[12]->getAsConstantUnion())
2761
0
            error(loc, "argument must be compile-time constant", "hitobjectattribute number", "");
2762
0
        else {
2763
0
            unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2764
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0)
2765
0
                error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location);
2766
0
        }
2767
0
        break;
2768
0
    case EOpHitObjectRecordHitMotionNV:
2769
0
        if (!(*argp)[13]->getAsConstantUnion())
2770
0
            error(loc, "argument must be compile-time constant", "hitobjectattribute number", "");
2771
0
        else {
2772
0
            unsigned int location = (*argp)[13]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2773
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0)
2774
0
                error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location);
2775
0
        }
2776
0
        break;
2777
0
    case EOpHitObjectRecordHitWithIndexNV:
2778
0
        if (!(*argp)[11]->getAsConstantUnion())
2779
0
            error(loc, "argument must be compile-time constant", "hitobjectattribute number", "");
2780
0
        else {
2781
0
            unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2782
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0)
2783
0
                error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location);
2784
0
        }
2785
0
        break;
2786
0
    case EOpHitObjectRecordHitWithIndexMotionNV:
2787
0
        if (!(*argp)[12]->getAsConstantUnion())
2788
0
            error(loc, "argument must be compile-time constant", "hitobjectattribute number", "");
2789
0
        else {
2790
0
            unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2791
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0)
2792
0
                error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location);
2793
0
        }
2794
0
        break;
2795
0
    case EOpHitObjectGetAttributesNV:
2796
0
        if (!(*argp)[1]->getAsConstantUnion())
2797
0
            error(loc, "argument must be compile-time constant", "hitobjectattribute number", "");
2798
0
        else {
2799
0
            unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst();
2800
0
            if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0)
2801
0
                error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location);
2802
0
        }
2803
0
        break;
2804
2805
0
    case EOpRayQueryGetIntersectionType:
2806
0
    case EOpRayQueryGetIntersectionT:
2807
0
    case EOpRayQueryGetIntersectionInstanceCustomIndex:
2808
0
    case EOpRayQueryGetIntersectionInstanceId:
2809
0
    case EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
2810
0
    case EOpRayQueryGetIntersectionGeometryIndex:
2811
0
    case EOpRayQueryGetIntersectionPrimitiveIndex:
2812
0
    case EOpRayQueryGetIntersectionBarycentrics:
2813
0
    case EOpRayQueryGetIntersectionFrontFace:
2814
0
    case EOpRayQueryGetIntersectionObjectRayDirection:
2815
0
    case EOpRayQueryGetIntersectionObjectRayOrigin:
2816
0
    case EOpRayQueryGetIntersectionObjectToWorld:
2817
0
    case EOpRayQueryGetIntersectionWorldToObject:
2818
0
    case EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
2819
0
    case EOpRayQueryGetIntersectionClusterIdNV:
2820
0
    case EOpRayQueryGetIntersectionSpherePositionNV:
2821
0
    case EOpRayQueryGetIntersectionSphereRadiusNV:
2822
0
    case EOpRayQueryGetIntersectionLSSHitValueNV:
2823
0
    case EOpRayQueryGetIntersectionLSSPositionsNV:
2824
0
    case EOpRayQueryGetIntersectionLSSRadiiNV:
2825
0
        if (!(*argp)[1]->getAsConstantUnion())
2826
0
            error(loc, "argument must be compile-time constant", "committed", "");
2827
0
        break;
2828
2829
0
    case EOpTextureQuerySamples:
2830
0
    case EOpImageQuerySamples:
2831
        // GL_ARB_shader_texture_image_samples
2832
0
        profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples");
2833
0
        break;
2834
2835
0
    case EOpImageAtomicAdd:
2836
0
    case EOpImageAtomicMin:
2837
0
    case EOpImageAtomicMax:
2838
0
    case EOpImageAtomicAnd:
2839
0
    case EOpImageAtomicOr:
2840
0
    case EOpImageAtomicXor:
2841
0
    case EOpImageAtomicExchange:
2842
0
    case EOpImageAtomicCompSwap:
2843
0
    case EOpImageAtomicLoad:
2844
0
    case EOpImageAtomicStore:
2845
0
    {
2846
        // Make sure the image types have the correct layout() format and correct argument types
2847
0
        const TType& imageType = arg0->getType();
2848
0
        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint ||
2849
0
            imageType.getSampler().type == EbtInt64 || imageType.getSampler().type == EbtUint64) {
2850
0
            if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui &&
2851
0
                imageType.getQualifier().getFormat() != ElfR64i && imageType.getQualifier().getFormat() != ElfR64ui)
2852
0
                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
2853
0
            if (callNode.getType().getBasicType() == EbtInt64 && imageType.getQualifier().getFormat() != ElfR64i)
2854
0
                error(loc, "only supported on image with format r64i", fnCandidate.getName().c_str(), "");
2855
0
            else if (callNode.getType().getBasicType() == EbtUint64 && imageType.getQualifier().getFormat() != ElfR64ui)
2856
0
                error(loc, "only supported on image with format r64ui", fnCandidate.getName().c_str(), "");
2857
0
        } else if(callNode.getType().getBasicType() == EbtFloat16 &&
2858
0
                ((callNode.getType().getVectorSize() == 2 && arg0->getType().getQualifier().getFormat() == ElfRg16f) ||
2859
0
                  (callNode.getType().getVectorSize() == 4 && arg0->getType().getQualifier().getFormat() == ElfRgba16f))) {
2860
0
            if (StartsWith(fnCandidate.getName(), "imageAtomicAdd") ||
2861
0
                StartsWith(fnCandidate.getName(), "imageAtomicExchange") ||
2862
0
                StartsWith(fnCandidate.getName(), "imageAtomicMin") ||
2863
0
                StartsWith(fnCandidate.getName(), "imageAtomicMax")) {
2864
0
                requireExtensions(loc, 1, &E_GL_NV_shader_atomic_fp16_vector, fnCandidate.getName().c_str());
2865
0
            } else {
2866
0
                error(loc, "f16vec2/4 operation not supported on: ", fnCandidate.getName().c_str(), "");
2867
0
            }
2868
0
        } else if (imageType.getSampler().type == EbtFloat) {
2869
0
            if (StartsWith(fnCandidate.getName(), "imageAtomicExchange")) {
2870
                // imageAtomicExchange doesn't require an extension
2871
0
            } else if (StartsWith(fnCandidate.getName(), "imageAtomicAdd") ||
2872
0
                       StartsWith(fnCandidate.getName(), "imageAtomicLoad") ||
2873
0
                       StartsWith(fnCandidate.getName(), "imageAtomicStore")) {
2874
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str());
2875
0
            } else if (StartsWith(fnCandidate.getName(), "imageAtomicMin") ||
2876
0
                       StartsWith(fnCandidate.getName(), "imageAtomicMax")) {
2877
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str());
2878
0
            } else {
2879
0
                error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
2880
0
            }
2881
0
            if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile())
2882
0
                error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
2883
0
        } else {
2884
0
            error(loc, "not supported on this image type", fnCandidate.getName().c_str(), "");
2885
0
        }
2886
2887
0
        const size_t maxArgs = imageType.getSampler().isMultiSample() ? 5 : 4;
2888
0
        if (argp->size() > maxArgs) {
2889
0
            requireExtensions(loc, 1, &E_GL_KHR_memory_scope_semantics, fnCandidate.getName().c_str());
2890
0
            memorySemanticsCheck(loc, fnCandidate, callNode);
2891
0
        }
2892
2893
0
        break;
2894
0
    }
2895
2896
0
    case EOpAtomicAdd:
2897
0
    case EOpAtomicSubtract:
2898
0
    case EOpAtomicMin:
2899
0
    case EOpAtomicMax:
2900
0
    case EOpAtomicAnd:
2901
0
    case EOpAtomicOr:
2902
0
    case EOpAtomicXor:
2903
0
    case EOpAtomicExchange:
2904
0
    case EOpAtomicCompSwap:
2905
0
    case EOpAtomicLoad:
2906
0
    case EOpAtomicStore:
2907
0
    {
2908
0
        if (argp->size() > 3) {
2909
0
            requireExtensions(loc, 1, &E_GL_KHR_memory_scope_semantics, fnCandidate.getName().c_str());
2910
0
            memorySemanticsCheck(loc, fnCandidate, callNode);
2911
0
            if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange ||
2912
0
                callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore) &&
2913
0
                (arg0->getType().getBasicType() == EbtFloat ||
2914
0
                 arg0->getType().getBasicType() == EbtDouble)) {
2915
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str());
2916
0
            } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange ||
2917
0
                        callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore ||
2918
0
                        callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) &&
2919
0
                       arg0->getType().isFloatingDomain()) {
2920
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str());
2921
0
            }
2922
0
        } else if (arg0->getType().getBasicType() == EbtInt64 || arg0->getType().getBasicType() == EbtUint64) {
2923
0
            const char* const extensions[2] = { E_GL_NV_shader_atomic_int64,
2924
0
                                                E_GL_EXT_shader_atomic_int64 };
2925
0
            requireExtensions(loc, 2, extensions, fnCandidate.getName().c_str());
2926
0
        } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange ||
2927
0
                    callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) &&
2928
0
                   arg0->getType().getBasicType() == EbtFloat16 &&
2929
0
                   (arg0->getType().getVectorSize() == 2 || arg0->getType().getVectorSize() == 4 )) {
2930
0
            requireExtensions(loc, 1, &E_GL_NV_shader_atomic_fp16_vector, fnCandidate.getName().c_str());
2931
0
        } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange) &&
2932
0
                   (arg0->getType().getBasicType() == EbtFloat ||
2933
0
                    arg0->getType().getBasicType() == EbtDouble)) {
2934
0
            requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str());
2935
0
        } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange ||
2936
0
                    callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpAtomicStore ||
2937
0
                    callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) &&
2938
0
                   arg0->getType().isFloatingDomain()) {
2939
0
            requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str());
2940
0
        }
2941
2942
0
        const TIntermTyped* base = TIntermediate::traverseLValueBase(arg0, true, true);
2943
0
        const char* errMsg = "Only l-values corresponding to shader block storage or shared variables can be used with "
2944
0
                             "atomic memory functions.";
2945
0
        if (base) {
2946
0
            const TType* refType = (base->getType().isReference()) ? base->getType().getReferentType() : nullptr;
2947
0
            const TQualifier& qualifier =
2948
0
                (refType != nullptr) ? refType->getQualifier() : base->getType().getQualifier();
2949
0
            if (qualifier.storage != EvqShared && qualifier.storage != EvqBuffer &&
2950
0
                qualifier.storage != EvqtaskPayloadSharedEXT)
2951
0
                error(loc, errMsg, fnCandidate.getName().c_str(), "");
2952
0
        } else {
2953
0
            error(loc, errMsg, fnCandidate.getName().c_str(), "");
2954
0
        }
2955
2956
0
        break;
2957
0
    }
2958
2959
0
    case EOpInterpolateAtCentroid:
2960
0
    case EOpInterpolateAtSample:
2961
0
    case EOpInterpolateAtOffset:
2962
0
    case EOpInterpolateAtVertex: {
2963
0
        if (arg0->getType().getQualifier().storage != EvqVaryingIn) {
2964
            // Traverse down the left branch of arg0 to ensure this argument is a valid interpolant.
2965
            //
2966
            // For desktop GL >4.3 we effectively only need to ensure that arg0 represents an l-value from an
2967
            // input declaration.
2968
            //
2969
            // For desktop GL <= 4.3 and ES, we must also ensure that swizzling is not used
2970
            //
2971
            // For ES, we must also ensure that a field selection operator (i.e., '.') is not used on a named
2972
            // struct.
2973
2974
0
            const bool esProfile = isEsProfile();
2975
0
            const bool swizzleOkay = !esProfile && (version >= 440);
2976
2977
0
            std::string interpolantErrorMsg = "first argument must be an interpolant, or interpolant-array element";
2978
0
            bool isValid = true; // Assume that the interpolant is valid until we find a condition making it invalid
2979
0
            bool isIn = false;   // Checks whether or not the interpolant is a shader input
2980
0
            bool structAccessOp = false; // Whether or not the previous node in the chain is a struct accessor
2981
0
            TIntermediate::traverseLValueBase(
2982
0
                arg0, swizzleOkay, false,
2983
0
                [&isValid, &isIn, &interpolantErrorMsg, esProfile, &structAccessOp](const TIntermNode& n) -> bool {
2984
0
                    auto* type = n.getAsTyped();
2985
0
                    if (type) {
2986
0
                        if (type->getType().getQualifier().storage == EvqVaryingIn) {
2987
0
                            isIn = true;
2988
0
                        }
2989
                        // If a field accessor was used, it can only be used to access a field with an input block, not a struct.
2990
0
                        if (structAccessOp && (type->getType().getBasicType() != EbtBlock)) {
2991
0
                            interpolantErrorMsg +=
2992
0
                                ". Using the field of a named struct as an interpolant argument is not "
2993
0
                                "allowed (ES-only).";
2994
0
                            isValid = false;
2995
0
                        }
2996
0
                    }
2997
2998
                    // ES has different requirements for interpolants than GL
2999
0
                    if (esProfile) {
3000
                        // Swizzling will be taken care of by the 'swizzleOkay' argument passsed to traverseLValueBase,
3001
                        // so we only ned to check whether or not a field accessor has been used with a named struct.
3002
0
                        auto* binary = n.getAsBinaryNode();
3003
0
                        if (binary && (binary->getOp() == EOpIndexDirectStruct)) {
3004
0
                            structAccessOp = true;
3005
0
                        }
3006
0
                    }
3007
                    // Don't continue traversing if we know we have an invalid interpolant at this point.
3008
0
                    return isValid;
3009
0
                });
3010
0
            if (!isIn || !isValid) {
3011
0
                error(loc, interpolantErrorMsg.c_str(), fnCandidate.getName().c_str(), "");
3012
0
            }
3013
0
        }
3014
3015
0
        if (callNode.getOp() == EOpInterpolateAtVertex) {
3016
0
            if (!arg0->getType().getQualifier().isExplicitInterpolation())
3017
0
                error(loc, "argument must be qualified as __explicitInterpAMD in", "interpolant", "");
3018
0
            else {
3019
0
                if (! (*argp)[1]->getAsConstantUnion())
3020
0
                    error(loc, "argument must be compile-time constant", "vertex index", "");
3021
0
                else {
3022
0
                    unsigned vertexIdx = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getUConst();
3023
0
                    if (vertexIdx > 2)
3024
0
                        error(loc, "must be in the range [0, 2]", "vertex index", "");
3025
0
                }
3026
0
            }
3027
0
        }
3028
0
    } break;
3029
3030
0
    case EOpEmitStreamVertex:
3031
0
    case EOpEndStreamPrimitive:
3032
0
        if (version == 150)
3033
0
            requireExtensions(loc, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, "if the verison is 150 , the EmitStreamVertex and EndStreamPrimitive only support at extension GL_ARB_gpu_shader5/GL_NV_gpu_shader5");
3034
0
        intermediate.setMultiStream();
3035
0
        break;
3036
3037
0
    case EOpSubgroupClusteredAdd:
3038
0
    case EOpSubgroupClusteredMul:
3039
0
    case EOpSubgroupClusteredMin:
3040
0
    case EOpSubgroupClusteredMax:
3041
0
    case EOpSubgroupClusteredAnd:
3042
0
    case EOpSubgroupClusteredOr:
3043
0
    case EOpSubgroupClusteredXor:
3044
        // The <clusterSize> as used in the subgroupClustered<op>() operations must be:
3045
        // - An integral constant expression.
3046
        // - At least 1.
3047
        // - A power of 2.
3048
0
        if ((*argp)[1]->getAsConstantUnion() == nullptr)
3049
0
            error(loc, "argument must be compile-time constant", "cluster size", "");
3050
0
        else {
3051
0
            int size = (*argp)[1]->getAsConstantUnion()->getConstArray()[0].getIConst();
3052
0
            if (size < 1)
3053
0
                error(loc, "argument must be at least 1", "cluster size", "");
3054
0
            else if (!IsPow2(size))
3055
0
                error(loc, "argument must be a power of 2", "cluster size", "");
3056
0
        }
3057
0
        break;
3058
3059
0
    case EOpSubgroupBroadcast:
3060
0
    case EOpSubgroupQuadBroadcast:
3061
0
        if (spvVersion.spv < EShTargetSpv_1_5) {
3062
            // <id> must be an integral constant expression.
3063
0
            if ((*argp)[1]->getAsConstantUnion() == nullptr)
3064
0
                error(loc, "argument must be compile-time constant", "id", "");
3065
0
        }
3066
0
        break;
3067
3068
0
    case EOpBarrier:
3069
0
    case EOpMemoryBarrier:
3070
0
        if (argp->size() > 0) {
3071
0
            requireExtensions(loc, 1, &E_GL_KHR_memory_scope_semantics, fnCandidate.getName().c_str());
3072
0
            memorySemanticsCheck(loc, fnCandidate, callNode);
3073
0
        }
3074
0
        break;
3075
3076
0
    case EOpMix:
3077
0
        if (profile == EEsProfile && version < 310) {
3078
            // Look for specific signatures
3079
0
            if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat &&
3080
0
                (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat &&
3081
0
                (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) {
3082
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, "specific signature of builtin mix");
3083
0
            }
3084
0
        }
3085
3086
0
        if (profile != EEsProfile && version < 450) {
3087
0
            if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat &&
3088
0
                (*argp)[0]->getAsTyped()->getBasicType() != EbtDouble &&
3089
0
                (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat &&
3090
0
                (*argp)[1]->getAsTyped()->getBasicType() != EbtDouble &&
3091
0
                (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) {
3092
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, fnCandidate.getName().c_str());
3093
0
            }
3094
0
        }
3095
3096
0
        break;
3097
0
    case EOpLessThan:
3098
0
    case EOpLessThanEqual:
3099
0
    case EOpGreaterThan:
3100
0
    case EOpGreaterThanEqual:
3101
0
    case EOpEqual:
3102
0
    case EOpNotEqual:
3103
0
        if (profile != EEsProfile && version >= 150 && version < 450) {
3104
0
            if ((*argp)[1]->getAsTyped()->getBasicType() == EbtInt64 ||                 
3105
0
                (*argp)[1]->getAsTyped()->getBasicType() == EbtUint64)
3106
0
                requireExtensions(loc, 1, &E_GL_NV_gpu_shader5, fnCandidate.getName().c_str());
3107
0
        }
3108
0
    break;
3109
0
    case EOpFma:
3110
0
    case EOpFrexp:
3111
0
    case EOpLdexp:
3112
0
        if (profile != EEsProfile && version < 400) {
3113
0
            if ((*argp)[0]->getAsTyped()->getBasicType() == EbtFloat) {
3114
0
                requireExtensions(loc, Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, fnCandidate.getName().c_str());
3115
0
            }
3116
0
        }
3117
3118
0
        break;
3119
0
    case EOpCooperativeVectorMatMulNV:
3120
0
    case EOpCooperativeVectorMatMulAddNV:
3121
0
        {
3122
0
            int inputInterpIdx = 2;
3123
0
            int matrixInterpIdx = 5;
3124
0
            int biasInterpIdx = 8;
3125
0
            int MIdx = callNode.getOp() == EOpCooperativeVectorMatMulAddNV ? 9 : 6;
3126
0
            int KIdx = callNode.getOp() == EOpCooperativeVectorMatMulAddNV ? 10 : 7;
3127
0
            int matrixLayoutIdx = callNode.getOp() == EOpCooperativeVectorMatMulAddNV ? 11 : 8;
3128
0
            int transposeIdx = callNode.getOp() == EOpCooperativeVectorMatMulAddNV ? 12 : 9;
3129
3130
0
            if (!(*argp)[inputInterpIdx]->getAsTyped()->getType().getQualifier().isConstant())
3131
0
                error(loc, "argument must be compile-time constant", "inputInterpretation", "");
3132
0
            if (!(*argp)[matrixInterpIdx]->getAsTyped()->getType().getQualifier().isConstant())
3133
0
                error(loc, "argument must be compile-time constant", "matrixInterpretation", "");
3134
0
            if (callNode.getOp() == EOpCooperativeVectorMatMulAddNV) {
3135
0
                if (!(*argp)[biasInterpIdx]->getAsTyped()->getType().getQualifier().isConstant())
3136
0
                    error(loc, "argument must be compile-time constant", "biasInterpretation", "");
3137
0
            }
3138
0
            if (!(*argp)[MIdx]->getAsTyped()->getType().getQualifier().isConstant())
3139
0
                error(loc, "argument must be compile-time constant", "M", "");
3140
0
            if (!(*argp)[KIdx]->getAsTyped()->getType().getQualifier().isConstant())
3141
0
                error(loc, "argument must be compile-time constant", "K", "");
3142
0
            if (!(*argp)[matrixLayoutIdx]->getAsTyped()->getType().getQualifier().isConstant())
3143
0
                error(loc, "argument must be compile-time constant", "matrixLayout", "");
3144
0
            if (!(*argp)[transposeIdx]->getAsTyped()->getType().getQualifier().isConstant())
3145
0
                error(loc, "argument must be compile-time constant", "transpose", "");
3146
0
        }
3147
0
        break;
3148
0
    case EOpCooperativeVectorOuterProductAccumulateNV:
3149
0
        if (!(*argp)[5]->getAsTyped()->getType().getQualifier().isConstant())
3150
0
            error(loc, "argument must be compile-time constant", "matrixLayout", "");
3151
0
        if (!(*argp)[6]->getAsTyped()->getType().getQualifier().isConstant())
3152
0
            error(loc, "argument must be compile-time constant", "matrixInterpretation", "");
3153
0
        break;
3154
0
    default:
3155
0
        break;
3156
0
    }
3157
3158
    // Texture operations on texture objects (aside from texelFetch on a
3159
    // textureBuffer) require EXT_samplerless_texture_functions.
3160
0
    switch (callNode.getOp()) {
3161
0
    case EOpTextureQuerySize:
3162
0
    case EOpTextureQueryLevels:
3163
0
    case EOpTextureQuerySamples:
3164
0
    case EOpTextureFetch:
3165
0
    case EOpTextureFetchOffset:
3166
0
    {
3167
0
        const TSampler& sampler = fnCandidate[0].type->getSampler();
3168
3169
0
        const bool isTexture = sampler.isTexture() && !sampler.isCombined();
3170
0
        const bool isBuffer = sampler.isBuffer();
3171
0
        const bool isFetch = callNode.getOp() == EOpTextureFetch || callNode.getOp() == EOpTextureFetchOffset;
3172
3173
0
        if (isTexture && (!isBuffer || !isFetch))
3174
0
            requireExtensions(loc, 1, &E_GL_EXT_samplerless_texture_functions, fnCandidate.getName().c_str());
3175
3176
0
        break;
3177
0
    }
3178
3179
0
    case EOpConstructSaturated:
3180
0
    {
3181
0
        auto &sequence = callNode.getAsAggregate()->getSequence();
3182
0
        if (sequence.size() != 2) {
3183
0
            error(loc, "requires exactly two parameters", "", "");
3184
0
        }
3185
0
        auto &op0Type = sequence[0]->getAsTyped()->getType();
3186
0
        auto &op1Type = sequence[1]->getAsTyped()->getType();
3187
0
        if (op0Type.getBasicType() != EbtFloatE5M2 && op0Type.getBasicType() != EbtFloatE4M3) {
3188
0
            error(loc, "first parameter must have floate5m2 or floate4m3 basic type", "", "");
3189
0
        }
3190
0
        if (op1Type.getBasicType() == EbtFloatE5M2 || op1Type.getBasicType() == EbtFloatE4M3) {
3191
0
            error(loc, "second parameter must not have floate5m2 or floate4m3 basic type", "", "");
3192
0
        }
3193
3194
0
        if (!(op0Type.isScalar() || op0Type.isVector() || op0Type.isCoopMatKHR())) {
3195
0
            error(loc, "first parameter must be scalar, vector, or cooperative matrix", "", "");
3196
0
        }
3197
0
        if (!(op1Type.isScalar() || op1Type.isVector() || op1Type.isCoopMatKHR())) {
3198
0
            error(loc, "second parameter must be scalar, vector, or cooperative matrix", "", "");
3199
0
        }
3200
0
        if (!(op0Type.sameElementShape(op1Type) || op0Type.sameCoopMatShape(op1Type))) {
3201
0
            error(loc, "types must match other than scalar type and coopmat Use", "", "");
3202
0
        }
3203
0
        break;
3204
0
    }
3205
0
    case EOpTensorReadARM:
3206
0
    case EOpTensorWriteARM:
3207
0
    {
3208
0
        const TType &tensorType = (*argp)[0]->getAsTyped()->getType();
3209
3210
        // Check that coordinates argument length matches rank of tensor argument.
3211
0
        int tensorRank = tensorType.getTensorRankARM();
3212
0
        const TArraySizes *coordArgArrayTy = (*argp)[1]->getAsTyped()->getType().getArraySizes();
3213
0
        assert(coordArgArrayTy->getNumDims() == 1 && "expecting 1D coordinate array");
3214
0
        if (coordArgArrayTy->getDimSize(0) != tensorRank) {
3215
0
            error(loc, "number of coordinates does not match tensor rank", "coord", "");
3216
0
        }
3217
3218
        // Check that tensor element type matches data argument.
3219
0
        TBasicType eltTy = tensorType.getBasicType();
3220
0
        TBasicType argTy = (*argp)[2]->getAsTyped()->getType().getBasicType();
3221
0
        if (eltTy != argTy) {
3222
0
            error(loc, "", "data", "data argument type (%s) does not match tensor element type (%s)",
3223
0
                  TType::getBasicString(argTy), TType::getBasicString(eltTy));
3224
0
        }
3225
3226
        // Check optional tensor operands.
3227
0
        if (argp->size() > 3) {
3228
0
            const TIntermConstantUnion* opArg = (*argp)[3]->getAsConstantUnion();
3229
0
            if (!opArg) {
3230
0
                error(loc, "tensor operands argument must be a constant integral expression", "tensorOps", "");
3231
0
            }
3232
0
            const unsigned int ops = opArg ? opArg->getConstArray()[0].getUConst() : 0;
3233
0
            const int gl_TensorOperandsOutOfBoundsValueARM = 0x2;
3234
0
            if (ops & gl_TensorOperandsOutOfBoundsValueARM) {
3235
                // Out-of-bounds values can only be used with reads.
3236
0
                if (callNode.getOp() != EOpTensorReadARM) {
3237
0
                    error(loc, "out-of-bounds value is only valid with tensorReadARM", "tensorOps", "");
3238
0
                }
3239
                // Check that an out-of-bounds value is present.
3240
0
                if (argp->size() == 4) {
3241
0
                    error(loc, "expecting out-of-bounds value as next argument", "tensorOps", "");
3242
0
                } else {
3243
                    // Check constantness of out-of-bounds value.
3244
0
                    const TIntermConstantUnion* oobArg = (*argp)[4]->getAsConstantUnion();
3245
0
                    if (!oobArg) {
3246
0
                        error(loc, "argument following gl_TensorOperandsOutOfBoundsValueARM must be constant", "vararg",
3247
0
                              "");
3248
0
                    } else if (oobArg->getType().getBasicType() != tensorType.getBasicType()) {
3249
                        // The type of the OOB value does not match the tensor type.
3250
0
                        error(loc, "", "vararg",
3251
0
                            "out-of-bounds value type (%s) does not match tensor element type (%s)",
3252
0
                            TType::getBasicString(oobArg->getBasicType()), TType::getBasicString(eltTy));
3253
3254
0
                    }
3255
0
                }
3256
0
            }
3257
0
        }
3258
0
        break;
3259
0
    }
3260
3261
0
    case EOpTensorSizeARM:
3262
0
    {
3263
0
        unsigned int tensorRank = (*argp)[0]->getAsTyped()->getType().getTensorRankARM();
3264
0
        const TIntermConstantUnion *dimArg = (*argp)[1]->getAsConstantUnion();
3265
0
        if (dimArg) {
3266
0
            if (dimArg->getConstArray()[0].getUConst() >= tensorRank) {
3267
0
                error(loc, "dimension argument exceeds tensor rank", "dim", "");
3268
0
            }
3269
0
        } else {
3270
0
            error(loc, "dimension argument must be constant", "dim", "");
3271
0
        }
3272
0
        break;
3273
0
    }
3274
3275
0
    default:
3276
0
        break;
3277
0
    }
3278
3279
0
    if (callNode.isSubgroup()) {
3280
        // these require SPIR-V 1.3
3281
0
        if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_3)
3282
0
            error(loc, "requires SPIR-V 1.3", "subgroup op", "");
3283
3284
        // Check that if extended types are being used that the correct extensions are enabled.
3285
0
        if (arg0 != nullptr) {
3286
0
            const TType& type = arg0->getType();
3287
0
            bool enhanced = intermediate.getEnhancedMsgs();
3288
0
            switch (type.getBasicType()) {
3289
0
            default:
3290
0
                break;
3291
0
            case EbtInt8:
3292
0
            case EbtUint8:
3293
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int8, type.getCompleteString(enhanced).c_str());
3294
0
                break;
3295
0
            case EbtInt16:
3296
0
            case EbtUint16:
3297
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int16, type.getCompleteString(enhanced).c_str());
3298
0
                break;
3299
0
            case EbtInt64:
3300
0
            case EbtUint64:
3301
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int64, type.getCompleteString(enhanced).c_str());
3302
0
                break;
3303
0
            case EbtFloat16:
3304
0
                requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_float16, type.getCompleteString(enhanced).c_str());
3305
0
                break;
3306
0
            }
3307
0
        }
3308
0
    }
3309
0
}
3310
3311
3312
// Deprecated!  Use PureOperatorBuiltins == true instead, in which case this
3313
// functionality is handled in builtInOpCheck() instead of here.
3314
//
3315
// Do additional checking of built-in function calls that were not mapped
3316
// to built-in operations (e.g., texturing functions).
3317
//
3318
// Assumes there has been a semantically correct match to a built-in function.
3319
//
3320
void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermAggregate& callNode)
3321
0
{
3322
    // Further maintenance of this function is deprecated, because the "correct"
3323
    // future-oriented design is to not have to do string compares on function names.
3324
3325
    // If PureOperatorBuiltins == true, then all built-ins should be mapped
3326
    // to a TOperator, and this function would then never get called.
3327
3328
0
    assert(PureOperatorBuiltins == false);
3329
3330
    // built-in texturing functions get their return value precision from the precision of the sampler
3331
0
    if (fnCandidate.getType().getQualifier().precision == EpqNone &&
3332
0
        fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler)
3333
0
        callNode.getQualifier().precision = callNode.getSequence()[0]->getAsTyped()->getQualifier().precision;
3334
3335
0
    if (fnCandidate.getName().compare(0, 7, "texture") == 0) {
3336
0
        if (fnCandidate.getName().compare(0, 13, "textureGather") == 0) {
3337
0
            TString featureString = fnCandidate.getName() + "(...)";
3338
0
            const char* feature = featureString.c_str();
3339
0
            profileRequires(loc, EEsProfile, 310, nullptr, feature);
3340
3341
0
            int compArg = -1;  // track which argument, if any, is the constant component argument
3342
0
            if (fnCandidate.getName().compare("textureGatherOffset") == 0) {
3343
                // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument
3344
0
                if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3)
3345
0
                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
3346
0
                else
3347
0
                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
3348
0
                int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2;
3349
0
                if (! callNode.getSequence()[offsetArg]->getAsConstantUnion())
3350
0
                    profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
3351
0
                                    "non-constant offset argument");
3352
0
                if (! fnCandidate[0].type->getSampler().shadow)
3353
0
                    compArg = 3;
3354
0
            } else if (fnCandidate.getName().compare("textureGatherOffsets") == 0) {
3355
0
                profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
3356
0
                if (! fnCandidate[0].type->getSampler().shadow)
3357
0
                    compArg = 3;
3358
                // check for constant offsets
3359
0
                int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2;
3360
0
                if (! callNode.getSequence()[offsetArg]->getAsConstantUnion() && !extensionTurnedOn(E_GL_NV_gpu_shader5))
3361
0
                    error(loc, "must be a compile-time constant:", feature, "offsets argument");
3362
0
            } else if (fnCandidate.getName().compare("textureGather") == 0) {
3363
                // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5,
3364
                // otherwise, need GL_ARB_texture_gather.
3365
0
                if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) {
3366
0
                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
3367
0
                    if (! fnCandidate[0].type->getSampler().shadow)
3368
0
                        compArg = 2;
3369
0
                } else
3370
0
                    profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
3371
0
            }
3372
3373
0
            if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
3374
0
                if (callNode.getSequence()[compArg]->getAsConstantUnion()) {
3375
0
                    int value = callNode.getSequence()[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
3376
0
                    if (value < 0 || value > 3)
3377
0
                        error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
3378
0
                } else
3379
0
                    error(loc, "must be a compile-time constant:", feature, "component argument");
3380
0
            }
3381
0
        } else {
3382
            // this is only for functions not starting "textureGather"...
3383
0
            if (fnCandidate.getName().find("Offset") != TString::npos) {
3384
3385
                // Handle texture-offset limits checking
3386
0
                int arg = -1;
3387
0
                if (fnCandidate.getName().compare("textureOffset") == 0)
3388
0
                    arg = 2;
3389
0
                else if (fnCandidate.getName().compare("texelFetchOffset") == 0)
3390
0
                    arg = 3;
3391
0
                else if (fnCandidate.getName().compare("textureProjOffset") == 0)
3392
0
                    arg = 2;
3393
0
                else if (fnCandidate.getName().compare("textureLodOffset") == 0)
3394
0
                    arg = 3;
3395
0
                else if (fnCandidate.getName().compare("textureProjLodOffset") == 0)
3396
0
                    arg = 3;
3397
0
                else if (fnCandidate.getName().compare("textureGradOffset") == 0)
3398
0
                    arg = 4;
3399
0
                else if (fnCandidate.getName().compare("textureProjGradOffset") == 0)
3400
0
                    arg = 4;
3401
3402
0
                if (arg > 0) {
3403
0
                    if (! callNode.getSequence()[arg]->getAsConstantUnion()) {
3404
0
                        if (!extensionTurnedOn(E_GL_EXT_texture_offset_non_const))
3405
0
                            error(loc, "argument must be compile-time constant", "texel offset", "");
3406
0
                    }
3407
0
                    else {
3408
0
                        const TType& type = callNode.getSequence()[arg]->getAsTyped()->getType();
3409
0
                        for (int c = 0; c < type.getVectorSize(); ++c) {
3410
0
                            int offset = callNode.getSequence()[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
3411
0
                            if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
3412
0
                                error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
3413
0
                        }
3414
0
                    }
3415
0
                }
3416
0
            }
3417
0
        }
3418
0
    }
3419
3420
    // GL_ARB_shader_texture_image_samples
3421
0
    if (fnCandidate.getName().compare(0, 14, "textureSamples") == 0 || fnCandidate.getName().compare(0, 12, "imageSamples") == 0)
3422
0
        profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples");
3423
3424
0
    if (fnCandidate.getName().compare(0, 11, "imageAtomic") == 0) {
3425
0
        const TType& imageType = callNode.getSequence()[0]->getAsTyped()->getType();
3426
0
        if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
3427
0
            if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui)
3428
0
                error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
3429
0
        } else {
3430
0
            if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0)
3431
0
                error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
3432
0
            else if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile())
3433
0
                error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
3434
0
        }
3435
0
    }
3436
0
}
3437
3438
//
3439
// Do any extra checking for a user function call.
3440
//
3441
void TParseContext::userFunctionCallCheck(const TSourceLoc& loc, TIntermAggregate& callNode)
3442
0
{
3443
0
    TIntermSequence& arguments = callNode.getSequence();
3444
3445
0
    for (int i = 0; i < (int)arguments.size(); ++i)
3446
0
        samplerConstructorLocationCheck(loc, "call argument", arguments[i]);
3447
0
}
3448
3449
//
3450
// Emit an error if this is a sampler constructor
3451
//
3452
void TParseContext::samplerConstructorLocationCheck(const TSourceLoc& loc, const char* token, TIntermNode* node)
3453
4
{
3454
4
    if (node->getAsOperator() && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
3455
0
        error(loc, "sampler constructor must appear at point of use", token, "");
3456
4
}
3457
3458
//
3459
// Handle seeing a built-in constructor in a grammar production.
3460
//
3461
TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPublicType& publicType)
3462
4.40k
{
3463
4.40k
    TType type(publicType);
3464
4.40k
    type.getQualifier().precision = EpqNone;
3465
3466
4.40k
    if (type.isArray()) {
3467
44
        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed constructor");
3468
44
        profileRequires(loc, EEsProfile, 300, nullptr, "arrayed constructor");
3469
44
    }
3470
3471
    // Reuse EOpConstructTextureSampler for bindless image constructor
3472
    // uvec2 imgHandle;
3473
    // imageLoad(image1D(imgHandle), 0);
3474
4.40k
    if (type.isImage() && extensionTurnedOn(E_GL_ARB_bindless_texture))
3475
0
    {
3476
0
        intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc);
3477
0
    }
3478
3479
4.40k
    TOperator op = intermediate.mapTypeToConstructorOp(type);
3480
3481
4.40k
    if (op == EOpNull) {
3482
0
      if (intermediate.getEnhancedMsgs() && type.getBasicType() == EbtSampler)
3483
0
            error(loc, "function not supported in this version; use texture() instead", "texture*D*", "");
3484
0
        else
3485
0
            error(loc, "cannot construct this type", type.getBasicString(), "");
3486
0
        op = EOpConstructFloat;
3487
0
        TType errorType(EbtFloat);
3488
0
        type.shallowCopy(errorType);
3489
0
    }
3490
3491
4.40k
    TString empty("");
3492
3493
4.40k
    return new TFunction(&empty, type, op);
3494
4.40k
}
3495
3496
// Handle seeing a precision qualifier in the grammar.
3497
void TParseContext::handlePrecisionQualifier(const TSourceLoc& /*loc*/, TQualifier& qualifier, TPrecisionQualifier precision)
3498
422k
{
3499
422k
    if (obeyPrecisionQualifiers())
3500
371k
        qualifier.precision = precision;
3501
422k
}
3502
3503
// Check for messages to give on seeing a precision qualifier used in a
3504
// declaration in the grammar.
3505
void TParseContext::checkPrecisionQualifier(const TSourceLoc& loc, TPrecisionQualifier)
3506
422k
{
3507
422k
    if (precisionManager.shouldWarnAboutDefaults()) {
3508
0
        warn(loc, "all default precisions are highp; use precision statements to quiet warning, e.g.:\n"
3509
0
                  "         \"precision mediump int; precision highp float;\"", "", "");
3510
0
        precisionManager.defaultWarningGiven();
3511
0
    }
3512
422k
}
3513
3514
//
3515
// Same error message for all places assignments don't work.
3516
//
3517
void TParseContext::assignError(const TSourceLoc& loc, const char* op, TString left, TString right)
3518
4
{
3519
4
    error(loc, "", op, "cannot convert from '%s' to '%s'",
3520
4
          right.c_str(), left.c_str());
3521
4
}
3522
3523
//
3524
// Same error message for all places unary operations don't work.
3525
//
3526
void TParseContext::unaryOpError(const TSourceLoc& loc, const char* op, TString operand)
3527
837
{
3528
837
   error(loc, " wrong operand type", op,
3529
837
          "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)",
3530
837
          op, operand.c_str());
3531
837
}
3532
3533
//
3534
// Same error message for all binary operations don't work.
3535
//
3536
void TParseContext::binaryOpError(const TSourceLoc& loc, const char* op, TString left, TString right)
3537
466
{
3538
466
    error(loc, " wrong operand types:", op,
3539
466
            "no operation '%s' exists that takes a left-hand operand of type '%s' and "
3540
466
            "a right operand of type '%s' (or there is no acceptable conversion)",
3541
466
            op, left.c_str(), right.c_str());
3542
466
}
3543
3544
//
3545
// A basic type of EbtVoid is a key that the name string was seen in the source, but
3546
// it was not found as a variable in the symbol table.  If so, give the error
3547
// message and insert a dummy variable in the symbol table to prevent future errors.
3548
//
3549
void TParseContext::variableCheck(TIntermTyped*& nodePtr)
3550
68.1k
{
3551
68.1k
    TIntermSymbol* symbol = nodePtr->getAsSymbolNode();
3552
68.1k
    if (! symbol)
3553
67.2k
        return;
3554
3555
851
    if (symbol->getType().getBasicType() == EbtVoid) {
3556
65
        const char *extraInfoFormat = "";
3557
65
        if (spvVersion.vulkan != 0 && symbol->getName() == "gl_VertexID") {
3558
0
          extraInfoFormat = "(Did you mean gl_VertexIndex?)";
3559
65
        } else if (spvVersion.vulkan != 0 && symbol->getName() == "gl_InstanceID") {
3560
0
          extraInfoFormat = "(Did you mean gl_InstanceIndex?)";
3561
0
        }
3562
65
        error(symbol->getLoc(), "undeclared identifier", symbol->getName().c_str(), extraInfoFormat);
3563
3564
        // Add to symbol table to prevent future error messages on the same name
3565
65
        if (symbol->getName().size() > 0) {
3566
65
            TVariable* fakeVariable = new TVariable(&symbol->getName(), TType(EbtFloat));
3567
65
            symbolTable.insert(*fakeVariable);
3568
3569
            // substitute a symbol node for this new variable
3570
65
            nodePtr = intermediate.addSymbol(*fakeVariable, symbol->getLoc());
3571
65
        }
3572
786
    } else {
3573
786
        switch (symbol->getQualifier().storage) {
3574
0
        case EvqPointCoord:
3575
0
            profileRequires(symbol->getLoc(), ENoProfile, 120, nullptr, "gl_PointCoord");
3576
0
            break;
3577
786
        default: break; // some compilers want this
3578
786
        }
3579
786
    }
3580
851
}
3581
3582
//
3583
// Both test and if necessary, spit out an error, to see if the node is really
3584
// an l-value that can be operated on this way.
3585
//
3586
// Returns true if there was an error.
3587
//
3588
bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
3589
384
{
3590
384
    TIntermBinary* binaryNode = node->getAsBinaryNode();
3591
3592
384
    if (binaryNode) {
3593
0
        bool errorReturn = false;
3594
3595
0
        switch(binaryNode->getOp()) {
3596
0
        case EOpIndexDirect:
3597
0
        case EOpIndexIndirect:
3598
            // ...  tessellation control shader ...
3599
            // If a per-vertex output variable is used as an l-value, it is a
3600
            // compile-time or link-time error if the expression indicating the
3601
            // vertex index is not the identifier gl_InvocationID.
3602
0
            if (language == EShLangTessControl) {
3603
0
                const TType& leftType = binaryNode->getLeft()->getType();
3604
0
                if (leftType.getQualifier().storage == EvqVaryingOut && ! leftType.getQualifier().patch && binaryNode->getLeft()->getAsSymbolNode()) {
3605
                    // we have a per-vertex output
3606
0
                    const TIntermSymbol* rightSymbol = binaryNode->getRight()->getAsSymbolNode();
3607
0
                    if (! rightSymbol || rightSymbol->getQualifier().builtIn != EbvInvocationId)
3608
0
                        error(loc, "tessellation-control per-vertex output l-value must be indexed with gl_InvocationID", "[]", "");
3609
0
                }
3610
0
            }
3611
0
            break; // left node is checked by base class
3612
0
        case EOpVectorSwizzle:
3613
0
            errorReturn = lValueErrorCheck(loc, op, binaryNode->getLeft());
3614
0
            if (!errorReturn) {
3615
0
                int offset[4] = {0,0,0,0};
3616
3617
0
                TIntermTyped* rightNode = binaryNode->getRight();
3618
0
                TIntermAggregate *aggrNode = rightNode->getAsAggregate();
3619
3620
0
                for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
3621
0
                                               p != aggrNode->getSequence().end(); p++) {
3622
0
                    int value = (*p)->getAsTyped()->getAsConstantUnion()->getConstArray()[0].getIConst();
3623
0
                    offset[value]++;
3624
0
                    if (offset[value] > 1) {
3625
0
                        error(loc, " l-value of swizzle cannot have duplicate components", op, "", "");
3626
3627
0
                        return true;
3628
0
                    }
3629
0
                }
3630
0
            }
3631
3632
0
            return errorReturn;
3633
0
        default:
3634
0
            break;
3635
0
        }
3636
3637
0
        if (errorReturn) {
3638
0
            error(loc, " l-value required", op, "", "");
3639
0
            return true;
3640
0
        }
3641
0
    }
3642
3643
384
    if (binaryNode && binaryNode->getOp() == EOpIndexDirectStruct && binaryNode->getLeft()->isReference())
3644
0
        return false;
3645
3646
    // Let the base class check errors
3647
384
    if (TParseContextBase::lValueErrorCheck(loc, op, node))
3648
7
        return true;
3649
3650
377
    const char* symbol = nullptr;
3651
377
    TIntermSymbol* symNode = node->getAsSymbolNode();
3652
377
    if (symNode != nullptr)
3653
377
        symbol = symNode->getName().c_str();
3654
3655
377
    const char* message = nullptr;
3656
377
    switch (node->getQualifier().storage) {
3657
0
    case EvqVaryingIn:      message = "can't modify shader input";   break;
3658
0
    case EvqInstanceId:     message = "can't modify gl_InstanceID";  break;
3659
0
    case EvqVertexId:       message = "can't modify gl_VertexID";    break;
3660
0
    case EvqFace:           message = "can't modify gl_FrontFace";   break;
3661
0
    case EvqFragCoord:      message = "can't modify gl_FragCoord";   break;
3662
0
    case EvqPointCoord:     message = "can't modify gl_PointCoord";  break;
3663
0
    case EvqFragDepth:
3664
0
        intermediate.setDepthReplacing();
3665
        // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
3666
0
        if (isEsProfile() && intermediate.getEarlyFragmentTests())
3667
0
            message = "can't modify gl_FragDepth if using early_fragment_tests";
3668
0
        break;
3669
0
    case EvqFragStencil:
3670
0
        intermediate.setStencilReplacing();
3671
        // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
3672
0
        if (isEsProfile() && intermediate.getEarlyFragmentTests())
3673
0
            message = "can't modify EvqFragStencil if using early_fragment_tests";
3674
0
        break;
3675
3676
0
    case EvqtaskPayloadSharedEXT:
3677
0
        if (language == EShLangMesh)
3678
0
            message = "can't modify variable with storage qualifier taskPayloadSharedEXT in mesh shaders";
3679
0
        break;
3680
377
    default:
3681
377
        break;
3682
377
    }
3683
3684
377
    if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
3685
0
        error(loc, " l-value required", op, "", "");
3686
3687
0
        return true;
3688
0
    }
3689
3690
    //
3691
    // Everything else is okay, no error.
3692
    //
3693
377
    if (message == nullptr)
3694
377
        return false;
3695
3696
    //
3697
    // If we get here, we have an error and a message.
3698
    //
3699
0
    if (symNode)
3700
0
        error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
3701
0
    else
3702
0
        error(loc, " l-value required", op, "(%s)", message);
3703
3704
0
    return true;
3705
377
}
3706
3707
// Test for and give an error if the node can't be read from.
3708
void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
3709
32.6k
{
3710
    // Let the base class check errors
3711
32.6k
    TParseContextBase::rValueErrorCheck(loc, op, node);
3712
3713
32.6k
    TIntermSymbol* symNode = node->getAsSymbolNode();
3714
32.6k
    if (!(symNode && symNode->getQualifier().isWriteOnly())) // base class checks
3715
32.6k
        if (symNode && symNode->getQualifier().isExplicitInterpolation())
3716
0
            error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str());
3717
3718
    // local_size_{xyz} must be assigned or specialized before gl_WorkGroupSize can be assigned.
3719
32.6k
    if(node->getQualifier().builtIn == EbvWorkGroupSize &&
3720
32.6k
       !(intermediate.isLocalSizeSet() || intermediate.isLocalSizeSpecialized()))
3721
0
        error(loc, "can't read from gl_WorkGroupSize before a fixed workgroup size has been declared", op, "");
3722
32.6k
}
3723
3724
//
3725
// Both test, and if necessary spit out an error, to see if the node is really
3726
// a constant.
3727
//
3728
void TParseContext::constantValueCheck(TIntermTyped* node, const char* token)
3729
0
{
3730
0
    if (! node->getQualifier().isConstant())
3731
0
        error(node->getLoc(), "constant expression required", token, "");
3732
0
}
3733
3734
//
3735
// Both test, and if necessary spit out an error, to see if the node is really
3736
// a 32-bit integer or can implicitly convert to one.
3737
//
3738
void TParseContext::integerCheck(const TIntermTyped* node, const char* token)
3739
4
{
3740
4
    auto from_type = node->getBasicType();
3741
4
    if ((from_type == EbtInt || from_type == EbtUint ||
3742
4
         intermediate.canImplicitlyPromote(from_type, EbtInt, EOpNull) ||
3743
4
         intermediate.canImplicitlyPromote(from_type, EbtUint, EOpNull)) && node->isScalar())
3744
2
        return;
3745
3746
2
    error(node->getLoc(), "scalar integer expression required", token, "");
3747
2
}
3748
3749
//
3750
// Both test, and if necessary spit out an error, to see if we are currently
3751
// globally scoped.
3752
//
3753
void TParseContext::globalCheck(const TSourceLoc& loc, const char* token)
3754
363k
{
3755
363k
    if (! symbolTable.atGlobalLevel())
3756
0
        error(loc, "not allowed in nested scope", token, "");
3757
363k
}
3758
3759
//
3760
// Reserved errors for GLSL.
3761
//
3762
void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& identifier)
3763
1.14M
{
3764
    // "Identifiers starting with "gl_" are reserved for use by OpenGL, and may not be
3765
    // declared in a shader; this results in a compile-time error."
3766
1.14M
    if (! symbolTable.atBuiltInLevel()) {
3767
1.52k
        if (builtInName(identifier) && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
3768
            // The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "gl_".
3769
7
            error(loc, "identifiers starting with \"gl_\" are reserved", identifier.c_str(), "");
3770
3771
        // "__" are not supposed to be an error.  ES 300 (and desktop) added the clarification:
3772
        // "In addition, all identifiers containing two consecutive underscores (__) are
3773
        // reserved; using such a name does not itself result in an error, but may result
3774
        // in undefined behavior."
3775
        // however, before that, ES tests required an error.
3776
1.52k
        if (identifier.find("__") != TString::npos && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) {
3777
            // The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "__".
3778
0
            if (isEsProfile() && version < 300)
3779
0
                error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version < 300", identifier.c_str(), "");
3780
0
            else
3781
0
                warn(loc, "identifiers containing consecutive underscores (\"__\") are reserved", identifier.c_str(), "");
3782
0
        }
3783
1.52k
    }
3784
1.14M
}
3785
3786
//
3787
// Reserved errors for the preprocessor.
3788
//
3789
void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* identifier, const char* op)
3790
69
{
3791
    // "__" are not supposed to be an error.  ES 300 (and desktop) added the clarification:
3792
    // "All macro names containing two consecutive underscores ( __ ) are reserved;
3793
    // defining such a name does not itself result in an error, but may result in
3794
    // undefined behavior.  All macro names prefixed with "GL_" ("GL" followed by a
3795
    // single underscore) are also reserved, and defining such a name results in a
3796
    // compile-time error."
3797
    // however, before that, ES tests required an error.
3798
69
    if (strncmp(identifier, "GL_", 3) == 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
3799
        // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "GL_".
3800
0
        ppError(loc, "names beginning with \"GL_\" can't be (un)defined:", op,  identifier);
3801
69
    else if (strncmp(identifier, "defined", 8) == 0)
3802
0
        if (relaxedErrors())
3803
0
            ppWarn(loc, "\"defined\" is (un)defined:", op,  identifier);
3804
0
        else
3805
0
            ppError(loc, "\"defined\" can't be (un)defined:", op,  identifier);
3806
69
    else if (strstr(identifier, "__") != nullptr && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) {
3807
        // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "__".
3808
0
        if (isEsProfile() && version >= 300 &&
3809
0
            (strcmp(identifier, "__LINE__") == 0 ||
3810
0
             strcmp(identifier, "__FILE__") == 0 ||
3811
0
             strcmp(identifier, "__VERSION__") == 0))
3812
0
            ppError(loc, "predefined names can't be (un)defined:", op,  identifier);
3813
0
        else {
3814
0
            if (isEsProfile() && version < 300 && !relaxedErrors())
3815
0
                ppError(loc, "names containing consecutive underscores are reserved, and an error if version < 300:", op, identifier);
3816
0
            else
3817
0
                ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier);
3818
0
        }
3819
0
    }
3820
69
}
3821
3822
//
3823
// See if this version/profile allows use of the line-continuation character '\'.
3824
//
3825
// Returns true if a line continuation should be done.
3826
//
3827
bool TParseContext::lineContinuationCheck(const TSourceLoc& loc, bool endOfComment)
3828
14.4k
{
3829
14.4k
    const char* message = "line continuation";
3830
3831
14.4k
    bool lineContinuationAllowed = (isEsProfile() && version >= 300) ||
3832
14.4k
                                   (!isEsProfile() && (version >= 420 || extensionTurnedOn(E_GL_ARB_shading_language_420pack)));
3833
3834
14.4k
    if (endOfComment) {
3835
9.74k
        if (lineContinuationAllowed)
3836
2.72k
            warn(loc, "used at end of comment; the following line is still part of the comment", message, "");
3837
7.02k
        else
3838
7.02k
            warn(loc, "used at end of comment, but this version does not provide line continuation", message, "");
3839
3840
9.74k
        return lineContinuationAllowed;
3841
9.74k
    }
3842
3843
4.73k
    if (relaxedErrors()) {
3844
0
        if (! lineContinuationAllowed)
3845
0
            warn(loc, "not allowed in this version", message, "");
3846
0
        return true;
3847
4.73k
    } else {
3848
4.73k
        profileRequires(loc, EEsProfile, 300, nullptr, message);
3849
4.73k
        profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, message);
3850
4.73k
    }
3851
3852
4.73k
    return lineContinuationAllowed;
3853
4.73k
}
3854
3855
bool TParseContext::builtInName(const TString& identifier)
3856
114k
{
3857
114k
    return identifier.compare(0, 3, "gl_") == 0;
3858
114k
}
3859
3860
//
3861
// Make sure there is enough data and not too many arguments provided to the
3862
// constructor to build something of the type of the constructor.  Also returns
3863
// the type of the constructor.
3864
//
3865
// Part of establishing type is establishing specialization-constness.
3866
// We don't yet know "top down" whether type is a specialization constant,
3867
// but a const constructor can becomes a specialization constant if any of
3868
// its children are, subject to KHR_vulkan_glsl rules:
3869
//
3870
//     - int(), uint(), and bool() constructors for type conversions
3871
//       from any of the following types to any of the following types:
3872
//         * int
3873
//         * uint
3874
//         * bool
3875
//     - vector versions of the above conversion constructors
3876
//
3877
// Returns true if there was an error in construction.
3878
//
3879
bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
3880
924
{
3881
    // See if the constructor does not establish the main type, only requalifies
3882
    // it, in which case the type comes from the argument instead of from the
3883
    // constructor function.
3884
924
    switch (op) {
3885
0
    case EOpConstructNonuniform:
3886
0
        if (node != nullptr && node->getAsTyped() != nullptr) {
3887
0
            type.shallowCopy(node->getAsTyped()->getType());
3888
0
            type.getQualifier().makeTemporary();
3889
0
            type.getQualifier().nonUniform = true;
3890
0
        }
3891
0
        break;
3892
924
    default:
3893
924
        type.shallowCopy(function.getType());
3894
924
        break;
3895
924
    }
3896
3897
924
    TString constructorString;
3898
924
    if (intermediate.getEnhancedMsgs())
3899
0
        constructorString.append(type.getCompleteString(true, false, false, true)).append(" constructor");
3900
924
    else
3901
924
        constructorString.append("constructor");
3902
3903
    // See if it's a matrix
3904
924
    bool constructingMatrix = false;
3905
924
    switch (op) {
3906
0
    case EOpConstructTextureSampler:
3907
0
        return constructorTextureSamplerError(loc, function);
3908
0
    case EOpConstructMat2x2:
3909
0
    case EOpConstructMat2x3:
3910
0
    case EOpConstructMat2x4:
3911
0
    case EOpConstructMat3x2:
3912
0
    case EOpConstructMat3x3:
3913
0
    case EOpConstructMat3x4:
3914
0
    case EOpConstructMat4x2:
3915
0
    case EOpConstructMat4x3:
3916
0
    case EOpConstructMat4x4:
3917
0
    case EOpConstructDMat2x2:
3918
0
    case EOpConstructDMat2x3:
3919
0
    case EOpConstructDMat2x4:
3920
0
    case EOpConstructDMat3x2:
3921
0
    case EOpConstructDMat3x3:
3922
0
    case EOpConstructDMat3x4:
3923
0
    case EOpConstructDMat4x2:
3924
0
    case EOpConstructDMat4x3:
3925
0
    case EOpConstructDMat4x4:
3926
0
    case EOpConstructF16Mat2x2:
3927
0
    case EOpConstructF16Mat2x3:
3928
0
    case EOpConstructF16Mat2x4:
3929
0
    case EOpConstructF16Mat3x2:
3930
0
    case EOpConstructF16Mat3x3:
3931
0
    case EOpConstructF16Mat3x4:
3932
0
    case EOpConstructF16Mat4x2:
3933
0
    case EOpConstructF16Mat4x3:
3934
0
    case EOpConstructF16Mat4x4:
3935
0
        constructingMatrix = true;
3936
0
        break;
3937
924
    default:
3938
924
        break;
3939
924
    }
3940
3941
    //
3942
    // Walk the arguments for first-pass checks and collection of information.
3943
    //
3944
3945
924
    int size = 0;
3946
924
    bool constType = true;
3947
924
    bool specConstType = false;   // value is only valid if constType is true
3948
924
    bool full = false;
3949
924
    bool overFull = false;
3950
924
    bool matrixInMatrix = false;
3951
924
    bool arrayArg = false;
3952
924
    bool floatArgument = false;
3953
924
    bool intArgument = false;
3954
3.30k
    for (int arg = 0; arg < function.getParamCount(); ++arg) {
3955
2.37k
        if (function[arg].type->isArray()) {
3956
0
            if (function[arg].type->isUnsizedArray()) {
3957
                // Can't construct from an unsized array.
3958
0
                error(loc, "array argument must be sized", constructorString.c_str(), "");
3959
0
                return true;
3960
0
            }
3961
0
            arrayArg = true;
3962
0
        }
3963
2.37k
        if (constructingMatrix && function[arg].type->isMatrix())
3964
0
            matrixInMatrix = true;
3965
3966
        // 'full' will go to true when enough args have been seen.  If we loop
3967
        // again, there is an extra argument.
3968
2.37k
        if (full) {
3969
            // For vectors and matrices, it's okay to have too many components
3970
            // available, but not okay to have unused arguments.
3971
0
            overFull = true;
3972
0
        }
3973
3974
2.37k
        size += function[arg].type->computeNumComponents();
3975
2.37k
        if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
3976
886
            full = true;
3977
3978
2.37k
        if (! function[arg].type->getQualifier().isConstant())
3979
94
            constType = false;
3980
2.37k
        if (function[arg].type->getQualifier().isSpecConstant())
3981
0
            specConstType = true;
3982
2.37k
        if (function[arg].type->isFloatingDomain())
3983
102
            floatArgument = true;
3984
2.37k
        if (function[arg].type->isIntegerDomain())
3985
2.27k
            intArgument = true;
3986
2.37k
        if (type.isStruct()) {
3987
0
            if (function[arg].type->contains16BitFloat()) {
3988
0
                requireFloat16Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 16-bit type");
3989
0
            }
3990
0
            if (function[arg].type->contains16BitInt()) {
3991
0
                requireInt16Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 16-bit type");
3992
0
            }
3993
0
            if (function[arg].type->contains8BitInt()) {
3994
0
                requireInt8Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 8-bit type");
3995
0
            }
3996
0
        }
3997
2.37k
    }
3998
924
    if (op == EOpConstructNonuniform)
3999
0
        constType = false;
4000
4001
924
    switch (op) {
4002
0
    case EOpConstructFloat16:
4003
0
    case EOpConstructF16Vec2:
4004
0
    case EOpConstructF16Vec3:
4005
0
    case EOpConstructF16Vec4:
4006
0
        if (type.isArray())
4007
0
            requireFloat16Arithmetic(loc, constructorString.c_str(), "16-bit arrays not supported");
4008
0
        if (type.isVector() && function.getParamCount() != 1)
4009
0
            requireFloat16Arithmetic(loc, constructorString.c_str(), "16-bit vectors only take vector types");
4010
0
        break;
4011
0
    case EOpConstructUint16:
4012
0
    case EOpConstructU16Vec2:
4013
0
    case EOpConstructU16Vec3:
4014
0
    case EOpConstructU16Vec4:
4015
0
    case EOpConstructInt16:
4016
0
    case EOpConstructI16Vec2:
4017
0
    case EOpConstructI16Vec3:
4018
0
    case EOpConstructI16Vec4:
4019
0
        if (type.isArray())
4020
0
            requireInt16Arithmetic(loc, constructorString.c_str(), "16-bit arrays not supported");
4021
0
        if (type.isVector() && function.getParamCount() != 1)
4022
0
            requireInt16Arithmetic(loc, constructorString.c_str(), "16-bit vectors only take vector types");
4023
0
        break;
4024
0
    case EOpConstructUint8:
4025
0
    case EOpConstructU8Vec2:
4026
0
    case EOpConstructU8Vec3:
4027
0
    case EOpConstructU8Vec4:
4028
0
    case EOpConstructInt8:
4029
0
    case EOpConstructI8Vec2:
4030
0
    case EOpConstructI8Vec3:
4031
0
    case EOpConstructI8Vec4:
4032
0
        if (type.isArray())
4033
0
            requireInt8Arithmetic(loc, constructorString.c_str(), "8-bit arrays not supported");
4034
0
        if (type.isVector() && function.getParamCount() != 1)
4035
0
            requireInt8Arithmetic(loc, constructorString.c_str(), "8-bit vectors only take vector types");
4036
0
        break;
4037
924
    default:
4038
924
        break;
4039
924
    }
4040
4041
    // inherit constness from children
4042
924
    if (constType) {
4043
830
        bool makeSpecConst;
4044
        // Finish pinning down spec-const semantics
4045
830
        if (specConstType) {
4046
0
            switch (op) {
4047
0
            case EOpConstructInt8:
4048
0
            case EOpConstructInt:
4049
0
            case EOpConstructUint:
4050
0
            case EOpConstructBool:
4051
0
            case EOpConstructBVec2:
4052
0
            case EOpConstructBVec3:
4053
0
            case EOpConstructBVec4:
4054
0
            case EOpConstructIVec2:
4055
0
            case EOpConstructIVec3:
4056
0
            case EOpConstructIVec4:
4057
0
            case EOpConstructUVec2:
4058
0
            case EOpConstructUVec3:
4059
0
            case EOpConstructUVec4:
4060
0
            case EOpConstructUint8:
4061
0
            case EOpConstructInt16:
4062
0
            case EOpConstructUint16:
4063
0
            case EOpConstructInt64:
4064
0
            case EOpConstructUint64:
4065
0
            case EOpConstructI8Vec2:
4066
0
            case EOpConstructI8Vec3:
4067
0
            case EOpConstructI8Vec4:
4068
0
            case EOpConstructU8Vec2:
4069
0
            case EOpConstructU8Vec3:
4070
0
            case EOpConstructU8Vec4:
4071
0
            case EOpConstructI16Vec2:
4072
0
            case EOpConstructI16Vec3:
4073
0
            case EOpConstructI16Vec4:
4074
0
            case EOpConstructU16Vec2:
4075
0
            case EOpConstructU16Vec3:
4076
0
            case EOpConstructU16Vec4:
4077
0
            case EOpConstructI64Vec2:
4078
0
            case EOpConstructI64Vec3:
4079
0
            case EOpConstructI64Vec4:
4080
0
            case EOpConstructU64Vec2:
4081
0
            case EOpConstructU64Vec3:
4082
0
            case EOpConstructU64Vec4:
4083
                // This was the list of valid ones, if they aren't converting from float
4084
                // and aren't making an array.
4085
0
                makeSpecConst = ! floatArgument && ! type.isArray();
4086
0
                break;
4087
4088
0
            case EOpConstructVec2:
4089
0
            case EOpConstructVec3:
4090
0
            case EOpConstructVec4:
4091
                // This was the list of valid ones, if they aren't converting from int
4092
                // and aren't making an array.
4093
0
                makeSpecConst = ! intArgument && !type.isArray();
4094
0
                break;
4095
4096
0
            case EOpConstructCooperativeMatrixNV:
4097
0
            case EOpConstructCooperativeMatrixKHR:
4098
0
            case EOpConstructStruct:
4099
0
                {
4100
0
                    const char *specConstantCompositeExt[] = { E_GL_EXT_spec_constant_composites };
4101
0
                    if (checkExtensionsRequested(loc, 1, specConstantCompositeExt, "spec constant aggregate constructor")) {
4102
0
                        makeSpecConst = true;
4103
0
                    } else {
4104
0
                        makeSpecConst = false;
4105
0
                    }
4106
0
                }
4107
0
                break;
4108
4109
0
            default:
4110
                // anything else wasn't white-listed in the spec as a conversion
4111
0
                makeSpecConst = false;
4112
0
                break;
4113
0
            }
4114
0
        } else
4115
830
            makeSpecConst = false;
4116
4117
830
        if (makeSpecConst)
4118
0
            type.getQualifier().makeSpecConstant();
4119
830
        else if (specConstType)
4120
0
            type.getQualifier().makeTemporary();
4121
830
        else
4122
830
            type.getQualifier().storage = EvqConst;
4123
830
    }
4124
4125
924
    if (type.isArray()) {
4126
38
        if (function.getParamCount() == 0) {
4127
0
            error(loc, "array constructor must have at least one argument", constructorString.c_str(), "");
4128
0
            return true;
4129
0
        }
4130
4131
38
        if (type.isUnsizedArray()) {
4132
            // auto adapt the constructor type to the number of arguments
4133
2
            type.changeOuterArraySize(function.getParamCount());
4134
36
        } else if (type.getOuterArraySize() != function.getParamCount()) {
4135
6
            error(loc, "array constructor needs one argument per array element", constructorString.c_str(), "");
4136
6
            return true;
4137
6
        }
4138
4139
32
        if (type.isArrayOfArrays()) {
4140
            // Types have to match, but we're still making the type.
4141
            // Finish making the type, and the comparison is done later
4142
            // when checking for conversion.
4143
0
            TArraySizes& arraySizes = *type.getArraySizes();
4144
4145
            // At least the dimensionalities have to match.
4146
0
            if (! function[0].type->isArray() ||
4147
0
                    arraySizes.getNumDims() != function[0].type->getArraySizes()->getNumDims() + 1) {
4148
0
                error(loc, "array constructor argument not correct type to construct array element", constructorString.c_str(), "");
4149
0
                return true;
4150
0
            }
4151
4152
0
            if (arraySizes.isInnerUnsized()) {
4153
                // "Arrays of arrays ..., and the size for any dimension is optional"
4154
                // That means we need to adopt (from the first argument) the other array sizes into the type.
4155
0
                for (int d = 1; d < arraySizes.getNumDims(); ++d) {
4156
0
                    if (arraySizes.getDimSize(d) == UnsizedArraySize) {
4157
0
                        arraySizes.setDimSize(d, function[0].type->getArraySizes()->getDimSize(d - 1));
4158
0
                    }
4159
0
                }
4160
0
            }
4161
0
        }
4162
32
    }
4163
4164
918
    if (arrayArg && op != EOpConstructStruct && ! type.isArrayOfArrays()) {
4165
0
        error(loc, "constructing non-array constituent from array argument", constructorString.c_str(), "");
4166
0
        return true;
4167
0
    }
4168
4169
918
    if (matrixInMatrix && ! type.isArray()) {
4170
0
        profileRequires(loc, ENoProfile, 120, nullptr, "constructing matrix from matrix");
4171
4172
        // "If a matrix argument is given to a matrix constructor,
4173
        // it is a compile-time error to have any other arguments."
4174
0
        if (function.getParamCount() != 1)
4175
0
            error(loc, "matrix constructed from matrix can only have one argument", constructorString.c_str(), "");
4176
0
        return false;
4177
0
    }
4178
4179
918
    if (overFull) {
4180
0
        error(loc, "too many arguments", constructorString.c_str(), "");
4181
0
        return true;
4182
0
    }
4183
4184
918
    if (op == EOpConstructStruct && ! type.isArray() && (int)type.getStruct()->size() != function.getParamCount()) {
4185
0
        error(loc, "Number of constructor parameters does not match the number of structure fields", constructorString.c_str(), "");
4186
0
        return true;
4187
0
    }
4188
4189
918
    if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) ||
4190
918
        (op == EOpConstructStruct && size < type.computeNumComponents())) {
4191
0
        error(loc, "not enough data provided for construction", constructorString.c_str(), "");
4192
0
        return true;
4193
0
    }
4194
4195
918
    if (type.isCoopMat() && function.getParamCount() != 1) {
4196
0
        error(loc, "wrong number of arguments", constructorString.c_str(), "");
4197
0
        return true;
4198
0
    }
4199
918
    if (type.isCoopMat() &&
4200
918
        !(function[0].type->isScalar() || function[0].type->isCoopMat())) {
4201
0
        error(loc, "Cooperative matrix constructor argument must be scalar or cooperative matrix", constructorString.c_str(), "");
4202
0
        return true;
4203
0
    }
4204
4205
918
    TIntermTyped* typed = node->getAsTyped();
4206
918
    if (type.isCoopMat() && typed->getType().isCoopMat() &&
4207
918
        ((extensionTurnedOn(E_GL_NV_cooperative_matrix2) && !type.sameCoopMatShape(typed->getType())) ||
4208
0
         (!extensionTurnedOn(E_GL_NV_cooperative_matrix2) && !type.sameCoopMatShapeAndUse(typed->getType())))) {
4209
0
        error(loc, "Cooperative matrix type parameters mismatch", constructorString.c_str(), "");
4210
0
        return true;
4211
0
    }
4212
4213
918
    if (typed == nullptr) {
4214
0
        error(loc, "constructor argument does not have a type", constructorString.c_str(), "");
4215
0
        return true;
4216
0
    }
4217
918
    if (op != EOpConstructStruct && op != EOpConstructNonuniform && typed->getBasicType() == EbtSampler) {
4218
0
        if (op == EOpConstructUVec2 && extensionTurnedOn(E_GL_ARB_bindless_texture)) {
4219
0
            intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc);
4220
0
        }
4221
0
        else {
4222
0
            error(loc, "cannot convert a sampler", constructorString.c_str(), "");
4223
0
            return true;
4224
0
        }
4225
0
    }
4226
918
    if (op != EOpConstructStruct && typed->isAtomic()) {
4227
0
        error(loc, "cannot convert an atomic_uint", constructorString.c_str(), "");
4228
0
        return true;
4229
0
    }
4230
918
    if (typed->getBasicType() == EbtVoid) {
4231
0
        error(loc, "cannot convert a void", constructorString.c_str(), "");
4232
0
        return true;
4233
0
    }
4234
4235
918
    return false;
4236
918
}
4237
4238
// Verify all the correct semantics for constructing a combined texture/sampler.
4239
// Return true if the semantics are incorrect.
4240
bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const TFunction& function)
4241
0
{
4242
0
    TString constructorName = function.getType().getBasicTypeString();  // TODO: performance: should not be making copy; interface needs to change
4243
0
    const char* token = constructorName.c_str();
4244
    // verify the constructor for bindless texture, the input must be ivec2 or uvec2
4245
0
    if (function.getParamCount() == 1) {
4246
0
        TType* pType = function[0].type;
4247
0
        TBasicType basicType = pType->getBasicType();
4248
0
        bool isIntegerVec2 = ((basicType == EbtUint || basicType == EbtInt) && pType->getVectorSize() == 2);
4249
0
        bool bindlessMode = extensionTurnedOn(E_GL_ARB_bindless_texture);
4250
0
        if (isIntegerVec2 && bindlessMode) {
4251
0
            if (pType->getSampler().isImage())
4252
0
                intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc);
4253
0
            else
4254
0
                intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc);
4255
0
            return false;
4256
0
        } else {
4257
0
            if (!bindlessMode)
4258
0
                error(loc, "sampler-constructor requires the extension GL_ARB_bindless_texture enabled", token, "");
4259
0
            else
4260
0
                error(loc, "sampler-constructor requires the input to be ivec2 or uvec2", token, "");
4261
0
            return true;
4262
0
        }
4263
0
    }
4264
4265
    // exactly two arguments needed
4266
0
    if (function.getParamCount() != 2) {
4267
0
        error(loc, "sampler-constructor requires two arguments", token, "");
4268
0
        return true;
4269
0
    }
4270
4271
    // For now, not allowing arrayed constructors, the rest of this function
4272
    // is set up to allow them, if this test is removed:
4273
0
    if (function.getType().isArray()) {
4274
0
        error(loc, "sampler-constructor cannot make an array of samplers", token, "");
4275
0
        return true;
4276
0
    }
4277
4278
    // first argument
4279
    //  * the constructor's first argument must be a texture type
4280
    //  * the dimensionality (1D, 2D, 3D, Cube, Rect, Buffer, MS, and Array)
4281
    //    of the texture type must match that of the constructed sampler type
4282
    //    (that is, the suffixes of the type of the first argument and the
4283
    //    type of the constructor will be spelled the same way)
4284
0
    if (function[0].type->getBasicType() != EbtSampler ||
4285
0
        ! function[0].type->getSampler().isTexture() ||
4286
0
        function[0].type->isArray()) {
4287
0
        error(loc, "sampler-constructor first argument must be a scalar *texture* type", token, "");
4288
0
        return true;
4289
0
    }
4290
4291
    // simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=()
4292
0
    TSampler texture = function.getType().getSampler();
4293
0
    texture.setCombined(false);
4294
0
    texture.shadow = false;
4295
0
    if (function[0].type->getSampler().isTileAttachmentQCOM()) {
4296
      //TSampler& texture = const_cast<TFunction&>(function).getWritableType().getSampler();
4297
0
      texture.image = true;
4298
0
      texture.tileQCOM = true;
4299
0
    }
4300
0
    if (texture != function[0].type->getSampler()) {
4301
0
        error(loc, "sampler-constructor first argument must be a *texture* type"
4302
0
                   " matching the dimensionality and sampled type of the constructor", token, "");
4303
0
        return true;
4304
0
    }
4305
4306
    // second argument
4307
    //   * the constructor's second argument must be a scalar of type
4308
    //     *sampler* or *samplerShadow*
4309
0
    if (  function[1].type->getBasicType() != EbtSampler ||
4310
0
        ! function[1].type->getSampler().isPureSampler() ||
4311
0
          function[1].type->isArray()) {
4312
0
        error(loc, "sampler-constructor second argument must be a scalar sampler or samplerShadow", token, "");
4313
0
        return true;
4314
0
    }
4315
4316
0
    return false;
4317
0
}
4318
4319
// Checks to see if a void variable has been declared and raise an error message for such a case
4320
//
4321
// returns true in case of an error
4322
//
4323
bool TParseContext::voidErrorCheck(const TSourceLoc& loc, const TString& identifier, const TBasicType basicType)
4324
125k
{
4325
125k
    if (basicType == EbtVoid) {
4326
1
        error(loc, "illegal use of type 'void'", identifier.c_str(), "");
4327
1
        return true;
4328
1
    }
4329
4330
125k
    return false;
4331
125k
}
4332
4333
// Checks to see if the node (for the expression) contains a scalar boolean expression or not
4334
void TParseContext::boolCheck(const TSourceLoc& loc, const TIntermTyped* type)
4335
1.11k
{
4336
1.11k
    if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
4337
741
        error(loc, "boolean expression expected", "", "");
4338
1.11k
}
4339
4340
// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
4341
void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
4342
0
{
4343
0
    if (pType.basicType != EbtBool || pType.arraySizes || pType.matrixCols > 1 || (pType.vectorSize > 1))
4344
0
        error(loc, "boolean expression expected", "", "");
4345
0
}
4346
4347
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/)
4348
112k
{
4349
    // Check that the appropriate extension is enabled if external sampler is used.
4350
    // There are two extensions. The correct one must be used based on GLSL version.
4351
112k
    if (type.getBasicType() == EbtSampler && type.getSampler().isExternal()) {
4352
0
        if (version < 300) {
4353
0
            requireExtensions(loc, 1, &E_GL_OES_EGL_image_external, "samplerExternalOES");
4354
0
        } else {
4355
0
            requireExtensions(loc, 1, &E_GL_OES_EGL_image_external_essl3, "samplerExternalOES");
4356
0
        }
4357
0
    }
4358
112k
    if (type.getSampler().isYuv()) {
4359
0
        requireExtensions(loc, 1, &E_GL_EXT_YUV_target, "__samplerExternal2DY2YEXT");
4360
0
    }
4361
4362
112k
    if (type.getQualifier().storage == EvqUniform)
4363
3.14k
        return;
4364
4365
109k
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler)) {
4366
        // For bindless texture, sampler can be declared as an struct member
4367
0
        if (extensionTurnedOn(E_GL_ARB_bindless_texture)) {
4368
0
            if (type.getSampler().isImage())
4369
0
                intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar);
4370
0
            else
4371
0
                intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar);
4372
0
        }
4373
0
        else {
4374
0
            error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str());
4375
0
        }
4376
0
    }
4377
109k
    else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) {
4378
        // For bindless texture, sampler can be declared as an input/output/block member
4379
0
        if (extensionTurnedOn(E_GL_ARB_bindless_texture)) {
4380
0
            if (type.getSampler().isImage())
4381
0
                intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar);
4382
0
            else
4383
0
                intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar);
4384
0
        }
4385
0
        else {
4386
            // non-uniform sampler
4387
            // not yet:  okay if it has an initializer
4388
            // if (! initializer)
4389
0
            if (type.getSampler().isAttachmentEXT() && type.getQualifier().storage != EvqTileImageEXT)
4390
0
                 error(loc, "can only be used in tileImageEXT variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
4391
0
            else if (type.getQualifier().storage != EvqTileImageEXT)
4392
0
                 error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
4393
0
        }
4394
0
    }
4395
109k
    else if (type.isTensorARM() && type.getQualifier().storage != EvqUniform) {
4396
0
        error(loc, "tensorARM types can only be used in uniform variables or function parameters:", "tensorARM", identifier.c_str());
4397
0
    }
4398
109k
}
4399
4400
void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
4401
112k
{
4402
112k
    if (type.getQualifier().storage == EvqUniform)
4403
3.14k
        return;
4404
4405
109k
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAtomicUint))
4406
0
        error(loc, "non-uniform struct contains an atomic_uint:", type.getBasicTypeString().c_str(), identifier.c_str());
4407
109k
    else if (type.getBasicType() == EbtAtomicUint && type.getQualifier().storage != EvqUniform)
4408
0
        error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
4409
109k
}
4410
4411
void TParseContext::accStructCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
4412
112k
{
4413
112k
    if (type.getQualifier().storage == EvqUniform)
4414
3.14k
        return;
4415
4416
109k
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAccStruct))
4417
0
        error(loc, "non-uniform struct contains an accelerationStructureNV:", type.getBasicTypeString().c_str(), identifier.c_str());
4418
109k
    else if (type.getBasicType() == EbtAccStruct && type.getQualifier().storage != EvqUniform)
4419
0
        error(loc, "accelerationStructureNV can only be used in uniform variables or function parameters:",
4420
0
            type.getBasicTypeString().c_str(), identifier.c_str());
4421
4422
109k
}
4423
4424
void TParseContext::hitObjectNVCheck(const TSourceLoc & loc, const TType & type, const TString & identifier)
4425
112k
{
4426
112k
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtHitObjectNV)) {
4427
0
        error(loc, "struct is not allowed to contain hitObjectNV:", type.getTypeName().c_str(), identifier.c_str());
4428
112k
    } else if (type.getBasicType() == EbtHitObjectNV) {
4429
0
        TStorageQualifier qualifier = type.getQualifier().storage;
4430
0
        if (qualifier != EvqGlobal && qualifier != EvqTemporary) {
4431
0
            error(loc, "hitObjectNV can only be declared in global or function scope with no storage qualifier:", "hitObjectNV", identifier.c_str());
4432
0
        }
4433
0
    }
4434
112k
}
4435
4436
void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
4437
112k
{
4438
112k
    if (parsingBuiltins)
4439
111k
        return;
4440
4441
1.19k
    if (type.getQualifier().storage != EvqUniform)
4442
1.19k
        return;
4443
4444
0
    if (type.containsNonOpaque()) {
4445
        // Vulkan doesn't allow transparent uniforms outside of blocks
4446
0
        if (spvVersion.vulkan > 0 && !spvVersion.vulkanRelaxed)
4447
0
            vulkanRemoved(loc, "non-opaque uniforms outside a block");
4448
        // OpenGL wants locations on these (unless they are getting automapped)
4449
0
        if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation() && !intermediate.getAutoMapLocations())
4450
0
            error(loc, "non-opaque uniform variables need a layout(location=L)", identifier.c_str(), "");
4451
0
    }
4452
0
}
4453
4454
//
4455
// Qualifier checks knowing the qualifier and that it is a member of a struct/block.
4456
//
4457
void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType)
4458
1.50k
{
4459
1.50k
    globalQualifierFixCheck(publicType.loc, publicType.qualifier, true);
4460
1.50k
    checkNoShaderLayouts(publicType.loc, publicType.shaderQualifiers);
4461
1.50k
    if (publicType.qualifier.isNonUniform()) {
4462
0
        error(publicType.loc, "not allowed on block or structure members", "nonuniformEXT", "");
4463
0
        publicType.qualifier.nonUniform = false;
4464
0
    }
4465
1.50k
    if (publicType.qualifier.isPatch()) {
4466
0
        error(publicType.loc, "not allowed on block or structure members",
4467
0
              "patch", "");
4468
0
    }
4469
1.50k
}
4470
4471
//
4472
// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
4473
//
4474
void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck, const TPublicType* publicType)
4475
282k
{
4476
282k
    bool nonuniformOkay = false;
4477
4478
    // move from parameter/unknown qualifiers to pipeline in/out qualifiers
4479
282k
    switch (qualifier.storage) {
4480
73.6k
    case EvqIn:
4481
73.6k
        profileRequires(loc, ENoProfile, 130, nullptr, "in for stage inputs");
4482
73.6k
        profileRequires(loc, EEsProfile, 300, nullptr, "in for stage inputs");
4483
73.6k
        qualifier.storage = EvqVaryingIn;
4484
73.6k
        nonuniformOkay = true;
4485
73.6k
        break;
4486
8.81k
    case EvqOut:
4487
8.81k
        profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs");
4488
8.81k
        profileRequires(loc, EEsProfile, 300, nullptr, "out for stage outputs");
4489
8.81k
        qualifier.storage = EvqVaryingOut;
4490
8.81k
        if (intermediate.isInvariantAll())
4491
0
            qualifier.invariant = true;
4492
8.81k
        break;
4493
0
    case EvqInOut:
4494
0
        qualifier.storage = EvqVaryingIn;
4495
0
        error(loc, "cannot use 'inout' at global scope", "", "");
4496
0
        break;
4497
159k
    case EvqGlobal:
4498
160k
    case EvqTemporary:
4499
160k
        nonuniformOkay = true;
4500
160k
        break;
4501
3.14k
    case EvqUniform:
4502
        // According to GLSL spec: The std430 qualifier is supported only for shader storage blocks; a shader using
4503
        // the std430 qualifier on a uniform block will fail to compile.
4504
        // Only check the global declaration: layout(std430) uniform;
4505
3.14k
        if (blockName == nullptr &&
4506
3.14k
            qualifier.layoutPacking == ElpStd430)
4507
0
        {
4508
0
            requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "default std430 layout for uniform");
4509
0
        }
4510
4511
3.14k
        if (publicType != nullptr && publicType->isImage() &&
4512
3.14k
            (qualifier.layoutFormat > ElfExtSizeGuard && qualifier.layoutFormat < ElfCount))
4513
0
            qualifier.layoutFormat = mapLegacyLayoutFormat(qualifier.layoutFormat, publicType->sampler.getBasicType());
4514
4515
3.14k
        break;
4516
35.8k
    default:
4517
35.8k
        break;
4518
282k
    }
4519
4520
282k
    if (!nonuniformOkay && qualifier.isNonUniform())
4521
0
        error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", "");
4522
4523
282k
    if (qualifier.isSpirvByReference())
4524
0
        error(loc, "can only apply to parameter", "spirv_by_reference", "");
4525
4526
282k
    if (qualifier.isSpirvLiteral())
4527
0
        error(loc, "can only apply to parameter", "spirv_literal", "");
4528
4529
    // Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it.
4530
282k
    if (!isMemberCheck || structNestingLevel > 0)
4531
281k
        invariantCheck(loc, qualifier);
4532
4533
282k
    if (qualifier.isFullQuads()) {
4534
0
        if (qualifier.storage != EvqVaryingIn)
4535
0
            error(loc, "can only apply to input layout", "full_quads ", "");
4536
0
        intermediate.setReqFullQuadsMode();
4537
0
    }
4538
4539
282k
    if (qualifier.isQuadDeriv()) {
4540
0
        if (qualifier.storage != EvqVaryingIn)
4541
0
            error(loc, "can only apply to input layout", "quad_derivatives", "");
4542
0
        intermediate.setQuadDerivMode();
4543
0
    }
4544
282k
}
4545
4546
//
4547
// Check a full qualifier and type (no variable yet) at global level.
4548
//
4549
void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TPublicType& publicType)
4550
2.45M
{
4551
2.45M
    if (! symbolTable.atGlobalLevel())
4552
454
        return;
4553
4554
2.45M
    if (!(publicType.userDef && publicType.userDef->isReference()) && !publicType.isTensorARM() && !parsingBuiltins) {
4555
27
        if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
4556
0
            error(loc, "memory qualifiers cannot be used on this type", "", "");
4557
27
        } else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
4558
0
            error(loc, "memory qualifiers cannot be used on this type", "", "");
4559
0
        }
4560
27
    }
4561
4562
2.45M
    if (qualifier.storage == EvqBuffer &&
4563
2.45M
        publicType.basicType != EbtBlock &&
4564
2.45M
        !qualifier.hasBufferReference())
4565
0
        error(loc, "buffers can be declared only as blocks", "buffer", "");
4566
4567
2.45M
    if (qualifier.storage != EvqVaryingIn && publicType.basicType == EbtDouble &&
4568
2.45M
        extensionTurnedOn(E_GL_ARB_vertex_attrib_64bit) && language == EShLangVertex &&
4569
2.45M
        version < 400) {
4570
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 410, E_GL_ARB_gpu_shader_fp64, "vertex-shader `double` type");
4571
0
    }
4572
2.45M
    if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
4573
2.37M
        return;
4574
4575
81.0k
    if (publicType.shaderQualifiers.hasBlendEquation())
4576
0
        error(loc, "can only be applied to a standalone 'out'", "blend equation", "");
4577
4578
    // now, knowing it is a shader in/out, do all the in/out semantic checks
4579
4580
81.0k
    if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) {
4581
77.8k
        profileRequires(loc, EEsProfile, 300, nullptr, "non-float shader input/output");
4582
77.8k
        profileRequires(loc, ~EEsProfile, 130, nullptr, "non-float shader input/output");
4583
77.8k
    }
4584
4585
81.0k
    if (!qualifier.flat && !qualifier.isExplicitInterpolation() && !qualifier.isPervertexNV() && !qualifier.isPervertexEXT()) {
4586
79.9k
        if (isTypeInt(publicType.basicType) ||
4587
79.9k
            publicType.basicType == EbtDouble ||
4588
79.9k
            (publicType.userDef && (   publicType.userDef->containsBasicType(EbtInt)
4589
0
                                    || publicType.userDef->containsBasicType(EbtUint)
4590
0
                                    || publicType.userDef->contains16BitInt()
4591
0
                                    || publicType.userDef->contains8BitInt()
4592
0
                                    || publicType.userDef->contains64BitInt()
4593
76.7k
                                    || publicType.userDef->containsDouble()))) {
4594
76.7k
            if (qualifier.storage == EvqVaryingIn && language == EShLangFragment)
4595
0
                error(loc, "must be qualified as flat", TType::getBasicString(publicType.basicType), GetStorageQualifierString(qualifier.storage));
4596
76.7k
            else if (qualifier.storage == EvqVaryingOut && language == EShLangVertex && version == 300)
4597
0
                error(loc, "must be qualified as flat", TType::getBasicString(publicType.basicType), GetStorageQualifierString(qualifier.storage));
4598
76.7k
        }
4599
79.9k
    }
4600
4601
81.0k
    if (qualifier.isPatch() && qualifier.isInterpolation())
4602
0
        error(loc, "cannot use interpolation qualifiers with patch", "patch", "");
4603
4604
    // Only "patch in" is supported via GL_NV_gpu_shader5
4605
81.0k
    if (! symbolTable.atBuiltInLevel() && qualifier.isPatch() && 
4606
81.0k
        (language == EShLangGeometry) && qualifier.storage != EvqVaryingIn &&
4607
81.0k
        extensionTurnedOn(E_GL_NV_gpu_shader5))
4608
0
            error(loc, "only 'patch in' is supported in this stage:", "patch", "geometry");
4609
4610
81.0k
    if (qualifier.isTaskPayload() && publicType.basicType == EbtBlock)
4611
0
        error(loc, "taskPayloadSharedEXT variables should not be declared as interface blocks", "taskPayloadSharedEXT", "");
4612
4613
81.0k
    if (qualifier.isTaskMemory() && publicType.basicType != EbtBlock)
4614
0
        error(loc, "taskNV variables can be declared only as blocks", "taskNV", "");
4615
4616
81.0k
    if (qualifier.storage == EvqVaryingIn) {
4617
73.7k
        switch (language) {
4618
6.96k
        case EShLangVertex:
4619
6.96k
            if (publicType.basicType == EbtStruct) {
4620
0
                error(loc, "cannot be a structure", GetStorageQualifierString(qualifier.storage), "");
4621
0
                return;
4622
0
            }
4623
6.96k
            if (publicType.arraySizes) {
4624
0
                requireProfile(loc, ~EEsProfile, "vertex input arrays");
4625
0
                profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
4626
0
            }
4627
6.96k
            if (publicType.basicType == EbtDouble) {
4628
0
              const char* const float64_attrib[] = {E_GL_NV_gpu_shader5, E_GL_ARB_vertex_attrib_64bit};
4629
0
                const int Num_float64_attrib = sizeof(float64_attrib) / sizeof(float64_attrib[0]);        
4630
0
                profileRequires(loc, ~EEsProfile, 410, Num_float64_attrib, float64_attrib, "vertex-shader `double` type input");
4631
0
      }
4632
6.96k
            if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)
4633
0
                error(loc, "vertex input cannot be further qualified", "", "");
4634
6.96k
            break;
4635
1.49k
        case EShLangFragment:
4636
1.49k
            if (publicType.userDef) {
4637
0
                profileRequires(loc, EEsProfile, 300, nullptr, "fragment-shader struct input");
4638
0
                profileRequires(loc, ~EEsProfile, 150, nullptr, "fragment-shader struct input");
4639
0
                if (publicType.userDef->containsStructure())
4640
0
                    requireProfile(loc, ~EEsProfile, "fragment-shader struct input containing structure");
4641
0
                if (publicType.userDef->containsArray())
4642
0
                    requireProfile(loc, ~EEsProfile, "fragment-shader struct input containing an array");
4643
0
            }
4644
1.49k
            break;
4645
6.36k
       case EShLangCompute:
4646
6.36k
            if (! symbolTable.atBuiltInLevel())
4647
0
                error(loc, "global storage input qualifier cannot be used in a compute shader", "in", "");
4648
6.36k
            break;
4649
5.79k
       case EShLangTessControl:
4650
5.79k
            if (qualifier.patch)
4651
0
                error(loc, "can only use on output in tessellation-control shader", "patch", "");
4652
5.79k
            break;
4653
53.1k
        default:
4654
53.1k
            break;
4655
73.7k
        }
4656
73.7k
    } else {
4657
        // qualifier.storage == EvqVaryingOut
4658
7.25k
        switch (language) {
4659
1.80k
        case EShLangVertex:
4660
1.80k
            if (publicType.userDef) {
4661
0
                profileRequires(loc, EEsProfile, 300, nullptr, "vertex-shader struct output");
4662
0
                profileRequires(loc, ~EEsProfile, 150, nullptr, "vertex-shader struct output");
4663
0
                if (publicType.userDef->containsStructure())
4664
0
                    requireProfile(loc, ~EEsProfile, "vertex-shader struct output containing structure");
4665
0
                if (publicType.userDef->containsArray())
4666
0
                    requireProfile(loc, ~EEsProfile, "vertex-shader struct output containing an array");
4667
0
            }
4668
4669
1.80k
            break;
4670
57
        case EShLangFragment:
4671
57
            profileRequires(loc, EEsProfile, 300, nullptr, "fragment shader output");
4672
57
            if (publicType.basicType == EbtStruct) {
4673
0
                error(loc, "cannot be a structure", GetStorageQualifierString(qualifier.storage), "");
4674
0
                return;
4675
0
            }
4676
57
            if (publicType.matrixRows > 0) {
4677
0
                error(loc, "cannot be a matrix", GetStorageQualifierString(qualifier.storage), "");
4678
0
                return;
4679
0
            }
4680
57
            if (qualifier.isAuxiliary())
4681
0
                error(loc, "can't use auxiliary qualifier on a fragment output", "centroid/sample/patch", "");
4682
57
            if (qualifier.isInterpolation())
4683
0
                error(loc, "can't use interpolation qualifier on a fragment output", "flat/smooth/noperspective", "");
4684
57
            if (publicType.basicType == EbtDouble || publicType.basicType == EbtInt64 || publicType.basicType == EbtUint64)
4685
0
                error(loc, "cannot contain a double, int64, or uint64", GetStorageQualifierString(qualifier.storage), "");
4686
57
        break;
4687
4688
0
        case EShLangCompute:
4689
0
            error(loc, "global storage output qualifier cannot be used in a compute shader", "out", "");
4690
0
            break;
4691
1.43k
        case EShLangTessEvaluation:
4692
1.43k
            if (qualifier.patch)
4693
0
                error(loc, "can only use on input in tessellation-evaluation shader", "patch", "");
4694
1.43k
            break;
4695
3.97k
        default:
4696
3.97k
            break;
4697
7.25k
        }
4698
7.25k
    }
4699
81.0k
}
4700
4701
//
4702
// Merge characteristics of the 'src' qualifier into the 'dst'.
4703
// If there is duplication, issue error messages, unless 'force'
4704
// is specified, which means to just override default settings.
4705
//
4706
// Also, when force is false, it will be assumed that 'src' follows
4707
// 'dst', for the purpose of error checking order for versions
4708
// that require specific orderings of qualifiers.
4709
//
4710
void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, const TQualifier& src, bool force)
4711
1.26M
{
4712
    // Multiple auxiliary qualifiers (mostly done later by 'individual qualifiers')
4713
1.26M
    if (src.isAuxiliary() && dst.isAuxiliary())
4714
0
        error(loc, "can only have one auxiliary qualifier (centroid, patch, and sample)", "", "");
4715
4716
    // Multiple interpolation qualifiers (mostly done later by 'individual qualifiers')
4717
1.26M
    if (src.isInterpolation() && dst.isInterpolation())
4718
0
        error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective, __explicitInterpAMD)", "", "");
4719
4720
    // Ordering
4721
1.26M
    if (! force && ((!isEsProfile() && version < 420) ||
4722
993k
                    (isEsProfile() && version < 310))
4723
1.26M
                && ! extensionTurnedOn(E_GL_ARB_shading_language_420pack)) {
4724
        // non-function parameters
4725
1.66k
        if (src.isNoContraction() && (dst.invariant || dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
4726
0
            error(loc, "precise qualifier must appear first", "", "");
4727
1.66k
        if (src.invariant && (dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
4728
0
            error(loc, "invariant qualifier must appear before interpolation, storage, and precision qualifiers ", "", "");
4729
1.66k
        else if (src.isInterpolation() && (dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
4730
0
            error(loc, "interpolation qualifiers must appear before storage and precision qualifiers", "", "");
4731
1.66k
        else if (src.isAuxiliary() && (dst.storage != EvqTemporary || dst.precision != EpqNone))
4732
0
            error(loc, "Auxiliary qualifiers (centroid, patch, and sample) must appear before storage and precision qualifiers", "", "");
4733
1.66k
        else if (src.storage != EvqTemporary && (dst.precision != EpqNone))
4734
0
            error(loc, "precision qualifier must appear as last qualifier", "", "");
4735
4736
        // function parameters
4737
1.66k
        if (src.isNoContraction() && (dst.storage == EvqConst || dst.storage == EvqIn || dst.storage == EvqOut))
4738
0
            error(loc, "precise qualifier must appear first", "", "");
4739
1.66k
        if (src.storage == EvqConst && (dst.storage == EvqIn || dst.storage == EvqOut))
4740
0
            error(loc, "in/out must appear before const", "", "");
4741
1.66k
    }
4742
4743
    // Storage qualification
4744
1.26M
    if (dst.storage == EvqTemporary || dst.storage == EvqGlobal)
4745
1.17M
        dst.storage = src.storage;
4746
86.7k
    else if ((dst.storage == EvqIn  && src.storage == EvqOut) ||
4747
86.7k
             (dst.storage == EvqOut && src.storage == EvqIn))
4748
0
        dst.storage = EvqInOut;
4749
86.7k
    else if ((dst.storage == EvqIn    && src.storage == EvqConst) ||
4750
86.7k
             (dst.storage == EvqConst && src.storage == EvqIn))
4751
0
        dst.storage = EvqConstReadOnly;
4752
86.7k
    else if (src.storage != EvqTemporary &&
4753
86.7k
             src.storage != EvqGlobal)
4754
0
        error(loc, "too many storage qualifiers", GetStorageQualifierString(src.storage), "");
4755
4756
    // Precision qualifiers
4757
1.26M
    if (! force && src.precision != EpqNone && dst.precision != EpqNone)
4758
0
        error(loc, "only one precision qualifier allowed", GetPrecisionQualifierString(src.precision), "");
4759
1.26M
    if (dst.precision == EpqNone || (force && src.precision != EpqNone))
4760
1.25M
        dst.precision = src.precision;
4761
4762
1.26M
    if (!force && ((src.coherent && (dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) ||
4763
993k
                   (src.devicecoherent && (dst.coherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) ||
4764
993k
                   (src.queuefamilycoherent && (dst.coherent || dst.devicecoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) ||
4765
993k
                   (src.workgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.subgroupcoherent || dst.shadercallcoherent)) ||
4766
993k
                   (src.subgroupcoherent  && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.shadercallcoherent)) ||
4767
993k
                   (src.shadercallcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)))) {
4768
0
        error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent/shadercallcoherent qualifier allowed",
4769
0
            GetPrecisionQualifierString(src.precision), "");
4770
0
    }
4771
4772
    // Layout qualifiers
4773
1.26M
    mergeObjectLayoutQualifiers(dst, src, false);
4774
4775
    // individual qualifiers
4776
1.26M
    bool repeated = false;
4777
32.8M
    #define MERGE_SINGLETON(field) repeated |= dst.field && src.field; dst.field |= src.field;
4778
1.26M
    MERGE_SINGLETON(invariant);
4779
1.26M
    MERGE_SINGLETON(centroid);
4780
1.26M
    MERGE_SINGLETON(smooth);
4781
1.26M
    MERGE_SINGLETON(flat);
4782
1.26M
    MERGE_SINGLETON(specConstant);
4783
1.26M
    MERGE_SINGLETON(noContraction);
4784
1.26M
    MERGE_SINGLETON(nopersp);
4785
1.26M
    MERGE_SINGLETON(explicitInterp);
4786
1.26M
    MERGE_SINGLETON(perPrimitiveNV);
4787
1.26M
    MERGE_SINGLETON(perViewNV);
4788
1.26M
    MERGE_SINGLETON(perTaskNV);
4789
1.26M
    MERGE_SINGLETON(patch);
4790
1.26M
    MERGE_SINGLETON(sample);
4791
1.26M
    MERGE_SINGLETON(coherent);
4792
1.26M
    MERGE_SINGLETON(devicecoherent);
4793
1.26M
    MERGE_SINGLETON(queuefamilycoherent);
4794
1.26M
    MERGE_SINGLETON(workgroupcoherent);
4795
1.26M
    MERGE_SINGLETON(subgroupcoherent);
4796
1.26M
    MERGE_SINGLETON(shadercallcoherent);
4797
1.26M
    MERGE_SINGLETON(nonprivate);
4798
1.26M
    MERGE_SINGLETON(volatil);
4799
1.26M
    MERGE_SINGLETON(nontemporal);
4800
1.26M
    MERGE_SINGLETON(restrict);
4801
1.26M
    MERGE_SINGLETON(readonly);
4802
1.26M
    MERGE_SINGLETON(writeonly);
4803
1.26M
    MERGE_SINGLETON(nonUniform);
4804
4805
    // SPIR-V storage class qualifier (GL_EXT_spirv_intrinsics)
4806
1.26M
    dst.spirvStorageClass = src.spirvStorageClass;
4807
4808
    // SPIR-V decorate qualifiers (GL_EXT_spirv_intrinsics)
4809
1.26M
    if (src.hasSpirvDecorate()) {
4810
0
        if (dst.hasSpirvDecorate()) {
4811
0
            const TSpirvDecorate& srcSpirvDecorate = src.getSpirvDecorate();
4812
0
            TSpirvDecorate& dstSpirvDecorate = dst.getSpirvDecorate();
4813
0
            for (auto& decorate : srcSpirvDecorate.decorates) {
4814
0
                if (dstSpirvDecorate.decorates.find(decorate.first) != dstSpirvDecorate.decorates.end())
4815
0
                    error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate", "(decoration=%u)", decorate.first);
4816
0
                else
4817
0
                    dstSpirvDecorate.decorates.insert(decorate);
4818
0
            }
4819
4820
0
            for (auto& decorateId : srcSpirvDecorate.decorateIds) {
4821
0
                if (dstSpirvDecorate.decorateIds.find(decorateId.first) != dstSpirvDecorate.decorateIds.end())
4822
0
                    error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_id", "(decoration=%u)", decorateId.first);
4823
0
                else
4824
0
                    dstSpirvDecorate.decorateIds.insert(decorateId);
4825
0
            }
4826
4827
0
            for (auto& decorateString : srcSpirvDecorate.decorateStrings) {
4828
0
                if (dstSpirvDecorate.decorates.find(decorateString.first) != dstSpirvDecorate.decorates.end())
4829
0
                    error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_string", "(decoration=%u)", decorateString.first);
4830
0
                else
4831
0
                    dstSpirvDecorate.decorateStrings.insert(decorateString);
4832
0
            }
4833
0
        } else {
4834
0
            dst.spirvDecorate = src.spirvDecorate;
4835
0
        }
4836
0
    }
4837
4838
1.26M
    if (repeated)
4839
0
        error(loc, "replicated qualifiers", "", "");
4840
1.26M
}
4841
4842
void TParseContext::setDefaultPrecision(const TSourceLoc& loc, TPublicType& publicType, TPrecisionQualifier qualifier)
4843
0
{
4844
0
    TBasicType basicType = publicType.basicType;
4845
4846
0
    if (basicType == EbtSampler) {
4847
0
        defaultSamplerPrecision[computeSamplerTypeIndex(publicType.sampler)] = qualifier;
4848
4849
0
        return;  // all is well
4850
0
    }
4851
4852
0
    if (basicType == EbtInt || basicType == EbtFloat) {
4853
0
        if (publicType.isScalar()) {
4854
0
            defaultPrecision[basicType] = qualifier;
4855
0
            if (basicType == EbtInt) {
4856
0
                defaultPrecision[EbtUint] = qualifier;
4857
0
                precisionManager.explicitIntDefaultSeen();
4858
0
            } else
4859
0
                precisionManager.explicitFloatDefaultSeen();
4860
4861
0
            return;  // all is well
4862
0
        }
4863
0
    }
4864
4865
0
    if (basicType == EbtAtomicUint) {
4866
0
        if (qualifier != EpqHigh)
4867
0
            error(loc, "can only apply highp to atomic_uint", "precision", "");
4868
4869
0
        return;
4870
0
    }
4871
4872
0
    error(loc, "cannot apply precision statement to this type; use 'float', 'int' or a sampler type", TType::getBasicString(basicType), "");
4873
0
}
4874
4875
// used to flatten the sampler type space into a single dimension
4876
// correlates with the declaration of defaultSamplerPrecision[]
4877
int TParseContext::computeSamplerTypeIndex(TSampler& sampler)
4878
883k
{
4879
883k
    int arrayIndex    = sampler.arrayed         ? 1 : 0;
4880
883k
    int shadowIndex   = sampler.shadow          ? 1 : 0;
4881
883k
    int externalIndex = sampler.isExternal()    ? 1 : 0;
4882
883k
    int imageIndex    = sampler.isImageClass()  ? 1 : 0;
4883
883k
    int msIndex       = sampler.isMultiSample() ? 1 : 0;
4884
4885
883k
    int flattened = EsdNumDims * (EbtNumTypes * (2 * (2 * (2 * (2 * arrayIndex + msIndex) + imageIndex) + shadowIndex) +
4886
883k
                                                 externalIndex) + sampler.type) + sampler.dim;
4887
883k
    assert(flattened < maxSamplerIndex);
4888
4889
883k
    return flattened;
4890
883k
}
4891
4892
TPrecisionQualifier TParseContext::getDefaultPrecision(TPublicType& publicType)
4893
8.88M
{
4894
8.88M
    if (publicType.basicType == EbtSampler)
4895
877k
        return defaultSamplerPrecision[computeSamplerTypeIndex(publicType.sampler)];
4896
8.00M
    else
4897
8.00M
        return defaultPrecision[publicType.basicType];
4898
8.88M
}
4899
4900
void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType baseType, TQualifier& qualifier, bool hasTypeParameter)
4901
8.87M
{
4902
    // Built-in symbols are allowed some ambiguous precisions, to be pinned down
4903
    // later by context.
4904
8.87M
    if (! obeyPrecisionQualifiers() || parsingBuiltins)
4905
8.87M
        return;
4906
4907
379
    if (baseType == EbtAtomicUint && qualifier.precision != EpqNone && qualifier.precision != EpqHigh)
4908
0
        error(loc, "atomic counters can only be highp", "atomic_uint", "");
4909
4910
379
    if (hasTypeParameter)
4911
0
        return;
4912
4913
379
    if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) {
4914
361
        if (qualifier.precision == EpqNone) {
4915
1
            if (relaxedErrors())
4916
0
                warn(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "substituting 'mediump'");
4917
1
            else
4918
1
                error(loc, "type requires declaration of default precision qualifier", TType::getBasicString(baseType), "");
4919
1
            qualifier.precision = EpqMedium;
4920
1
            defaultPrecision[baseType] = EpqMedium;
4921
1
        }
4922
361
    } else if (qualifier.precision != EpqNone)
4923
0
        error(loc, "type cannot have precision qualifier", TType::getBasicString(baseType), "");
4924
379
}
4925
4926
void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier qualifier, const TType& type)
4927
6.41M
{
4928
6.41M
    if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque() && !intermediate.getBindlessMode())
4929
0
        error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), "");
4930
6.41M
    if (!parsingBuiltins && type.contains16BitFloat())
4931
0
        requireFloat16Arithmetic(loc, type.getBasicTypeString().c_str(), "float16 types can only be in uniform block or buffer storage");
4932
6.41M
    if (!parsingBuiltins && type.contains16BitInt())
4933
0
        requireInt16Arithmetic(loc, type.getBasicTypeString().c_str(), "(u)int16 types can only be in uniform block or buffer storage");
4934
6.41M
    if (!parsingBuiltins && type.contains8BitInt())
4935
0
        requireInt8Arithmetic(loc, type.getBasicTypeString().c_str(), "(u)int8 types can only be in uniform block or buffer storage");
4936
6.41M
}
4937
4938
bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType basicType)
4939
1.54k
{
4940
1.54k
    if (type.getBasicType() == basicType)
4941
0
        return true;
4942
4943
1.54k
    if (type.getBasicType() == EbtStruct) {
4944
376
        const TTypeList& structure = *type.getStruct();
4945
1.54k
        for (unsigned int i = 0; i < structure.size(); ++i) {
4946
1.16k
            if (containsFieldWithBasicType(*structure[i].type, basicType))
4947
0
                return true;
4948
1.16k
        }
4949
376
    }
4950
4951
1.54k
    return false;
4952
1.54k
}
4953
4954
//
4955
// Do size checking for an array type's size.
4956
//
4957
void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair,
4958
                                   const char* sizeType, const bool isTypeParameter)
4959
25.9k
{
4960
25.9k
    bool isConst = false;
4961
25.9k
    sizePair.node = nullptr;
4962
4963
25.9k
    int size = 1;
4964
4965
25.9k
    TIntermConstantUnion* constant = expr->getAsConstantUnion();
4966
25.9k
    if (constant) {
4967
        // handle true (non-specialization) constant
4968
25.9k
        size = constant->getConstArray()[0].getIConst();
4969
25.9k
        isConst = true;
4970
25.9k
    } else {
4971
        // see if it's a specialization constant instead
4972
3
        if (expr->getQualifier().isSpecConstant()) {
4973
0
            isConst = true;
4974
0
            sizePair.node = expr;
4975
0
            TIntermSymbol* symbol = expr->getAsSymbolNode();
4976
0
            if (symbol && symbol->getConstArray().size() > 0)
4977
0
                size = symbol->getConstArray()[0].getIConst();
4978
3
        } else if (expr->getAsUnaryNode() && expr->getAsUnaryNode()->getOp() == glslang::EOpArrayLength &&
4979
3
                   expr->getAsUnaryNode()->getOperand()->getType().isCoopMatNV()) {
4980
0
            isConst = true;
4981
0
            size = 1;
4982
0
            sizePair.node = expr->getAsUnaryNode();
4983
0
        }
4984
3
    }
4985
4986
25.9k
    sizePair.size = size;
4987
4988
25.9k
    if (isTypeParameter) {
4989
1
        if (extensionTurnedOn(E_GL_NV_cooperative_matrix2)) {
4990
0
            if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint && expr->getBasicType() != EbtBool)) {
4991
0
                error(loc, sizeType, "", "must be a constant integer or boolean expression");
4992
0
                return;
4993
0
            }
4994
1
        } else {
4995
1
            if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
4996
1
                error(loc, sizeType, "", "must be a constant integer expression");
4997
1
                return;
4998
1
            }
4999
1
        }
5000
0
        if (size < 0) {
5001
0
            error(loc, sizeType, "", "must be a non-negative integer");
5002
0
            return;
5003
0
        }
5004
25.9k
    } else {
5005
25.9k
        if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
5006
3
            error(loc, sizeType, "", "must be a constant integer expression");
5007
3
            return;
5008
3
        }
5009
25.9k
        if (size <= 0) {
5010
5
            error(loc, sizeType, "", "must be a positive integer");
5011
5
            return;
5012
5
        }
5013
25.9k
    }
5014
25.9k
}
5015
5016
//
5017
// See if this qualifier can be an array.
5018
//
5019
// Returns true if there is an error.
5020
//
5021
bool TParseContext::arrayQualifierError(const TSourceLoc& loc, const TQualifier& qualifier)
5022
4.79k
{
5023
4.79k
    if (qualifier.storage == EvqConst) {
5024
0
        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "const array");
5025
0
        profileRequires(loc, EEsProfile, 300, nullptr, "const array");
5026
0
    }
5027
5028
4.79k
    if (qualifier.storage == EvqVaryingIn && language == EShLangVertex) {
5029
0
        requireProfile(loc, ~EEsProfile, "vertex input arrays");
5030
0
        profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
5031
0
    }
5032
5033
4.79k
    return false;
5034
4.79k
}
5035
5036
//
5037
// See if this qualifier and type combination can be an array.
5038
// Assumes arrayQualifierError() was also called to catch the type-invariant tests.
5039
//
5040
// Returns true if there is an error.
5041
//
5042
bool TParseContext::arrayError(const TSourceLoc& loc, const TType& type)
5043
4.79k
{
5044
4.79k
    if (type.getQualifier().storage == EvqVaryingOut && language == EShLangVertex) {
5045
843
        if (type.isArrayOfArrays())
5046
0
            requireProfile(loc, ~EEsProfile, "vertex-shader array-of-array output");
5047
843
        else if (type.isStruct())
5048
0
            requireProfile(loc, ~EEsProfile, "vertex-shader array-of-struct output");
5049
843
    }
5050
4.79k
    if (type.getQualifier().storage == EvqVaryingIn && language == EShLangFragment) {
5051
85
        if (type.isArrayOfArrays())
5052
0
            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-array input");
5053
85
        else if (type.isStruct())
5054
0
            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-struct input");
5055
85
    }
5056
4.79k
    if (type.getQualifier().storage == EvqVaryingOut && language == EShLangFragment) {
5057
32
        if (type.isArrayOfArrays())
5058
0
            requireProfile(loc, ~EEsProfile, "fragment-shader array-of-array output");
5059
32
    }
5060
5061
4.79k
    return false;
5062
4.79k
}
5063
5064
//
5065
// Require array to be completely sized
5066
//
5067
void TParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes)
5068
143k
{
5069
143k
    if (!parsingBuiltins && arraySizes.hasUnsized())
5070
15
        error(loc, "array size required", "", "");
5071
143k
}
5072
5073
void TParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& type)
5074
771
{
5075
771
    const TTypeList& structure = *type.getStruct();
5076
3.93k
    for (int m = 0; m < (int)structure.size(); ++m) {
5077
3.16k
        const TType& member = *structure[m].type;
5078
3.16k
        if (member.isArray())
5079
0
            arraySizeRequiredCheck(structure[m].loc, *member.getArraySizes());
5080
3.16k
    }
5081
771
}
5082
5083
void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qualifier, TArraySizes* arraySizes,
5084
    const TIntermTyped* initializer, bool lastMember)
5085
11.1k
{
5086
11.1k
    assert(arraySizes);
5087
5088
    // always allow special built-in ins/outs sized to topologies
5089
11.1k
    if (parsingBuiltins)
5090
11.1k
        return;
5091
5092
    // initializer must be a sized array, in which case
5093
    // allow the initializer to set any unknown array sizes
5094
37
    if (initializer != nullptr) {
5095
4
        if (initializer->getType().isUnsizedArray())
5096
0
            error(loc, "array initializer must be sized", "[]", "");
5097
4
        return;
5098
4
    }
5099
5100
    // No environment allows any non-outer-dimension to be implicitly sized
5101
33
    if (arraySizes->isInnerUnsized()) {
5102
5
        error(loc, "only outermost dimension of an array of arrays can be implicitly sized", "[]", "");
5103
5
        arraySizes->clearInnerUnsized();
5104
5
    }
5105
5106
33
    if (arraySizes->isInnerSpecialization() &&
5107
33
        (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal && qualifier.storage != EvqShared && qualifier.storage != EvqConst))
5108
0
        error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", "");
5109
5110
    // desktop always allows outer-dimension-unsized variable arrays,
5111
33
    if (!isEsProfile())
5112
0
        return;
5113
5114
    // for ES, if size isn't coming from an initializer, it has to be explicitly declared now,
5115
    // with very few exceptions
5116
5117
    // implicitly-sized io exceptions:
5118
33
    switch (language) {
5119
0
    case EShLangGeometry:
5120
0
        if (qualifier.storage == EvqVaryingIn)
5121
0
            if ((isEsProfile() && version >= 320) ||
5122
0
                extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader))
5123
0
                return;
5124
0
        break;
5125
0
    case EShLangTessControl:
5126
0
        if ( qualifier.storage == EvqVaryingIn ||
5127
0
            (qualifier.storage == EvqVaryingOut && ! qualifier.isPatch()))
5128
0
            if ((isEsProfile() && version >= 320) ||
5129
0
                extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
5130
0
                return;
5131
0
        break;
5132
0
    case EShLangTessEvaluation:
5133
0
        if ((qualifier.storage == EvqVaryingIn && ! qualifier.isPatch()) ||
5134
0
             qualifier.storage == EvqVaryingOut)
5135
0
            if ((isEsProfile() && version >= 320) ||
5136
0
                extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
5137
0
                return;
5138
0
        break;
5139
0
    case EShLangMesh:
5140
0
        if (qualifier.storage == EvqVaryingOut)
5141
0
            if ((isEsProfile() && version >= 320) ||
5142
0
                extensionsTurnedOn(Num_AEP_mesh_shader, AEP_mesh_shader))
5143
0
                return;
5144
0
        break;
5145
33
    default:
5146
33
        break;
5147
33
    }
5148
5149
    // last member of ssbo block exception:
5150
33
    if (qualifier.storage == EvqBuffer && lastMember)
5151
0
        return;
5152
5153
33
    arraySizeRequiredCheck(loc, *arraySizes);
5154
33
}
5155
5156
void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc, const TArraySizes* sizes)
5157
276k
{
5158
276k
    if (sizes == nullptr || sizes->getNumDims() == 1)
5159
274k
        return;
5160
5161
1.27k
    const char* feature = "arrays of arrays";
5162
5163
1.27k
    requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
5164
1.27k
    profileRequires(loc, EEsProfile, 310, nullptr, feature);
5165
1.27k
    profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature);
5166
1.27k
}
5167
5168
//
5169
// Do all the semantic checking for declaring or redeclaring an array, with and
5170
// without a size, and make the right changes to the symbol table.
5171
//
5172
void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifier, const TType& type, TSymbol*& symbol)
5173
4.79k
{
5174
4.79k
    if (symbol == nullptr) {
5175
4.79k
        bool currentScope;
5176
4.79k
        symbol = symbolTable.find(identifier, nullptr, &currentScope);
5177
5178
4.79k
        if (symbol && builtInName(identifier) && ! symbolTable.atBuiltInLevel()) {
5179
            // bad shader (errors already reported) trying to redeclare a built-in name as an array
5180
0
            symbol = nullptr;
5181
0
            return;
5182
0
        }
5183
4.79k
        if (symbol == nullptr || ! currentScope) {
5184
            //
5185
            // Successfully process a new definition.
5186
            // (Redeclarations have to take place at the same scope; otherwise they are hiding declarations)
5187
            //
5188
4.78k
            symbol = new TVariable(&identifier, type);
5189
4.78k
            symbolTable.insert(*symbol);
5190
4.78k
            if (symbolTable.atGlobalLevel())
5191
4.75k
                trackLinkage(*symbol);
5192
5193
4.78k
            if (! symbolTable.atBuiltInLevel()) {
5194
31
                if (isIoResizeArray(type)) {
5195
0
                    ioArraySymbolResizeList.push_back(symbol);
5196
0
                    checkIoArraysConsistency(loc, true);
5197
0
                } else
5198
31
                    fixIoArraySize(loc, symbol->getWritableType());
5199
31
            }
5200
5201
4.78k
            return;
5202
4.78k
        }
5203
6
        if (symbol->getAsAnonMember()) {
5204
0
            error(loc, "cannot redeclare a user-block member array", identifier.c_str(), "");
5205
0
            symbol = nullptr;
5206
0
            return;
5207
0
        }
5208
6
    }
5209
5210
    //
5211
    // Process a redeclaration.
5212
    //
5213
5214
6
    if (symbol == nullptr) {
5215
0
        error(loc, "array variable name expected", identifier.c_str(), "");
5216
0
        return;
5217
0
    }
5218
5219
    // redeclareBuiltinVariable() should have already done the copyUp()
5220
6
    TType& existingType = symbol->getWritableType();
5221
5222
6
    if (! existingType.isArray()) {
5223
0
        error(loc, "redeclaring non-array as array", identifier.c_str(), "");
5224
0
        return;
5225
0
    }
5226
5227
6
    if (! existingType.sameElementType(type)) {
5228
0
        error(loc, "redeclaration of array with a different element type", identifier.c_str(), "");
5229
0
        return;
5230
0
    }
5231
5232
6
    if (! existingType.sameInnerArrayness(type)) {
5233
0
        error(loc, "redeclaration of array with a different array dimensions or sizes", identifier.c_str(), "");
5234
0
        return;
5235
0
    }
5236
5237
6
    if (existingType.isSizedArray()) {
5238
        // be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
5239
1
        if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize()))
5240
1
            error(loc, "redeclaration of array with size", identifier.c_str(), "");
5241
1
        return;
5242
1
    }
5243
5244
5
    arrayLimitCheck(loc, identifier, type.getOuterArraySize());
5245
5246
5
    existingType.updateArraySizes(type);
5247
5248
5
    if (isIoResizeArray(type))
5249
0
        checkIoArraysConsistency(loc);
5250
5
}
5251
5252
// Policy and error check for needing a runtime sized array.
5253
void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermTyped& base)
5254
0
{
5255
    // runtime length implies runtime sizeable, so no problem
5256
0
    if (isRuntimeLength(base))
5257
0
        return;
5258
5259
0
    if (base.getType().getQualifier().builtIn == EbvSampleMask)
5260
0
        return;
5261
5262
    // Check for last member of a bufferreference type, which is runtime sizeable
5263
    // but doesn't support runtime length
5264
0
    if (base.getType().getQualifier().storage == EvqBuffer) {
5265
0
        const TIntermBinary* binary = base.getAsBinaryNode();
5266
0
        if (binary != nullptr &&
5267
0
            binary->getOp() == EOpIndexDirectStruct &&
5268
0
            binary->getLeft()->isReference()) {
5269
5270
0
            const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
5271
0
            const int memberCount = (int)binary->getLeft()->getType().getReferentType()->getStruct()->size();
5272
0
            if (index == memberCount - 1)
5273
0
                return;
5274
0
        }
5275
0
    }
5276
5277
    // check for additional things allowed by GL_EXT_nonuniform_qualifier
5278
0
    if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStruct || base.getBasicType() == EbtRayQuery ||
5279
0
        base.getBasicType() == EbtHitObjectNV || (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer()))
5280
0
        requireExtensions(loc, 1, &E_GL_EXT_nonuniform_qualifier, "variable index");
5281
0
    else
5282
0
        error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
5283
0
}
5284
5285
// Policy decision for whether a run-time .length() is allowed.
5286
bool TParseContext::isRuntimeLength(const TIntermTyped& base) const
5287
0
{
5288
0
    if (base.getType().getQualifier().storage == EvqBuffer) {
5289
        // in a buffer block
5290
0
        const TIntermBinary* binary = base.getAsBinaryNode();
5291
0
        if (binary != nullptr && binary->getOp() == EOpIndexDirectStruct) {
5292
            // is it the last member?
5293
0
            const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
5294
5295
0
            if (binary->getLeft()->isReference())
5296
0
                return false;
5297
5298
0
            const int memberCount = (int)binary->getLeft()->getType().getStruct()->size();
5299
0
            if (index == memberCount - 1)
5300
0
                return true;
5301
0
        }
5302
0
    }
5303
5304
0
    return false;
5305
0
}
5306
5307
// Check if mesh perviewNV attributes have a view dimension
5308
// and resize it to gl_MaxMeshViewCountNV when implicitly sized.
5309
void TParseContext::checkAndResizeMeshViewDim(const TSourceLoc& loc, TType& type, bool isBlockMember)
5310
115k
{
5311
    // see if member is a per-view attribute
5312
115k
    if (!type.getQualifier().isPerView())
5313
114k
        return;
5314
5315
1.02k
    if ((isBlockMember && type.isArray()) || (!isBlockMember && type.isArrayOfArrays())) {
5316
        // since we don't have the maxMeshViewCountNV set during parsing builtins, we hardcode the value.
5317
1.02k
        int maxViewCount = parsingBuiltins ? 4 : resources.maxMeshViewCountNV;
5318
        // For block members, outermost array dimension is the view dimension.
5319
        // For non-block members, outermost array dimension is the vertex/primitive dimension
5320
        // and 2nd outermost is the view dimension.
5321
1.02k
        int viewDim = isBlockMember ? 0 : 1;
5322
1.02k
        int viewDimSize = type.getArraySizes()->getDimSize(viewDim);
5323
5324
1.02k
        if (viewDimSize != UnsizedArraySize && viewDimSize != maxViewCount)
5325
0
            error(loc, "mesh view output array size must be gl_MaxMeshViewCountNV or implicitly sized", "[]", "");
5326
1.02k
        else if (viewDimSize == UnsizedArraySize)
5327
1.02k
            type.getArraySizes()->setDimSize(viewDim, maxViewCount);
5328
1.02k
    }
5329
0
    else {
5330
0
        error(loc, "requires a view array dimension", "perviewNV", "");
5331
0
    }
5332
1.02k
}
5333
5334
// Returns true if the first argument to the #line directive is the line number for the next line.
5335
//
5336
// Desktop, pre-version 3.30:  "After processing this directive
5337
// (including its new-line), the implementation will behave as if it is compiling at line number line+1 and
5338
// source string number source-string-number."
5339
//
5340
// Desktop, version 3.30 and later, and ES:  "After processing this directive
5341
// (including its new-line), the implementation will behave as if it is compiling at line number line and
5342
// source string number source-string-number.
5343
bool TParseContext::lineDirectiveShouldSetNextLine() const
5344
2
{
5345
2
    return isEsProfile() || version >= 330;
5346
2
}
5347
5348
//
5349
// Enforce non-initializer type/qualifier rules.
5350
//
5351
void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier, TType& type)
5352
86.3k
{
5353
    //
5354
    // Make the qualifier make sense, given that there is not an initializer.
5355
    //
5356
86.3k
    if (type.getQualifier().storage == EvqConst ||
5357
86.3k
        type.getQualifier().storage == EvqConstReadOnly) {
5358
0
        type.getQualifier().makeTemporary();
5359
0
        error(loc, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
5360
0
    }
5361
86.3k
}
5362
5363
//
5364
// See if the identifier is a built-in symbol that can be redeclared, and if so,
5365
// copy the symbol table's read-only built-in variable to the current
5366
// global level, where it can be modified based on the passed in type.
5367
//
5368
// Returns nullptr if no redeclaration took place; meaning a normal declaration still
5369
// needs to occur for it, not necessarily an error.
5370
//
5371
// Returns a redeclared and type-modified variable if a redeclarated occurred.
5372
//
5373
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier,
5374
                                                 const TQualifier& qualifier, const TShaderQualifiers& publicType)
5375
112k
{
5376
112k
    if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel())
5377
112k
        return nullptr;
5378
5379
0
    bool nonEsRedecls = (!isEsProfile() && (version >= 130 || identifier == "gl_TexCoord"));
5380
0
    bool    esRedecls = (isEsProfile() &&
5381
0
                         (version >= 320 || extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks)));
5382
0
    if (! esRedecls && ! nonEsRedecls)
5383
0
        return nullptr;
5384
5385
    // Special case when using GL_ARB_separate_shader_objects
5386
0
    bool ssoPre150 = false;  // means the only reason this variable is redeclared is due to this combination
5387
0
    if (!isEsProfile() && version <= 140 && extensionTurnedOn(E_GL_ARB_separate_shader_objects)) {
5388
0
        if (identifier == "gl_Position"     ||
5389
0
            identifier == "gl_PointSize"    ||
5390
0
            identifier == "gl_ClipVertex"   ||
5391
0
            identifier == "gl_FogFragCoord")
5392
0
            ssoPre150 = true;
5393
0
    }
5394
5395
    // Potentially redeclaring a built-in variable...
5396
5397
0
    if (ssoPre150 ||
5398
0
        (identifier == "gl_FragDepth"           && ((nonEsRedecls && version >= 420) || esRedecls)) ||
5399
0
        (identifier == "gl_FragCoord"           && ((nonEsRedecls && version >= 140) || esRedecls)) ||
5400
0
         identifier == "gl_ClipDistance"                                                            ||
5401
0
         identifier == "gl_CullDistance"                                                            ||
5402
0
         identifier == "gl_ShadingRateEXT"                                                          ||
5403
0
         identifier == "gl_PrimitiveShadingRateEXT"                                                 ||
5404
0
         identifier == "gl_FrontColor"                                                              ||
5405
0
         identifier == "gl_BackColor"                                                               ||
5406
0
         identifier == "gl_FrontSecondaryColor"                                                     ||
5407
0
         identifier == "gl_BackSecondaryColor"                                                      ||
5408
0
         identifier == "gl_SecondaryColor"                                                          ||
5409
0
        (identifier == "gl_Color"               && language == EShLangFragment)                     ||
5410
0
        (identifier == "gl_FragStencilRefARB"   && (nonEsRedecls && version >= 140)
5411
0
                                                && language == EShLangFragment)                     ||
5412
0
         identifier == "gl_SampleMask"                                                              ||
5413
0
         identifier == "gl_Layer"                                                                   ||
5414
0
         identifier == "gl_PrimitiveIndicesNV"                                                      ||
5415
0
         identifier == "gl_PrimitivePointIndicesEXT"                                                ||
5416
0
         identifier == "gl_PrimitiveLineIndicesEXT"                                                 ||
5417
0
         identifier == "gl_PrimitiveTriangleIndicesEXT"                                             ||
5418
0
         identifier == "gl_TexCoord") {
5419
5420
        // Find the existing symbol, if any.
5421
0
        bool builtIn;
5422
0
        TSymbol* symbol = symbolTable.find(identifier, &builtIn);
5423
5424
        // If the symbol was not found, this must be a version/profile/stage
5425
        // that doesn't have it.
5426
0
        if (! symbol)
5427
0
            return nullptr;
5428
5429
        // If it wasn't at a built-in level, then it's already been redeclared;
5430
        // that is, this is a redeclaration of a redeclaration; reuse that initial
5431
        // redeclaration.  Otherwise, make the new one.
5432
0
        if (builtIn) {
5433
0
            makeEditable(symbol);
5434
0
            symbolTable.amendSymbolIdLevel(*symbol);
5435
0
        }
5436
5437
        // Now, modify the type of the copy, as per the type of the current redeclaration.
5438
5439
0
        TQualifier& symbolQualifier = symbol->getWritableType().getQualifier();
5440
0
        if (ssoPre150) {
5441
0
            if (intermediate.inIoAccessed(identifier))
5442
0
                error(loc, "cannot redeclare after use", identifier.c_str(), "");
5443
0
            if (qualifier.hasLayout())
5444
0
                error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
5445
0
            if (qualifier.isMemory() || qualifier.isAuxiliary() || (language == EShLangVertex   && qualifier.storage != EvqVaryingOut) ||
5446
0
                                                                   (language == EShLangFragment && qualifier.storage != EvqVaryingIn))
5447
0
                error(loc, "cannot change storage, memory, or auxiliary qualification of", "redeclaration", symbol->getName().c_str());
5448
0
            if (! qualifier.smooth)
5449
0
                error(loc, "cannot change interpolation qualification of", "redeclaration", symbol->getName().c_str());
5450
0
        } else if (identifier == "gl_FrontColor"          ||
5451
0
                   identifier == "gl_BackColor"           ||
5452
0
                   identifier == "gl_FrontSecondaryColor" ||
5453
0
                   identifier == "gl_BackSecondaryColor"  ||
5454
0
                   identifier == "gl_SecondaryColor"      ||
5455
0
                   identifier == "gl_Color") {
5456
0
            symbolQualifier.flat = qualifier.flat;
5457
0
            symbolQualifier.smooth = qualifier.smooth;
5458
0
            symbolQualifier.nopersp = qualifier.nopersp;
5459
0
            if (qualifier.hasLayout())
5460
0
                error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
5461
0
            if (qualifier.isMemory() || qualifier.isAuxiliary() || symbol->getType().getQualifier().storage != qualifier.storage)
5462
0
                error(loc, "cannot change storage, memory, or auxiliary qualification of", "redeclaration", symbol->getName().c_str());
5463
0
        } else if (identifier == "gl_TexCoord"     ||
5464
0
                   identifier == "gl_ClipDistance" ||
5465
0
                   identifier == "gl_CullDistance") {
5466
0
            if (qualifier.hasLayout() || qualifier.isMemory() || qualifier.isAuxiliary() ||
5467
0
                qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
5468
0
                symbolQualifier.storage != qualifier.storage)
5469
0
                error(loc, "cannot change qualification of", "redeclaration", symbol->getName().c_str());
5470
0
        } else if (identifier == "gl_FragCoord") {
5471
0
            if (!intermediate.getTexCoordRedeclared() && intermediate.inIoAccessed("gl_FragCoord"))
5472
0
                error(loc, "cannot redeclare after use", "gl_FragCoord", "");
5473
0
            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
5474
0
                qualifier.isMemory() || qualifier.isAuxiliary())
5475
0
                error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
5476
0
            if (qualifier.storage != EvqVaryingIn)
5477
0
                error(loc, "cannot change input storage qualification of", "redeclaration", symbol->getName().c_str());
5478
0
            if (! builtIn && (publicType.pixelCenterInteger != intermediate.getPixelCenterInteger() ||
5479
0
                              publicType.originUpperLeft != intermediate.getOriginUpperLeft()))
5480
0
                error(loc, "cannot redeclare with different qualification:", "redeclaration", symbol->getName().c_str());
5481
5482
5483
0
            intermediate.setTexCoordRedeclared();
5484
0
            if (publicType.pixelCenterInteger)
5485
0
                intermediate.setPixelCenterInteger();
5486
0
            if (publicType.originUpperLeft)
5487
0
                intermediate.setOriginUpperLeft();
5488
0
        } else if (identifier == "gl_FragDepth") {
5489
0
            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
5490
0
                qualifier.isMemory() || qualifier.isAuxiliary())
5491
0
                error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
5492
0
            if (qualifier.storage != EvqVaryingOut)
5493
0
                error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
5494
0
            if (publicType.layoutDepth != EldNone) {
5495
0
                if (intermediate.inIoAccessed("gl_FragDepth"))
5496
0
                    error(loc, "cannot redeclare after use", "gl_FragDepth", "");
5497
0
                if (! intermediate.setDepth(publicType.layoutDepth))
5498
0
                    error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str());
5499
0
            }
5500
0
        } else if (identifier == "gl_FragStencilRefARB") {
5501
0
            if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat ||
5502
0
                qualifier.isMemory() || qualifier.isAuxiliary())
5503
0
                error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str());
5504
0
            if (qualifier.storage != EvqVaryingOut)
5505
0
                error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
5506
0
            if (publicType.layoutStencil != ElsNone) {
5507
0
                if (intermediate.inIoAccessed("gl_FragStencilRefARB"))
5508
0
                    error(loc, "cannot redeclare after use", "gl_FragStencilRefARB", "");
5509
0
                if (!intermediate.setStencil(publicType.layoutStencil))
5510
0
                    error(loc, "all redeclarations must use the same stencil layout on", "redeclaration",
5511
0
                          symbol->getName().c_str());
5512
0
            }
5513
0
        }
5514
0
        else if (
5515
0
            identifier == "gl_PrimitiveIndicesNV") {
5516
0
            if (qualifier.hasLayout())
5517
0
                error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
5518
0
            if (qualifier.storage != EvqVaryingOut)
5519
0
                error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
5520
0
        }
5521
0
        else if (identifier == "gl_SampleMask") {
5522
0
            if (!publicType.layoutOverrideCoverage) {
5523
0
                error(loc, "redeclaration only allowed for override_coverage layout", "redeclaration", symbol->getName().c_str());
5524
0
            }
5525
0
            intermediate.setLayoutOverrideCoverage();
5526
0
        }
5527
0
        else if (identifier == "gl_Layer") {
5528
0
            if (!qualifier.layoutViewportRelative && qualifier.layoutSecondaryViewportRelativeOffset == -2048)
5529
0
                error(loc, "redeclaration only allowed for viewport_relative or secondary_view_offset layout", "redeclaration", symbol->getName().c_str());
5530
0
            symbolQualifier.layoutViewportRelative = qualifier.layoutViewportRelative;
5531
0
            symbolQualifier.layoutSecondaryViewportRelativeOffset = qualifier.layoutSecondaryViewportRelativeOffset;
5532
0
        }
5533
5534
        // TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
5535
5536
0
        return symbol;
5537
0
    }
5538
5539
0
    return nullptr;
5540
0
}
5541
5542
//
5543
// Either redeclare the requested block, or give an error message why it can't be done.
5544
//
5545
// TODO: functionality: explicitly sizing members of redeclared blocks is not giving them an explicit size
5546
void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName,
5547
    const TString* instanceName, TArraySizes* arraySizes)
5548
0
{
5549
0
    const char* feature = "built-in block redeclaration";
5550
0
    profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
5551
0
    profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
5552
5553
0
    if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment" &&
5554
0
        blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV" &&
5555
0
        blockName != "gl_MeshPerVertexEXT" && blockName != "gl_MeshPerPrimitiveEXT") {
5556
0
        error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str());
5557
0
        return;
5558
0
    }
5559
5560
    // Redeclaring a built-in block...
5561
5562
0
    if (instanceName && ! builtInName(*instanceName)) {
5563
0
        error(loc, "cannot redeclare a built-in block with a user name", instanceName->c_str(), "");
5564
0
        return;
5565
0
    }
5566
5567
    // Blocks with instance names are easy to find, lookup the instance name,
5568
    // Anonymous blocks need to be found via a member.
5569
0
    bool builtIn;
5570
0
    TSymbol* block;
5571
0
    if (instanceName)
5572
0
        block = symbolTable.find(*instanceName, &builtIn);
5573
0
    else
5574
0
        block = symbolTable.find(newTypeList.front().type->getFieldName(), &builtIn);
5575
5576
    // If the block was not found, this must be a version/profile/stage
5577
    // that doesn't have it, or the instance name is wrong.
5578
0
    const char* errorName = instanceName ? instanceName->c_str() : newTypeList.front().type->getFieldName().c_str();
5579
0
    if (! block) {
5580
0
        error(loc, "no declaration found for redeclaration", errorName, "");
5581
0
        return;
5582
0
    }
5583
    // Built-in blocks cannot be redeclared more than once, which if happened,
5584
    // we'd be finding the already redeclared one here, rather than the built in.
5585
0
    if (! builtIn) {
5586
0
        error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), "");
5587
0
        return;
5588
0
    }
5589
5590
    // Copy the block to make a writable version, to insert into the block table after editing.
5591
0
    block = symbolTable.copyUpDeferredInsert(block);
5592
5593
0
    if (block->getType().getBasicType() != EbtBlock) {
5594
0
        error(loc, "cannot redeclare a non block as a block", errorName, "");
5595
0
        return;
5596
0
    }
5597
5598
    // Fix XFB stuff up, it applies to the order of the redeclaration, not
5599
    // the order of the original members.
5600
0
    if (currentBlockQualifier.storage == EvqVaryingOut && globalOutputDefaults.hasXfbBuffer()) {
5601
0
        if (!currentBlockQualifier.hasXfbBuffer())
5602
0
            currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
5603
0
        if (!currentBlockQualifier.hasStream())
5604
0
            currentBlockQualifier.layoutStream = globalOutputDefaults.layoutStream;
5605
0
        fixXfbOffsets(currentBlockQualifier, newTypeList);
5606
0
    }
5607
5608
    // Edit and error check the container against the redeclaration
5609
    //  - remove unused members
5610
    //  - ensure remaining qualifiers/types match
5611
5612
0
    TType& type = block->getWritableType();
5613
5614
    // if gl_PerVertex is redeclared for the purpose of passing through "gl_Position"
5615
    // for passthrough purpose, the redeclared block should have the same qualifers as
5616
    // the current one
5617
0
    if (currentBlockQualifier.layoutPassthrough) {
5618
0
        type.getQualifier().layoutPassthrough = currentBlockQualifier.layoutPassthrough;
5619
0
        type.getQualifier().storage = currentBlockQualifier.storage;
5620
0
        type.getQualifier().layoutStream = currentBlockQualifier.layoutStream;
5621
0
        type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
5622
0
    }
5623
5624
0
    TTypeList::iterator member = type.getWritableStruct()->begin();
5625
0
    size_t numOriginalMembersFound = 0;
5626
0
    while (member != type.getStruct()->end()) {
5627
        // look for match
5628
0
        bool found = false;
5629
0
        TTypeList::const_iterator newMember;
5630
0
        TSourceLoc memberLoc;
5631
0
        memberLoc.init();
5632
0
        for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) {
5633
0
            if (member->type->getFieldName() == newMember->type->getFieldName()) {
5634
0
                found = true;
5635
0
                memberLoc = newMember->loc;
5636
0
                break;
5637
0
            }
5638
0
        }
5639
5640
0
        if (found) {
5641
0
            ++numOriginalMembersFound;
5642
            // - ensure match between redeclared members' types
5643
            // - check for things that can't be changed
5644
            // - update things that can be changed
5645
0
            TType& oldType = *member->type;
5646
0
            const TType& newType = *newMember->type;
5647
0
            if (! newType.sameElementType(oldType))
5648
0
                error(memberLoc, "cannot redeclare block member with a different type", member->type->getFieldName().c_str(), "");
5649
0
            if (oldType.isArray() != newType.isArray())
5650
0
                error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), "");
5651
0
            else if (! oldType.getQualifier().isPerView() && ! oldType.sameArrayness(newType) && oldType.isSizedArray())
5652
0
                error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), "");
5653
0
            else if (! oldType.getQualifier().isPerView() && newType.isArray())
5654
0
                arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize());
5655
0
            if (oldType.getQualifier().isPerView() && ! newType.getQualifier().isPerView())
5656
0
                error(memberLoc, "missing perviewNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
5657
0
            else if (! oldType.getQualifier().isPerView() && newType.getQualifier().isPerView())
5658
0
                error(memberLoc, "cannot add perviewNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
5659
0
            else if (newType.getQualifier().isPerView()) {
5660
0
                if (oldType.getArraySizes()->getNumDims() != newType.getArraySizes()->getNumDims())
5661
0
                    error(memberLoc, "cannot change arrayness of redeclared block member", member->type->getFieldName().c_str(), "");
5662
0
                else if (! newType.isUnsizedArray() && newType.getOuterArraySize() != resources.maxMeshViewCountNV)
5663
0
                    error(loc, "mesh view output array size must be gl_MaxMeshViewCountNV or implicitly sized", "[]", "");
5664
0
                else if (newType.getArraySizes()->getNumDims() == 2) {
5665
0
                    int innerDimSize = newType.getArraySizes()->getDimSize(1);
5666
0
                    arrayLimitCheck(memberLoc, member->type->getFieldName(), innerDimSize);
5667
0
                    oldType.getArraySizes()->setDimSize(1, innerDimSize);
5668
0
                }
5669
0
            }
5670
0
            if (oldType.getQualifier().isPerPrimitive() && ! newType.getQualifier().isPerPrimitive())
5671
0
                error(memberLoc, "missing perprimitiveNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
5672
0
            else if (! oldType.getQualifier().isPerPrimitive() && newType.getQualifier().isPerPrimitive())
5673
0
                error(memberLoc, "cannot add perprimitiveNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
5674
0
            if (newType.getQualifier().isMemory())
5675
0
                error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
5676
0
            if (newType.getQualifier().hasNonXfbLayout())
5677
0
                error(memberLoc, "cannot add non-XFB layout to redeclared block member", member->type->getFieldName().c_str(), "");
5678
0
            if (newType.getQualifier().patch)
5679
0
                error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), "");
5680
0
            if (newType.getQualifier().hasXfbBuffer() &&
5681
0
                newType.getQualifier().layoutXfbBuffer != currentBlockQualifier.layoutXfbBuffer)
5682
0
                error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", "");
5683
0
            if (newType.getQualifier().hasStream() &&
5684
0
                newType.getQualifier().layoutStream != currentBlockQualifier.layoutStream)
5685
0
                error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_stream", "");
5686
0
            oldType.getQualifier().centroid = newType.getQualifier().centroid;
5687
0
            oldType.getQualifier().sample = newType.getQualifier().sample;
5688
0
            oldType.getQualifier().invariant = newType.getQualifier().invariant;
5689
0
            oldType.getQualifier().noContraction = newType.getQualifier().noContraction;
5690
0
            oldType.getQualifier().smooth = newType.getQualifier().smooth;
5691
0
            oldType.getQualifier().flat = newType.getQualifier().flat;
5692
0
            oldType.getQualifier().nopersp = newType.getQualifier().nopersp;
5693
0
            oldType.getQualifier().layoutXfbOffset = newType.getQualifier().layoutXfbOffset;
5694
0
            oldType.getQualifier().layoutXfbBuffer = newType.getQualifier().layoutXfbBuffer;
5695
0
            oldType.getQualifier().layoutXfbStride = newType.getQualifier().layoutXfbStride;
5696
0
            if (oldType.getQualifier().layoutXfbOffset != TQualifier::layoutXfbBufferEnd) {
5697
                // If any member has an xfb_offset, then the block's xfb_buffer inherents current xfb_buffer,
5698
                // and for xfb processing, the member needs it as well, along with xfb_stride.
5699
0
                type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
5700
0
                oldType.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
5701
0
            }
5702
0
            if (oldType.isUnsizedArray() && newType.isSizedArray())
5703
0
                oldType.changeOuterArraySize(newType.getOuterArraySize());
5704
5705
            //  check and process the member's type, which will include managing xfb information
5706
0
            layoutTypeCheck(loc, oldType);
5707
5708
            // go to next member
5709
0
            ++member;
5710
0
        } else {
5711
            // For missing members of anonymous blocks that have been redeclared,
5712
            // hide the original (shared) declaration.
5713
            // Instance-named blocks can just have the member removed.
5714
0
            if (instanceName)
5715
0
                member = type.getWritableStruct()->erase(member);
5716
0
            else {
5717
0
                member->type->hideMember();
5718
0
                ++member;
5719
0
            }
5720
0
        }
5721
0
    }
5722
5723
0
    if (spvVersion.vulkan > 0) {
5724
        // ...then streams apply to built-in blocks, instead of them being only on stream 0
5725
0
        type.getQualifier().layoutStream = currentBlockQualifier.layoutStream;
5726
0
    }
5727
5728
0
    if (numOriginalMembersFound < newTypeList.size())
5729
0
        error(loc, "block redeclaration has extra members", blockName.c_str(), "");
5730
0
    if (type.isArray() != (arraySizes != nullptr) ||
5731
0
        (type.isArray() && arraySizes != nullptr && type.getArraySizes()->getNumDims() != arraySizes->getNumDims()))
5732
0
        error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), "");
5733
0
    else if (type.isArray()) {
5734
        // At this point, we know both are arrays and both have the same number of dimensions.
5735
5736
        // It is okay for a built-in block redeclaration to be unsized, and keep the size of the
5737
        // original block declaration.
5738
0
        if (!arraySizes->isSized() && type.isSizedArray())
5739
0
            arraySizes->changeOuterSize(type.getOuterArraySize());
5740
5741
        // And, okay to be giving a size to the array, by the redeclaration
5742
0
        if (!type.isSizedArray() && arraySizes->isSized())
5743
0
            type.changeOuterArraySize(arraySizes->getOuterSize());
5744
5745
        // Now, they must match in all dimensions.
5746
0
        if (type.isSizedArray() && *type.getArraySizes() != *arraySizes)
5747
0
            error(loc, "cannot change array size of redeclared block", blockName.c_str(), "");
5748
0
    }
5749
5750
0
    symbolTable.insert(*block);
5751
5752
    // Check for general layout qualifier errors
5753
0
    layoutObjectCheck(loc, *block);
5754
5755
    // Tracking for implicit sizing of array
5756
0
    if (isIoResizeArray(block->getType())) {
5757
0
        ioArraySymbolResizeList.push_back(block);
5758
0
        checkIoArraysConsistency(loc, true);
5759
0
    } else if (block->getType().isArray())
5760
0
        fixIoArraySize(loc, block->getWritableType());
5761
5762
    // Save it in the AST for linker use.
5763
0
    trackLinkage(*block);
5764
0
}
5765
5766
void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
5767
6.41M
{
5768
6.41M
    switch (qualifier) {
5769
0
    case EvqConst:
5770
0
    case EvqConstReadOnly:
5771
0
        type.getQualifier().storage = EvqConstReadOnly;
5772
0
        break;
5773
2.26k
    case EvqIn:
5774
252k
    case EvqOut:
5775
273k
    case EvqInOut:
5776
273k
    case EvqTileImageEXT:
5777
273k
        type.getQualifier().storage = qualifier;
5778
273k
        break;
5779
191k
    case EvqGlobal:
5780
6.13M
    case EvqTemporary:
5781
6.13M
        type.getQualifier().storage = EvqIn;
5782
6.13M
        break;
5783
0
    default:
5784
0
        type.getQualifier().storage = EvqIn;
5785
0
        error(loc, "storage qualifier not allowed on function parameter", GetStorageQualifierString(qualifier), "");
5786
0
        break;
5787
6.41M
    }
5788
6.41M
}
5789
5790
void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& qualifier, TType& type)
5791
846k
{
5792
846k
    if (qualifier.isMemory()) {
5793
403k
        type.getQualifier().volatil   = qualifier.volatil;
5794
403k
        type.getQualifier().nontemporal   = qualifier.nontemporal;
5795
403k
        type.getQualifier().coherent  = qualifier.coherent;
5796
403k
        type.getQualifier().devicecoherent  = qualifier.devicecoherent ;
5797
403k
        type.getQualifier().queuefamilycoherent  = qualifier.queuefamilycoherent;
5798
403k
        type.getQualifier().workgroupcoherent  = qualifier.workgroupcoherent;
5799
403k
        type.getQualifier().subgroupcoherent  = qualifier.subgroupcoherent;
5800
403k
        type.getQualifier().shadercallcoherent = qualifier.shadercallcoherent;
5801
403k
        type.getQualifier().nonprivate = qualifier.nonprivate;
5802
403k
        type.getQualifier().readonly  = qualifier.readonly;
5803
403k
        type.getQualifier().writeonly = qualifier.writeonly;
5804
403k
        type.getQualifier().restrict  = qualifier.restrict;
5805
403k
    }
5806
5807
846k
    if (qualifier.isAuxiliary() ||
5808
846k
        qualifier.isInterpolation())
5809
0
        error(loc, "cannot use auxiliary or interpolation qualifiers on a function parameter", "", "");
5810
846k
    if (qualifier.hasLayout())
5811
0
        error(loc, "cannot use layout qualifiers on a function parameter", "", "");
5812
846k
    if (qualifier.invariant)
5813
0
        error(loc, "cannot use invariant qualifier on a function parameter", "", "");
5814
846k
    if (qualifier.isNoContraction()) {
5815
0
        if (qualifier.isParamOutput())
5816
0
            type.getQualifier().setNoContraction();
5817
0
        else
5818
0
            warn(loc, "qualifier has no effect on non-output parameters", "precise", "");
5819
0
    }
5820
846k
    if (qualifier.isNonUniform())
5821
0
        type.getQualifier().nonUniform = qualifier.nonUniform;
5822
846k
    if (qualifier.isSpirvByReference())
5823
0
        type.getQualifier().setSpirvByReference();
5824
846k
    if (qualifier.isSpirvLiteral()) {
5825
0
        if (type.getBasicType() == EbtFloat || type.getBasicType() == EbtInt || type.getBasicType() == EbtUint ||
5826
0
            type.getBasicType() == EbtBool)
5827
0
            type.getQualifier().setSpirvLiteral();
5828
0
        else
5829
0
            error(loc, "cannot use spirv_literal qualifier", type.getBasicTypeString().c_str(), "");
5830
0
    }
5831
5832
846k
    paramCheckFixStorage(loc, qualifier.storage, type);
5833
846k
}
5834
5835
void TParseContext::nestedBlockCheck(const TSourceLoc& loc)
5836
1.91k
{
5837
1.91k
    if (structNestingLevel > 0 || blockNestingLevel > 0)
5838
0
        error(loc, "cannot nest a block definition inside a structure or block", "", "");
5839
1.91k
    ++blockNestingLevel;
5840
1.91k
}
5841
5842
void TParseContext::nestedStructCheck(const TSourceLoc& loc)
5843
771
{
5844
771
    if (structNestingLevel > 0 || blockNestingLevel > 0)
5845
0
        error(loc, "cannot nest a structure definition inside a structure or block", "", "");
5846
771
    ++structNestingLevel;
5847
771
}
5848
5849
void TParseContext::arrayObjectCheck(const TSourceLoc& loc, const TType& type, const char* op)
5850
2.36M
{
5851
    // Some versions don't allow comparing arrays or structures containing arrays
5852
2.36M
    if (type.containsArray()) {
5853
4
        profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, op);
5854
4
        profileRequires(loc, EEsProfile, 300, nullptr, op);
5855
4
    }
5856
2.36M
}
5857
5858
void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const char* op)
5859
6
{
5860
6
    if (containsFieldWithBasicType(type, EbtSampler) && !extensionTurnedOn(E_GL_ARB_bindless_texture))
5861
0
        error(loc, "can't use with samplers or structs containing samplers", op, "");
5862
6
}
5863
5864
void TParseContext::referenceCheck(const TSourceLoc& loc, const TType& type, const char* op)
5865
0
{
5866
0
    if (containsFieldWithBasicType(type, EbtReference))
5867
0
        error(loc, "can't use with reference types", op, "");
5868
0
}
5869
5870
void TParseContext::storage16BitAssignmentCheck(const TSourceLoc& loc, const TType& type, const char* op)
5871
6
{
5872
6
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtFloat16))
5873
0
        requireFloat16Arithmetic(loc, op, "can't use with structs containing float16");
5874
5875
6
    if (type.isArray() && type.getBasicType() == EbtFloat16)
5876
0
        requireFloat16Arithmetic(loc, op, "can't use with arrays containing float16");
5877
5878
6
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtInt16))
5879
0
        requireInt16Arithmetic(loc, op, "can't use with structs containing int16");
5880
5881
6
    if (type.isArray() && type.getBasicType() == EbtInt16)
5882
0
        requireInt16Arithmetic(loc, op, "can't use with arrays containing int16");
5883
5884
6
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtUint16))
5885
0
        requireInt16Arithmetic(loc, op, "can't use with structs containing uint16");
5886
5887
6
    if (type.isArray() && type.getBasicType() == EbtUint16)
5888
0
        requireInt16Arithmetic(loc, op, "can't use with arrays containing uint16");
5889
5890
6
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtInt8))
5891
0
        requireInt8Arithmetic(loc, op, "can't use with structs containing int8");
5892
5893
6
    if (type.isArray() && type.getBasicType() == EbtInt8)
5894
0
        requireInt8Arithmetic(loc, op, "can't use with arrays containing int8");
5895
5896
6
    if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtUint8))
5897
0
        requireInt8Arithmetic(loc, op, "can't use with structs containing uint8");
5898
5899
6
    if (type.isArray() && type.getBasicType() == EbtUint8)
5900
0
        requireInt8Arithmetic(loc, op, "can't use with arrays containing uint8");
5901
6
}
5902
5903
void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
5904
935
{
5905
935
    if (type.containsSpecializationSize())
5906
0
        error(loc, "can't use with types containing arrays sized with a specialization constant", op, "");
5907
935
}
5908
5909
void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publicType)
5910
771
{
5911
771
    const TTypeList& typeList = *publicType.userDef->getStruct();
5912
5913
    // fix and check for member storage qualifiers and types that don't belong within a structure
5914
3.93k
    for (unsigned int member = 0; member < typeList.size(); ++member) {
5915
3.16k
        TQualifier& memberQualifier = typeList[member].type->getQualifier();
5916
3.16k
        const TSourceLoc& memberLoc = typeList[member].loc;
5917
3.16k
        if (memberQualifier.isAuxiliary() ||
5918
3.16k
            memberQualifier.isInterpolation() ||
5919
3.16k
            (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal))
5920
0
            error(memberLoc, "cannot use storage or interpolation qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
5921
3.16k
        if (memberQualifier.isMemory())
5922
0
            error(memberLoc, "cannot use memory qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
5923
3.16k
        if (memberQualifier.hasLayout()) {
5924
0
            error(memberLoc, "cannot use layout qualifiers on structure members", typeList[member].type->getFieldName().c_str(), "");
5925
0
            memberQualifier.clearLayout();
5926
0
        }
5927
3.16k
        if (memberQualifier.invariant)
5928
0
            error(memberLoc, "cannot use invariant qualifier on structure members", typeList[member].type->getFieldName().c_str(), "");
5929
3.16k
    }
5930
771
}
5931
5932
//
5933
// See if this loop satisfies the limitations for ES 2.0 (version 100) for loops in Appendex A:
5934
//
5935
// "The loop index has type int or float.
5936
//
5937
// "The for statement has the form:
5938
//     for ( init-declaration ; condition ; expression )
5939
//     init-declaration has the form: type-specifier identifier = constant-expression
5940
//     condition has the form:  loop-index relational_operator constant-expression
5941
//         where relational_operator is one of: > >= < <= == or !=
5942
//     expression [sic] has one of the following forms:
5943
//         loop-index++
5944
//         loop-index--
5945
//         loop-index += constant-expression
5946
//         loop-index -= constant-expression
5947
//
5948
// The body is handled in an AST traversal.
5949
//
5950
void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, TIntermLoop* loop)
5951
0
{
5952
    // loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration
5953
0
    bool badInit = false;
5954
0
    if (! init || ! init->getAsAggregate() || init->getAsAggregate()->getSequence().size() != 1)
5955
0
        badInit = true;
5956
0
    TIntermBinary* binaryInit = nullptr;
5957
0
    if (! badInit) {
5958
        // get the declaration assignment
5959
0
        binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode();
5960
0
        if (! binaryInit)
5961
0
            badInit = true;
5962
0
    }
5963
0
    if (badInit) {
5964
0
        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
5965
0
        return;
5966
0
    }
5967
5968
    // loop index must be type int or float
5969
0
    if (! binaryInit->getType().isScalar() || (binaryInit->getBasicType() != EbtInt && binaryInit->getBasicType() != EbtFloat)) {
5970
0
        error(loc, "inductive loop requires a scalar 'int' or 'float' loop index", "limitations", "");
5971
0
        return;
5972
0
    }
5973
5974
    // init is the form "loop-index = constant"
5975
0
    if (binaryInit->getOp() != EOpAssign || ! binaryInit->getLeft()->getAsSymbolNode() || ! binaryInit->getRight()->getAsConstantUnion()) {
5976
0
        error(loc, "inductive-loop init-declaration requires the form \"type-specifier loop-index = constant-expression\"", "limitations", "");
5977
0
        return;
5978
0
    }
5979
5980
    // get the unique id of the loop index
5981
0
    long long loopIndex = binaryInit->getLeft()->getAsSymbolNode()->getId();
5982
0
    inductiveLoopIds.insert(loopIndex);
5983
5984
    // condition's form must be "loop-index relational-operator constant-expression"
5985
0
    bool badCond = ! loop->getTest();
5986
0
    if (! badCond) {
5987
0
        TIntermBinary* binaryCond = loop->getTest()->getAsBinaryNode();
5988
0
        badCond = ! binaryCond;
5989
0
        if (! badCond) {
5990
0
            switch (binaryCond->getOp()) {
5991
0
            case EOpGreaterThan:
5992
0
            case EOpGreaterThanEqual:
5993
0
            case EOpLessThan:
5994
0
            case EOpLessThanEqual:
5995
0
            case EOpEqual:
5996
0
            case EOpNotEqual:
5997
0
                break;
5998
0
            default:
5999
0
                badCond = true;
6000
0
            }
6001
0
        }
6002
0
        if (binaryCond && (! binaryCond->getLeft()->getAsSymbolNode() ||
6003
0
                           binaryCond->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
6004
0
                           ! binaryCond->getRight()->getAsConstantUnion()))
6005
0
            badCond = true;
6006
0
    }
6007
0
    if (badCond) {
6008
0
        error(loc, "inductive-loop condition requires the form \"loop-index <comparison-op> constant-expression\"", "limitations", "");
6009
0
        return;
6010
0
    }
6011
6012
    // loop-index++
6013
    // loop-index--
6014
    // loop-index += constant-expression
6015
    // loop-index -= constant-expression
6016
0
    bool badTerminal = ! loop->getTerminal();
6017
0
    if (! badTerminal) {
6018
0
        TIntermUnary* unaryTerminal = loop->getTerminal()->getAsUnaryNode();
6019
0
        TIntermBinary* binaryTerminal = loop->getTerminal()->getAsBinaryNode();
6020
0
        if (unaryTerminal || binaryTerminal) {
6021
0
            switch(loop->getTerminal()->getAsOperator()->getOp()) {
6022
0
            case EOpPostDecrement:
6023
0
            case EOpPostIncrement:
6024
0
            case EOpAddAssign:
6025
0
            case EOpSubAssign:
6026
0
                break;
6027
0
            default:
6028
0
                badTerminal = true;
6029
0
            }
6030
0
        } else
6031
0
            badTerminal = true;
6032
0
        if (binaryTerminal && (! binaryTerminal->getLeft()->getAsSymbolNode() ||
6033
0
                               binaryTerminal->getLeft()->getAsSymbolNode()->getId() != loopIndex ||
6034
0
                               ! binaryTerminal->getRight()->getAsConstantUnion()))
6035
0
            badTerminal = true;
6036
0
        if (unaryTerminal && (! unaryTerminal->getOperand()->getAsSymbolNode() ||
6037
0
                              unaryTerminal->getOperand()->getAsSymbolNode()->getId() != loopIndex))
6038
0
            badTerminal = true;
6039
0
    }
6040
0
    if (badTerminal) {
6041
0
        error(loc, "inductive-loop termination requires the form \"loop-index++, loop-index--, loop-index += constant-expression, or loop-index -= constant-expression\"", "limitations", "");
6042
0
        return;
6043
0
    }
6044
6045
    // the body
6046
0
    inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
6047
0
}
6048
6049
// Do limit checks for built-in arrays.
6050
void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identifier, int size)
6051
5
{
6052
5
    if (identifier.compare("gl_TexCoord") == 0)
6053
0
        limitCheck(loc, size, "gl_MaxTextureCoords", "gl_TexCoord array size");
6054
5
    else if (identifier.compare("gl_ClipDistance") == 0)
6055
0
        limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistance array size");
6056
5
    else if (identifier.compare("gl_CullDistance") == 0)
6057
0
        limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistance array size");
6058
5
    else if (identifier.compare("gl_ClipDistancePerViewNV") == 0)
6059
0
        limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistancePerViewNV array size");
6060
5
    else if (identifier.compare("gl_CullDistancePerViewNV") == 0)
6061
0
        limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistancePerViewNV array size");
6062
5
}
6063
6064
// See if the provided value is less than or equal to the symbol indicated by limit,
6065
// which should be a constant in the symbol table.
6066
void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* limit, const char* feature)
6067
0
{
6068
0
    TSymbol* symbol = symbolTable.find(limit);
6069
0
    assert(symbol->getAsVariable());
6070
0
    const TConstUnionArray& constArray = symbol->getAsVariable()->getConstArray();
6071
0
    assert(! constArray.empty());
6072
0
    if (value > constArray[0].getIConst())
6073
0
        error(loc, "must be less than or equal to", feature, "%s (%d)", limit, constArray[0].getIConst());
6074
0
}
6075
6076
//
6077
// Do any additional error checking, etc., once we know the parsing is done.
6078
//
6079
void TParseContext::finish()
6080
5.09k
{
6081
5.09k
    TParseContextBase::finish();
6082
6083
5.09k
    if (parsingBuiltins)
6084
4.99k
        return;
6085
6086
    // Check on array indexes for ES 2.0 (version 100) limitations.
6087
96
    for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
6088
0
        constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
6089
6090
    // Check for stages that are enabled by extension.
6091
    // Can't do this at the beginning, it is chicken and egg to add a stage by
6092
    // extension.
6093
    // Stage-specific features were correctly tested for already, this is just
6094
    // about the stage itself.
6095
96
    switch (language) {
6096
0
    case EShLangGeometry:
6097
0
        if (isEsProfile() && version == 310)
6098
0
            requireExtensions(getCurrentLoc(), Num_AEP_geometry_shader, AEP_geometry_shader, "geometry shaders");
6099
0
        break;
6100
0
    case EShLangTessControl:
6101
0
    case EShLangTessEvaluation:
6102
0
        if (isEsProfile() && version == 310)
6103
0
            requireExtensions(getCurrentLoc(), Num_AEP_tessellation_shader, AEP_tessellation_shader, "tessellation shaders");
6104
0
        else if (!isEsProfile() && version < 400)
6105
0
            requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_tessellation_shader, "tessellation shaders");
6106
0
        break;
6107
0
    case EShLangCompute:
6108
0
        if (!isEsProfile() && version < 430)
6109
0
            requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_compute_shader, "compute shaders");
6110
0
        break;
6111
0
    case EShLangTask:
6112
0
        requireExtensions(getCurrentLoc(), Num_AEP_mesh_shader, AEP_mesh_shader, "task shaders");
6113
0
        break;
6114
0
    case EShLangMesh:
6115
0
        requireExtensions(getCurrentLoc(), Num_AEP_mesh_shader, AEP_mesh_shader, "mesh shaders");
6116
0
        break;
6117
96
    default:
6118
96
        break;
6119
96
    }
6120
6121
    // Set default outputs for GL_NV_geometry_shader_passthrough
6122
96
    if (language == EShLangGeometry && extensionTurnedOn(E_SPV_NV_geometry_shader_passthrough)) {
6123
0
        if (intermediate.getOutputPrimitive() == ElgNone) {
6124
0
            switch (intermediate.getInputPrimitive()) {
6125
0
            case ElgPoints:      intermediate.setOutputPrimitive(ElgPoints);    break;
6126
0
            case ElgLines:       intermediate.setOutputPrimitive(ElgLineStrip); break;
6127
0
            case ElgTriangles:   intermediate.setOutputPrimitive(ElgTriangleStrip); break;
6128
0
            default: break;
6129
0
            }
6130
0
        }
6131
0
        if (intermediate.getVertices() == TQualifier::layoutNotSet) {
6132
0
            switch (intermediate.getInputPrimitive()) {
6133
0
            case ElgPoints:      intermediate.setVertices(1); break;
6134
0
            case ElgLines:       intermediate.setVertices(2); break;
6135
0
            case ElgTriangles:   intermediate.setVertices(3); break;
6136
0
            default: break;
6137
0
            }
6138
0
        }
6139
0
    }
6140
96
}
6141
6142
//
6143
// Layout qualifier stuff.
6144
//
6145
6146
// Put the id's layout qualification into the public type, for qualifiers not having a number set.
6147
// This is before we know any type information for error checking.
6148
void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id)
6149
0
{
6150
0
    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
6151
6152
0
    if (id == TQualifier::getLayoutMatrixString(ElmColumnMajor)) {
6153
0
        publicType.qualifier.layoutMatrix = ElmColumnMajor;
6154
0
        return;
6155
0
    }
6156
0
    if (id == TQualifier::getLayoutMatrixString(ElmRowMajor)) {
6157
0
        publicType.qualifier.layoutMatrix = ElmRowMajor;
6158
0
        return;
6159
0
    }
6160
0
    if (id == TQualifier::getLayoutPackingString(ElpPacked)) {
6161
0
        if (spvVersion.spv != 0) {
6162
0
            if (spvVersion.vulkanRelaxed)
6163
0
                return; // silently ignore qualifier
6164
0
            else
6165
0
                spvRemoved(loc, "packed");
6166
0
        }
6167
0
        publicType.qualifier.layoutPacking = ElpPacked;
6168
0
        return;
6169
0
    }
6170
0
    if (id == TQualifier::getLayoutPackingString(ElpShared)) {
6171
0
        if (spvVersion.spv != 0) {
6172
0
            if (spvVersion.vulkanRelaxed)
6173
0
                return; // silently ignore qualifier
6174
0
            else
6175
0
                spvRemoved(loc, "shared");
6176
0
        }
6177
0
        publicType.qualifier.layoutPacking = ElpShared;
6178
0
        return;
6179
0
    }
6180
0
    if (id == TQualifier::getLayoutPackingString(ElpStd140)) {
6181
0
        publicType.qualifier.layoutPacking = ElpStd140;
6182
0
        return;
6183
0
    }
6184
0
    if (id == TQualifier::getLayoutPackingString(ElpStd430)) {
6185
0
        requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "std430");
6186
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_shader_storage_buffer_object, "std430");
6187
0
        profileRequires(loc, EEsProfile, 310, nullptr, "std430");
6188
0
        publicType.qualifier.layoutPacking = ElpStd430;
6189
0
        return;
6190
0
    }
6191
0
    if (id == TQualifier::getLayoutPackingString(ElpScalar)) {
6192
0
        requireVulkan(loc, "scalar");
6193
0
        requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "scalar block layout");
6194
0
        publicType.qualifier.layoutPacking = ElpScalar;
6195
0
        return;
6196
0
    }
6197
    // TODO: compile-time performance: may need to stop doing linear searches
6198
0
    for (TLayoutFormat format = (TLayoutFormat)(ElfNone + 1); format < ElfCount; format = (TLayoutFormat)(format + 1)) {
6199
0
        if (id == TQualifier::getLayoutFormatString(format)) {
6200
0
            if ((format > ElfEsFloatGuard && format < ElfFloatGuard) ||
6201
0
                (format > ElfEsIntGuard && format < ElfIntGuard) ||
6202
0
                (format > ElfEsUintGuard && format < ElfCount))
6203
0
                requireProfile(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, "image load-store format");
6204
0
            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_ARB_shader_image_load_store, "image load store");
6205
0
            profileRequires(loc, EEsProfile, 310, E_GL_ARB_shader_image_load_store, "image load store");
6206
0
            publicType.qualifier.layoutFormat = format;
6207
0
            return;
6208
0
        }
6209
0
    }
6210
0
    if (id == "push_constant") {
6211
0
        requireVulkan(loc, "push_constant");
6212
0
        publicType.qualifier.layoutPushConstant = true;
6213
0
        return;
6214
0
    }
6215
0
    if (id == "buffer_reference") {
6216
0
        requireVulkan(loc, "buffer_reference");
6217
0
        requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference");
6218
0
        publicType.qualifier.layoutBufferReference = true;
6219
0
        intermediate.setUseStorageBuffer();
6220
0
        intermediate.setUsePhysicalStorageBuffer();
6221
0
        return;
6222
0
    }
6223
0
    if (id == "bindless_sampler") {
6224
0
        requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_sampler");
6225
0
        publicType.qualifier.layoutBindlessSampler = true;
6226
0
        intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout);
6227
0
        return;
6228
0
    }
6229
0
    if (id == "bindless_image") {
6230
0
        requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_image");
6231
0
        publicType.qualifier.layoutBindlessImage = true;
6232
0
        intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout);
6233
0
        return;
6234
0
    }
6235
0
    if (id == "bound_sampler") {
6236
0
        requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_sampler");
6237
0
        publicType.qualifier.layoutBindlessSampler = false;
6238
0
        return;
6239
0
    }
6240
0
    if (id == "bound_image") {
6241
0
        requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_image");
6242
0
        publicType.qualifier.layoutBindlessImage = false;
6243
0
        return;
6244
0
    }
6245
0
    if (language == EShLangGeometry || language == EShLangTessEvaluation || language == EShLangMesh) {
6246
0
        if (id == TQualifier::getGeometryString(ElgTriangles)) {
6247
0
            publicType.shaderQualifiers.geometry = ElgTriangles;
6248
0
            return;
6249
0
        }
6250
0
        if (language == EShLangGeometry || language == EShLangMesh) {
6251
0
            if (id == TQualifier::getGeometryString(ElgPoints)) {
6252
0
                publicType.shaderQualifiers.geometry = ElgPoints;
6253
0
                return;
6254
0
            }
6255
0
            if (id == TQualifier::getGeometryString(ElgLines)) {
6256
0
                publicType.shaderQualifiers.geometry = ElgLines;
6257
0
                return;
6258
0
            }
6259
0
            if (language == EShLangGeometry) {
6260
0
                if (id == TQualifier::getGeometryString(ElgLineStrip)) {
6261
0
                    publicType.shaderQualifiers.geometry = ElgLineStrip;
6262
0
                    return;
6263
0
                }
6264
0
                if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) {
6265
0
                    publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
6266
0
                    return;
6267
0
                }
6268
0
                if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) {
6269
0
                    publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
6270
0
                    return;
6271
0
                }
6272
0
                if (id == TQualifier::getGeometryString(ElgTriangleStrip)) {
6273
0
                    publicType.shaderQualifiers.geometry = ElgTriangleStrip;
6274
0
                    return;
6275
0
                }
6276
0
                if (id == "passthrough") {
6277
0
                    requireExtensions(loc, 1, &E_SPV_NV_geometry_shader_passthrough, "geometry shader passthrough");
6278
0
                    publicType.qualifier.layoutPassthrough = true;
6279
0
                    intermediate.setGeoPassthroughEXT();
6280
0
                    return;
6281
0
                }
6282
0
            }
6283
0
        } else {
6284
0
            assert(language == EShLangTessEvaluation);
6285
6286
            // input primitive
6287
0
            if (id == TQualifier::getGeometryString(ElgTriangles)) {
6288
0
                publicType.shaderQualifiers.geometry = ElgTriangles;
6289
0
                return;
6290
0
            }
6291
0
            if (id == TQualifier::getGeometryString(ElgQuads)) {
6292
0
                publicType.shaderQualifiers.geometry = ElgQuads;
6293
0
                return;
6294
0
            }
6295
0
            if (id == TQualifier::getGeometryString(ElgIsolines)) {
6296
0
                publicType.shaderQualifiers.geometry = ElgIsolines;
6297
0
                return;
6298
0
            }
6299
6300
            // vertex spacing
6301
0
            if (id == TQualifier::getVertexSpacingString(EvsEqual)) {
6302
0
                publicType.shaderQualifiers.spacing = EvsEqual;
6303
0
                return;
6304
0
            }
6305
0
            if (id == TQualifier::getVertexSpacingString(EvsFractionalEven)) {
6306
0
                publicType.shaderQualifiers.spacing = EvsFractionalEven;
6307
0
                return;
6308
0
            }
6309
0
            if (id == TQualifier::getVertexSpacingString(EvsFractionalOdd)) {
6310
0
                publicType.shaderQualifiers.spacing = EvsFractionalOdd;
6311
0
                return;
6312
0
            }
6313
6314
            // triangle order
6315
0
            if (id == TQualifier::getVertexOrderString(EvoCw)) {
6316
0
                publicType.shaderQualifiers.order = EvoCw;
6317
0
                return;
6318
0
            }
6319
0
            if (id == TQualifier::getVertexOrderString(EvoCcw)) {
6320
0
                publicType.shaderQualifiers.order = EvoCcw;
6321
0
                return;
6322
0
            }
6323
6324
            // point mode
6325
0
            if (id == "point_mode") {
6326
0
                publicType.shaderQualifiers.pointMode = true;
6327
0
                return;
6328
0
            }
6329
0
        }
6330
0
    }
6331
0
    if (language == EShLangFragment) {
6332
0
        if (id == "origin_upper_left") {
6333
0
            requireProfile(loc, ECoreProfile | ECompatibilityProfile | ENoProfile, "origin_upper_left");
6334
0
            if (profile == ENoProfile) {
6335
0
                profileRequires(loc,ECoreProfile | ECompatibilityProfile, 140, E_GL_ARB_fragment_coord_conventions, "origin_upper_left");
6336
0
            }
6337
6338
0
            publicType.shaderQualifiers.originUpperLeft = true;
6339
0
            return;
6340
0
        }
6341
0
        if (id == "pixel_center_integer") {
6342
0
            requireProfile(loc, ECoreProfile | ECompatibilityProfile | ENoProfile, "pixel_center_integer");
6343
0
            if (profile == ENoProfile) {
6344
0
                profileRequires(loc,ECoreProfile | ECompatibilityProfile, 140, E_GL_ARB_fragment_coord_conventions, "pixel_center_integer");
6345
0
            }
6346
0
            publicType.shaderQualifiers.pixelCenterInteger = true;
6347
0
            return;
6348
0
        }
6349
0
        if (id == "early_fragment_tests") {
6350
0
            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_ARB_shader_image_load_store, "early_fragment_tests");
6351
0
            profileRequires(loc, EEsProfile, 310, nullptr, "early_fragment_tests");
6352
0
            publicType.shaderQualifiers.earlyFragmentTests = true;
6353
0
            return;
6354
0
        }
6355
0
        if (id == "early_and_late_fragment_tests_amd") {
6356
0
            profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_AMD_shader_early_and_late_fragment_tests, "early_and_late_fragment_tests_amd");
6357
0
            profileRequires(loc, EEsProfile, 310, nullptr, "early_and_late_fragment_tests_amd");
6358
0
            publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD = true;
6359
0
            return;
6360
0
        }
6361
0
        if (id == "post_depth_coverage") {
6362
0
            requireExtensions(loc, Num_post_depth_coverageEXTs, post_depth_coverageEXTs, "post depth coverage");
6363
0
            if (extensionTurnedOn(E_GL_ARB_post_depth_coverage)) {
6364
0
                publicType.shaderQualifiers.earlyFragmentTests = true;
6365
0
            }
6366
0
            publicType.shaderQualifiers.postDepthCoverage = true;
6367
0
            return;
6368
0
        }
6369
        /* id is transformed into lower case in the beginning of this function. */
6370
0
        if (id == "non_coherent_color_attachment_readext") {
6371
0
            requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_color_attachment_readEXT");
6372
0
            publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT = true;
6373
0
            return;
6374
0
        }
6375
0
        if (id == "non_coherent_depth_attachment_readext") {
6376
0
            requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_depth_attachment_readEXT");
6377
0
            publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT = true;
6378
0
            return;
6379
0
        }
6380
0
        if (id == "non_coherent_stencil_attachment_readext") {
6381
0
            requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_stencil_attachment_readEXT");
6382
0
            publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT = true;
6383
0
            return;
6384
0
        }
6385
0
        for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) {
6386
0
            if (id == TQualifier::getLayoutDepthString(depth)) {
6387
0
                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier");
6388
0
                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, nullptr, "depth layout qualifier");
6389
0
                publicType.shaderQualifiers.layoutDepth = depth;
6390
0
                return;
6391
0
            }
6392
0
        }
6393
0
        for (TLayoutStencil stencil = (TLayoutStencil)(ElsNone + 1); stencil < ElsCount; stencil = (TLayoutStencil)(stencil+1)) {
6394
0
            if (id == TQualifier::getLayoutStencilString(stencil)) {
6395
0
                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "stencil layout qualifier");
6396
0
                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, nullptr, "stencil layout qualifier");
6397
0
                publicType.shaderQualifiers.layoutStencil = stencil;
6398
0
                return;
6399
0
            }
6400
0
        }
6401
0
        for (TInterlockOrdering order = (TInterlockOrdering)(EioNone + 1); order < EioCount; order = (TInterlockOrdering)(order+1)) {
6402
0
            if (id == TQualifier::getInterlockOrderingString(order)) {
6403
0
                requireProfile(loc, ECoreProfile | ECompatibilityProfile, "fragment shader interlock layout qualifier");
6404
0
                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 450, nullptr, "fragment shader interlock layout qualifier");
6405
0
                requireExtensions(loc, 1, &E_GL_ARB_fragment_shader_interlock, TQualifier::getInterlockOrderingString(order));
6406
0
                if (order == EioShadingRateInterlockOrdered || order == EioShadingRateInterlockUnordered)
6407
0
                    requireExtensions(loc, 1, &E_GL_NV_shading_rate_image, TQualifier::getInterlockOrderingString(order));
6408
0
                publicType.shaderQualifiers.interlockOrdering = order;
6409
0
                return;
6410
0
            }
6411
0
        }
6412
0
        if (id.compare(0, 13, "blend_support") == 0) {
6413
0
            bool found = false;
6414
0
            for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
6415
0
                if (id == TQualifier::getBlendEquationString(be)) {
6416
0
                    profileRequires(loc, EEsProfile, 320, E_GL_KHR_blend_equation_advanced, "blend equation");
6417
0
                    profileRequires(loc, ~EEsProfile, 0, E_GL_KHR_blend_equation_advanced, "blend equation");
6418
0
                    intermediate.addBlendEquation(be);
6419
0
                    publicType.shaderQualifiers.blendEquation = true;
6420
0
                    found = true;
6421
0
                    break;
6422
0
                }
6423
0
            }
6424
0
            if (! found)
6425
0
                error(loc, "unknown blend equation", "blend_support", "");
6426
0
            return;
6427
0
        }
6428
0
        if (id == "override_coverage") {
6429
0
            requireExtensions(loc, 1, &E_GL_NV_sample_mask_override_coverage, "sample mask override coverage");
6430
0
            publicType.shaderQualifiers.layoutOverrideCoverage = true;
6431
0
            return;
6432
0
        }
6433
0
        if (id == "full_quads")
6434
0
        {
6435
0
            const char* feature = "full_quads qualifier";
6436
0
            requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, feature);
6437
0
            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 140, E_GL_EXT_shader_quad_control, feature);
6438
0
            profileRequires(loc, EEsProfile, 310, E_GL_EXT_shader_quad_control, feature);
6439
0
            publicType.qualifier.layoutFullQuads = true;
6440
0
            return;
6441
0
        }
6442
0
        if (id == "non_coherent_attachment_readqcom") {
6443
0
            requireExtensions(loc, 1, &E_GL_QCOM_tile_shading, "tile shading QCOM");
6444
0
            publicType.shaderQualifiers.layoutNonCoherentTileAttachmentReadQCOM = true;
6445
0
            return;
6446
0
        }
6447
0
        if (id == "tile_attachmentqcom") {
6448
0
            requireExtensions(loc, 1, &E_GL_QCOM_tile_shading, "tile shading QCOM");
6449
0
            publicType.qualifier.layoutTileAttachmentQCOM = true;
6450
0
            return;
6451
0
        }
6452
0
    }
6453
0
    if (language == EShLangVertex ||
6454
0
        language == EShLangTessControl ||
6455
0
        language == EShLangTessEvaluation ||
6456
0
        language == EShLangGeometry ) {
6457
0
        if (id == "viewport_relative") {
6458
0
            requireExtensions(loc, 1, &E_GL_NV_viewport_array2, "view port array2");
6459
0
            publicType.qualifier.layoutViewportRelative = true;
6460
0
            return;
6461
0
        }
6462
0
    } else {
6463
0
        if (language == EShLangRayGen || language == EShLangIntersect ||
6464
0
        language == EShLangAnyHit || language == EShLangClosestHit ||
6465
0
        language == EShLangMiss || language == EShLangCallable) {
6466
0
            if (id == "shaderrecordnv" || id == "shaderrecordext") {
6467
0
                if (id == "shaderrecordnv") {
6468
0
                    requireExtensions(loc, 1, &E_GL_NV_ray_tracing, "shader record NV");
6469
0
                } else {
6470
0
                    requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "shader record EXT");
6471
0
                }
6472
0
                publicType.qualifier.layoutShaderRecord = true;
6473
0
                return;
6474
0
            } else if (id == "hitobjectshaderrecordnv") {
6475
0
                requireExtensions(loc, 1, &E_GL_NV_shader_invocation_reorder, "hitobject shader record NV");
6476
0
                publicType.qualifier.layoutHitObjectShaderRecordNV = true;
6477
0
                return;
6478
0
            }
6479
6480
0
        }
6481
0
    }
6482
0
    if (language == EShLangCompute) {
6483
0
        if (id.compare(0, 17, "derivative_group_") == 0) {
6484
0
            requireExtensions(loc, 1, &E_GL_NV_compute_shader_derivatives, "compute shader derivatives");
6485
0
            if (id == "derivative_group_quadsnv") {
6486
0
                publicType.shaderQualifiers.layoutDerivativeGroupQuads = true;
6487
0
                return;
6488
0
            } else if (id == "derivative_group_linearnv") {
6489
0
                publicType.shaderQualifiers.layoutDerivativeGroupLinear = true;
6490
0
                return;
6491
0
            }
6492
0
        }
6493
0
        if (id == "tile_attachmentqcom") {
6494
0
            requireExtensions(loc, 1, &E_GL_QCOM_tile_shading, "tile shading QCOM");
6495
0
            publicType.qualifier.layoutTileAttachmentQCOM = true;
6496
0
            return;
6497
0
        }
6498
0
    }
6499
6500
0
    if (id == "primitive_culling") {
6501
0
        requireExtensions(loc, 1, &E_GL_EXT_ray_flags_primitive_culling, "primitive culling");
6502
0
        publicType.shaderQualifiers.layoutPrimitiveCulling = true;
6503
0
        return;
6504
0
    }
6505
6506
0
    if (id == "quad_derivatives")
6507
0
    {
6508
0
        const char* feature = "quad_derivatives qualifier";
6509
0
        requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, feature);
6510
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 140, E_GL_EXT_shader_quad_control, feature);
6511
0
        profileRequires(loc, EEsProfile, 310, E_GL_EXT_shader_quad_control, feature);
6512
0
        publicType.qualifier.layoutQuadDeriv = true;
6513
0
        return;
6514
0
    }
6515
6516
0
    error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
6517
0
}
6518
6519
// Put the id's layout qualifier value into the public type, for qualifiers having a number set.
6520
// This is before we know any type information for error checking.
6521
void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id, const TIntermTyped* node)
6522
0
{
6523
0
    const char* feature = "layout-id value";
6524
0
    const char* nonLiteralFeature = "non-literal layout-id value";
6525
6526
0
    integerCheck(node, feature);
6527
0
    const TIntermConstantUnion* constUnion = node->getAsConstantUnion();
6528
0
    int value;
6529
0
    bool nonLiteral = false;
6530
0
    if (constUnion) {
6531
0
        value = constUnion->getConstArray()[0].getIConst();
6532
0
        if (! constUnion->isLiteral()) {
6533
0
            requireProfile(loc, ECoreProfile | ECompatibilityProfile, nonLiteralFeature);
6534
0
            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, nonLiteralFeature);
6535
0
        }
6536
0
    } else {
6537
        // grammar should have give out the error message
6538
0
        value = 0;
6539
0
        nonLiteral = true;
6540
0
    }
6541
6542
0
    if (value < 0) {
6543
0
        error(loc, "cannot be negative", feature, "");
6544
0
        return;
6545
0
    }
6546
6547
0
    std::transform(id.begin(), id.end(), id.begin(), ::tolower);
6548
6549
0
    if (id == "offset") {
6550
        // "offset" can be for either
6551
        //  - uniform offsets
6552
        //  - atomic_uint offsets
6553
0
        const char* feature = "offset";
6554
0
        if (spvVersion.spv == 0) {
6555
0
            requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
6556
0
            const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters };
6557
0
            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature);
6558
0
            profileRequires(loc, EEsProfile, 310, nullptr, feature);
6559
0
        }
6560
0
        publicType.qualifier.layoutOffset = value;
6561
0
        publicType.qualifier.explicitOffset = true;
6562
0
        if (nonLiteral)
6563
0
            error(loc, "needs a literal integer", "offset", "");
6564
0
        return;
6565
0
    } else if (id == "align") {
6566
0
        const char* feature = "uniform buffer-member align";
6567
0
        if (spvVersion.spv == 0) {
6568
0
            requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
6569
0
            profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
6570
0
        }
6571
        // "The specified alignment must be a power of 2, or a compile-time error results."
6572
0
        if (! IsPow2(value))
6573
0
            error(loc, "must be a power of 2", "align", "");
6574
0
        else
6575
0
            publicType.qualifier.layoutAlign = value;
6576
0
        if (nonLiteral)
6577
0
            error(loc, "needs a literal integer", "align", "");
6578
0
        return;
6579
0
    } else if (id == "location") {
6580
0
        profileRequires(loc, EEsProfile, 300, nullptr, "location");
6581
0
        const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
6582
        // GL_ARB_explicit_uniform_location requires 330 or GL_ARB_explicit_attrib_location we do not need to add it here
6583
0
        profileRequires(loc, ~EEsProfile, 330, 2, exts, "location");
6584
0
        if ((unsigned int)value >= TQualifier::layoutLocationEnd)
6585
0
            error(loc, "location is too large", id.c_str(), "");
6586
0
        else
6587
0
            publicType.qualifier.layoutLocation = value;
6588
0
        if (nonLiteral)
6589
0
            error(loc, "needs a literal integer", "location", "");
6590
0
        return;
6591
0
    } else if (id == "set") {
6592
0
        if ((unsigned int)value >= TQualifier::layoutSetEnd)
6593
0
            error(loc, "set is too large", id.c_str(), "");
6594
0
        else
6595
0
            publicType.qualifier.layoutSet = value;
6596
0
        if (value != 0)
6597
0
            requireVulkan(loc, "descriptor set");
6598
0
        if (nonLiteral)
6599
0
            error(loc, "needs a literal integer", "set", "");
6600
0
        return;
6601
0
    } else if (id == "binding") {
6602
0
        profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, "binding");
6603
0
        profileRequires(loc, EEsProfile, 310, nullptr, "binding");
6604
0
        if ((unsigned int)value >= TQualifier::layoutBindingEnd)
6605
0
            error(loc, "binding is too large", id.c_str(), "");
6606
0
        else
6607
0
            publicType.qualifier.layoutBinding = value;
6608
0
        if (nonLiteral)
6609
0
            error(loc, "needs a literal integer", "binding", "");
6610
0
        return;
6611
0
    }
6612
0
    if (id == "constant_id") {
6613
0
        requireSpv(loc, "constant_id");
6614
0
        if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
6615
0
            error(loc, "specialization-constant id is too large", id.c_str(), "");
6616
0
        } else {
6617
0
            publicType.qualifier.layoutSpecConstantId = value;
6618
0
            publicType.qualifier.specConstant = true;
6619
0
            if (! intermediate.addUsedConstantId(value))
6620
0
                error(loc, "specialization-constant id already used", id.c_str(), "");
6621
0
        }
6622
0
        if (nonLiteral)
6623
0
            error(loc, "needs a literal integer", "constant_id", "");
6624
0
        return;
6625
0
    }
6626
0
    if (id == "component") {
6627
0
        requireProfile(loc, ECoreProfile | ECompatibilityProfile, "component");
6628
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "component");
6629
0
        if ((unsigned)value >= TQualifier::layoutComponentEnd)
6630
0
            error(loc, "component is too large", id.c_str(), "");
6631
0
        else
6632
0
            publicType.qualifier.layoutComponent = value;
6633
0
        if (nonLiteral)
6634
0
            error(loc, "needs a literal integer", "component", "");
6635
0
        return;
6636
0
    }
6637
0
    if (id.compare(0, 4, "xfb_") == 0) {
6638
        // "Any shader making any static use (after preprocessing) of any of these
6639
        // *xfb_* qualifiers will cause the shader to be in a transform feedback
6640
        // capturing mode and hence responsible for describing the transform feedback
6641
        // setup."
6642
0
        intermediate.setXfbMode();
6643
0
        const char* feature = "transform feedback qualifier";
6644
0
        requireStage(loc, (EShLanguageMask)(EShLangVertexMask | EShLangGeometryMask | EShLangTessControlMask | EShLangTessEvaluationMask), feature);
6645
0
        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
6646
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
6647
0
        if (id == "xfb_buffer") {
6648
            // "It is a compile-time error to specify an *xfb_buffer* that is greater than
6649
            // the implementation-dependent constant gl_MaxTransformFeedbackBuffers."
6650
0
            if (value >= resources.maxTransformFeedbackBuffers)
6651
0
                error(loc, "buffer is too large:", id.c_str(), "gl_MaxTransformFeedbackBuffers is %d", resources.maxTransformFeedbackBuffers);
6652
0
            if (value >= (int)TQualifier::layoutXfbBufferEnd)
6653
0
                error(loc, "buffer is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbBufferEnd-1);
6654
0
            else
6655
0
                publicType.qualifier.layoutXfbBuffer = value;
6656
0
            if (nonLiteral)
6657
0
                error(loc, "needs a literal integer", "xfb_buffer", "");
6658
0
            return;
6659
0
        } else if (id == "xfb_offset") {
6660
0
            if (value >= (int)TQualifier::layoutXfbOffsetEnd)
6661
0
                error(loc, "offset is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbOffsetEnd-1);
6662
0
            else
6663
0
                publicType.qualifier.layoutXfbOffset = value;
6664
0
            if (nonLiteral)
6665
0
                error(loc, "needs a literal integer", "xfb_offset", "");
6666
0
            return;
6667
0
        } else if (id == "xfb_stride") {
6668
            // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
6669
            // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
6670
0
            if (value > 4 * resources.maxTransformFeedbackInterleavedComponents) {
6671
0
                error(loc, "1/4 stride is too large:", id.c_str(), "gl_MaxTransformFeedbackInterleavedComponents is %d",
6672
0
                    resources.maxTransformFeedbackInterleavedComponents);
6673
0
            }
6674
0
            if (value >= (int)TQualifier::layoutXfbStrideEnd)
6675
0
                error(loc, "stride is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbStrideEnd-1);
6676
0
            else
6677
0
                publicType.qualifier.layoutXfbStride = value;
6678
0
            if (nonLiteral)
6679
0
                error(loc, "needs a literal integer", "xfb_stride", "");
6680
0
            return;
6681
0
        }
6682
0
    }
6683
0
    if (id == "input_attachment_index") {
6684
0
        requireVulkan(loc, "input_attachment_index");
6685
0
        if (value >= (int)TQualifier::layoutAttachmentEnd)
6686
0
            error(loc, "attachment index is too large", id.c_str(), "");
6687
0
        else
6688
0
            publicType.qualifier.layoutAttachment = value;
6689
0
        if (nonLiteral)
6690
0
            error(loc, "needs a literal integer", "input_attachment_index", "");
6691
0
        return;
6692
0
    }
6693
0
    if (id == "num_views") {
6694
0
        requireExtensions(loc, Num_OVR_multiview_EXTs, OVR_multiview_EXTs, "num_views");
6695
0
        publicType.shaderQualifiers.numViews = value;
6696
0
        if (nonLiteral)
6697
0
            error(loc, "needs a literal integer", "num_views", "");
6698
0
        return;
6699
0
    }
6700
0
    if (language == EShLangVertex ||
6701
0
        language == EShLangTessControl ||
6702
0
        language == EShLangTessEvaluation ||
6703
0
        language == EShLangGeometry) {
6704
0
        if (id == "secondary_view_offset") {
6705
0
            requireExtensions(loc, 1, &E_GL_NV_stereo_view_rendering, "stereo view rendering");
6706
0
            publicType.qualifier.layoutSecondaryViewportRelativeOffset = value;
6707
0
            if (nonLiteral)
6708
0
                error(loc, "needs a literal integer", "secondary_view_offset", "");
6709
0
            return;
6710
0
        }
6711
0
    }
6712
6713
0
    if (id == "buffer_reference_align") {
6714
0
        requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference_align");
6715
0
        if (! IsPow2(value))
6716
0
            error(loc, "must be a power of 2", "buffer_reference_align", "");
6717
0
        else
6718
0
            publicType.qualifier.layoutBufferReferenceAlign = IntLog2(value);
6719
0
        if (nonLiteral)
6720
0
            error(loc, "needs a literal integer", "buffer_reference_align", "");
6721
0
        return;
6722
0
    }
6723
6724
0
    switch (language) {
6725
0
    case EShLangTessControl:
6726
0
        if (id == "vertices") {
6727
0
            if (value == 0)
6728
0
                error(loc, "must be greater than 0", "vertices", "");
6729
0
            else
6730
0
                publicType.shaderQualifiers.vertices = value;
6731
0
            if (nonLiteral)
6732
0
                error(loc, "needs a literal integer", "vertices", "");
6733
0
            return;
6734
0
        }
6735
0
        break;
6736
6737
0
    case EShLangGeometry:
6738
0
        if (id == "invocations") {
6739
0
            profileRequires(loc, ECompatibilityProfile | ECoreProfile, 400,
6740
0
                Num_AEP_core_gpu_shader5, AEP_core_gpu_shader5, "invocations");
6741
6742
0
            if (value == 0)
6743
0
                error(loc, "must be at least 1", "invocations", "");
6744
0
            else
6745
0
                publicType.shaderQualifiers.invocations = value;
6746
0
            if (nonLiteral)
6747
0
                error(loc, "needs a literal integer", "invocations", "");
6748
0
            return;
6749
0
        }
6750
0
        if (id == "max_vertices") {
6751
0
            publicType.shaderQualifiers.vertices = value;
6752
0
            if (value > resources.maxGeometryOutputVertices)
6753
0
                error(loc, "too large, must be less than gl_MaxGeometryOutputVertices", "max_vertices", "");
6754
0
            if (nonLiteral)
6755
0
                error(loc, "needs a literal integer", "max_vertices", "");
6756
0
            return;
6757
0
        }
6758
0
        if (id == "stream") {
6759
0
            requireProfile(loc, ~EEsProfile, "selecting output stream");
6760
0
            publicType.qualifier.layoutStream = value;
6761
0
            if (value > 0)
6762
0
                intermediate.setMultiStream();
6763
0
            if (nonLiteral)
6764
0
                error(loc, "needs a literal integer", "stream", "");
6765
0
            return;
6766
0
        }
6767
0
        break;
6768
6769
0
    case EShLangFragment:
6770
0
        if (id == "index") {
6771
0
            requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, "index layout qualifier on fragment output");
6772
0
            const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
6773
0
            profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output");
6774
0
            profileRequires(loc, EEsProfile ,310, E_GL_EXT_blend_func_extended, "index layout qualifier on fragment output");
6775
            // "It is also a compile-time error if a fragment shader sets a layout index to less than 0 or greater than 1."
6776
0
            if (value < 0 || value > 1) {
6777
0
                value = 0;
6778
0
                error(loc, "value must be 0 or 1", "index", "");
6779
0
            }
6780
6781
0
            publicType.qualifier.layoutIndex = value;
6782
0
            if (nonLiteral)
6783
0
                error(loc, "needs a literal integer", "index", "");
6784
0
            return;
6785
0
        }
6786
0
        break;
6787
6788
0
    case EShLangMesh:
6789
0
        if (id == "max_vertices") {
6790
0
            requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_vertices");
6791
0
            publicType.shaderQualifiers.vertices = value;
6792
0
            int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputVerticesEXT
6793
0
                                                              : resources.maxMeshOutputVerticesNV;
6794
0
            if (value > max) {
6795
0
                TString maxsErrtring = "too large, must be less than ";
6796
0
                maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputVerticesEXT"
6797
0
                                                                            : "gl_MaxMeshOutputVerticesNV");
6798
0
                error(loc, maxsErrtring.c_str(), "max_vertices", "");
6799
0
            }
6800
0
            if (nonLiteral)
6801
0
                error(loc, "needs a literal integer", "max_vertices", "");
6802
0
            return;
6803
0
        }
6804
0
        if (id == "max_primitives") {
6805
0
            requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_primitives");
6806
0
            publicType.shaderQualifiers.primitives = value;
6807
0
            int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputPrimitivesEXT
6808
0
                                                              : resources.maxMeshOutputPrimitivesNV;
6809
0
            if (value > max) {
6810
0
                TString maxsErrtring = "too large, must be less than ";
6811
0
                maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputPrimitivesEXT"
6812
0
                                                                            : "gl_MaxMeshOutputPrimitivesNV");
6813
0
                error(loc, maxsErrtring.c_str(), "max_primitives", "");
6814
0
            }
6815
0
            if (nonLiteral)
6816
0
                error(loc, "needs a literal integer", "max_primitives", "");
6817
0
            return;
6818
0
        }
6819
0
        [[fallthrough]];
6820
6821
0
    case EShLangTask:
6822
        // Fall through
6823
0
    case EShLangCompute:
6824
0
        if (id.compare(0, 11, "local_size_") == 0) {
6825
0
            if (language == EShLangMesh || language == EShLangTask) {
6826
0
                requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "gl_WorkGroupSize");
6827
0
            } else {
6828
0
                profileRequires(loc, EEsProfile, 310, nullptr, "gl_WorkGroupSize");
6829
0
                profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize");
6830
0
            }
6831
0
            if (nonLiteral)
6832
0
                error(loc, "needs a literal integer", "local_size", "");
6833
0
            if (id.size() == 12 && value == 0) {
6834
0
                error(loc, "must be at least 1", id.c_str(), "");
6835
0
                return;
6836
0
            }
6837
0
            if (id == "local_size_x") {
6838
0
                publicType.shaderQualifiers.localSize[0] = value;
6839
0
                publicType.shaderQualifiers.localSizeNotDefault[0] = true;
6840
0
                return;
6841
0
            }
6842
0
            if (id == "local_size_y") {
6843
0
                publicType.shaderQualifiers.localSize[1] = value;
6844
0
                publicType.shaderQualifiers.localSizeNotDefault[1] = true;
6845
0
                return;
6846
0
            }
6847
0
            if (id == "local_size_z") {
6848
0
                publicType.shaderQualifiers.localSize[2] = value;
6849
0
                publicType.shaderQualifiers.localSizeNotDefault[2] = true;
6850
0
                return;
6851
0
            }
6852
0
            if (spvVersion.spv != 0) {
6853
0
                if (id == "local_size_x_id") {
6854
0
                    publicType.shaderQualifiers.localSizeSpecId[0] = value;
6855
0
                    return;
6856
0
                }
6857
0
                if (id == "local_size_y_id") {
6858
0
                    publicType.shaderQualifiers.localSizeSpecId[1] = value;
6859
0
                    return;
6860
0
                }
6861
0
                if (id == "local_size_z_id") {
6862
0
                    publicType.shaderQualifiers.localSizeSpecId[2] = value;
6863
0
                    return;
6864
0
                }
6865
0
            }
6866
0
        }
6867
0
        if (id.compare(0, 18, "shading_rate_xqcom") == 0 ||
6868
0
            id.compare(0, 18, "shading_rate_yqcom") == 0 ||
6869
0
            id.compare(0, 18, "shading_rate_zqcom") == 0) {
6870
0
            requireExtensions(loc, 1, &E_GL_QCOM_tile_shading, "tile shading QCOM");
6871
0
            if (nonLiteral)
6872
0
                error(loc, "needs a literal integer", "shading_rate_*QCOM", "");
6873
0
            if (id.size() == 18 && value == 0) {
6874
0
                error(loc, "must be at least 1", id.c_str(), "");
6875
0
                return;
6876
0
            }
6877
0
            if (id == "shading_rate_xqcom") {
6878
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOM[0] = value;
6879
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOMNotDefault[0] = true;
6880
0
                if (! IsPow2(value))
6881
0
                    error(loc, "must be a power of 2", id.c_str(), "");
6882
0
                return;
6883
0
            }
6884
0
            if (id == "shading_rate_yqcom") {
6885
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOM[1] = value;
6886
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOMNotDefault[1] = true;
6887
0
                if (! IsPow2(value))
6888
0
                    error(loc, "must be a power of 2", id.c_str(), "");
6889
0
                return;
6890
0
            }
6891
0
            if (id == "shading_rate_zqcom") {
6892
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOM[2] = value;
6893
0
                publicType.shaderQualifiers.layoutTileShadingRateQCOMNotDefault[2] = true;
6894
0
                if (value <= 0)
6895
0
                    error(loc, "must be a positive value", id.c_str(), "");
6896
0
                return;
6897
0
            }
6898
0
        }
6899
0
        break;
6900
6901
0
    default:
6902
0
        break;
6903
0
    }
6904
6905
0
    error(loc, "there is no such layout identifier for this stage taking an assigned value", id.c_str(), "");
6906
0
}
6907
6908
// Merge any layout qualifier information from src into dst, leaving everything else in dst alone
6909
//
6910
// "More than one layout qualifier may appear in a single declaration.
6911
// Additionally, the same layout-qualifier-name can occur multiple times
6912
// within a layout qualifier or across multiple layout qualifiers in the
6913
// same declaration. When the same layout-qualifier-name occurs
6914
// multiple times, in a single declaration, the last occurrence overrides
6915
// the former occurrence(s).  Further, if such a layout-qualifier-name
6916
// will effect subsequent declarations or other observable behavior, it
6917
// is only the last occurrence that will have any effect, behaving as if
6918
// the earlier occurrence(s) within the declaration are not present.
6919
// This is also true for overriding layout-qualifier-names, where one
6920
// overrides the other (e.g., row_major vs. column_major); only the last
6921
// occurrence has any effect."
6922
void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifier& src, bool inheritOnly)
6923
1.26M
{
6924
1.26M
    if (src.hasMatrix())
6925
0
        dst.layoutMatrix = src.layoutMatrix;
6926
1.26M
    if (src.hasPacking())
6927
0
        dst.layoutPacking = src.layoutPacking;
6928
6929
1.26M
    if (src.hasStream())
6930
218
        dst.layoutStream = src.layoutStream;
6931
1.26M
    if (src.hasFormat())
6932
0
        dst.layoutFormat = src.layoutFormat;
6933
1.26M
    if (src.hasXfbBuffer())
6934
872
        dst.layoutXfbBuffer = src.layoutXfbBuffer;
6935
1.26M
    if (src.hasBufferReferenceAlign())
6936
0
        dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign;
6937
6938
1.26M
    if (src.hasAlign())
6939
0
        dst.layoutAlign = src.layoutAlign;
6940
6941
1.26M
    if (! inheritOnly) {
6942
1.26M
        if (src.hasLocation())
6943
0
            dst.layoutLocation = src.layoutLocation;
6944
1.26M
        if (src.hasOffset())
6945
0
            dst.layoutOffset = src.layoutOffset;
6946
1.26M
        if (src.hasSet())
6947
0
            dst.layoutSet = src.layoutSet;
6948
1.26M
        if (src.layoutBinding != TQualifier::layoutBindingEnd)
6949
0
            dst.layoutBinding = src.layoutBinding;
6950
6951
1.26M
        if (src.hasSpecConstantId())
6952
0
            dst.layoutSpecConstantId = src.layoutSpecConstantId;
6953
6954
1.26M
        if (src.hasComponent())
6955
0
            dst.layoutComponent = src.layoutComponent;
6956
1.26M
        if (src.hasIndex())
6957
0
            dst.layoutIndex = src.layoutIndex;
6958
1.26M
        if (src.hasXfbStride())
6959
0
            dst.layoutXfbStride = src.layoutXfbStride;
6960
1.26M
        if (src.hasXfbOffset())
6961
0
            dst.layoutXfbOffset = src.layoutXfbOffset;
6962
1.26M
        if (src.hasAttachment())
6963
0
            dst.layoutAttachment = src.layoutAttachment;
6964
1.26M
        if (src.layoutPushConstant)
6965
0
            dst.layoutPushConstant = true;
6966
6967
1.26M
        if (src.layoutBufferReference)
6968
0
            dst.layoutBufferReference = true;
6969
6970
1.26M
        if (src.layoutPassthrough)
6971
0
            dst.layoutPassthrough = true;
6972
1.26M
        if (src.layoutViewportRelative)
6973
0
            dst.layoutViewportRelative = true;
6974
1.26M
        if (src.layoutSecondaryViewportRelativeOffset != -2048)
6975
0
            dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset;
6976
1.26M
        if (src.layoutShaderRecord)
6977
0
            dst.layoutShaderRecord = true;
6978
1.26M
        if (src.layoutFullQuads)
6979
0
            dst.layoutFullQuads = true;
6980
1.26M
        if (src.layoutQuadDeriv)
6981
0
            dst.layoutQuadDeriv = true;
6982
1.26M
        if (src.layoutBindlessSampler)
6983
0
            dst.layoutBindlessSampler = true;
6984
1.26M
        if (src.layoutBindlessImage)
6985
0
            dst.layoutBindlessImage = true;
6986
1.26M
        if (src.pervertexNV)
6987
0
            dst.pervertexNV = true;
6988
1.26M
        if (src.pervertexEXT)
6989
0
            dst.pervertexEXT = true;
6990
1.26M
        if (src.layoutHitObjectShaderRecordNV)
6991
0
            dst.layoutHitObjectShaderRecordNV = true;
6992
1.26M
        dst.layoutTileAttachmentQCOM |= src.layoutTileAttachmentQCOM;
6993
1.26M
    }
6994
1.26M
}
6995
6996
// Do error layout error checking given a full variable/block declaration.
6997
void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symbol)
6998
114k
{
6999
114k
    const TType& type = symbol.getType();
7000
114k
    const TQualifier& qualifier = type.getQualifier();
7001
7002
    // first, cross check WRT to just the type
7003
114k
    layoutTypeCheck(loc, type);
7004
7005
    // now, any remaining error checking based on the object itself
7006
7007
114k
    if (qualifier.hasAnyLocation()) {
7008
0
        switch (qualifier.storage) {
7009
0
        case EvqUniform:
7010
0
        case EvqBuffer:
7011
0
            if (symbol.getAsVariable() == nullptr)
7012
0
                error(loc, "can only be used on variable declaration", "location", "");
7013
0
            break;
7014
0
        default:
7015
0
            break;
7016
0
        }
7017
0
    }
7018
7019
    // user-variable location check, which are required for SPIR-V in/out:
7020
    //  - variables have it directly,
7021
    //  - blocks have it on each member (already enforced), so check first one
7022
114k
    if (spvVersion.spv > 0 && !parsingBuiltins && qualifier.builtIn == EbvNone &&
7023
114k
        !qualifier.hasLocation() && !intermediate.getAutoMapLocations()) {
7024
7025
0
        switch (qualifier.storage) {
7026
0
        case EvqVaryingIn:
7027
0
        case EvqVaryingOut:
7028
0
            if (!type.getQualifier().isTaskMemory() && !type.getQualifier().hasSpirvDecorate() &&
7029
0
                (type.getBasicType() != EbtBlock ||
7030
0
                 (!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
7031
0
                   (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone)))
7032
0
                error(loc, "SPIR-V requires location for user input/output", "location", "");
7033
0
            break;
7034
0
        default:
7035
0
            break;
7036
0
        }
7037
0
    }
7038
7039
    // Check packing and matrix
7040
114k
    if (qualifier.hasUniformLayout()) {
7041
0
        switch (qualifier.storage) {
7042
0
        case EvqUniform:
7043
0
        case EvqBuffer:
7044
0
            if (type.getBasicType() != EbtBlock) {
7045
0
                if (qualifier.hasMatrix())
7046
0
                    error(loc, "cannot specify matrix layout on a variable declaration", "layout", "");
7047
0
                if (qualifier.hasPacking())
7048
0
                    error(loc, "cannot specify packing on a variable declaration", "layout", "");
7049
                // "The offset qualifier can only be used on block members of blocks..."
7050
0
                if (qualifier.hasOffset() && !type.isAtomic())
7051
0
                    error(loc, "cannot specify on a variable declaration", "offset", "");
7052
                // "The align qualifier can only be used on blocks or block members..."
7053
0
                if (qualifier.hasAlign())
7054
0
                    error(loc, "cannot specify on a variable declaration", "align", "");
7055
0
                if (qualifier.isPushConstant())
7056
0
                    error(loc, "can only specify on a uniform block", "push_constant", "");
7057
0
                if (qualifier.isShaderRecord())
7058
0
                    error(loc, "can only specify on a buffer block", "shaderRecordNV", "");
7059
0
                if (qualifier.hasLocation() && type.isAtomic())
7060
0
                    error(loc, "cannot specify on atomic counter", "location", "");
7061
0
            }
7062
0
            break;
7063
0
        default:
7064
            // these were already filtered by layoutTypeCheck() (or its callees)
7065
0
            break;
7066
0
        }
7067
0
    }
7068
7069
    // Check that an in/out variable or block doesn't contain a boolean member
7070
    // Don't enforce if redeclaring a builtin, which are allowed to contain bool
7071
114k
    if (!parsingBuiltins && type.containsBasicType(EbtBool) && !builtInName(symbol.getName())) {
7072
37
        switch(qualifier.storage) {
7073
0
        case EvqVaryingIn:
7074
0
        case EvqVaryingOut:
7075
0
        {
7076
0
            const char *reason = type.getBasicType() == EbtBool ? "cannot be bool" : "cannot contain bool";
7077
0
            error(loc, reason, GetStorageQualifierString(qualifier.storage), "");
7078
0
            break;
7079
0
        }
7080
37
        default:
7081
37
            break;
7082
37
        }
7083
37
    }
7084
114k
}
7085
7086
// "For some blocks declared as arrays, the location can only be applied at the block level:
7087
// When a block is declared as an array where additional locations are needed for each member
7088
// for each block array element, it is a compile-time error to specify locations on the block
7089
// members.  That is, when locations would be under specified by applying them on block members,
7090
// they are not allowed on block members.  For arrayed interfaces (those generally having an
7091
// extra level of arrayness due to interface expansion), the outer array is stripped before
7092
// applying this rule."
7093
void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool memberWithLocation,
7094
    TArraySizes* arraySizes)
7095
1.91k
{
7096
1.91k
    if (memberWithLocation && arraySizes != nullptr) {
7097
0
        if (arraySizes->getNumDims() > (currentBlockQualifier.isArrayedIo(language) ? 1 : 0))
7098
0
            error(loc, "cannot use in a block array where new locations are needed for each block element",
7099
0
                       "location", "");
7100
0
    }
7101
1.91k
}
7102
7103
// Do layout error checking with respect to a type.
7104
void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
7105
124k
{
7106
124k
    const TQualifier& qualifier = type.getQualifier();
7107
7108
    // first, intra-layout qualifier-only error checking
7109
124k
    layoutQualifierCheck(loc, qualifier);
7110
7111
    // now, error checking combining type and qualifier
7112
7113
124k
    if (qualifier.hasAnyLocation()) {
7114
0
        if (qualifier.hasLocation()) {
7115
0
            if (qualifier.storage == EvqVaryingOut && language == EShLangFragment) {
7116
0
                if (qualifier.layoutLocation >= (unsigned int)resources.maxDrawBuffers)
7117
0
                    error(loc, "too large for fragment output", "location", "");
7118
0
            }
7119
0
        }
7120
0
        if (qualifier.hasComponent()) {
7121
            // "It is a compile-time error if this sequence of components gets larger than 3."
7122
0
            if (qualifier.layoutComponent + type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1) > 4)
7123
0
                error(loc, "type overflows the available 4 components", "component", "");
7124
7125
            // "It is a compile-time error to apply the component qualifier to a matrix, a structure, a block, or an array containing any of these."
7126
0
            if (type.isMatrix() || type.getBasicType() == EbtBlock || type.getBasicType() == EbtStruct)
7127
0
                error(loc, "cannot apply to a matrix, structure, or block", "component", "");
7128
7129
            // " It is a compile-time error to use component 1 or 3 as the beginning of a double or dvec2."
7130
0
            if (type.getBasicType() == EbtDouble)
7131
0
                if (qualifier.layoutComponent & 1)
7132
0
                    error(loc, "doubles cannot start on an odd-numbered component", "component", "");
7133
0
        }
7134
7135
0
        switch (qualifier.storage) {
7136
0
        case EvqVaryingIn:
7137
0
        case EvqVaryingOut:
7138
0
            if (type.getBasicType() == EbtBlock)
7139
0
                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "location qualifier on in/out block");
7140
0
            if (type.getQualifier().isTaskMemory())
7141
0
                error(loc, "cannot apply to taskNV in/out blocks", "location", "");
7142
0
            break;
7143
0
        case EvqUniform:
7144
0
        case EvqBuffer:
7145
0
            if (type.getBasicType() == EbtBlock)
7146
0
                error(loc, "cannot apply to uniform or buffer block", "location", "");
7147
0
            else if (type.getBasicType() == EbtSampler && type.getSampler().isAttachmentEXT())
7148
0
                error(loc, "only applies to", "location", "%s with storage tileImageEXT", type.getBasicTypeString().c_str());
7149
0
            break;
7150
0
        case EvqtaskPayloadSharedEXT:
7151
0
            error(loc, "cannot apply to taskPayloadSharedEXT", "location", "");
7152
0
            break;
7153
0
        case EvqPayload:
7154
0
        case EvqPayloadIn:
7155
0
        case EvqHitAttr:
7156
0
        case EvqCallableData:
7157
0
        case EvqCallableDataIn:
7158
0
        case EvqHitObjectAttrNV:
7159
0
        case EvqSpirvStorageClass:
7160
0
            break;
7161
0
        case EvqTileImageEXT:
7162
0
            break;
7163
0
        default:
7164
0
            error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
7165
0
            break;
7166
0
        }
7167
7168
0
        bool typeCollision;
7169
0
        int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision);
7170
0
        if (repeated >= 0 && ! typeCollision)
7171
0
            error(loc, "overlapping use of location", "location", "%d", repeated);
7172
        // When location aliasing, the aliases sharing the location must have the same underlying numerical type and bit width(
7173
        // floating - point or integer, 32 - bit versus 64 - bit,etc.)
7174
0
        if (typeCollision && (qualifier.isPipeInput() || qualifier.isPipeOutput() || qualifier.storage == EvqTileImageEXT))
7175
0
            error(loc, "the aliases sharing the location", "location", "%d must be the same basic type and interpolation qualification", repeated);
7176
0
    }
7177
7178
124k
    if (qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()) {
7179
0
        if (type.isUnsizedArray()) {
7180
0
            error(loc, "unsized array", "xfb_offset", "in buffer %d", qualifier.layoutXfbBuffer);
7181
0
        } else {
7182
0
            int repeated = intermediate.addXfbBufferOffset(type);
7183
0
            if (repeated >= 0)
7184
0
                error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer);
7185
0
        }
7186
7187
        // "The offset must be a multiple of the size of the first component of the first
7188
        // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate
7189
        // containing a double or 64-bit integer, the offset must also be a multiple of 8..."
7190
0
        if ((type.containsBasicType(EbtDouble) || type.containsBasicType(EbtInt64) || type.containsBasicType(EbtUint64)) &&
7191
0
            ! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8))
7192
0
            error(loc, "type contains double or 64-bit integer; xfb_offset must be a multiple of 8", "xfb_offset", "");
7193
0
        else if ((type.containsBasicType(EbtBool) || type.containsBasicType(EbtFloat) ||
7194
0
                  type.containsBasicType(EbtInt) || type.containsBasicType(EbtUint)) &&
7195
0
                 ! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
7196
0
            error(loc, "must be a multiple of size of first component", "xfb_offset", "");
7197
        // ..., if applied to an aggregate containing a half float or 16-bit integer, the offset must also be a multiple of 2..."
7198
0
        else if ((type.contains16BitFloat() || type.containsBasicType(EbtInt16) || type.containsBasicType(EbtUint16)) &&
7199
0
                 !IsMultipleOfPow2(qualifier.layoutXfbOffset, 2))
7200
0
            error(loc, "type contains half float or 16-bit integer; xfb_offset must be a multiple of 2", "xfb_offset", "");
7201
0
    }
7202
124k
    if (qualifier.hasXfbStride() && qualifier.hasXfbBuffer()) {
7203
0
        if (! intermediate.setXfbBufferStride(qualifier.layoutXfbBuffer, qualifier.layoutXfbStride))
7204
0
            error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
7205
0
    }
7206
7207
124k
    if (qualifier.hasBinding()) {
7208
        // Binding checking, from the spec:
7209
        //
7210
        // "If the binding point for any uniform or shader storage block instance is less than zero, or greater than or
7211
        // equal to the implementation-dependent maximum number of uniform buffer bindings, a compile-time
7212
        // error will occur. When the binding identifier is used with a uniform or shader storage block instanced as
7213
        // an array of size N, all elements of the array from binding through binding + N - 1 must be within this
7214
        // range."
7215
        //
7216
0
        if (!type.isOpaque() && type.getBasicType() != EbtBlock && type.getBasicType() != EbtSpirvType)
7217
0
            error(loc, "requires block, or sampler/image, or atomic-counter type", "binding", "");
7218
0
        if (type.getBasicType() == EbtSampler) {
7219
0
            int lastBinding = qualifier.layoutBinding;
7220
0
            if (type.isArray()) {
7221
0
                if (spvVersion.vulkan == 0) {
7222
0
                    if (type.isSizedArray())
7223
0
                        lastBinding += (type.getCumulativeArraySize() - 1);
7224
0
                    else {
7225
0
                        warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", "");
7226
0
                    }
7227
0
                }
7228
0
            }
7229
0
            if (spvVersion.vulkan == 0 && lastBinding >= resources.maxCombinedTextureImageUnits)
7230
0
                error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
7231
0
        }
7232
0
        if (type.isAtomic() && !spvVersion.vulkanRelaxed) {
7233
0
            if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
7234
0
                error(loc, "atomic_uint binding is too large; see gl_MaxAtomicCounterBindings", "binding", "");
7235
0
                return;
7236
0
            }
7237
0
        }
7238
124k
    } else if (!intermediate.getAutoMapBindings()) {
7239
        // some types require bindings
7240
7241
        // atomic_uint
7242
124k
        if (type.isAtomic())
7243
0
            error(loc, "layout(binding=X) is required", "atomic_uint", "");
7244
7245
        // SPIR-V
7246
124k
        if (spvVersion.spv > 0) {
7247
0
            if (qualifier.isUniformOrBuffer()) {
7248
0
                if (type.getBasicType() == EbtBlock && !qualifier.isPushConstant() &&
7249
0
                       !qualifier.isShaderRecord() &&
7250
0
                       !qualifier.hasAttachment() &&
7251
0
                       !qualifier.hasBufferReference())
7252
0
                    error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", "");
7253
0
                else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler && !type.getSampler().isAttachmentEXT())
7254
0
                    error(loc, "sampler/texture/image requires layout(binding=X)", "binding", "");
7255
0
            }
7256
0
        }
7257
124k
    }
7258
7259
    // some things can't have arrays of arrays
7260
124k
    if (type.isArrayOfArrays()) {
7261
652
        if (spvVersion.vulkan > 0) {
7262
540
            if (type.isOpaque() || (type.getQualifier().isUniformOrBuffer() && type.getBasicType() == EbtBlock))
7263
0
                warn(loc, "Generating SPIR-V array-of-arrays, but Vulkan only supports single array level for this resource", "[][]", "");
7264
540
        }
7265
652
    }
7266
7267
    // "The offset qualifier can only be used on block members of blocks..."
7268
124k
    if (qualifier.hasOffset()) {
7269
0
        if (type.getBasicType() == EbtBlock)
7270
0
            error(loc, "only applies to block members, not blocks", "offset", "");
7271
0
    }
7272
7273
    // Image format
7274
124k
    if (qualifier.hasFormat()) {
7275
0
        if (! type.isImage() && !intermediate.getBindlessImageMode())
7276
0
            error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
7277
0
        else {
7278
0
            if (type.getSampler().type == EbtFloat && qualifier.getFormat() > ElfFloatGuard)
7279
0
                error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
7280
0
            if (type.getSampler().type == EbtInt && (qualifier.getFormat() < ElfFloatGuard || qualifier.getFormat() > ElfIntGuard))
7281
0
                error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
7282
0
            if (type.getSampler().type == EbtUint && qualifier.getFormat() < ElfIntGuard)
7283
0
                error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
7284
7285
0
            if (isEsProfile()) {
7286
                // "Except for image variables qualified with the format qualifiers r32f, r32i, and r32ui, image variables must
7287
                // specify either memory qualifier readonly or the memory qualifier writeonly."
7288
0
                if (! (qualifier.getFormat() == ElfR32f || qualifier.getFormat() == ElfR32i || qualifier.getFormat() == ElfR32ui)) {
7289
0
                    if (! qualifier.isReadOnly() && ! qualifier.isWriteOnly())
7290
0
                        error(loc, "format requires readonly or writeonly memory qualifier", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
7291
0
                }
7292
0
            }
7293
0
        }
7294
124k
    } else if (type.isImage() && ! qualifier.isWriteOnly() && !intermediate.getBindlessImageMode()) {
7295
0
        const char *explanation = "image variables not declared 'writeonly' and without a format layout qualifier";
7296
0
        requireProfile(loc, ECoreProfile | ECompatibilityProfile, explanation);
7297
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shader_image_load_formatted, explanation);
7298
0
    }
7299
7300
124k
    if (qualifier.isPushConstant()) {
7301
0
        if (type.getBasicType() != EbtBlock)
7302
0
            error(loc, "can only be used with a block", "push_constant", "");
7303
0
        if (type.isArray())
7304
0
            error(loc, "Push constants blocks can't be an array", "push_constant", "");
7305
0
    }
7306
7307
124k
    if (type.getBasicType() == EbtReference) {
7308
0
        if (qualifier.isPipeInput())
7309
0
            error(loc, "cannot contain any structs with buffer_reference.", "in",
7310
0
                  "If you want to interface shader stages with a buffer_reference cast to a uint64 or uvec2 instead.");
7311
0
        if (qualifier.isPipeOutput())
7312
0
            error(loc, "cannot contain any structs with buffer_reference.", "out",
7313
0
                  "If you want to interface shader stages with a buffer_reference cast to a uint64 or uvec2 instead.");
7314
0
    }
7315
7316
124k
    if (qualifier.hasBufferReference() && type.getBasicType() != EbtBlock)
7317
0
        error(loc, "can only be used with a block", "buffer_reference", "");
7318
7319
124k
    if (qualifier.isShaderRecord() && type.getBasicType() != EbtBlock)
7320
0
        error(loc, "can only be used with a block", "shaderRecordNV", "");
7321
7322
    // input attachment
7323
124k
    if (type.isSubpass()) {
7324
0
        if (extensionTurnedOn(E_GL_EXT_shader_tile_image))
7325
0
            error(loc, "cannot be used with GL_EXT_shader_tile_image enabled", type.getSampler().getString().c_str(),
7326
0
                  "");
7327
0
        if (! qualifier.hasAttachment())
7328
0
            error(loc, "requires an input_attachment_index layout qualifier", "subpass", "");
7329
124k
    } else {
7330
124k
        if (qualifier.hasAttachment())
7331
0
            error(loc, "can only be used with a subpass", "input_attachment_index", "");
7332
124k
    }
7333
7334
    // specialization-constant id
7335
124k
    if (qualifier.hasSpecConstantId()) {
7336
0
        if (type.getQualifier().storage != EvqConst)
7337
0
            error(loc, "can only be applied to 'const'-qualified scalar", "constant_id", "");
7338
0
        if (! type.isScalar())
7339
0
            error(loc, "can only be applied to a scalar", "constant_id", "");
7340
0
        switch (type.getBasicType())
7341
0
        {
7342
0
        case EbtInt8:
7343
0
        case EbtUint8:
7344
0
        case EbtInt16:
7345
0
        case EbtUint16:
7346
0
        case EbtInt:
7347
0
        case EbtUint:
7348
0
        case EbtInt64:
7349
0
        case EbtUint64:
7350
0
        case EbtBool:
7351
0
        case EbtFloat:
7352
0
        case EbtDouble:
7353
0
        case EbtFloat16:
7354
0
        case EbtBFloat16:
7355
0
        case EbtFloatE5M2:
7356
0
        case EbtFloatE4M3:
7357
0
            break;
7358
0
        default:
7359
0
            error(loc, "cannot be applied to this type", "constant_id", "");
7360
0
            break;
7361
0
        }
7362
0
    }
7363
124k
}
7364
7365
static bool storageCanHaveLayoutInBlock(const enum TStorageQualifier storage)
7366
1.91k
{
7367
1.91k
    switch (storage) {
7368
0
    case EvqUniform:
7369
0
    case EvqBuffer:
7370
0
    case EvqShared:
7371
0
        return true;
7372
1.91k
    default:
7373
1.91k
        return false;
7374
1.91k
    }
7375
1.91k
}
7376
7377
// Do layout error checking that can be done within a layout qualifier proper, not needing to know
7378
// if there are blocks, atomic counters, variables, etc.
7379
void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier)
7380
124k
{
7381
124k
    if (qualifier.storage == EvqShared && qualifier.hasLayout()) {
7382
0
        if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) {
7383
0
            error(loc, "shared block requires at least SPIR-V 1.4", "shared block", "");
7384
0
        }
7385
0
        profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block");
7386
0
    }
7387
7388
    // "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
7389
124k
    if (qualifier.hasComponent() && ! qualifier.hasLocation())
7390
0
        error(loc, "must specify 'location' to use 'component'", "component", "");
7391
7392
124k
    if (qualifier.hasAnyLocation()) {
7393
7394
        // "As with input layout qualifiers, all shaders except compute shaders
7395
        // allow *location* layout qualifiers on output variable declarations,
7396
        // output block declarations, and output block member declarations."
7397
7398
0
        switch (qualifier.storage) {
7399
0
        case EvqVaryingIn:
7400
0
        {
7401
0
            const char* feature = "location qualifier on input";
7402
0
            if (isEsProfile() && version < 310)
7403
0
                requireStage(loc, EShLangVertex, feature);
7404
0
            else
7405
0
                requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
7406
0
            if (language == EShLangVertex) {
7407
0
                const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
7408
0
                profileRequires(loc, ~EEsProfile, 330, 2, exts, feature);
7409
0
                profileRequires(loc, EEsProfile, 300, nullptr, feature);
7410
0
            } else {
7411
0
                profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
7412
0
                profileRequires(loc, EEsProfile, 310, nullptr, feature);
7413
0
            }
7414
0
            break;
7415
0
        }
7416
0
        case EvqVaryingOut:
7417
0
        {
7418
0
            const char* feature = "location qualifier on output";
7419
0
            if (isEsProfile() && version < 310)
7420
0
                requireStage(loc, EShLangFragment, feature);
7421
0
            else
7422
0
                requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
7423
0
            if (language == EShLangFragment) {
7424
0
                const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
7425
0
                profileRequires(loc, ~EEsProfile, 330, 2, exts, feature);
7426
0
                profileRequires(loc, EEsProfile, 300, nullptr, feature);
7427
0
            } else {
7428
0
                profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
7429
0
                profileRequires(loc, EEsProfile, 310, nullptr, feature);
7430
0
            }
7431
0
            break;
7432
0
        }
7433
0
        case EvqUniform:
7434
0
        case EvqBuffer:
7435
0
        {
7436
0
            const char* feature = "location qualifier on uniform or buffer";
7437
0
            requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile | ENoProfile, feature);
7438
0
            profileRequires(loc, ~EEsProfile, 330, E_GL_ARB_explicit_attrib_location, feature);
7439
0
            profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_explicit_uniform_location, feature);
7440
0
            profileRequires(loc, EEsProfile, 310, nullptr, feature);
7441
0
            break;
7442
0
        }
7443
0
        default:
7444
0
            break;
7445
0
        }
7446
0
        if (qualifier.hasIndex()) {
7447
0
            if (qualifier.storage != EvqVaryingOut)
7448
0
                error(loc, "can only be used on an output", "index", "");
7449
0
            if (! qualifier.hasLocation())
7450
0
                error(loc, "can only be used with an explicit location", "index", "");
7451
0
        }
7452
0
    }
7453
7454
124k
    if (qualifier.hasBinding()) {
7455
0
        if (! qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory() && !qualifier.isTileAttachmentQCOM())
7456
0
            error(loc, "requires uniform or buffer or tile image storage qualifier", "binding", "");
7457
0
    }
7458
124k
    if (qualifier.hasStream()) {
7459
2.93k
        if (!qualifier.isPipeOutput())
7460
0
            error(loc, "can only be used on an output", "stream", "");
7461
2.93k
    }
7462
124k
    if (qualifier.hasXfb()) {
7463
11.2k
        if (!qualifier.isPipeOutput())
7464
0
            error(loc, "can only be used on an output", "xfb layout qualifier", "");
7465
11.2k
    }
7466
124k
    if (qualifier.hasUniformLayout()) {
7467
0
        if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory()) {
7468
0
            if (qualifier.hasMatrix() || qualifier.hasPacking())
7469
0
                error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", "");
7470
0
            if (qualifier.hasOffset() || qualifier.hasAlign())
7471
0
                error(loc, "offset/align can only be used on a uniform or buffer", "layout", "");
7472
0
        }
7473
0
    }
7474
124k
    if (qualifier.isPushConstant()) {
7475
0
        if (qualifier.storage != EvqUniform)
7476
0
            error(loc, "can only be used with a uniform", "push_constant", "");
7477
0
        if (qualifier.hasSet())
7478
0
            error(loc, "cannot be used with push_constant", "set", "");
7479
0
        if (qualifier.hasBinding())
7480
0
            error(loc, "cannot be used with push_constant", "binding", "");
7481
0
    }
7482
124k
    if (qualifier.hasBufferReference()) {
7483
0
        if (qualifier.storage != EvqBuffer)
7484
0
            error(loc, "can only be used with buffer", "buffer_reference", "");
7485
0
    }
7486
124k
    if (qualifier.isShaderRecord()) {
7487
0
        if (qualifier.storage != EvqBuffer)
7488
0
            error(loc, "can only be used with a buffer", "shaderRecordNV", "");
7489
0
        if (qualifier.hasBinding())
7490
0
            error(loc, "cannot be used with shaderRecordNV", "binding", "");
7491
0
        if (qualifier.hasSet())
7492
0
            error(loc, "cannot be used with shaderRecordNV", "set", "");
7493
7494
0
    }
7495
7496
124k
    if (qualifier.storage == EvqTileImageEXT) {
7497
0
        if (qualifier.hasSet())
7498
0
            error(loc, "cannot be used with tileImageEXT", "set", "");
7499
0
        if (!qualifier.hasLocation())
7500
0
            error(loc, "can only be used with an explicit location", "tileImageEXT", "");
7501
0
    }
7502
7503
124k
    if (qualifier.storage == EvqHitAttr && qualifier.hasLayout()) {
7504
0
        error(loc, "cannot apply layout qualifiers to hitAttributeNV variable", "hitAttributeNV", "");
7505
0
    }
7506
124k
}
7507
7508
// For places that can't have shader-level layout qualifiers
7509
void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQualifiers& shaderQualifiers)
7510
1.11M
{
7511
1.11M
    const char* message = "can only apply to a standalone qualifier";
7512
7513
1.11M
    if (shaderQualifiers.geometry != ElgNone)
7514
0
        error(loc, message, TQualifier::getGeometryString(shaderQualifiers.geometry), "");
7515
1.11M
    if (shaderQualifiers.spacing != EvsNone)
7516
0
        error(loc, message, TQualifier::getVertexSpacingString(shaderQualifiers.spacing), "");
7517
1.11M
    if (shaderQualifiers.order != EvoNone)
7518
0
        error(loc, message, TQualifier::getVertexOrderString(shaderQualifiers.order), "");
7519
1.11M
    if (shaderQualifiers.pointMode)
7520
0
        error(loc, message, "point_mode", "");
7521
1.11M
    if (shaderQualifiers.invocations != TQualifier::layoutNotSet)
7522
0
        error(loc, message, "invocations", "");
7523
4.47M
    for (int i = 0; i < 3; ++i) {
7524
3.35M
        if (shaderQualifiers.localSize[i] > 1)
7525
0
            error(loc, message, "local_size", "");
7526
3.35M
        if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
7527
0
            error(loc, message, "local_size id", "");
7528
3.35M
    }
7529
1.11M
    if (shaderQualifiers.vertices != TQualifier::layoutNotSet) {
7530
0
        if (language == EShLangGeometry || language == EShLangMesh)
7531
0
            error(loc, message, "max_vertices", "");
7532
0
        else if (language == EShLangTessControl)
7533
0
            error(loc, message, "vertices", "");
7534
0
        else
7535
0
            assert(0);
7536
0
    }
7537
1.11M
    if (shaderQualifiers.earlyFragmentTests)
7538
0
        error(loc, message, "early_fragment_tests", "");
7539
1.11M
    if (shaderQualifiers.postDepthCoverage)
7540
0
        error(loc, message, "post_depth_coverage", "");
7541
1.11M
    if (shaderQualifiers.nonCoherentColorAttachmentReadEXT)
7542
0
        error(loc, message, "non_coherent_color_attachment_readEXT", "");
7543
1.11M
    if (shaderQualifiers.nonCoherentDepthAttachmentReadEXT)
7544
0
        error(loc, message, "non_coherent_depth_attachment_readEXT", "");
7545
1.11M
    if (shaderQualifiers.nonCoherentStencilAttachmentReadEXT)
7546
0
        error(loc, message, "non_coherent_stencil_attachment_readEXT", "");
7547
1.11M
    if (shaderQualifiers.primitives != TQualifier::layoutNotSet) {
7548
0
        if (language == EShLangMesh)
7549
0
            error(loc, message, "max_primitives", "");
7550
0
        else
7551
0
            assert(0);
7552
0
    }
7553
1.11M
    if (shaderQualifiers.hasBlendEquation())
7554
0
        error(loc, message, "blend equation", "");
7555
1.11M
    if (shaderQualifiers.numViews != TQualifier::layoutNotSet)
7556
0
        error(loc, message, "num_views", "");
7557
1.11M
    if (shaderQualifiers.interlockOrdering != EioNone)
7558
0
        error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), "");
7559
1.11M
    if (shaderQualifiers.layoutPrimitiveCulling)
7560
0
        error(loc, "can only be applied as standalone", "primitive_culling", "");
7561
7562
1.11M
    if (shaderQualifiers.layoutNonCoherentTileAttachmentReadQCOM)
7563
0
        error(loc, message, "non_coherent_attachment_readQCOM", "");
7564
1.11M
    if (shaderQualifiers.layoutTileShadingRateQCOM[0] >= 1)
7565
0
        error(loc, message, "shading_rate_xQCOM", "");
7566
1.11M
    if (shaderQualifiers.layoutTileShadingRateQCOM[1] >= 1)
7567
0
        error(loc, message, "shading_rate_yQCOM", "");
7568
1.11M
    if (shaderQualifiers.layoutTileShadingRateQCOM[2] >= 1)
7569
0
        error(loc, message, "shading_rate_zQCOM", "");
7570
1.11M
}
7571
7572
// Correct and/or advance an object's offset layout qualifier.
7573
void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
7574
112k
{
7575
112k
    const TQualifier& qualifier = symbol.getType().getQualifier();
7576
112k
    if (symbol.getType().isAtomic()) {
7577
0
        if (qualifier.hasBinding() && (int)qualifier.layoutBinding < resources.maxAtomicCounterBindings) {
7578
7579
            // Set the offset
7580
0
            int offset;
7581
0
            if (qualifier.hasOffset())
7582
0
                offset = qualifier.layoutOffset;
7583
0
            else
7584
0
                offset = atomicUintOffsets[qualifier.layoutBinding];
7585
7586
0
            if (offset % 4 != 0)
7587
0
                error(loc, "atomic counters offset should align based on 4:", "offset", "%d", offset);
7588
7589
0
            symbol.getWritableType().getQualifier().layoutOffset = offset;
7590
7591
            // Check for overlap
7592
0
            int numOffsets = 4;
7593
0
            if (symbol.getType().isArray()) {
7594
0
                if (symbol.getType().isSizedArray() && !symbol.getType().getArraySizes()->isInnerUnsized())
7595
0
                    numOffsets *= symbol.getType().getCumulativeArraySize();
7596
0
                else {
7597
                    // "It is a compile-time error to declare an unsized array of atomic_uint."
7598
0
                    error(loc, "array must be explicitly sized", "atomic_uint", "");
7599
0
                }
7600
0
            }
7601
0
            int repeated = intermediate.addUsedOffsets(qualifier.layoutBinding, offset, numOffsets);
7602
0
            if (repeated >= 0)
7603
0
                error(loc, "atomic counters sharing the same offset:", "offset", "%d", repeated);
7604
7605
            // Bump the default offset
7606
0
            atomicUintOffsets[qualifier.layoutBinding] = offset + numOffsets;
7607
0
        }
7608
0
    }
7609
112k
}
7610
7611
//
7612
// Look up a function name in the symbol table, and make sure it is a function.
7613
//
7614
// Return the function symbol if found, otherwise nullptr.
7615
//
7616
const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
7617
89
{
7618
89
    if (symbolTable.isFunctionNameVariable(call.getName())) {
7619
1
        error(loc, "can't use function syntax on variable", call.getName().c_str(), "");
7620
1
        return nullptr;
7621
1
    }
7622
7623
88
    const TFunction* function = nullptr;
7624
7625
    // debugPrintfEXT has var args and is in the symbol table as "debugPrintfEXT()",
7626
    // mangled to "debugPrintfEXT("
7627
88
    if (call.getName() == "debugPrintfEXT") {
7628
0
        TSymbol* symbol = symbolTable.find("debugPrintfEXT(", &builtIn);
7629
0
        if (symbol)
7630
0
            return symbol->getAsFunction();
7631
0
    }
7632
7633
    // coopMatPerElementNV is variadic. There is some function signature error
7634
    // checking in handleCoopMat2FunctionCall.
7635
88
    if (call.getName() == "coopMatPerElementNV") {
7636
0
        TSymbol* symbol = symbolTable.find("coopMatPerElementNV(", &builtIn);
7637
0
        if (symbol)
7638
0
            return symbol->getAsFunction();
7639
0
    }
7640
7641
88
    if (call.getName() == "saturatedConvertEXT") {
7642
0
        TSymbol* symbol = symbolTable.find("saturatedConvertEXT(", &builtIn);
7643
0
        if (symbol)
7644
0
            return symbol->getAsFunction();
7645
0
    }
7646
7647
88
    bool explicitTypesEnabled = extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types) ||
7648
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int8) ||
7649
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int16) ||
7650
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int32) ||
7651
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int64) ||
7652
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float16) ||
7653
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float32) ||
7654
88
                                extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float64);
7655
7656
88
    if (isEsProfile())
7657
10
        function = (explicitTypesEnabled && version >= 310)
7658
10
                   ? findFunctionExplicitTypes(loc, call, builtIn)
7659
10
                   : ((extensionTurnedOn(E_GL_EXT_shader_implicit_conversions) && version >= 310)
7660
10
                      ? findFunction120(loc, call, builtIn)
7661
10
                      : findFunctionExact(loc, call, builtIn));
7662
78
    else if (version < 120)
7663
0
        function = findFunctionExact(loc, call, builtIn);
7664
78
    else if (version < 400) {
7665
0
        bool needfindFunction400 = extensionTurnedOn(E_GL_ARB_gpu_shader_fp64)
7666
0
                                  || extensionTurnedOn(E_GL_ARB_gpu_shader5)
7667
0
                                  || extensionTurnedOn(E_GL_NV_gpu_shader5);
7668
0
        function = needfindFunction400 ? findFunction400(loc, call, builtIn) : findFunction120(loc, call, builtIn);
7669
0
    }
7670
78
    else if (explicitTypesEnabled)
7671
0
        function = findFunctionExplicitTypes(loc, call, builtIn);
7672
78
    else
7673
78
        function = findFunction400(loc, call, builtIn);
7674
7675
88
    return function;
7676
88
}
7677
7678
// Function finding algorithm for ES and desktop 110.
7679
const TFunction* TParseContext::findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
7680
10
{
7681
10
    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
7682
10
    if (symbol == nullptr) {
7683
10
        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
7684
7685
10
        return nullptr;
7686
10
    }
7687
7688
0
    return symbol->getAsFunction();
7689
10
}
7690
7691
// Function finding algorithm for desktop versions 120 through 330.
7692
const TFunction* TParseContext::findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
7693
0
{
7694
    // first, look for an exact match
7695
0
    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
7696
0
    if (symbol)
7697
0
        return symbol->getAsFunction();
7698
7699
    // exact match not found, look through a list of overloaded functions of the same name
7700
7701
    // "If no exact match is found, then [implicit conversions] will be applied to find a match. Mismatched types
7702
    // on input parameters (in or inout or default) must have a conversion from the calling argument type to the
7703
    // formal parameter type. Mismatched types on output parameters (out or inout) must have a conversion
7704
    // from the formal parameter type to the calling argument type.  When argument conversions are used to find
7705
    // a match, it is a semantic error if there are multiple ways to apply these conversions to make the call match
7706
    // more than one function."
7707
7708
0
    const TFunction* candidate = nullptr;
7709
0
    TVector<const TFunction*> candidateList;
7710
0
    symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
7711
7712
0
    for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
7713
0
        const TFunction& function = *(*it);
7714
7715
        // to even be a potential match, number of arguments has to match
7716
0
        if (call.getParamCount() != function.getParamCount())
7717
0
            continue;
7718
7719
0
        bool possibleMatch = true;
7720
0
        for (int i = 0; i < function.getParamCount(); ++i) {
7721
            // same types is easy
7722
0
            if (*function[i].type == *call[i].type)
7723
0
                continue;
7724
7725
            // We have a mismatch in type, see if it is implicitly convertible
7726
7727
0
            if (function[i].type->isArray() || call[i].type->isArray() ||
7728
0
                ! function[i].type->sameElementShape(*call[i].type))
7729
0
                possibleMatch = false;
7730
0
            else {
7731
                // do direction-specific checks for conversion of basic type
7732
0
                if (function[i].type->getQualifier().isParamInput()) {
7733
0
                    if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
7734
0
                        possibleMatch = false;
7735
0
                }
7736
0
                if (function[i].type->getQualifier().isParamOutput()) {
7737
0
                    if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
7738
0
                        possibleMatch = false;
7739
0
                }
7740
0
            }
7741
0
            if (! possibleMatch)
7742
0
                break;
7743
0
        }
7744
0
        if (possibleMatch) {
7745
0
            if (candidate) {
7746
                // our second match, meaning ambiguity
7747
0
                error(loc, "ambiguous function signature match: multiple signatures match under implicit type conversion", call.getName().c_str(), "");
7748
0
            } else
7749
0
                candidate = &function;
7750
0
        }
7751
0
    }
7752
7753
0
    if (candidate == nullptr)
7754
0
        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
7755
7756
0
    return candidate;
7757
0
}
7758
7759
// Function finding algorithm for desktop version 400 and above.
7760
//
7761
// "When function calls are resolved, an exact type match for all the arguments
7762
// is sought. If an exact match is found, all other functions are ignored, and
7763
// the exact match is used. If no exact match is found, then the implicit
7764
// conversions in section 4.1.10 Implicit Conversions will be applied to find
7765
// a match. Mismatched types on input parameters (in or inout or default) must
7766
// have a conversion from the calling argument type to the formal parameter type.
7767
// Mismatched types on output parameters (out or inout) must have a conversion
7768
// from the formal parameter type to the calling argument type.
7769
//
7770
// "If implicit conversions can be used to find more than one matching function,
7771
// a single best-matching function is sought. To determine a best match, the
7772
// conversions between calling argument and formal parameter types are compared
7773
// for each function argument and pair of matching functions. After these
7774
// comparisons are performed, each pair of matching functions are compared.
7775
// A function declaration A is considered a better match than function
7776
// declaration B if
7777
//
7778
//  * for at least one function argument, the conversion for that argument in A
7779
//    is better than the corresponding conversion in B; and
7780
//  * there is no function argument for which the conversion in B is better than
7781
//    the corresponding conversion in A.
7782
//
7783
// "If a single function declaration is considered a better match than every
7784
// other matching function declaration, it will be used. Otherwise, a
7785
// compile-time semantic error for an ambiguous overloaded function call occurs.
7786
//
7787
// "To determine whether the conversion for a single argument in one match is
7788
// better than that for another match, the following rules are applied, in order:
7789
//
7790
//  1. An exact match is better than a match involving any implicit conversion.
7791
//  2. A match involving an implicit conversion from float to double is better
7792
//     than a match involving any other implicit conversion.
7793
//  3. A match involving an implicit conversion from either int or uint to float
7794
//     is better than a match involving an implicit conversion from either int
7795
//     or uint to double.
7796
//
7797
// "If none of the rules above apply to a particular pair of conversions, neither
7798
// conversion is considered better than the other."
7799
//
7800
const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
7801
78
{
7802
    // first, look for an exact match
7803
78
    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
7804
78
    if (symbol)
7805
0
        return symbol->getAsFunction();
7806
7807
    // no exact match, use the generic selector, parameterized by the GLSL rules
7808
7809
    // create list of candidates to send
7810
78
    TVector<const TFunction*> candidateList;
7811
78
    symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
7812
7813
    // can 'from' convert to 'to'?
7814
78
    const auto convertible = [this,builtIn](const TType& from, const TType& to, TOperator op, int param) -> bool {
7815
0
        if (from == to)
7816
0
            return true;
7817
0
        if (from.coopMatParameterOK(to))
7818
0
            return true;
7819
0
        if (from.tensorParameterOK(to))
7820
0
            return true;
7821
0
        if (from.getBasicType() == EbtFunction && to.getBasicType() == EbtFunction)
7822
0
            return true;
7823
0
        if (from.coopVecParameterOK(to))
7824
0
            return true;
7825
        // Allow a sized array to be passed through an unsized array parameter, for coopMatLoad/Store functions
7826
0
        if (builtIn && from.isArray() && to.isUnsizedArray()) {
7827
0
            TType fromElementType(from, 0);
7828
0
            TType toElementType(to, 0);
7829
            // Load/store tensor functions allow any element type for the pointer
7830
0
            if ((op == EOpCooperativeMatrixLoadTensorNV || op == EOpCooperativeMatrixStoreTensorNV) &&
7831
0
                param == 1 &&
7832
0
                (from.getQualifier().storage == EvqBuffer || from.getQualifier().storage == EvqShared)) {
7833
0
                return true;
7834
0
            }
7835
0
            if (fromElementType == toElementType)
7836
0
                return true;
7837
0
        }
7838
0
        if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
7839
0
            return false;
7840
0
        if (from.isCoopMat() && to.isCoopMat())
7841
0
            return from.sameCoopMatBaseType(to);
7842
0
        if (from.isCoopVecNV() && to.isCoopVecNV())
7843
0
            return from.sameCoopVecBaseType(to);
7844
0
        if (from.isTensorARM() && to.isTensorARM())
7845
0
            return from.sameTensorBaseTypeARM(to);
7846
0
        return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
7847
0
    };
7848
7849
    // Is 'to2' a better conversion than 'to1'?
7850
    // Ties should not be considered as better.
7851
    // Assumes 'convertible' already said true.
7852
78
    const auto better = [&](const TType& from, const TType& to1, const TType& to2) -> bool {
7853
        // 1. exact match
7854
0
        if (from == to2)
7855
0
            return from != to1;
7856
0
        if (from == to1)
7857
0
            return false;
7858
0
        if (extensionTurnedOn(E_GL_NV_gpu_shader5)) {
7859
            // This map refers to the conversion table mentioned under the 
7860
            // section "Modify Section 6.1, Function Definitions, p. 63" in NV_gpu_shader5 spec
7861
0
            const static std::map<int, std::vector<int>> conversionTable = {
7862
0
                {EbtInt8,   {EbtInt, EbtInt64}},
7863
0
                {EbtInt16,  {EbtInt, EbtInt64}},
7864
0
                {EbtInt,    {EbtInt64}},
7865
0
                {EbtUint8,  {EbtUint, EbtUint64}}, 
7866
0
                {EbtUint16, {EbtUint, EbtUint64}}, 
7867
0
                {EbtUint,   {EbtUint64}},
7868
0
            };
7869
0
            auto source = conversionTable.find(from.getBasicType());
7870
0
            if (source != conversionTable.end()) {
7871
0
                for (auto destination : source->second) {
7872
0
                    if (to2.getBasicType() == destination &&
7873
0
                        to1.getBasicType() != destination) // to2 is better then to1
7874
0
                        return true;
7875
0
                    else if (to1.getBasicType() == destination &&
7876
0
                             to2.getBasicType() != destination) // This means to1 is better then to2
7877
0
                        return false;
7878
0
                }
7879
0
            }
7880
0
        }
7881
        // 2. float -> double is better
7882
0
        if (from.getBasicType() == EbtFloat) {
7883
0
            if (to2.getBasicType() == EbtDouble && to1.getBasicType() != EbtDouble)
7884
0
                return true;
7885
0
        }
7886
7887
        // 3. -> float is better than -> double
7888
0
        return to2.getBasicType() == EbtFloat && to1.getBasicType() == EbtDouble;
7889
0
    };
7890
7891
    // for ambiguity reporting
7892
78
    bool tie = false;
7893
7894
    // send to the generic selector
7895
78
    const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie);
7896
7897
78
    if (bestMatch == nullptr)
7898
78
        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
7899
0
    else if (tie)
7900
0
        error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), "");
7901
7902
78
    return bestMatch;
7903
78
}
7904
7905
// "To determine whether the conversion for a single argument in one match
7906
//  is better than that for another match, the conversion is assigned of the
7907
//  three ranks ordered from best to worst:
7908
//   1. Exact match: no conversion.
7909
//    2. Promotion: integral or floating-point promotion.
7910
//    3. Conversion: integral conversion, floating-point conversion,
7911
//       floating-integral conversion.
7912
//  A conversion C1 is better than a conversion C2 if the rank of C1 is
7913
//  better than the rank of C2."
7914
const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
7915
0
{
7916
    // first, look for an exact match
7917
0
    TSymbol* symbol = symbolTable.find(call.getMangledName(), &builtIn);
7918
0
    if (symbol)
7919
0
        return symbol->getAsFunction();
7920
7921
    // no exact match, use the generic selector, parameterized by the GLSL rules
7922
7923
    // create list of candidates to send
7924
0
    TVector<const TFunction*> candidateList;
7925
0
    symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
7926
7927
    // can 'from' convert to 'to'?
7928
0
    const auto convertible = [this,builtIn](const TType& from, const TType& to, TOperator op, int param) -> bool {
7929
0
        if (from == to)
7930
0
            return true;
7931
0
        if (from.coopMatParameterOK(to))
7932
0
            return true;
7933
0
        if (from.tensorParameterOK(to))
7934
0
            return true;
7935
0
        if (from.getBasicType() == EbtFunction && to.getBasicType() == EbtFunction)
7936
0
            return true;
7937
0
        if (from.coopVecParameterOK(to))
7938
0
            return true;
7939
        // Allow a sized array to be passed through an unsized array parameter, for coopMatLoad/Store functions
7940
0
        if (builtIn && from.isArray() && to.isUnsizedArray()) {
7941
0
            TType fromElementType(from, 0);
7942
0
            TType toElementType(to, 0);
7943
            // Load/store tensor functions allow any element type for the pointer
7944
0
            if ((op == EOpCooperativeMatrixLoadTensorNV || op == EOpCooperativeMatrixStoreTensorNV) &&
7945
0
                param == 1 &&
7946
0
                (from.getQualifier().storage == EvqBuffer || from.getQualifier().storage == EvqShared)) {
7947
0
                return true;
7948
0
            }
7949
0
            if (fromElementType == toElementType)
7950
0
                return true;
7951
0
        }
7952
0
        if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
7953
0
            return false;
7954
0
        if (from.isCoopMat() && to.isCoopMat())
7955
0
            return from.sameCoopMatBaseType(to);
7956
0
        if (from.isCoopVecNV() && to.isCoopVecNV())
7957
0
            return from.sameCoopVecBaseType(to);
7958
0
        if (from.isTensorARM() && to.isTensorARM())
7959
0
            return from.sameTensorBaseTypeARM(to);
7960
0
        return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
7961
0
    };
7962
7963
    // Is 'to2' a better conversion than 'to1'?
7964
    // Ties should not be considered as better.
7965
    // Assumes 'convertible' already said true.
7966
0
    const auto better = [this](const TType& from, const TType& to1, const TType& to2) -> bool {
7967
        // 1. exact match
7968
0
        if (from == to2)
7969
0
            return from != to1;
7970
0
        if (from == to1)
7971
0
            return false;
7972
7973
        // 2. Promotion (integral, floating-point) is better
7974
0
        TBasicType from_type = from.getBasicType();
7975
0
        TBasicType to1_type = to1.getBasicType();
7976
0
        TBasicType to2_type = to2.getBasicType();
7977
0
        bool isPromotion1 = (intermediate.isIntegralPromotion(from_type, to1_type) ||
7978
0
                             intermediate.isFPPromotion(from_type, to1_type));
7979
0
        bool isPromotion2 = (intermediate.isIntegralPromotion(from_type, to2_type) ||
7980
0
                             intermediate.isFPPromotion(from_type, to2_type));
7981
0
        if (isPromotion2)
7982
0
            return !isPromotion1;
7983
0
        if(isPromotion1)
7984
0
            return false;
7985
7986
        // 3. Conversion (integral, floating-point , floating-integral)
7987
0
        bool isConversion1 = (intermediate.isIntegralConversion(from_type, to1_type) ||
7988
0
                              intermediate.isFPConversion(from_type, to1_type) ||
7989
0
                              intermediate.isFPIntegralConversion(from_type, to1_type));
7990
0
        bool isConversion2 = (intermediate.isIntegralConversion(from_type, to2_type) ||
7991
0
                              intermediate.isFPConversion(from_type, to2_type) ||
7992
0
                              intermediate.isFPIntegralConversion(from_type, to2_type));
7993
7994
0
        return isConversion2 && !isConversion1;
7995
0
    };
7996
7997
    // for ambiguity reporting
7998
0
    bool tie = false;
7999
8000
    // send to the generic selector
8001
0
    const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie);
8002
8003
0
    if (bestMatch == nullptr)
8004
0
        error(loc, "no matching overloaded function found", call.getName().c_str(), "");
8005
0
    else if (tie)
8006
0
        error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), "");
8007
8008
0
    return bestMatch;
8009
0
}
8010
8011
//
8012
// Adjust function calls that aren't declared in Vulkan to a
8013
// calls with equivalent effects
8014
//
8015
TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments)
8016
0
{
8017
0
    TIntermTyped* result = nullptr;
8018
8019
0
    if (function->getBuiltInOp() != EOpNull) {
8020
0
        return nullptr;
8021
0
    }
8022
8023
0
    if (function->getName() == "atomicCounterIncrement") {
8024
        // change atomicCounterIncrement into an atomicAdd of 1
8025
0
        TString name("atomicAdd");
8026
0
        TType uintType(EbtUint);
8027
8028
0
        TFunction realFunc(&name, function->getType());
8029
8030
        // Use copyParam to avoid shared ownership of the 'type' field
8031
        // of the parameter.
8032
0
        for (int i = 0; i < function->getParamCount(); ++i) {
8033
0
            realFunc.addParameter(TParameter().copyParam((*function)[i]));
8034
0
        }
8035
8036
0
        TParameter tmpP = { nullptr, &uintType, {} };
8037
0
        realFunc.addParameter(TParameter().copyParam(tmpP));
8038
0
        arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(1, loc, true));
8039
8040
0
        result = handleFunctionCall(loc, &realFunc, arguments);
8041
0
    } else if (function->getName() == "atomicCounterDecrement") {
8042
        // change atomicCounterDecrement into an atomicAdd with -1
8043
        // and subtract 1 from result, to return post-decrement value
8044
0
        TString name("atomicAdd");
8045
0
        TType uintType(EbtUint);
8046
8047
0
        TFunction realFunc(&name, function->getType());
8048
8049
0
        for (int i = 0; i < function->getParamCount(); ++i) {
8050
0
            realFunc.addParameter(TParameter().copyParam((*function)[i]));
8051
0
        }
8052
8053
0
        TParameter tmpP = { nullptr, &uintType, {} };
8054
0
        realFunc.addParameter(TParameter().copyParam(tmpP));
8055
0
        arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(-1, loc, true));
8056
8057
0
        result = handleFunctionCall(loc, &realFunc, arguments);
8058
8059
        // post decrement, so that it matches AtomicCounterDecrement semantics
8060
0
        if (result) {
8061
0
            result = handleBinaryMath(loc, "-", EOpSub, result, intermediate.addConstantUnion(1, loc, true));
8062
0
        }
8063
0
    } else if (function->getName() == "atomicCounter") {
8064
        // change atomicCounter into a direct read of the variable
8065
0
        if (arguments && arguments->getAsTyped()) {
8066
0
            result = arguments->getAsTyped();
8067
0
        }
8068
0
    }
8069
8070
0
    return result;
8071
0
}
8072
8073
// When a declaration includes a type, but not a variable name, it can be used
8074
// to establish defaults.
8075
void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType)
8076
2.05k
{
8077
2.05k
    if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding()) {
8078
0
        if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
8079
0
            error(loc, "atomic_uint binding is too large", "binding", "");
8080
0
            return;
8081
0
        }
8082
0
        if (publicType.qualifier.hasOffset())
8083
0
            atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
8084
0
        return;
8085
0
    }
8086
8087
2.05k
    if (publicType.arraySizes) {
8088
2
        error(loc, "expect an array name", "", "");
8089
2
    }
8090
8091
2.05k
    if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference())
8092
0
        warn(loc, "useless application of layout qualifier", "layout", "");
8093
2.05k
}
8094
8095
void TParseContext::typeParametersCheck(const TSourceLoc& loc, const TPublicType& publicType)
8096
8.88M
{
8097
8.88M
    if (parsingBuiltins)
8098
8.88M
        return;
8099
4.16k
    if (publicType.isCoopmatKHR()) {
8100
0
        if (publicType.typeParameters == nullptr) {
8101
0
            error(loc, "coopmat missing type parameters", "", "");
8102
0
            return;
8103
0
        }
8104
0
        switch (publicType.typeParameters->basicType) {
8105
0
        case EbtFloat:
8106
0
        case EbtFloat16:
8107
0
        case EbtBFloat16:
8108
0
        case EbtFloatE5M2:
8109
0
        case EbtFloatE4M3:
8110
0
        case EbtInt:
8111
0
        case EbtInt8:
8112
0
        case EbtInt16:
8113
0
        case EbtUint:
8114
0
        case EbtUint8:
8115
0
        case EbtUint16:
8116
0
        case EbtSpirvType:
8117
0
            break;
8118
0
        default:
8119
0
            error(loc, "coopmat invalid basic type", TType::getBasicString(publicType.typeParameters->basicType), "");
8120
0
            break;
8121
0
        }
8122
0
        if (publicType.typeParameters->arraySizes->getNumDims() != 4) {
8123
0
            error(loc, "coopmat incorrect number of type parameters", "", "");
8124
0
            return;
8125
0
        }
8126
0
        int use = publicType.typeParameters->arraySizes->getDimSize(3);
8127
0
        if (use < 0 || use > 2) {
8128
0
            error(loc, "coopmat invalid matrix Use", "", "");
8129
0
            return;
8130
0
        }
8131
0
    }
8132
4.16k
    if (publicType.isTensorLayoutNV()) {
8133
0
        if (publicType.typeParameters == nullptr) {
8134
0
            error(loc, "tensorLayout missing type parameters", "", "");
8135
0
            return;
8136
0
        }
8137
0
        if (publicType.typeParameters->arraySizes->getNumDims() > 2) {
8138
0
            error(loc, "tensorLayout incorrect number of type parameters", "", "");
8139
0
            return;
8140
0
        }
8141
0
        if (publicType.typeParameters && publicType.typeParameters->arraySizes->getNumDims() < 2) {
8142
0
            while (publicType.typeParameters->arraySizes->getNumDims() < 2) {
8143
0
                publicType.typeParameters->arraySizes->addInnerSize(0);
8144
0
            }
8145
0
        }
8146
0
    }
8147
4.16k
    if (publicType.isTensorViewNV()) {
8148
0
        if (publicType.typeParameters == nullptr) {
8149
0
            error(loc, "tensorView missing type parameters", "", "");
8150
0
            return;
8151
0
        }
8152
0
        if (publicType.typeParameters->arraySizes->getNumDims() < 1 ||
8153
0
            publicType.typeParameters->arraySizes->getNumDims() > 7) {
8154
0
            error(loc, "tensorView incorrect number of type parameters", "", "");
8155
0
            return;
8156
0
        }
8157
0
        if (publicType.typeParameters && publicType.typeParameters->arraySizes->getNumDims() < 7) {
8158
0
            uint32_t numDims = publicType.typeParameters->arraySizes->getNumDims();
8159
0
            while (numDims < 7) {
8160
0
                uint32_t dim = (numDims == 1) ? 0 : (numDims - 2);
8161
0
                publicType.typeParameters->arraySizes->addInnerSize(dim);
8162
0
                numDims++;
8163
0
            }
8164
0
        }
8165
0
    }
8166
4.16k
    if (publicType.isTensorARM()) {
8167
0
        if (publicType.typeParameters == nullptr) {
8168
0
            error(loc, "tensor type is missing type parameters", "", "");
8169
0
            return;
8170
0
        }
8171
0
        if (publicType.typeParameters->arraySizes == nullptr) {
8172
0
            error(loc, "tensor type is missing rank information", "", "");
8173
0
            return;
8174
0
        }
8175
0
        if (publicType.typeParameters->arraySizes->getNumDims() != 1) {
8176
0
            error(loc, "tensor type requires exactly 1 rank specifier", "", "");
8177
0
            return;
8178
0
        }
8179
0
        if (publicType.typeParameters->arraySizes->getDimSize(0) < 1) {
8180
0
            error(loc, "tensor rank must be greater than or equal to 1", "", "");
8181
0
            return;
8182
0
        }
8183
0
    }
8184
4.16k
}
8185
8186
bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType,
8187
    TArraySizes*, TIntermTyped* initializer, TType& type)
8188
0
{
8189
0
    vkRelaxedRemapUniformMembers(loc, publicType, type, identifier);
8190
8191
0
    if (parsingBuiltins || symbolTable.atBuiltInLevel() || !symbolTable.atGlobalLevel() ||
8192
0
        type.getQualifier().storage != EvqUniform ||
8193
0
        !(type.containsNonOpaque() || type.getBasicType() == EbtAtomicUint || (type.containsSampler() && type.isStruct()))) {
8194
0
        return false;
8195
0
    }
8196
8197
0
    if (type.getQualifier().hasLocation()) {
8198
0
        warn(loc, "ignoring layout qualifier for uniform", identifier.c_str(), "location");
8199
0
        type.getQualifier().layoutLocation = TQualifier::layoutLocationEnd;
8200
0
    }
8201
8202
0
    if (initializer) {
8203
0
        warn(loc, "Ignoring initializer for uniform", identifier.c_str(), "");
8204
0
        initializer = nullptr;
8205
0
    }
8206
8207
0
    if (type.isArray()) {
8208
        // do array size checks here
8209
0
        arraySizesCheck(loc, type.getQualifier(), type.getArraySizes(), initializer, false);
8210
8211
0
        if (arrayQualifierError(loc, type.getQualifier()) || arrayError(loc, type)) {
8212
0
            error(loc, "array param error", identifier.c_str(), "");
8213
0
        }
8214
0
    }
8215
8216
    // do some checking on the type as it was declared
8217
0
    layoutTypeCheck(loc, type);
8218
8219
0
    int bufferBinding = TQualifier::layoutBindingEnd;
8220
0
    TVariable* updatedBlock = nullptr;
8221
8222
    // Convert atomic_uint into members of a buffer block
8223
0
    if (type.isAtomic()) {
8224
0
        type.setBasicType(EbtUint);
8225
0
        type.getQualifier().storage = EvqBuffer;
8226
8227
0
        type.getQualifier().volatil = true;
8228
0
        type.getQualifier().coherent = true;
8229
8230
        // xxTODO: use logic from fixOffset() to apply explicit member offset
8231
0
        bufferBinding = type.getQualifier().layoutBinding;
8232
0
        type.getQualifier().layoutBinding = TQualifier::layoutBindingEnd;
8233
0
        type.getQualifier().explicitOffset = false;
8234
0
        growAtomicCounterBlock(bufferBinding, loc, type, identifier, nullptr);
8235
0
        updatedBlock = atomicCounterBuffers[bufferBinding];
8236
0
    }
8237
8238
0
    if (!updatedBlock) {
8239
0
        growGlobalUniformBlock(loc, type, identifier, nullptr);
8240
0
        updatedBlock = globalUniformBlock;
8241
0
    }
8242
8243
    //
8244
    //      don't assign explicit member offsets here
8245
    //      if any are assigned, need to be updated here and in the merge/link step
8246
    // fixBlockUniformOffsets(updatedBlock->getWritableType().getQualifier(), *updatedBlock->getWritableType().getWritableStruct());
8247
8248
    // checks on update buffer object
8249
0
    layoutObjectCheck(loc, *updatedBlock);
8250
8251
0
    TSymbol* symbol = symbolTable.find(identifier);
8252
8253
0
    if (!symbol) {
8254
0
        if (updatedBlock == globalUniformBlock)
8255
0
            error(loc, "error adding uniform to default uniform block", identifier.c_str(), "");
8256
0
        else
8257
0
            error(loc, "error adding atomic counter to atomic counter block", identifier.c_str(), "");
8258
0
        return false;
8259
0
    }
8260
8261
    // merge qualifiers
8262
0
    mergeObjectLayoutQualifiers(updatedBlock->getWritableType().getQualifier(), type.getQualifier(), true);
8263
8264
0
    return true;
8265
0
}
8266
8267
template <typename Function>
8268
static void ForEachOpaque(const TType& type, const TString& path, Function callback)
8269
0
{
8270
0
    auto recursion = [&callback](const TType& type, const TString& path, bool skipArray, auto& recursion) -> void {
8271
0
        if (!skipArray && type.isArray())
8272
0
        {
8273
0
            std::vector<int> indices(type.getArraySizes()->getNumDims());
8274
0
            for (int flatIndex = 0;
8275
0
                 flatIndex < type.getArraySizes()->getCumulativeSize();
8276
0
                 ++flatIndex)
8277
0
            {
8278
0
                TString subscriptPath = path;
8279
0
                for (size_t dimIndex = 0; dimIndex < indices.size(); ++dimIndex)
8280
0
                {
8281
0
                    int index = indices[dimIndex];
8282
0
                    subscriptPath.append("[");
8283
0
                    subscriptPath.append(String(index));
8284
0
                    subscriptPath.append("]");
8285
0
                }
8286
8287
0
                recursion(type, subscriptPath, true, recursion);
8288
8289
0
                for (size_t dimIndex = 0; dimIndex < indices.size(); ++dimIndex)
8290
0
                {
8291
0
                    ++indices[dimIndex];
8292
0
                    if (indices[dimIndex] < type.getArraySizes()->getDimSize(dimIndex))
8293
0
                        break;
8294
0
                    else
8295
0
                        indices[dimIndex] = 0;
8296
0
                }
8297
0
            }
8298
0
        }
8299
8300
0
        else if (type.isStruct() && type.containsOpaque())
8301
0
        {
8302
0
            const TTypeList& types = *type.getStruct();
8303
0
            for (const TTypeLoc& typeLoc : types)
8304
0
            {
8305
0
                TString nextPath = path;
8306
0
                nextPath.append(".");
8307
0
                nextPath.append(typeLoc.type->getFieldName());
8308
8309
0
                recursion(*(typeLoc.type), nextPath, false, recursion);
8310
0
            }
8311
0
        }
8312
8313
0
        else if (type.isOpaque())
8314
0
        {
8315
0
            callback(type, path);
8316
0
        }
8317
0
    };
Unexecuted instantiation: ParseHelper.cpp:void glslang::ForEachOpaque<glslang::TParseContext::vkRelaxedRemapUniformMembers(glslang::TSourceLoc const&, glslang::TPublicType const&, glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&)::$_0>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, glslang::TParseContext::vkRelaxedRemapUniformMembers(glslang::TSourceLoc const&, glslang::TPublicType const&, glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&)::$_0)::{lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}::operator()<{lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, {lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}&) const
Unexecuted instantiation: ParseHelper.cpp:void glslang::ForEachOpaque<glslang::TParseContext::vkRelaxedRemapFunctionParameter(glslang::TFunction*, glslang::TParameter&, std::__1::vector<int, std::__1::allocator<int> >*)::$_0>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, glslang::TParseContext::vkRelaxedRemapFunctionParameter(glslang::TFunction*, glslang::TParameter&, std::__1::vector<int, std::__1::allocator<int> >*)::$_0)::{lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}::operator()<{lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, {lambda(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, bool, auto:1&)#1}&) const
8318
8319
0
    recursion(type, path, false, recursion);
8320
0
}
Unexecuted instantiation: ParseHelper.cpp:void glslang::ForEachOpaque<glslang::TParseContext::vkRelaxedRemapUniformMembers(glslang::TSourceLoc const&, glslang::TPublicType const&, glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&)::$_0>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, glslang::TParseContext::vkRelaxedRemapUniformMembers(glslang::TSourceLoc const&, glslang::TPublicType const&, glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&)::$_0)
Unexecuted instantiation: ParseHelper.cpp:void glslang::ForEachOpaque<glslang::TParseContext::vkRelaxedRemapFunctionParameter(glslang::TFunction*, glslang::TParameter&, std::__1::vector<int, std::__1::allocator<int> >*)::$_0>(glslang::TType const&, std::__1::basic_string<char, std::__1::char_traits<char>, glslang::pool_allocator<char> > const&, glslang::TParseContext::vkRelaxedRemapFunctionParameter(glslang::TFunction*, glslang::TParameter&, std::__1::vector<int, std::__1::allocator<int> >*)::$_0)
8321
8322
void TParseContext::vkRelaxedRemapUniformMembers(const TSourceLoc& loc, const TPublicType& publicType, const TType& type,
8323
    const TString& identifier)
8324
0
{
8325
0
    if (!type.isStruct() || !type.containsOpaque())
8326
0
        return;
8327
8328
0
    ForEachOpaque(type, identifier,
8329
0
                  [&publicType, &loc, this](const TType& type, const TString& path) {
8330
0
                      TArraySizes arraySizes = {};
8331
0
                      if (type.getArraySizes()) arraySizes = *type.getArraySizes();
8332
0
                      TTypeParameters typeParameters = {};
8333
0
                      if (type.getTypeParameters()) typeParameters = *type.getTypeParameters();
8334
8335
0
                      TPublicType memberType{};
8336
0
                      memberType.basicType = type.getBasicType();
8337
0
                      memberType.sampler = type.getSampler();
8338
0
                      memberType.qualifier = type.getQualifier();
8339
0
                      memberType.vectorSize = type.getVectorSize();
8340
0
                      memberType.matrixCols = type.getMatrixCols();
8341
0
                      memberType.matrixRows = type.getMatrixRows();
8342
0
                      memberType.coopmatNV = type.isCoopMatNV();
8343
0
                      memberType.coopmatKHR = type.isCoopMatKHR();
8344
0
                      memberType.arraySizes = nullptr;
8345
0
                      memberType.userDef = nullptr;
8346
0
                      memberType.loc = loc;
8347
0
                      memberType.typeParameters = (type.getTypeParameters() ? &typeParameters : nullptr);
8348
0
                      memberType.spirvType = nullptr;
8349
8350
0
                      memberType.qualifier.storage = publicType.qualifier.storage;
8351
0
                      memberType.shaderQualifiers = publicType.shaderQualifiers;
8352
8353
0
                      TString& structMemberName = *NewPoolTString(path.c_str()); // A copy is required due to declareVariable() signature.
8354
0
                      declareVariable(loc, structMemberName, memberType, nullptr, nullptr);
8355
0
                  });
8356
0
}
8357
8358
void TParseContext::vkRelaxedRemapFunctionParameter(TFunction* function, TParameter& param, std::vector<int>* newParams)
8359
0
{
8360
0
    function->addParameter(param);
8361
8362
0
    if (!param.type->isStruct() || !param.type->containsOpaque())
8363
0
        return;
8364
8365
0
    ForEachOpaque(*param.type, (param.name ? *param.name : param.type->getFieldName()),
8366
0
                  [function, param, newParams](const TType& type, const TString& path) {
8367
0
                      TString* memberName = NewPoolTString(path.c_str());
8368
8369
0
                      TType* memberType = new TType();
8370
0
                      memberType->shallowCopy(type);
8371
0
                      memberType->getQualifier().storage = param.type->getQualifier().storage;
8372
0
                      memberType->clearArraySizes();
8373
8374
0
                      TParameter memberParam = {};
8375
0
                      memberParam.name = memberName;
8376
0
                      memberParam.type = memberType;
8377
0
                      memberParam.defaultValue = nullptr;
8378
0
                      function->addParameter(memberParam);
8379
0
                      if (newParams)
8380
0
                          newParams->push_back(function->getParamCount()-1);
8381
0
                  });
8382
0
}
8383
8384
//
8385
// Generates a valid GLSL dereferencing string for the input TIntermNode
8386
//
8387
struct AccessChainTraverser : public TIntermTraverser {
8388
0
    AccessChainTraverser() : TIntermTraverser(false, false, true)
8389
0
    {}
8390
8391
    TString path = "";
8392
    TStorageQualifier topLevelStorageQualifier = TStorageQualifier::EvqLast;
8393
8394
0
    bool visitBinary(TVisit, TIntermBinary* binary) override {
8395
0
        if (binary->getOp() == EOpIndexDirectStruct)
8396
0
        {
8397
0
            const TTypeList& members = *binary->getLeft()->getType().getStruct();
8398
0
            const TTypeLoc& member =
8399
0
                members[binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()];
8400
0
            TString memberName = member.type->getFieldName();
8401
8402
0
            if (path != "")
8403
0
                path.append(".");
8404
8405
0
            path.append(memberName);
8406
0
        }
8407
8408
0
        if (binary->getOp() == EOpIndexDirect)
8409
0
        {
8410
0
            const TConstUnionArray& indices = binary->getRight()->getAsConstantUnion()->getConstArray();
8411
0
            for (int index = 0; index < indices.size(); ++index)
8412
0
            {
8413
0
                path.append("[");
8414
0
                path.append(String(indices[index].getIConst()));
8415
0
                path.append("]");
8416
0
            }
8417
0
        }
8418
8419
0
        return true;
8420
0
    }
8421
8422
0
    void visitSymbol(TIntermSymbol* symbol) override {
8423
0
        if (symbol->getType().isOpaque())
8424
0
            topLevelStorageQualifier = symbol->getQualifier().storage;
8425
0
        if (!IsAnonymous(symbol->getName()))
8426
0
            path.append(symbol->getName());
8427
0
    }
8428
};
8429
8430
TIntermNode* TParseContext::vkRelaxedRemapFunctionArgument(const TSourceLoc& loc, TFunction* function, TIntermTyped* intermTyped)
8431
0
{
8432
0
    AccessChainTraverser accessChainTraverser{};
8433
0
    intermTyped->traverse(&accessChainTraverser);
8434
8435
0
    if (accessChainTraverser.topLevelStorageQualifier == TStorageQualifier::EvqUniform)
8436
0
    {
8437
0
        TParameter param = { 0, new TType, {} };
8438
0
        param.type->shallowCopy(intermTyped->getType());
8439
8440
0
        function->addParameter(param);
8441
0
        return intermTyped;
8442
0
    }
8443
8444
0
    TParameter param = { NewPoolTString(accessChainTraverser.path.c_str()), new TType, {} };
8445
0
    param.type->shallowCopy(intermTyped->getType());
8446
8447
0
    std::vector<int> newParams = {};
8448
0
    vkRelaxedRemapFunctionParameter(function, param, &newParams);
8449
8450
0
    if (intermTyped->getType().isOpaque())
8451
0
    {
8452
0
        TIntermNode* remappedArgument = intermTyped;
8453
0
        {
8454
0
            TIntermSymbol* intermSymbol = nullptr;
8455
0
            TSymbol* symbol = symbolTable.find(*param.name);
8456
0
            if (symbol && symbol->getAsVariable())
8457
0
                intermSymbol = intermediate.addSymbol(*symbol->getAsVariable(), loc);
8458
0
            else
8459
0
            {
8460
0
                TVariable* variable = new TVariable(param.name, *param.type);
8461
0
                intermSymbol = intermediate.addSymbol(*variable, loc);
8462
0
            }
8463
8464
0
            remappedArgument = intermSymbol;
8465
0
        }
8466
8467
0
        return remappedArgument;
8468
0
    }
8469
0
    else if (!(intermTyped->isStruct() && intermTyped->getType().containsOpaque()))
8470
0
        return intermTyped;
8471
0
    else
8472
0
    {
8473
0
        TIntermNode* remappedArgument = intermTyped;
8474
0
        {
8475
0
            TSymbol* symbol = symbolTable.find(*param.name);
8476
0
            if (symbol && symbol->getAsVariable())
8477
0
                remappedArgument = intermediate.addSymbol(*symbol->getAsVariable(), loc);
8478
0
        }
8479
8480
0
        if (!newParams.empty())
8481
0
            remappedArgument = intermediate.makeAggregate(remappedArgument, loc);
8482
8483
0
        for (int paramIndex : newParams)
8484
0
        {
8485
0
            TParameter& newParam = function->operator[](paramIndex);
8486
0
            TIntermSymbol* intermSymbol = nullptr;
8487
0
            TSymbol* symbol = symbolTable.find(*newParam.name);
8488
0
            if (symbol && symbol->getAsVariable())
8489
0
                intermSymbol = intermediate.addSymbol(*symbol->getAsVariable(), loc);
8490
0
            else
8491
0
            {
8492
0
                TVariable* variable = new TVariable(newParam.name, *newParam.type);
8493
0
                intermSymbol = intermediate.addSymbol(*variable, loc);
8494
0
            }
8495
8496
0
            remappedArgument = intermediate.growAggregate(remappedArgument, intermSymbol);
8497
0
        }
8498
8499
0
        return remappedArgument;
8500
0
    }
8501
0
}
8502
8503
TIntermTyped* TParseContext::vkRelaxedRemapDotDereference(const TSourceLoc&, TIntermTyped& base, const TType& member,
8504
    const TString& identifier)
8505
0
{
8506
0
    if (!member.isOpaque())
8507
0
        return &base;
8508
8509
0
    AccessChainTraverser traverser{};
8510
0
    base.traverse(&traverser);
8511
0
    if (!traverser.path.empty())
8512
0
        traverser.path.append(".");
8513
0
    traverser.path.append(identifier);
8514
8515
0
    const TSymbol* symbol = symbolTable.find(traverser.path);
8516
0
    if (!symbol)
8517
0
        return &base;
8518
8519
0
    TIntermTyped* result = intermediate.addSymbol(*symbol->getAsVariable());
8520
0
    result->setType(symbol->getType());
8521
0
    return result;
8522
0
}
8523
8524
//
8525
// Do everything necessary to handle a variable (non-block) declaration.
8526
// Either redeclaring a variable, or making a new one, updating the symbol
8527
// table, and all error checking.
8528
//
8529
// Returns a subtree node that computes an initializer, if needed.
8530
// Returns nullptr if there is no code to execute for initialization.
8531
//
8532
// 'publicType' is the type part of the declaration (to the left)
8533
// 'arraySizes' is the arrayness tagged on the identifier (to the right)
8534
//
8535
TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType,
8536
    TArraySizes* arraySizes, TIntermTyped* initializer)
8537
112k
{
8538
    // Make a fresh type that combines the characteristics from the individual
8539
    // identifier syntax and the declaration-type syntax.
8540
112k
    TType type(publicType);
8541
112k
    type.transferArraySizes(arraySizes);
8542
112k
    type.copyArrayInnerSizes(publicType.arraySizes);
8543
112k
    arrayOfArrayVersionCheck(loc, type.getArraySizes());
8544
8545
112k
    if (initializer) {
8546
26.1k
        if (type.getBasicType() == EbtRayQuery) {
8547
0
            error(loc, "ray queries can only be initialized by using the rayQueryInitializeEXT intrinsic:", "=", identifier.c_str());
8548
26.1k
        } else if (type.getBasicType() == EbtHitObjectNV) {
8549
0
            error(loc, "hit objects cannot be initialized using initializers", "=", identifier.c_str());
8550
0
        }
8551
8552
26.1k
    }
8553
8554
112k
    if (type.isCoopMatKHR()) {
8555
0
        intermediate.setUseVulkanMemoryModel();
8556
0
        intermediate.setUseStorageBuffer();
8557
8558
0
        if (!publicType.typeParameters || !publicType.typeParameters->arraySizes ||
8559
0
            publicType.typeParameters->arraySizes->getNumDims() != 4) {
8560
0
            error(loc, "unexpected number type parameters", identifier.c_str(), "");
8561
0
        }
8562
0
        if (publicType.typeParameters) {
8563
0
            if (!isTypeFloat(publicType.typeParameters->basicType) &&
8564
0
                !isTypeInt(publicType.typeParameters->basicType) && publicType.typeParameters->basicType != EbtSpirvType) {
8565
0
                error(loc, "expected 8, 16, 32, or 64 bit signed or unsigned integer or 16, 32, or 64 bit float type", identifier.c_str(), "");
8566
0
            }
8567
0
        }
8568
0
    }
8569
112k
    else if (type.isCoopMatNV()) {
8570
0
        intermediate.setUseVulkanMemoryModel();
8571
0
        intermediate.setUseStorageBuffer();
8572
8573
0
        if (!publicType.typeParameters || !publicType.typeParameters->arraySizes || publicType.typeParameters->arraySizes->getNumDims() != 4) {
8574
0
            error(loc, "expected four type parameters", identifier.c_str(), "");
8575
0
        } else {
8576
0
            if (isTypeFloat(publicType.basicType) &&
8577
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 16 &&
8578
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 32 &&
8579
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 64) {
8580
0
                error(loc, "expected 16, 32, or 64 bits for first type parameter", identifier.c_str(), "");
8581
0
            }
8582
0
            if (isTypeInt(publicType.basicType) &&
8583
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 8 &&
8584
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 16 &&
8585
0
                publicType.typeParameters->arraySizes->getDimSize(0) != 32) {
8586
0
                error(loc, "expected 8, 16, or 32 bits for first type parameter", identifier.c_str(), "");
8587
0
            }
8588
0
        }
8589
112k
    } else if (type.isTensorLayoutNV()) {
8590
0
        if (!publicType.typeParameters || publicType.typeParameters->arraySizes->getNumDims() > 2) {
8591
0
            error(loc, "expected 1-2 type parameters", identifier.c_str(), "");
8592
0
        }
8593
112k
    } else if (type.isTensorViewNV()) {
8594
0
        if (!publicType.typeParameters || publicType.typeParameters->arraySizes->getNumDims() > 7) {
8595
0
            error(loc, "expected 1-7 type parameters", identifier.c_str(), "");
8596
0
        }
8597
112k
    } else if (type.isCoopVecNV()) {
8598
0
        intermediate.setUseVulkanMemoryModel();
8599
0
        intermediate.setUseStorageBuffer();
8600
8601
0
        if (!publicType.typeParameters || !publicType.typeParameters->arraySizes || publicType.typeParameters->arraySizes->getNumDims() != 1) {
8602
0
            error(loc, "expected two type parameters", identifier.c_str(), "");
8603
0
        } else if (publicType.typeParameters->arraySizes->getDimSize(0) <= 0) {
8604
0
            error(loc, "expected positive number of components", identifier.c_str(), "");
8605
0
        }
8606
112k
    } else if (type.isTensorARM()) {
8607
0
        intermediate.setUseStorageBuffer();
8608
8609
0
        if (!publicType.typeParameters || publicType.typeParameters->arraySizes->getNumDims() != 1) {
8610
0
            error(loc, "expected two type parameters", identifier.c_str(), "");
8611
0
        }
8612
0
        if (publicType.typeParameters) {
8613
0
            if (publicType.typeParameters->basicType != EbtBool &&
8614
0
                publicType.typeParameters->basicType != EbtInt8 &&
8615
0
                publicType.typeParameters->basicType != EbtInt16 &&
8616
0
                publicType.typeParameters->basicType != EbtInt &&
8617
0
                publicType.typeParameters->basicType != EbtInt64 &&
8618
0
                publicType.typeParameters->basicType != EbtUint8 &&
8619
0
                publicType.typeParameters->basicType != EbtUint16 &&
8620
0
                publicType.typeParameters->basicType != EbtUint &&
8621
0
                publicType.typeParameters->basicType != EbtUint64 &&
8622
0
                publicType.typeParameters->basicType != EbtFloat16 &&
8623
0
                publicType.typeParameters->basicType != EbtFloat &&
8624
0
                publicType.typeParameters->basicType != EbtDouble) {
8625
0
                error(loc, "expected bool, integer or floating point type parameter", identifier.c_str(), "");
8626
0
            }
8627
8628
0
        }
8629
112k
    } else {
8630
112k
        if (publicType.typeParameters && publicType.typeParameters->arraySizes->getNumDims() != 0) {
8631
0
            error(loc, "unexpected type parameters", identifier.c_str(), "");
8632
0
        }
8633
112k
    }
8634
8635
112k
    if (voidErrorCheck(loc, identifier, type.getBasicType()))
8636
1
        return nullptr;
8637
8638
112k
    if (initializer)
8639
26.1k
        rValueErrorCheck(loc, "initializer", initializer);
8640
86.3k
    else
8641
86.3k
        nonInitConstCheck(loc, identifier, type);
8642
8643
112k
    samplerCheck(loc, type, identifier, initializer);
8644
112k
    transparentOpaqueCheck(loc, type, identifier);
8645
112k
    atomicUintCheck(loc, type, identifier);
8646
112k
    accStructCheck(loc, type, identifier);
8647
112k
    hitObjectNVCheck(loc, type, identifier);
8648
112k
    checkAndResizeMeshViewDim(loc, type, /*isBlockMember*/ false);
8649
112k
    if (type.getQualifier().storage == EvqConst && type.containsReference()) {
8650
0
        error(loc, "variables with reference type can't have qualifier 'const'", "qualifier", "");
8651
0
    }
8652
8653
112k
    if (type.getQualifier().storage != EvqUniform && type.getQualifier().storage != EvqBuffer) {
8654
109k
        if (type.contains16BitFloat())
8655
0
            requireFloat16Arithmetic(loc, "qualifier", "float16 types can only be in uniform block or buffer storage");
8656
109k
        if (type.contains16BitInt())
8657
0
            requireInt16Arithmetic(loc, "qualifier", "(u)int16 types can only be in uniform block or buffer storage");
8658
109k
        if (type.contains8BitInt())
8659
0
            requireInt8Arithmetic(loc, "qualifier", "(u)int8 types can only be in uniform block or buffer storage");
8660
109k
    }
8661
112k
    if (type.getBasicType() == EbtBFloat16 &&
8662
112k
        (type.getQualifier().storage == EvqVaryingIn || type.getQualifier().storage == EvqVaryingOut))
8663
0
        error(loc, "qualifier", "bfloat16 types not allowed as input/output", "");
8664
8665
112k
    if ((type.getBasicType() == EbtFloatE5M2 || type.getBasicType() == EbtFloatE4M3) &&
8666
112k
        (type.getQualifier().storage == EvqVaryingIn || type.getQualifier().storage == EvqVaryingOut))
8667
0
        error(loc, "qualifier", "fp8 types not allowed as input/output", "");
8668
8669
112k
    if (type.getQualifier().storage == EvqtaskPayloadSharedEXT)
8670
0
        intermediate.addTaskPayloadEXTCount();
8671
112k
    if (type.getQualifier().storage == EvqShared && type.containsCoopMat())
8672
0
        error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", "");
8673
8674
112k
    if (profile == EEsProfile) {
8675
5.03k
        if (type.getQualifier().isPipeInput() && type.getBasicType() == EbtStruct) {
8676
0
            if (type.getQualifier().isArrayedIo(language)) {
8677
0
                TType perVertexType(type, 0);
8678
0
                if (perVertexType.containsArray() && perVertexType.containsBuiltIn() == false) {
8679
0
                    error(loc, "A per vertex structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
8680
0
                }
8681
0
            }
8682
0
            else if (type.containsArray() && type.containsBuiltIn() == false) {
8683
0
                error(loc, "A structure containing an array is not allowed as input in ES", type.getTypeName().c_str(), "");
8684
0
            }
8685
0
            if (type.containsStructure())
8686
0
                error(loc, "A structure containing an struct is not allowed as input in ES", type.getTypeName().c_str(), "");
8687
0
        }
8688
5.03k
    }
8689
8690
112k
    if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
8691
0
        error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
8692
112k
    if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone)
8693
0
        error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
8694
112k
    if (identifier != "gl_FragStencilRefARB" && publicType.shaderQualifiers.getStencil() != ElsNone)
8695
0
        error(loc, "can only apply depth layout to gl_FragStencilRefARB", "layout qualifier", "");
8696
8697
    // Check for redeclaration of built-ins and/or attempting to declare a reserved name
8698
112k
    TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers);
8699
112k
    if (symbol == nullptr)
8700
112k
        reservedErrorCheck(loc, identifier);
8701
8702
112k
    if (symbol == nullptr && spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) {
8703
0
        bool remapped = vkRelaxedRemapUniformVariable(loc, identifier, publicType, arraySizes, initializer, type);
8704
8705
0
        if (remapped) {
8706
0
            return nullptr;
8707
0
        }
8708
0
    }
8709
8710
112k
    inheritGlobalDefaults(type.getQualifier());
8711
8712
    // Declare the variable
8713
112k
    if (type.isArray()) {
8714
        // Check that implicit sizing is only where allowed.
8715
4.79k
        arraySizesCheck(loc, type.getQualifier(), type.getArraySizes(), initializer, false);
8716
8717
4.79k
        if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type))
8718
4.79k
            declareArray(loc, identifier, type, symbol);
8719
8720
4.79k
        if (initializer) {
8721
4
            profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "initializer");
8722
4
            profileRequires(loc, EEsProfile, 300, nullptr, "initializer");
8723
4
        }
8724
107k
    } else {
8725
        // non-array case
8726
107k
        if (symbol == nullptr)
8727
107k
            symbol = declareNonArray(loc, identifier, type);
8728
0
        else if (type != symbol->getType())
8729
0
            error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
8730
107k
    }
8731
8732
112k
    if (symbol == nullptr)
8733
22
        return nullptr;
8734
8735
    // Deal with initializer
8736
112k
    TIntermNode* initNode = nullptr;
8737
112k
    if (symbol != nullptr && initializer) {
8738
26.1k
        TVariable* variable = symbol->getAsVariable();
8739
26.1k
        if (! variable) {
8740
0
            error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
8741
0
            return nullptr;
8742
0
        }
8743
26.1k
        initNode = executeInitializer(loc, initializer, variable);
8744
26.1k
    }
8745
8746
    // look for errors in layout qualifier use
8747
112k
    layoutObjectCheck(loc, *symbol);
8748
8749
    // fix up
8750
112k
    fixOffset(loc, *symbol);
8751
8752
112k
    return initNode;
8753
112k
}
8754
8755
// Pick up global defaults from the provide global defaults into dst.
8756
void TParseContext::inheritGlobalDefaults(TQualifier& dst) const
8757
112k
{
8758
112k
    if (dst.storage == EvqVaryingOut) {
8759
7.25k
        if (! dst.hasStream() && language == EShLangGeometry)
8760
1.87k
            dst.layoutStream = globalOutputDefaults.layoutStream;
8761
7.25k
        if (! dst.hasXfbBuffer())
8762
7.25k
            dst.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
8763
7.25k
    }
8764
112k
}
8765
8766
//
8767
// Make an internal-only variable whose name is for debug purposes only
8768
// and won't be searched for.  Callers will only use the return value to use
8769
// the variable, not the name to look it up.  It is okay if the name
8770
// is the same as other names; there won't be any conflict.
8771
//
8772
TVariable* TParseContext::makeInternalVariable(const char* name, const TType& type) const
8773
0
{
8774
0
    TString* nameString = NewPoolTString(name);
8775
0
    TVariable* variable = new TVariable(nameString, type);
8776
0
    symbolTable.makeInternalVariable(*variable);
8777
8778
0
    return variable;
8779
0
}
8780
8781
//
8782
// Declare a non-array variable, the main point being there is no redeclaration
8783
// for resizing allowed.
8784
//
8785
// Return the successfully declared variable.
8786
//
8787
TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString& identifier, const TType& type)
8788
107k
{
8789
    // make a new variable
8790
107k
    TVariable* variable = new TVariable(&identifier, type);
8791
8792
107k
    ioArrayCheck(loc, type, identifier);
8793
8794
    // add variable to symbol table
8795
107k
    if (symbolTable.insert(*variable)) {
8796
107k
        if (symbolTable.atGlobalLevel())
8797
106k
            trackLinkage(*variable);
8798
107k
        return variable;
8799
107k
    }
8800
8801
22
    error(loc, "redefinition", variable->getName().c_str(), "");
8802
22
    return nullptr;
8803
107k
}
8804
8805
//
8806
// Handle all types of initializers from the grammar.
8807
//
8808
// Returning nullptr just means there is no code to execute to handle the
8809
// initializer, which will, for example, be the case for constant initializers.
8810
//
8811
TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
8812
26.1k
{
8813
    // A null initializer is an aggregate that hasn't had an op assigned yet
8814
    // (still EOpNull, no relation to nullInit), and has no children.
8815
26.1k
    bool nullInit = initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull &&
8816
26.1k
        initializer->getAsAggregate()->getSequence().size() == 0;
8817
8818
    //
8819
    // Identifier must be of type constant, a global, or a temporary, and
8820
    // starting at version 120, desktop allows uniforms to have initializers.
8821
    //
8822
26.1k
    TStorageQualifier qualifier = variable->getType().getQualifier().storage;
8823
26.1k
    if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
8824
26.1k
           (qualifier == EvqUniform && !isEsProfile() && version >= 120))) {
8825
0
        if (qualifier == EvqShared) {
8826
            // GL_EXT_null_initializer allows this for shared, if it's a null initializer
8827
0
            if (nullInit) {
8828
0
                const char* feature = "initialization with shared qualifier";
8829
0
                profileRequires(loc, EEsProfile, 0, E_GL_EXT_null_initializer, feature);
8830
0
                profileRequires(loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, feature);
8831
0
            } else {
8832
0
                error(loc, "initializer can only be a null initializer ('{}')", "shared", "");
8833
0
            }
8834
0
        } else {
8835
0
            error(loc, " cannot initialize this type of qualifier ",
8836
0
                  variable->getType().getStorageQualifierString(), "");
8837
0
            return nullptr;
8838
0
        }
8839
0
    }
8840
8841
26.1k
    if (nullInit) {
8842
        // only some types can be null initialized
8843
0
        if (variable->getType().containsUnsizedArray()) {
8844
0
            error(loc, "null initializers can't size unsized arrays", "{}", "");
8845
0
            return nullptr;
8846
0
        }
8847
0
        if (variable->getType().containsOpaque()) {
8848
0
            error(loc, "null initializers can't be used on opaque values", "{}", "");
8849
0
            return nullptr;
8850
0
        }
8851
0
        variable->getWritableType().getQualifier().setNullInit();
8852
0
        return nullptr;
8853
0
    }
8854
8855
26.1k
    arrayObjectCheck(loc, variable->getType(), "array initializer");
8856
8857
    //
8858
    // If the initializer was from braces { ... }, we convert the whole subtree to a
8859
    // constructor-style subtree, allowing the rest of the code to operate
8860
    // identically for both kinds of initializers.
8861
    //
8862
    // Type can't be deduced from the initializer list, so a skeletal type to
8863
    // follow has to be passed in.  Constness and specialization-constness
8864
    // should be deduced bottom up, not dictated by the skeletal type.
8865
    //
8866
26.1k
    TType skeletalType;
8867
26.1k
    skeletalType.shallowCopy(variable->getType());
8868
26.1k
    skeletalType.getQualifier().makeTemporary();
8869
26.1k
    initializer = convertInitializerList(loc, skeletalType, initializer);
8870
26.1k
    if (! initializer) {
8871
        // error recovery; don't leave const without constant values
8872
0
        if (qualifier == EvqConst)
8873
0
            variable->getWritableType().getQualifier().makeTemporary();
8874
0
        return nullptr;
8875
0
    }
8876
8877
    // Fix outer arrayness if variable is unsized, getting size from the initializer
8878
26.1k
    if (initializer->getType().isSizedArray() && variable->getType().isUnsizedArray())
8879
0
        variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize());
8880
8881
    // Inner arrayness can also get set by an initializer
8882
26.1k
    if (initializer->getType().isArrayOfArrays() && variable->getType().isArrayOfArrays() &&
8883
26.1k
        initializer->getType().getArraySizes()->getNumDims() ==
8884
0
           variable->getType().getArraySizes()->getNumDims()) {
8885
        // adopt unsized sizes from the initializer's sizes
8886
0
        for (int d = 1; d < variable->getType().getArraySizes()->getNumDims(); ++d) {
8887
0
            if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize) {
8888
0
                variable->getWritableType().getArraySizes()->setDimSize(d,
8889
0
                    initializer->getType().getArraySizes()->getDimSize(d));
8890
0
            }
8891
0
        }
8892
0
    }
8893
8894
    // Uniforms require a compile-time constant initializer
8895
26.1k
    if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
8896
0
        error(loc, "uniform initializers must be constant", "=", "'%s'",
8897
0
              variable->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str());
8898
0
        variable->getWritableType().getQualifier().makeTemporary();
8899
0
        return nullptr;
8900
0
    }
8901
    // Global consts require a constant initializer (specialization constant is okay)
8902
26.1k
    if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
8903
0
        error(loc, "global const initializers must be constant", "=", "'%s'",
8904
0
              variable->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str());
8905
0
        variable->getWritableType().getQualifier().makeTemporary();
8906
0
        return nullptr;
8907
0
    }
8908
8909
    // Const variables require a constant initializer, depending on version
8910
26.1k
    if (qualifier == EvqConst) {
8911
25.2k
        if (! initializer->getType().getQualifier().isConstant()) {
8912
0
            const char* initFeature = "non-constant initializer";
8913
0
            requireProfile(loc, ~EEsProfile, initFeature);
8914
0
            profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature);
8915
0
            variable->getWritableType().getQualifier().storage = EvqConstReadOnly;
8916
0
            qualifier = EvqConstReadOnly;
8917
0
        }
8918
25.2k
    } else {
8919
        // Non-const global variables in ES need a const initializer.
8920
        //
8921
        // "In declarations of global variables with no storage qualifier or with a const
8922
        // qualifier any initializer must be a constant expression."
8923
929
        if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
8924
0
            const char* initFeature =
8925
0
                "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
8926
0
            if (isEsProfile()) {
8927
0
                if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
8928
0
                    warn(loc, "not allowed in this version", initFeature, "");
8929
0
                else
8930
0
                    profileRequires(loc, EEsProfile, 0, E_GL_EXT_shader_non_constant_global_initializers, initFeature);
8931
0
            }
8932
0
        }
8933
929
    }
8934
8935
26.1k
    if (qualifier == EvqConst || qualifier == EvqUniform) {
8936
        // Compile-time tagging of the variable with its constant value...
8937
8938
25.2k
        initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
8939
25.2k
        if (! initializer || ! initializer->getType().getQualifier().isConstant() ||
8940
25.2k
            variable->getType() != initializer->getType()) {
8941
0
            error(loc, "non-matching or non-convertible constant type for const initializer",
8942
0
                  variable->getType().getStorageQualifierString(), "");
8943
0
            variable->getWritableType().getQualifier().makeTemporary();
8944
0
            return nullptr;
8945
0
        }
8946
8947
        // We either have a folded constant in getAsConstantUnion, or we have to use
8948
        // the initializer's subtree in the AST to represent the computation of a
8949
        // specialization constant.
8950
25.2k
        assert(initializer->getAsConstantUnion() || initializer->getType().getQualifier().isSpecConstant());
8951
25.2k
        if (initializer->getAsConstantUnion())
8952
25.2k
            variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
8953
0
        else {
8954
            // It's a specialization constant.
8955
0
            variable->getWritableType().getQualifier().makeSpecConstant();
8956
8957
            // Keep the subtree that computes the specialization constant with the variable.
8958
            // Later, a symbol node will adopt the subtree from the variable.
8959
0
            variable->setConstSubtree(initializer);
8960
0
        }
8961
25.2k
    } else {
8962
        // normal assigning of a value to a variable...
8963
929
        specializationCheck(loc, initializer->getType(), "initializer");
8964
929
        TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
8965
929
        TIntermTyped* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
8966
929
        if (! initNode)
8967
4
            assignError(loc, "=", intermSymbol->getCompleteString(intermediate.getEnhancedMsgs()), initializer->getCompleteString(intermediate.getEnhancedMsgs()));
8968
8969
929
        return initNode;
8970
929
    }
8971
8972
25.2k
    return nullptr;
8973
26.1k
}
8974
8975
//
8976
// Reprocess any initializer-list (the  "{ ... }" syntax) parts of the
8977
// initializer.
8978
//
8979
// Need to hierarchically assign correct types and implicit
8980
// conversions. Will do this mimicking the same process used for
8981
// creating a constructor-style initializer, ensuring we get the
8982
// same form.  However, it has to in parallel walk the 'type'
8983
// passed in, as type cannot be deduced from an initializer list.
8984
//
8985
TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const TType& type, TIntermTyped* initializer)
8986
26.1k
{
8987
    // Will operate recursively.  Once a subtree is found that is constructor style,
8988
    // everything below it is already good: Only the "top part" of the initializer
8989
    // can be an initializer list, where "top part" can extend for several (or all) levels.
8990
8991
    // see if we have bottomed out in the tree within the initializer-list part
8992
26.1k
    TIntermAggregate* initList = initializer->getAsAggregate();
8993
26.1k
    if (! initList || initList->getOp() != EOpNull)
8994
26.1k
        return initializer;
8995
8996
    // Of the initializer-list set of nodes, need to process bottom up,
8997
    // so recurse deep, then process on the way up.
8998
8999
    // Go down the tree here...
9000
0
    if (type.isArray()) {
9001
        // The type's array might be unsized, which could be okay, so base sizes on the size of the aggregate.
9002
        // Later on, initializer execution code will deal with array size logic.
9003
0
        TType arrayType;
9004
0
        arrayType.shallowCopy(type);                     // sharing struct stuff is fine
9005
0
        arrayType.copyArraySizes(*type.getArraySizes());  // but get a fresh copy of the array information, to edit below
9006
9007
        // edit array sizes to fill in unsized dimensions
9008
0
        arrayType.changeOuterArraySize((int)initList->getSequence().size());
9009
0
        TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped();
9010
0
        if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() &&
9011
0
            arrayType.getArraySizes()->getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) {
9012
0
            for (int d = 1; d < arrayType.getArraySizes()->getNumDims(); ++d) {
9013
0
                if (arrayType.getArraySizes()->getDimSize(d) == UnsizedArraySize)
9014
0
                    arrayType.getArraySizes()->setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1));
9015
0
            }
9016
0
        }
9017
9018
0
        TType elementType(arrayType, 0); // dereferenced type
9019
0
        for (size_t i = 0; i < initList->getSequence().size(); ++i) {
9020
0
            initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped());
9021
0
            if (initList->getSequence()[i] == nullptr)
9022
0
                return nullptr;
9023
0
        }
9024
9025
0
        return addConstructor(loc, initList, arrayType);
9026
0
    } else if (type.isStruct()) {
9027
0
        if (type.getStruct()->size() != initList->getSequence().size()) {
9028
0
            error(loc, "wrong number of structure members", "initializer list", "");
9029
0
            return nullptr;
9030
0
        }
9031
0
        for (size_t i = 0; i < type.getStruct()->size(); ++i) {
9032
0
            initList->getSequence()[i] = convertInitializerList(loc, *(*type.getStruct())[i].type, initList->getSequence()[i]->getAsTyped());
9033
0
            if (initList->getSequence()[i] == nullptr)
9034
0
                return nullptr;
9035
0
        }
9036
0
    } else if (type.isMatrix()) {
9037
0
        if (type.getMatrixCols() != (int)initList->getSequence().size()) {
9038
0
            error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str());
9039
0
            return nullptr;
9040
0
        }
9041
0
        TType vectorType(type, 0); // dereferenced type
9042
0
        for (int i = 0; i < type.getMatrixCols(); ++i) {
9043
0
            initList->getSequence()[i] = convertInitializerList(loc, vectorType, initList->getSequence()[i]->getAsTyped());
9044
0
            if (initList->getSequence()[i] == nullptr)
9045
0
                return nullptr;
9046
0
        }
9047
0
    } else if (type.isVector()) {
9048
0
        if (type.getVectorSize() != (int)initList->getSequence().size()) {
9049
0
            error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str());
9050
0
            return nullptr;
9051
0
        }
9052
0
        TBasicType destType = type.getBasicType();
9053
0
        for (int i = 0; i < type.getVectorSize(); ++i) {
9054
0
            TBasicType initType = initList->getSequence()[i]->getAsTyped()->getBasicType();
9055
0
            if (destType != initType && !intermediate.canImplicitlyPromote(initType, destType)) {
9056
0
                error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str());
9057
0
                return nullptr;
9058
0
            }
9059
9060
0
        }
9061
0
    } else {
9062
0
        error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str());
9063
0
        return nullptr;
9064
0
    }
9065
9066
    // Now that the subtree is processed, process this node as if the
9067
    // initializer list is a set of arguments to a constructor.
9068
0
    TIntermNode* emulatedConstructorArguments;
9069
0
    if (initList->getSequence().size() == 1)
9070
0
        emulatedConstructorArguments = initList->getSequence()[0];
9071
0
    else
9072
0
        emulatedConstructorArguments = initList;
9073
0
    return addConstructor(loc, emulatedConstructorArguments, type);
9074
0
}
9075
9076
//
9077
// Test for the correctness of the parameters passed to various constructor functions
9078
// and also convert them to the right data type, if allowed and required.
9079
//
9080
// 'node' is what to construct from.
9081
// 'type' is what type to construct.
9082
//
9083
// Returns nullptr for an error or the constructed node (aggregate or typed) for no error.
9084
//
9085
TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type)
9086
1.25k
{
9087
1.25k
    if (node == nullptr || node->getAsTyped() == nullptr)
9088
0
        return nullptr;
9089
1.25k
    rValueErrorCheck(loc, "constructor", node->getAsTyped());
9090
9091
1.25k
    TIntermAggregate* aggrNode = node->getAsAggregate();
9092
1.25k
    TOperator op = intermediate.mapTypeToConstructorOp(type);
9093
9094
    // Combined texture-sampler constructors are completely semantic checked
9095
    // in constructorTextureSamplerError()
9096
1.25k
    if (op == EOpConstructTextureSampler) {
9097
0
        if (aggrNode != nullptr) {
9098
0
            if (aggrNode->getSequence()[1]->getAsTyped()->getType().getSampler().shadow) {
9099
                // Transfer depth into the texture (SPIR-V image) type, as a hint
9100
                // for tools to know this texture/image is a depth image.
9101
0
                aggrNode->getSequence()[0]->getAsTyped()->getWritableType().getSampler().shadow = true;
9102
0
            }
9103
0
            return intermediate.setAggregateOperator(aggrNode, op, type, loc);
9104
0
        }
9105
0
    }
9106
9107
1.25k
    TTypeList::const_iterator memberTypes;
9108
1.25k
    if (op == EOpConstructStruct)
9109
0
        memberTypes = type.getStruct()->begin();
9110
9111
1.25k
    TType elementType;
9112
1.25k
    if (type.isArray()) {
9113
32
        TType dereferenced(type, 0);
9114
32
        elementType.shallowCopy(dereferenced);
9115
32
    } else
9116
1.22k
        elementType.shallowCopy(type);
9117
9118
1.25k
    bool singleArg;
9119
1.25k
    if (aggrNode) {
9120
808
        if (aggrNode->getOp() != EOpNull)
9121
82
            singleArg = true;
9122
726
        else
9123
726
            singleArg = false;
9124
808
    } else
9125
449
        singleArg = true;
9126
9127
1.25k
    TIntermTyped *newNode;
9128
1.25k
    if (singleArg) {
9129
        // If structure constructor or array constructor is being called
9130
        // for only one parameter inside the structure, we need to call constructAggregate function once.
9131
531
        if (type.isArray())
9132
32
            newNode = constructAggregate(node, elementType, 1, node->getLoc());
9133
499
        else if (op == EOpConstructStruct)
9134
0
            newNode = constructAggregate(node, *(*memberTypes).type, 1, node->getLoc());
9135
499
        else
9136
499
            newNode = constructBuiltIn(type, op, node->getAsTyped(), node->getLoc(), false);
9137
9138
531
        if (newNode && (type.isArray() || op == EOpConstructStruct))
9139
0
            newNode = intermediate.setAggregateOperator(newNode, EOpConstructStruct, type, loc);
9140
9141
531
        return newNode;
9142
531
    }
9143
9144
    //
9145
    // Handle list of arguments.
9146
    //
9147
726
    TIntermSequence &sequenceVector = aggrNode->getSequence();    // Stores the information about the parameter to the constructor
9148
    // if the structure constructor contains more than one parameter, then construct
9149
    // each parameter
9150
9151
726
    int paramCount = 0;  // keeps track of the constructor parameter number being checked
9152
9153
    // We don't know "top down" whether type is a specialization constant,
9154
    // but a const becomes a specialization constant if any of its children are.
9155
726
    bool hasSpecConst = false;
9156
726
    bool isConstConstructor = true;
9157
9158
    // for each parameter to the constructor call, check to see if the right type is passed or convert them
9159
    // to the right type if possible (and allowed).
9160
    // for structure constructors, just check if the right type is passed, no conversion is allowed.
9161
726
    for (TIntermSequence::iterator p = sequenceVector.begin();
9162
2.90k
                                   p != sequenceVector.end(); p++, paramCount++) {
9163
2.17k
        if (type.isArray())
9164
0
            newNode = constructAggregate(*p, elementType, paramCount+1, node->getLoc());
9165
2.17k
        else if (op == EOpConstructStruct)
9166
0
            newNode = constructAggregate(*p, *(memberTypes[paramCount]).type, paramCount+1, node->getLoc());
9167
2.17k
        else
9168
2.17k
            newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
9169
9170
2.17k
        if (newNode) {
9171
2.17k
            *p = newNode;
9172
2.17k
            if (!newNode->getType().getQualifier().isConstant())
9173
0
                isConstConstructor = false;
9174
2.17k
            if (newNode->getType().getQualifier().isSpecConstant())
9175
0
                hasSpecConst = true;
9176
2.17k
        } else
9177
0
            return nullptr;
9178
2.17k
    }
9179
9180
726
    TIntermTyped* ret_node = intermediate.setAggregateOperator(aggrNode, op, type, loc);
9181
9182
726
    const char *specConstantCompositeExt[] = { E_GL_EXT_spec_constant_composites };
9183
726
    if (checkExtensionsRequested(loc, 1, specConstantCompositeExt, "spec constant aggregate constructor")) {
9184
0
        if (isConstConstructor && hasSpecConst) {
9185
0
            ret_node->getWritableType().getQualifier().makeSpecConstant();
9186
0
        }
9187
0
    }
9188
9189
726
    TIntermAggregate *agg_node = ret_node->getAsAggregate();
9190
726
    if (agg_node && (agg_node->isVector() || agg_node->isArray() || agg_node->isMatrix()))
9191
0
        agg_node->updatePrecision();
9192
9193
726
    return ret_node;
9194
726
}
9195
9196
// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
9197
// for the parameter to the constructor (passed to this function). Essentially, it converts
9198
// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
9199
// float, then float is converted to int.
9200
//
9201
// Returns nullptr for an error or the constructed node.
9202
//
9203
TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, TIntermTyped* node, const TSourceLoc& loc,
9204
    bool subset)
9205
2.67k
{
9206
    // If we are changing a matrix in both domain of basic type and to a non matrix,
9207
    // do the shape change first (by default, below, basic type is changed before shape).
9208
    // This avoids requesting a matrix of a new type that is going to be discarded anyway.
9209
    // TODO: This could be generalized to more type combinations, but that would require
9210
    // more extensive testing and full algorithm rework. For now, the need to do two changes makes
9211
    // the recursive call work, and avoids the most egregious case of creating integer matrices.
9212
2.67k
    if (node->getType().isMatrix() && (type.isScalar() || type.isVector()) &&
9213
2.67k
            type.isFloatingDomain() != node->getType().isFloatingDomain()) {
9214
0
        TType transitionType(node->getBasicType(), glslang::EvqTemporary, type.getVectorSize(), 0, 0, node->isVector());
9215
0
        TOperator transitionOp = intermediate.mapTypeToConstructorOp(transitionType);
9216
0
        node = constructBuiltIn(transitionType, transitionOp, node, loc, false);
9217
0
    }
9218
9219
2.67k
    TIntermTyped* newNode;
9220
2.67k
    TOperator basicOp;
9221
9222
    //
9223
    // First, convert types as needed.
9224
    //
9225
2.67k
    switch (op) {
9226
5
    case EOpConstructVec2:
9227
5
    case EOpConstructVec3:
9228
5
    case EOpConstructVec4:
9229
5
    case EOpConstructMat2x2:
9230
5
    case EOpConstructMat2x3:
9231
5
    case EOpConstructMat2x4:
9232
5
    case EOpConstructMat3x2:
9233
5
    case EOpConstructMat3x3:
9234
5
    case EOpConstructMat3x4:
9235
5
    case EOpConstructMat4x2:
9236
5
    case EOpConstructMat4x3:
9237
5
    case EOpConstructMat4x4:
9238
5
    case EOpConstructFloat:
9239
5
        basicOp = EOpConstructFloat;
9240
5
        break;
9241
9242
334
    case EOpConstructIVec2:
9243
640
    case EOpConstructIVec3:
9244
640
    case EOpConstructIVec4:
9245
800
    case EOpConstructInt:
9246
800
        basicOp = EOpConstructInt;
9247
800
        break;
9248
9249
0
    case EOpConstructUVec2:
9250
0
        if (node->getType().getBasicType() == EbtReference) {
9251
0
            requireExtensions(loc, 1, &E_GL_EXT_buffer_reference_uvec2, "reference conversion to uvec2");
9252
0
            TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUvec2, true, node,
9253
0
                type);
9254
0
            return newNode;
9255
0
        } else if (node->getType().getBasicType() == EbtSampler) {
9256
0
            requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler conversion to uvec2");
9257
            // force the basic type of the constructor param to uvec2, otherwise spv builder will
9258
            // report some errors
9259
0
            TIntermTyped* newSrcNode = intermediate.createConversion(EbtUint, node);
9260
0
            newSrcNode->getAsTyped()->getWritableType().setVectorSize(2);
9261
9262
0
            TIntermTyped* newNode =
9263
0
                intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConstructUVec2, false, newSrcNode, type);
9264
0
            return newNode;
9265
0
        }
9266
0
        [[fallthrough]];
9267
1.87k
    case EOpConstructUVec3:
9268
1.87k
    case EOpConstructUVec4:
9269
1.87k
    case EOpConstructUint:
9270
1.87k
        basicOp = EOpConstructUint;
9271
1.87k
        break;
9272
9273
0
    case EOpConstructBVec2:
9274
0
    case EOpConstructBVec3:
9275
0
    case EOpConstructBVec4:
9276
0
    case EOpConstructBool:
9277
0
        basicOp = EOpConstructBool;
9278
0
        break;
9279
0
    case EOpConstructTextureSampler:
9280
0
        if ((node->getType().getBasicType() == EbtUint || node->getType().getBasicType() == EbtInt) &&
9281
0
            node->getType().getVectorSize() == 2) {
9282
0
            requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "ivec2/uvec2 convert to texture handle");
9283
            // No matter ivec2 or uvec2, Set EOpPackUint2x32 just to generate an opBitcast op code
9284
0
            TIntermTyped* newNode =
9285
0
                intermediate.addBuiltInFunctionCall(node->getLoc(), EOpPackUint2x32, true, node, type);
9286
0
            return newNode;
9287
0
        }
9288
0
        [[fallthrough]];
9289
0
    case EOpConstructDVec2:
9290
0
    case EOpConstructDVec3:
9291
0
    case EOpConstructDVec4:
9292
0
    case EOpConstructDMat2x2:
9293
0
    case EOpConstructDMat2x3:
9294
0
    case EOpConstructDMat2x4:
9295
0
    case EOpConstructDMat3x2:
9296
0
    case EOpConstructDMat3x3:
9297
0
    case EOpConstructDMat3x4:
9298
0
    case EOpConstructDMat4x2:
9299
0
    case EOpConstructDMat4x3:
9300
0
    case EOpConstructDMat4x4:
9301
0
    case EOpConstructDouble:
9302
0
        basicOp = EOpConstructDouble;
9303
0
        break;
9304
9305
0
    case EOpConstructF16Vec2:
9306
0
    case EOpConstructF16Vec3:
9307
0
    case EOpConstructF16Vec4:
9308
0
    case EOpConstructF16Mat2x2:
9309
0
    case EOpConstructF16Mat2x3:
9310
0
    case EOpConstructF16Mat2x4:
9311
0
    case EOpConstructF16Mat3x2:
9312
0
    case EOpConstructF16Mat3x3:
9313
0
    case EOpConstructF16Mat3x4:
9314
0
    case EOpConstructF16Mat4x2:
9315
0
    case EOpConstructF16Mat4x3:
9316
0
    case EOpConstructF16Mat4x4:
9317
0
    case EOpConstructFloat16:
9318
0
        basicOp = EOpConstructFloat16;
9319
        // 8/16-bit storage extensions don't support direct constructing composites of 8/16-bit types,
9320
        // so construct a 32-bit type and convert
9321
        // and do not generate any conversion if it is an identity conversion, i.e. float16_t(<float16_t> var)
9322
0
        if (!intermediate.getArithemeticFloat16Enabled() && (node->getBasicType() != EbtFloat16)) {
9323
0
            TType tempType(EbtFloat, EvqTemporary, type.getVectorSize());
9324
0
            newNode = node;
9325
0
            if (tempType != newNode->getType()) {
9326
0
                TOperator aggregateOp;
9327
0
                if (op == EOpConstructFloat16)
9328
0
                    aggregateOp = EOpConstructFloat;
9329
0
                else
9330
0
                    aggregateOp = (TOperator)(EOpConstructVec2 + op - EOpConstructF16Vec2);
9331
0
                newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
9332
0
            }
9333
0
            newNode = intermediate.addConversion(EbtFloat16, newNode);
9334
0
            return newNode;
9335
0
        }
9336
0
        break;
9337
9338
0
    case EOpConstructBF16Vec2:
9339
0
    case EOpConstructBF16Vec3:
9340
0
    case EOpConstructBF16Vec4:
9341
0
    case EOpConstructBFloat16:
9342
0
        basicOp = EOpConstructBFloat16;
9343
0
        break;
9344
9345
0
    case EOpConstructFloatE5M2Vec2:
9346
0
    case EOpConstructFloatE5M2Vec3:
9347
0
    case EOpConstructFloatE5M2Vec4:
9348
0
    case EOpConstructFloatE5M2:
9349
0
        basicOp = EOpConstructFloatE5M2;
9350
0
        break;
9351
9352
0
    case EOpConstructFloatE4M3Vec2:
9353
0
    case EOpConstructFloatE4M3Vec3:
9354
0
    case EOpConstructFloatE4M3Vec4:
9355
0
    case EOpConstructFloatE4M3:
9356
0
        basicOp = EOpConstructFloatE4M3;
9357
0
        break;
9358
9359
0
    case EOpConstructI8Vec2:
9360
0
    case EOpConstructI8Vec3:
9361
0
    case EOpConstructI8Vec4:
9362
0
    case EOpConstructInt8:
9363
0
        basicOp = EOpConstructInt8;
9364
        // 8/16-bit storage extensions don't support direct constructing composites of 8/16-bit types,
9365
        // so construct a 32-bit type and convert
9366
        // and do not generate any conversion if it is an identity conversion, i.e. int8_t(<int8_t> var)
9367
0
        if (!intermediate.getArithemeticInt8Enabled() && (node->getBasicType() != EbtInt8)) {
9368
0
            TType tempType(EbtInt, EvqTemporary, type.getVectorSize());
9369
0
            newNode = node;
9370
0
            if (tempType != newNode->getType()) {
9371
0
                TOperator aggregateOp;
9372
0
                if (op == EOpConstructInt8)
9373
0
                    aggregateOp = EOpConstructInt;
9374
0
                else
9375
0
                    aggregateOp = (TOperator)(EOpConstructIVec2 + op - EOpConstructI8Vec2);
9376
0
                newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
9377
0
            }
9378
0
            newNode = intermediate.addConversion(EbtInt8, newNode);
9379
0
            return newNode;
9380
0
        }
9381
0
        break;
9382
9383
0
    case EOpConstructU8Vec2:
9384
0
    case EOpConstructU8Vec3:
9385
0
    case EOpConstructU8Vec4:
9386
0
    case EOpConstructUint8:
9387
0
        basicOp = EOpConstructUint8;
9388
        // 8/16-bit storage extensions don't support direct constructing composites of 8/16-bit types,
9389
        // so construct a 32-bit type and convert
9390
        // and do not generate any conversion if it is an identity conversion, i.e. uint8_t(<uint8_t> var)
9391
0
        if (!intermediate.getArithemeticInt8Enabled() && (node->getBasicType() != EbtUint8)) {
9392
0
            TType tempType(EbtUint, EvqTemporary, type.getVectorSize());
9393
0
            newNode = node;
9394
0
            if (tempType != newNode->getType()) {
9395
0
                TOperator aggregateOp;
9396
0
                if (op == EOpConstructUint8)
9397
0
                    aggregateOp = EOpConstructUint;
9398
0
                else
9399
0
                    aggregateOp = (TOperator)(EOpConstructUVec2 + op - EOpConstructU8Vec2);
9400
0
                newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
9401
0
            }
9402
0
            newNode = intermediate.addConversion(EbtUint8, newNode);
9403
0
            return newNode;
9404
0
        }
9405
0
        break;
9406
9407
0
    case EOpConstructI16Vec2:
9408
0
    case EOpConstructI16Vec3:
9409
0
    case EOpConstructI16Vec4:
9410
0
    case EOpConstructInt16:
9411
0
        basicOp = EOpConstructInt16;
9412
        // 8/16-bit storage extensions don't support direct constructing composites of 8/16-bit types,
9413
        // so construct a 32-bit type and convert
9414
        // and do not generate any conversion if it is an identity conversion, i.e. int16_t(<int16_t> var)
9415
0
        if (!intermediate.getArithemeticInt16Enabled() && (node->getBasicType() != EbtInt16)) {
9416
0
            TType tempType(EbtInt, EvqTemporary, type.getVectorSize());
9417
0
            newNode = node;
9418
0
            if (tempType != newNode->getType()) {
9419
0
                TOperator aggregateOp;
9420
0
                if (op == EOpConstructInt16)
9421
0
                    aggregateOp = EOpConstructInt;
9422
0
                else
9423
0
                    aggregateOp = (TOperator)(EOpConstructIVec2 + op - EOpConstructI16Vec2);
9424
0
                newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
9425
0
            }
9426
0
            newNode = intermediate.addConversion(EbtInt16, newNode);
9427
0
            return newNode;
9428
0
        }
9429
0
        break;
9430
9431
0
    case EOpConstructU16Vec2:
9432
0
    case EOpConstructU16Vec3:
9433
0
    case EOpConstructU16Vec4:
9434
0
    case EOpConstructUint16:
9435
0
        basicOp = EOpConstructUint16;
9436
        // 8/16-bit storage extensions don't support direct constructing composites of 8/16-bit types,
9437
        // so construct a 32-bit type and convert
9438
        // and do not generate any conversion if it is an identity conversion, i.e. uint16_t(<uint16_t> var)
9439
0
        if (!intermediate.getArithemeticInt16Enabled() && (node->getBasicType() != EbtUint16)) {
9440
0
            TType tempType(EbtUint, EvqTemporary, type.getVectorSize());
9441
0
            newNode = node;
9442
0
            if (tempType != newNode->getType()) {
9443
0
                TOperator aggregateOp;
9444
0
                if (op == EOpConstructUint16)
9445
0
                    aggregateOp = EOpConstructUint;
9446
0
                else
9447
0
                    aggregateOp = (TOperator)(EOpConstructUVec2 + op - EOpConstructU16Vec2);
9448
0
                newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
9449
0
            }
9450
0
            newNode = intermediate.addConversion(EbtUint16, newNode);
9451
0
            return newNode;
9452
0
        }
9453
0
        break;
9454
9455
0
    case EOpConstructI64Vec2:
9456
0
    case EOpConstructI64Vec3:
9457
0
    case EOpConstructI64Vec4:
9458
0
    case EOpConstructInt64:
9459
0
        basicOp = EOpConstructInt64;
9460
0
        break;
9461
9462
0
    case EOpConstructUint64:
9463
0
        if (type.isScalar() && node->getType().isReference()) {
9464
0
            TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUint64, true, node, type);
9465
0
            return newNode;
9466
0
        }
9467
0
        [[fallthrough]];
9468
0
    case EOpConstructU64Vec2:
9469
0
    case EOpConstructU64Vec3:
9470
0
    case EOpConstructU64Vec4:
9471
0
        basicOp = EOpConstructUint64;
9472
0
        break;
9473
9474
0
    case EOpConstructNonuniform:
9475
        // Make a nonuniform copy of node
9476
0
        newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpCopyObject, true, node, type);
9477
0
        return newNode;
9478
9479
0
    case EOpConstructReference:
9480
        // construct reference from reference
9481
0
        if (node->getType().isReference()) {
9482
0
            newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConstructReference, true, node, type);
9483
0
            return newNode;
9484
        // construct reference from uint64
9485
0
        } else if (node->getType().isScalar() && node->getType().getBasicType() == EbtUint64) {
9486
0
            TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToPtr, true, node,
9487
0
                type);
9488
0
            return newNode;
9489
        // construct reference from uvec2
9490
0
        } else if (node->getType().isVector() && node->getType().getBasicType() == EbtUint &&
9491
0
                   node->getVectorSize() == 2) {
9492
0
            requireExtensions(loc, 1, &E_GL_EXT_buffer_reference_uvec2, "uvec2 conversion to reference");
9493
0
            TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUvec2ToPtr, true, node,
9494
0
                type);
9495
0
            return newNode;
9496
0
        } else {
9497
0
            return nullptr;
9498
0
        }
9499
9500
0
    case EOpConstructCooperativeVectorNV:
9501
0
        if (!node->getType().isCoopVecNV()) {
9502
0
            if (type.getBasicType() != node->getType().getBasicType()) {
9503
0
                node = intermediate.addConversion(type.getBasicType(), node);
9504
0
                if (node == nullptr)
9505
0
                    return nullptr;
9506
0
            }
9507
0
        }
9508
0
        if (type.getBasicType() != node->getType().getBasicType()) {
9509
0
            intermediate.buildConvertOp(type.getBasicType(), node->getType().getBasicType(), op);
9510
0
            node = intermediate.addUnaryNode(op, node, node->getLoc(), type);
9511
0
            return node;
9512
0
        }
9513
0
        if (subset) {
9514
0
            return node;
9515
0
        }
9516
9517
0
        node = intermediate.setAggregateOperator(node, op, type, node->getLoc());
9518
9519
0
        return node;
9520
9521
0
    case EOpConstructCooperativeMatrixNV:
9522
0
    case EOpConstructCooperativeMatrixKHR:
9523
0
        if (node->getType() == type) {
9524
0
            return node;
9525
0
        }
9526
0
        if (!node->getType().isCoopMat()) {
9527
0
            if (type.getBasicType() != node->getType().getBasicType()) {
9528
0
                node = intermediate.addConversion(type.getBasicType(), node);
9529
0
                if (node == nullptr)
9530
0
                    return nullptr;
9531
0
            }
9532
0
            node = intermediate.setAggregateOperator(node, op, type, node->getLoc());
9533
0
        } else if (type.sameCoopMatShape(node->getType()) && !type.sameCoopMatUse(node->getType()) &&
9534
0
                   type.getBasicType() == node->getType().getBasicType()) {
9535
0
            node = intermediate.setAggregateOperator(node, op, type, node->getLoc());
9536
0
        } else {
9537
0
            TOperator op = EOpConvNumeric;
9538
9539
0
            node = intermediate.addUnaryNode(op, node, node->getLoc(), type);
9540
            // If it's a (non-specialization) constant, it must be folded.
9541
0
            if (node->getAsUnaryNode()->getOperand()->getAsConstantUnion())
9542
0
                return node->getAsUnaryNode()->getOperand()->getAsConstantUnion()->fold(op, node->getType());
9543
0
        }
9544
9545
0
        return node;
9546
9547
0
    case EOpConstructAccStruct:
9548
0
        if ((node->getType().isScalar() && node->getType().getBasicType() == EbtUint64)) {
9549
            // construct acceleration structure from uint64
9550
0
            requireExtensions(loc, Num_ray_tracing_EXTs, ray_tracing_EXTs, "uint64_t conversion to acclerationStructureEXT");
9551
0
            return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToAccStruct, true, node,
9552
0
                type);
9553
0
        } else if (node->getType().isVector() && node->getType().getBasicType() == EbtUint && node->getVectorSize() == 2) {
9554
            // construct acceleration structure from uint64
9555
0
            requireExtensions(loc, Num_ray_tracing_EXTs, ray_tracing_EXTs, "uvec2 conversion to accelerationStructureEXT");
9556
0
            return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUvec2ToAccStruct, true, node,
9557
0
                type);
9558
0
        } else
9559
0
            return nullptr;
9560
9561
0
    default:
9562
0
        error(loc, "unsupported construction", "", "");
9563
9564
0
        return nullptr;
9565
2.67k
    }
9566
2.67k
    newNode = intermediate.addUnaryMath(basicOp, node, node->getLoc());
9567
2.67k
    if (newNode == nullptr) {
9568
0
        error(loc, "can't convert", "constructor", "");
9569
0
        return nullptr;
9570
0
    }
9571
9572
    //
9573
    // Now, if there still isn't an operation to do the construction, and we need one, add one.
9574
    //
9575
9576
    // Otherwise, skip out early.
9577
2.67k
    if (subset || (newNode != node && newNode->getType() == type))
9578
2.28k
        return newNode;
9579
9580
    // setAggregateOperator will insert a new node for the constructor, as needed.
9581
393
    return intermediate.setAggregateOperator(newNode, op, type, loc);
9582
2.67k
}
9583
9584
9.69k
void TParseContext::makeVariadic(TFunction *F, const TSourceLoc &loc) {
9585
9.69k
    if (parsingBuiltins) {
9586
9.69k
        F->setVariadic();
9587
9.69k
    } else {
9588
0
        error(loc, "variadic argument specifier is only available for builtins", "...", "");
9589
0
    }
9590
9.69k
}
9591
9592
TParameter TParseContext::getParamWithDefault(const TPublicType& ty, TString* identifier, TIntermTyped* initializer,
9593
                                              const TSourceLoc& loc)
9594
9.69k
{
9595
9.69k
    if (!parsingBuiltins) {
9596
0
        error(loc, "default argument values are only available for builtins", "=", "");
9597
0
        initializer = nullptr;
9598
0
    }
9599
9.69k
    if (ty.arraySizes) {
9600
0
        error(loc, "array arguments cannot be default-initialized", identifier->c_str(), "");
9601
0
        initializer = nullptr;
9602
0
    }
9603
9.69k
    if (ty.basicType == EbtVoid) {
9604
0
        error(loc, "illegal use of type 'void'", identifier->c_str(), "");
9605
0
        initializer = nullptr;
9606
0
    }
9607
9.69k
    reservedErrorCheck(loc, *identifier);
9608
9.69k
    TParameter param = {identifier, new TType(ty), initializer};
9609
9.69k
    return param;
9610
9.69k
}
9611
9612
// This function tests for the type of the parameters to the structure or array constructor. Raises
9613
// an error message if the expected type does not match the parameter passed to the constructor.
9614
//
9615
// Returns nullptr for an error or the input node itself if the expected and the given parameter types match.
9616
//
9617
TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount, const TSourceLoc& loc)
9618
32
{
9619
32
    TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped());
9620
32
    if (! converted || converted->getType() != type) {
9621
32
        bool enhanced = intermediate.getEnhancedMsgs();
9622
32
        error(loc, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount,
9623
32
              node->getAsTyped()->getType().getCompleteString(enhanced).c_str(), type.getCompleteString(enhanced).c_str());
9624
9625
32
        return nullptr;
9626
32
    }
9627
9628
0
    return converted;
9629
32
}
9630
9631
// If a memory qualifier is present in 'to', also make it present in 'from'.
9632
void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& to)
9633
10.1k
{
9634
10.1k
    if (from.isReadOnly())
9635
0
        to.readonly = from.readonly;
9636
10.1k
    if (from.isWriteOnly())
9637
0
        to.writeonly = from.writeonly;
9638
10.1k
    if (from.coherent)
9639
0
        to.coherent = from.coherent;
9640
10.1k
    if (from.volatil)
9641
0
        to.volatil = from.volatil;
9642
10.1k
    if (from.nontemporal)
9643
0
        to.nontemporal = from.nontemporal;
9644
10.1k
    if (from.restrict)
9645
0
        to.restrict = from.restrict;
9646
10.1k
}
9647
9648
//
9649
// Update qualifier layoutBindlessImage & layoutBindlessSampler on block member
9650
//
9651
void TParseContext::updateBindlessQualifier(TType& memberType)
9652
0
{
9653
0
    if (memberType.containsSampler()) {
9654
0
        if (memberType.isStruct()) {
9655
0
            TTypeList* typeList = memberType.getWritableStruct();
9656
0
            for (unsigned int member = 0; member < typeList->size(); ++member) {
9657
0
                TType* subMemberType = (*typeList)[member].type;
9658
0
                updateBindlessQualifier(*subMemberType);
9659
0
            }
9660
0
        }
9661
0
        else if (memberType.getSampler().isImage()) {
9662
0
            intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout);
9663
0
            memberType.getQualifier().layoutBindlessImage = true;
9664
0
        }
9665
0
        else {
9666
0
            intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout);
9667
0
            memberType.getQualifier().layoutBindlessSampler = true;
9668
0
        }
9669
0
    }
9670
0
}
9671
9672
//
9673
// Do everything needed to add an interface block.
9674
//
9675
void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName,
9676
    TArraySizes* arraySizes)
9677
1.91k
{
9678
1.91k
    if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed)
9679
0
        blockStorageRemap(loc, blockName, currentBlockQualifier);
9680
1.91k
    blockStageIoCheck(loc, currentBlockQualifier);
9681
1.91k
    blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr);
9682
1.91k
    if (arraySizes != nullptr) {
9683
1.25k
        arraySizesCheck(loc, currentBlockQualifier, arraySizes, nullptr, false);
9684
1.25k
        arrayOfArrayVersionCheck(loc, arraySizes);
9685
1.25k
        if (arraySizes->getNumDims() > 1)
9686
0
            requireProfile(loc, ~EEsProfile, "array-of-array of block");
9687
1.25k
    }
9688
9689
    // Inherit and check member storage qualifiers WRT to the block-level qualifier.
9690
12.0k
    for (unsigned int member = 0; member < typeList.size(); ++member) {
9691
10.1k
        TType& memberType = *typeList[member].type;
9692
10.1k
        TQualifier& memberQualifier = memberType.getQualifier();
9693
10.1k
        const TSourceLoc& memberLoc = typeList[member].loc;
9694
10.1k
        if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
9695
0
            error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
9696
10.1k
        memberQualifier.storage = currentBlockQualifier.storage;
9697
10.1k
        globalQualifierFixCheck(memberLoc, memberQualifier);
9698
10.1k
        inheritMemoryQualifiers(currentBlockQualifier, memberQualifier);
9699
10.1k
        if (currentBlockQualifier.perPrimitiveNV)
9700
2.25k
            memberQualifier.perPrimitiveNV = currentBlockQualifier.perPrimitiveNV;
9701
10.1k
        if (currentBlockQualifier.perViewNV)
9702
0
            memberQualifier.perViewNV = currentBlockQualifier.perViewNV;
9703
10.1k
        if (currentBlockQualifier.perTaskNV)
9704
0
            memberQualifier.perTaskNV = currentBlockQualifier.perTaskNV;
9705
10.1k
        if (currentBlockQualifier.storage == EvqtaskPayloadSharedEXT)
9706
0
            memberQualifier.storage = EvqtaskPayloadSharedEXT;
9707
10.1k
        if (memberQualifier.storage == EvqSpirvStorageClass)
9708
0
            error(memberLoc, "member cannot have a spirv_storage_class qualifier", memberType.getFieldName().c_str(), "");
9709
10.1k
        if (memberQualifier.hasSpirvDecorate() && !memberQualifier.getSpirvDecorate().decorateIds.empty())
9710
0
            error(memberLoc, "member cannot have a spirv_decorate_id qualifier", memberType.getFieldName().c_str(), "");
9711
10.1k
        if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
9712
0
            error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), "");
9713
10.1k
        if (memberType.isArray())
9714
5.13k
            arraySizesCheck(memberLoc, currentBlockQualifier, memberType.getArraySizes(), nullptr, member == typeList.size() - 1);
9715
10.1k
        if (memberQualifier.hasOffset()) {
9716
0
            if (spvVersion.spv == 0) {
9717
0
                profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "\"offset\" on block member");
9718
0
                profileRequires(memberLoc, EEsProfile, 300, E_GL_ARB_enhanced_layouts, "\"offset\" on block member");
9719
0
            }
9720
0
        }
9721
9722
        // For bindless texture, sampler can be declared as uniform/storage block member,
9723
10.1k
        if (memberType.containsOpaque()) {
9724
0
            if (memberType.containsSampler() && extensionTurnedOn(E_GL_ARB_bindless_texture))
9725
0
                updateBindlessQualifier(memberType);
9726
0
            else
9727
0
                error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), "");
9728
0
            }
9729
9730
10.1k
        if (memberType.containsCoopMat())
9731
0
            error(memberLoc, "member of block cannot be or contain a cooperative matrix type", typeList[member].type->getFieldName().c_str(), "");
9732
9733
10.1k
        if (memberType.containsCoopVec())
9734
0
            error(memberLoc, "member of block cannot be or contain a cooperative vector type", typeList[member].type->getFieldName().c_str(), "");
9735
10.1k
    }
9736
9737
    // This might be a redeclaration of a built-in block.  If so, redeclareBuiltinBlock() will
9738
    // do all the rest.
9739
1.91k
    if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) {
9740
0
        redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes);
9741
0
        return;
9742
0
    }
9743
9744
    // Not a redeclaration of a built-in; check that all names are user names.
9745
1.91k
    reservedErrorCheck(loc, *blockName);
9746
1.91k
    if (instanceName)
9747
1.25k
        reservedErrorCheck(loc, *instanceName);
9748
12.0k
    for (unsigned int member = 0; member < typeList.size(); ++member)
9749
10.1k
        reservedErrorCheck(typeList[member].loc, typeList[member].type->getFieldName());
9750
9751
    // Make default block qualification, and adjust the member qualifications
9752
9753
1.91k
    TQualifier defaultQualification;
9754
1.91k
    switch (currentBlockQualifier.storage) {
9755
0
    case EvqUniform:    defaultQualification = globalUniformDefaults;    break;
9756
0
    case EvqBuffer:     defaultQualification = globalBufferDefaults;     break;
9757
218
    case EvqVaryingIn:  defaultQualification = globalInputDefaults;      break;
9758
1.69k
    case EvqVaryingOut: defaultQualification = globalOutputDefaults;     break;
9759
0
    case EvqShared:     defaultQualification = globalSharedDefaults;     break;
9760
0
    default:            defaultQualification.clear();                    break;
9761
1.91k
    }
9762
9763
    // Special case for "push_constant uniform", which has a default of std430,
9764
    // contrary to normal uniform defaults, and can't have a default tracked for it.
9765
1.91k
    if ((currentBlockQualifier.isPushConstant() && !currentBlockQualifier.hasPacking()) ||
9766
1.91k
        (currentBlockQualifier.isShaderRecord() && !currentBlockQualifier.hasPacking()))
9767
0
        currentBlockQualifier.layoutPacking = ElpStd430;
9768
9769
    // Special case for "taskNV in/out", which has a default of std430,
9770
1.91k
    if (currentBlockQualifier.isTaskMemory() && !currentBlockQualifier.hasPacking())
9771
0
        currentBlockQualifier.layoutPacking = ElpStd430;
9772
9773
    // fix and check for member layout qualifiers
9774
9775
1.91k
    mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
9776
9777
    // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts."
9778
1.91k
    if (currentBlockQualifier.hasAlign()) {
9779
0
        if (defaultQualification.layoutPacking != ElpStd140 &&
9780
0
            defaultQualification.layoutPacking != ElpStd430 &&
9781
0
            defaultQualification.layoutPacking != ElpScalar) {
9782
0
            error(loc, "can only be used with std140, std430, or scalar layout packing", "align", "");
9783
0
            defaultQualification.layoutAlign = -1;
9784
0
        }
9785
0
    }
9786
9787
1.91k
    bool memberWithLocation = false;
9788
1.91k
    bool memberWithoutLocation = false;
9789
1.91k
    bool memberWithPerViewQualifier = false;
9790
12.0k
    for (unsigned int member = 0; member < typeList.size(); ++member) {
9791
10.1k
        TQualifier& memberQualifier = typeList[member].type->getQualifier();
9792
10.1k
        const TSourceLoc& memberLoc = typeList[member].loc;
9793
10.1k
        if (memberQualifier.hasStream()) {
9794
0
            if (defaultQualification.layoutStream != memberQualifier.layoutStream)
9795
0
                error(memberLoc, "member cannot contradict block", "stream", "");
9796
0
        }
9797
9798
        // "This includes a block's inheritance of the
9799
        // current global default buffer, a block member's inheritance of the block's
9800
        // buffer, and the requirement that any *xfb_buffer* declared on a block
9801
        // member must match the buffer inherited from the block."
9802
10.1k
        if (memberQualifier.hasXfbBuffer()) {
9803
0
            if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer)
9804
0
                error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", "");
9805
0
        }
9806
9807
10.1k
        if (memberQualifier.hasPacking())
9808
0
            error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), "");
9809
10.1k
        if (memberQualifier.hasLocation()) {
9810
0
            const char* feature = "location on block member";
9811
0
            switch (currentBlockQualifier.storage) {
9812
0
            case EvqVaryingIn:
9813
0
            case EvqVaryingOut:
9814
0
                requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature);
9815
0
                profileRequires(memberLoc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
9816
0
                profileRequires(memberLoc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
9817
0
                memberWithLocation = true;
9818
0
                break;
9819
0
            default:
9820
0
                error(memberLoc, "can only use in an in/out block", feature, "");
9821
0
                break;
9822
0
            }
9823
0
        } else
9824
10.1k
            memberWithoutLocation = true;
9825
9826
        // "The offset qualifier can only be used on block members of blocks declared with std140 or std430 layouts."
9827
        // "The align qualifier can only be used on blocks or block members, and only for blocks declared with std140 or std430 layouts."
9828
10.1k
        if (memberQualifier.hasAlign() || memberQualifier.hasOffset()) {
9829
0
            if (defaultQualification.layoutPacking != ElpStd140 &&
9830
0
                defaultQualification.layoutPacking != ElpStd430 &&
9831
0
                defaultQualification.layoutPacking != ElpScalar)
9832
0
                error(memberLoc, "can only be used with std140, std430, or scalar layout packing", "offset/align", "");
9833
0
        }
9834
9835
10.1k
        if (memberQualifier.isPerView()) {
9836
1.02k
            memberWithPerViewQualifier = true;
9837
1.02k
        }
9838
9839
10.1k
        TQualifier newMemberQualification = defaultQualification;
9840
10.1k
        mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false);
9841
10.1k
        memberQualifier = newMemberQualification;
9842
10.1k
    }
9843
9844
1.91k
    layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes);
9845
9846
    // Ensure that the block has an XfbBuffer assigned. This is needed
9847
    // because if the block has a XfbOffset assigned, then it is
9848
    // assumed that it has implicitly assigned the current global
9849
    // XfbBuffer, and because it's members need to be assigned a
9850
    // XfbOffset if they lack it.
9851
1.91k
    if (currentBlockQualifier.storage == EvqVaryingOut && globalOutputDefaults.hasXfbBuffer()) {
9852
872
       if (!currentBlockQualifier.hasXfbBuffer() && currentBlockQualifier.hasXfbOffset())
9853
0
          currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
9854
872
    }
9855
9856
    // Process the members
9857
1.91k
    fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
9858
1.91k
    fixXfbOffsets(currentBlockQualifier, typeList);
9859
1.91k
    fixBlockUniformOffsets(currentBlockQualifier, typeList);
9860
1.91k
    fixBlockUniformLayoutMatrix(currentBlockQualifier, &typeList, nullptr);
9861
1.91k
    fixBlockUniformLayoutPacking(currentBlockQualifier, &typeList, nullptr);
9862
12.0k
    for (unsigned int member = 0; member < typeList.size(); ++member)
9863
10.1k
        layoutTypeCheck(typeList[member].loc, *typeList[member].type);
9864
9865
1.91k
    if (memberWithPerViewQualifier) {
9866
3.07k
        for (unsigned int member = 0; member < typeList.size(); ++member) {
9867
2.66k
            checkAndResizeMeshViewDim(typeList[member].loc, *typeList[member].type, /*isBlockMember*/ true);
9868
2.66k
        }
9869
410
    }
9870
9871
    // reverse merge, so that currentBlockQualifier now has all layout information
9872
    // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
9873
1.91k
    mergeObjectLayoutQualifiers(currentBlockQualifier, defaultQualification, true);
9874
9875
    //
9876
    // Build and add the interface block as a new type named 'blockName'
9877
    //
9878
9879
1.91k
    TType blockType(&typeList, *blockName, currentBlockQualifier);
9880
1.91k
    if (arraySizes != nullptr)
9881
1.25k
        blockType.transferArraySizes(arraySizes);
9882
9883
1.91k
    if (arraySizes == nullptr)
9884
654
        ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
9885
1.91k
    if (currentBlockQualifier.hasBufferReference()) {
9886
9887
0
        if (currentBlockQualifier.storage != EvqBuffer)
9888
0
            error(loc, "can only be used with buffer", "buffer_reference", "");
9889
9890
        // Create the block reference type. If it was forward-declared, detect that
9891
        // as a referent struct type with no members. Replace the referent type with
9892
        // blockType.
9893
0
        TType blockNameType(EbtReference, blockType, *blockName);
9894
0
        TVariable* blockNameVar = new TVariable(blockName, blockNameType, true);
9895
0
        if (! symbolTable.insert(*blockNameVar)) {
9896
0
            TSymbol* existingName = symbolTable.find(*blockName);
9897
0
            if (existingName->getType().isReference() &&
9898
0
                existingName->getType().getReferentType()->getStruct() &&
9899
0
                existingName->getType().getReferentType()->getStruct()->size() == 0 &&
9900
0
                existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
9901
0
                existingName->getType().getReferentType()->deepCopy(blockType);
9902
0
            } else {
9903
0
                error(loc, "block name cannot be redefined", blockName->c_str(), "");
9904
0
            }
9905
0
        }
9906
0
        if (!instanceName) {
9907
0
            return;
9908
0
        }
9909
1.91k
    } else {
9910
        //
9911
        // Don't make a user-defined type out of block name; that will cause an error
9912
        // if the same block name gets reused in a different interface.
9913
        //
9914
        // "Block names have no other use within a shader
9915
        // beyond interface matching; it is a compile-time error to use a block name at global scope for anything
9916
        // other than as a block name (e.g., use of a block name for a global variable name or function name is
9917
        // currently reserved)."
9918
        //
9919
        // Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
9920
        // whose type is EbtBlock, but without all the structure; that will come from the type
9921
        // the instances point to.
9922
        //
9923
1.91k
        TType blockNameType(EbtBlock, blockType.getQualifier().storage);
9924
1.91k
        TVariable* blockNameVar = new TVariable(blockName, blockNameType);
9925
1.91k
        if (! symbolTable.insert(*blockNameVar)) {
9926
218
            TSymbol* existingName = symbolTable.find(*blockName);
9927
218
            if (existingName->getType().getBasicType() == EbtBlock) {
9928
218
                if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
9929
0
                    error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
9930
0
                    return;
9931
0
                }
9932
218
            } else {
9933
0
                error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
9934
0
                return;
9935
0
            }
9936
218
        }
9937
1.91k
    }
9938
9939
    // Add the variable, as anonymous or named instanceName.
9940
    // Make an anonymous variable if no name was provided.
9941
1.91k
    if (! instanceName)
9942
654
        instanceName = NewPoolTString("");
9943
9944
1.91k
    TVariable& variable = *new TVariable(instanceName, blockType);
9945
1.91k
    if (! symbolTable.insert(variable)) {
9946
0
        if (*instanceName == "")
9947
0
            error(loc, "nameless block contains a member that already has a name at global scope", blockName->c_str(), "");
9948
0
        else
9949
0
            error(loc, "block instance name redefinition", variable.getName().c_str(), "");
9950
9951
0
        return;
9952
0
    }
9953
9954
    // Check for general layout qualifier errors
9955
1.91k
    layoutObjectCheck(loc, variable);
9956
9957
    // fix up
9958
1.91k
    if (isIoResizeArray(blockType)) {
9959
1.25k
        ioArraySymbolResizeList.push_back(&variable);
9960
1.25k
        checkIoArraysConsistency(loc, true);
9961
1.25k
    } else
9962
654
        fixIoArraySize(loc, variable.getWritableType());
9963
9964
    // Save it in the AST for linker use.
9965
1.91k
    trackLinkage(variable);
9966
1.91k
}
9967
9968
//
9969
// allow storage type of block to be remapped at compile time
9970
//
9971
void TParseContext::blockStorageRemap(const TSourceLoc&, const TString* instanceName, TQualifier& qualifier)
9972
0
{
9973
0
    TBlockStorageClass type = intermediate.getBlockStorageOverride(instanceName->c_str());
9974
0
    if (type != EbsNone) {
9975
0
        qualifier.setBlockStorage(type);
9976
0
    }
9977
0
}
9978
9979
// Do all block-declaration checking regarding the combination of in/out/uniform/buffer
9980
// with a particular stage.
9981
void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& qualifier)
9982
1.91k
{
9983
1.91k
    const char *extsrt[2] = { E_GL_NV_ray_tracing, E_GL_EXT_ray_tracing };
9984
1.91k
    switch (qualifier.storage) {
9985
0
    case EvqUniform:
9986
0
        profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
9987
0
        profileRequires(loc, ENoProfile, 140, E_GL_ARB_uniform_buffer_object, "uniform block");
9988
0
        if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.isPushConstant())
9989
0
            requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "std430 requires the buffer storage qualifier");
9990
0
        break;
9991
0
    case EvqBuffer:
9992
0
        requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "buffer block");
9993
0
        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_shader_storage_buffer_object, "buffer block");
9994
0
        profileRequires(loc, EEsProfile, 310, nullptr, "buffer block");
9995
0
        break;
9996
218
    case EvqVaryingIn:
9997
218
        profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "input block");
9998
        // It is a compile-time error to have an input block in a vertex shader or an output block in a fragment shader
9999
        // "Compute shaders do not permit user-defined input variables..."
10000
218
        requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|
10001
218
            EShLangFragmentMask|EShLangMeshMask), "input block");
10002
218
        if (language == EShLangFragment) {
10003
0
            profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block");
10004
218
        } else if (language == EShLangMesh && ! qualifier.isTaskMemory()) {
10005
0
            error(loc, "input blocks cannot be used in a mesh shader", "out", "");
10006
0
        }
10007
218
        break;
10008
1.69k
    case EvqVaryingOut:
10009
1.69k
        profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block");
10010
1.69k
        requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|
10011
1.69k
            EShLangGeometryMask|EShLangMeshMask|EShLangTaskMask), "output block");
10012
        // ES 310 can have a block before shader_io is turned on, so skip this test for built-ins
10013
1.69k
        if (language == EShLangVertex && ! parsingBuiltins) {
10014
0
            profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block");
10015
1.69k
        } else if (language == EShLangMesh && qualifier.isTaskMemory()) {
10016
0
            error(loc, "can only use on input blocks in mesh shader", "taskNV", "");
10017
1.69k
        } else if (language == EShLangTask && ! qualifier.isTaskMemory()) {
10018
0
            error(loc, "output blocks cannot be used in a task shader", "out", "");
10019
0
        }
10020
1.69k
        break;
10021
0
    case EvqShared:
10022
0
        if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) {
10023
0
            error(loc, "shared block requires at least SPIR-V 1.4", "shared block", "");
10024
0
        }
10025
0
        profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block");
10026
0
        break;
10027
0
    case EvqPayload:
10028
0
        profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadNV block");
10029
0
        requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangAnyHitMask | EShLangClosestHitMask | EShLangMissMask),
10030
0
            "rayPayloadNV block");
10031
0
        break;
10032
0
    case EvqPayloadIn:
10033
0
        profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadInNV block");
10034
0
        requireStage(loc, (EShLanguageMask)(EShLangAnyHitMask | EShLangClosestHitMask | EShLangMissMask),
10035
0
            "rayPayloadInNV block");
10036
0
        break;
10037
0
    case EvqHitAttr:
10038
0
        profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "hitAttributeNV block");
10039
0
        requireStage(loc, (EShLanguageMask)(EShLangIntersectMask | EShLangAnyHitMask | EShLangClosestHitMask), "hitAttributeNV block");
10040
0
        break;
10041
0
    case EvqCallableData:
10042
0
        profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataNV block");
10043
0
        requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | EShLangMissMask | EShLangCallableMask),
10044
0
            "callableDataNV block");
10045
0
        break;
10046
0
    case EvqCallableDataIn:
10047
0
        profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataInNV block");
10048
0
        requireStage(loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV block");
10049
0
        break;
10050
0
    case EvqHitObjectAttrNV:
10051
0
        profileRequires(loc, ~EEsProfile, 460, E_GL_NV_shader_invocation_reorder, "hitObjectAttributeNV block");
10052
0
        requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | EShLangMissMask), "hitObjectAttributeNV block");
10053
0
        break;
10054
0
    default:
10055
0
        error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
10056
0
        break;
10057
1.91k
    }
10058
1.91k
}
10059
10060
// Do all block-declaration checking regarding its qualifiers.
10061
void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool /*instanceName*/)
10062
1.91k
{
10063
    // The 4.5 specification says:
10064
    //
10065
    // interface-block :
10066
    //    layout-qualifieropt interface-qualifier  block-name { member-list } instance-nameopt ;
10067
    //
10068
    // interface-qualifier :
10069
    //    in
10070
    //    out
10071
    //    patch in
10072
    //    patch out
10073
    //    uniform
10074
    //    buffer
10075
    //
10076
    // Note however memory qualifiers aren't included, yet the specification also says
10077
    //
10078
    // "...memory qualifiers may also be used in the declaration of shader storage blocks..."
10079
10080
1.91k
    if (qualifier.isInterpolation())
10081
0
        error(loc, "cannot use interpolation qualifiers on an interface block", "flat/smooth/noperspective", "");
10082
1.91k
    if (qualifier.centroid)
10083
0
        error(loc, "cannot use centroid qualifier on an interface block", "centroid", "");
10084
1.91k
    if (qualifier.isSample())
10085
0
        error(loc, "cannot use sample qualifier on an interface block", "sample", "");
10086
1.91k
    if (qualifier.invariant)
10087
0
        error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
10088
1.91k
    if (qualifier.isPushConstant())
10089
0
        intermediate.addPushConstantCount();
10090
1.91k
    if (qualifier.isShaderRecord())
10091
0
        intermediate.addShaderRecordCount();
10092
1.91k
    if (qualifier.isTaskMemory())
10093
0
        intermediate.addTaskNVCount();
10094
1.91k
}
10095
10096
//
10097
// "For a block, this process applies to the entire block, or until the first member
10098
// is reached that has a location layout qualifier. When a block member is declared with a location
10099
// qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level
10100
// declaration. Subsequent members are again assigned consecutive locations, based on the newest location,
10101
// until the next member declared with a location qualifier. The values used for locations do not have to be
10102
// declared in increasing order."
10103
void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation)
10104
1.91k
{
10105
    // "If a block has no block-level location layout qualifier, it is required that either all or none of its members
10106
    // have a location layout qualifier, or a compile-time error results."
10107
1.91k
    if (! qualifier.hasLocation() && memberWithLocation && memberWithoutLocation)
10108
0
        error(loc, "either the block needs a location, or all members need a location, or no members have a location", "location", "");
10109
1.91k
    else {
10110
1.91k
        if (memberWithLocation) {
10111
            // remove any block-level location and make it per *every* member
10112
0
            int nextLocation = 0;  // by the rule above, initial value is not relevant
10113
0
            if (qualifier.hasAnyLocation()) {
10114
0
                nextLocation = qualifier.layoutLocation;
10115
0
                qualifier.layoutLocation = TQualifier::layoutLocationEnd;
10116
0
                if (qualifier.hasComponent()) {
10117
                    // "It is a compile-time error to apply the *component* qualifier to a ... block"
10118
0
                    error(loc, "cannot apply to a block", "component", "");
10119
0
                }
10120
0
                if (qualifier.hasIndex()) {
10121
0
                    error(loc, "cannot apply to a block", "index", "");
10122
0
                }
10123
0
            }
10124
0
            for (unsigned int member = 0; member < typeList.size(); ++member) {
10125
0
                TQualifier& memberQualifier = typeList[member].type->getQualifier();
10126
0
                const TSourceLoc& memberLoc = typeList[member].loc;
10127
0
                if (! memberQualifier.hasLocation()) {
10128
0
                    if (nextLocation >= (int)TQualifier::layoutLocationEnd)
10129
0
                        error(memberLoc, "location is too large", "location", "");
10130
0
                    memberQualifier.layoutLocation = nextLocation;
10131
0
                    memberQualifier.layoutComponent = TQualifier::layoutComponentEnd;
10132
0
                }
10133
0
                nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize(
10134
0
                                    *typeList[member].type, language);
10135
0
            }
10136
0
        }
10137
1.91k
    }
10138
1.91k
}
10139
10140
void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
10141
1.91k
{
10142
    // "If a block is qualified with xfb_offset, all its
10143
    // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any
10144
    // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer
10145
    // offsets."
10146
10147
1.91k
    if (! qualifier.hasXfbBuffer() || ! qualifier.hasXfbOffset())
10148
1.91k
        return;
10149
10150
0
    int nextOffset = qualifier.layoutXfbOffset;
10151
0
    for (unsigned int member = 0; member < typeList.size(); ++member) {
10152
0
        TQualifier& memberQualifier = typeList[member].type->getQualifier();
10153
0
        bool contains64BitType = false;
10154
0
        bool contains32BitType = false;
10155
0
        bool contains16BitType = false;
10156
0
        int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType, contains32BitType, contains16BitType);
10157
        // see if we need to auto-assign an offset to this member
10158
0
        if (! memberQualifier.hasXfbOffset()) {
10159
            // "if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8"
10160
0
            if (contains64BitType)
10161
0
                RoundToPow2(nextOffset, 8);
10162
0
            else if (contains32BitType)
10163
0
                RoundToPow2(nextOffset, 4);
10164
0
            else if (contains16BitType)
10165
0
                RoundToPow2(nextOffset, 2);
10166
0
            memberQualifier.layoutXfbOffset = nextOffset;
10167
0
        } else
10168
0
            nextOffset = memberQualifier.layoutXfbOffset;
10169
0
        nextOffset += memberSize;
10170
0
    }
10171
10172
    // The above gave all block members an offset, so we can take it off the block now,
10173
    // which will avoid double counting the offset usage.
10174
0
    qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd;
10175
0
}
10176
10177
// Calculate and save the offset of each block member, using the recursively
10178
// defined block offset rules and the user-provided offset and align.
10179
//
10180
// Also, compute and save the total size of the block. For the block's size, arrayness
10181
// is not taken into account, as each element is backed by a separate buffer.
10182
//
10183
void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList)
10184
1.91k
{
10185
1.91k
    if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory())
10186
1.91k
        return;
10187
0
    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar)
10188
0
        return;
10189
10190
0
    int offset = 0;
10191
0
    int memberSize;
10192
0
    for (unsigned int member = 0; member < typeList.size(); ++member) {
10193
0
        TQualifier& memberQualifier = typeList[member].type->getQualifier();
10194
0
        const TSourceLoc& memberLoc = typeList[member].loc;
10195
10196
        // "When align is applied to an array, it effects only the start of the array, not the array's internal stride."
10197
10198
        // modify just the children's view of matrix layout, if there is one for this member
10199
0
        TLayoutMatrix subMatrixLayout = typeList[member].type->getQualifier().layoutMatrix;
10200
0
        int dummyStride;
10201
0
        int memberAlignment = intermediate.getMemberAlignment(*typeList[member].type, memberSize, dummyStride, qualifier.layoutPacking,
10202
0
                                                              subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : qualifier.layoutMatrix == ElmRowMajor);
10203
0
        if (memberQualifier.hasOffset()) {
10204
            // "The specified offset must be a multiple
10205
            // of the base alignment of the type of the block member it qualifies, or a compile-time error results."
10206
0
            if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment))
10207
0
                error(memberLoc, "must be a multiple of the member's alignment", "offset",
10208
0
                    "(layout offset = %d | member alignment = %d)", memberQualifier.layoutOffset, memberAlignment);
10209
10210
            // GLSL: "It is a compile-time error to specify an offset that is smaller than the offset of the previous
10211
            // member in the block or that lies within the previous member of the block"
10212
0
            if (spvVersion.spv == 0) {
10213
0
                if (memberQualifier.layoutOffset < offset)
10214
0
                    error(memberLoc, "cannot lie in previous members", "offset", "");
10215
10216
                // "The offset qualifier forces the qualified member to start at or after the specified
10217
                // integral-constant expression, which will be its byte offset from the beginning of the buffer.
10218
                // "The actual offset of a member is computed as
10219
                // follows: If offset was declared, start with that offset, otherwise start with the next available offset."
10220
0
                offset = std::max(offset, memberQualifier.layoutOffset);
10221
0
            } else {
10222
                // TODO: Vulkan: "It is a compile-time error to have any offset, explicit or assigned,
10223
                // that lies within another member of the block."
10224
10225
0
                offset = memberQualifier.layoutOffset;
10226
0
            }
10227
0
        }
10228
10229
        // "The actual alignment of a member will be the greater of the specified align alignment and the standard
10230
        // (e.g., std140) base alignment for the member's type."
10231
0
        if (memberQualifier.hasAlign())
10232
0
            memberAlignment = std::max(memberAlignment, memberQualifier.layoutAlign);
10233
10234
        // "If the resulting offset is not a multiple of the actual alignment,
10235
        // increase it to the first offset that is a multiple of
10236
        // the actual alignment."
10237
0
        RoundToPow2(offset, memberAlignment);
10238
0
        typeList[member].type->getQualifier().layoutOffset = offset;
10239
0
        offset += memberSize;
10240
0
    }
10241
0
}
10242
10243
//
10244
// Spread LayoutMatrix to uniform block member, if a uniform block member is a struct,
10245
// we need spread LayoutMatrix to this struct member too. and keep this rule for recursive.
10246
//
10247
void TParseContext::fixBlockUniformLayoutMatrix(TQualifier& qualifier, TTypeList* originTypeList,
10248
                                                TTypeList* tmpTypeList)
10249
1.91k
{
10250
1.91k
    assert(tmpTypeList == nullptr || originTypeList->size() == tmpTypeList->size());
10251
12.0k
    for (unsigned int member = 0; member < originTypeList->size(); ++member) {
10252
10.1k
        if (qualifier.layoutPacking != ElpNone) {
10253
0
            if (tmpTypeList == nullptr) {
10254
0
                if (((*originTypeList)[member].type->isMatrix() ||
10255
0
                     (*originTypeList)[member].type->getBasicType() == EbtStruct) &&
10256
0
                    (*originTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) {
10257
0
                    (*originTypeList)[member].type->getQualifier().layoutMatrix = qualifier.layoutMatrix;
10258
0
                }
10259
0
            } else {
10260
0
                if (((*tmpTypeList)[member].type->isMatrix() ||
10261
0
                     (*tmpTypeList)[member].type->getBasicType() == EbtStruct) &&
10262
0
                    (*tmpTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) {
10263
0
                    (*tmpTypeList)[member].type->getQualifier().layoutMatrix = qualifier.layoutMatrix;
10264
0
                }
10265
0
            }
10266
0
        }
10267
10268
10.1k
        if ((*originTypeList)[member].type->getBasicType() == EbtStruct) {
10269
0
            TQualifier* memberQualifier = nullptr;
10270
            // block member can be declare a matrix style, so it should be update to the member's style
10271
0
            if ((*originTypeList)[member].type->getQualifier().layoutMatrix == ElmNone) {
10272
0
                memberQualifier = &qualifier;
10273
0
            } else {
10274
0
                memberQualifier = &((*originTypeList)[member].type->getQualifier());
10275
0
            }
10276
10277
0
            const TType* tmpType = tmpTypeList == nullptr ?
10278
0
                (*originTypeList)[member].type->clone() : (*tmpTypeList)[member].type;
10279
10280
0
            fixBlockUniformLayoutMatrix(*memberQualifier, (*originTypeList)[member].type->getWritableStruct(),
10281
0
                                        tmpType->getWritableStruct());
10282
10283
0
            const TTypeList* structure = recordStructCopy(matrixFixRecord, (*originTypeList)[member].type, tmpType);
10284
10285
0
            if (tmpTypeList == nullptr) {
10286
0
                (*originTypeList)[member].type->setStruct(const_cast<TTypeList*>(structure));
10287
0
            }
10288
0
            if (tmpTypeList != nullptr) {
10289
0
                (*tmpTypeList)[member].type->setStruct(const_cast<TTypeList*>(structure));
10290
0
            }
10291
0
        }
10292
10.1k
    }
10293
1.91k
}
10294
10295
//
10296
// Spread LayoutPacking to matrix or aggregate block members. If a block member is a struct or
10297
// array of struct, spread LayoutPacking recursively to its matrix or aggregate members.
10298
//
10299
void TParseContext::fixBlockUniformLayoutPacking(TQualifier& qualifier, TTypeList* originTypeList,
10300
                                                 TTypeList* tmpTypeList)
10301
1.91k
{
10302
1.91k
    assert(tmpTypeList == nullptr || originTypeList->size() == tmpTypeList->size());
10303
12.0k
    for (unsigned int member = 0; member < originTypeList->size(); ++member) {
10304
10.1k
        if (qualifier.layoutPacking != ElpNone) {
10305
0
            if (tmpTypeList == nullptr) {
10306
0
                if ((*originTypeList)[member].type->getQualifier().layoutPacking == ElpNone &&
10307
0
                    !(*originTypeList)[member].type->isScalarOrVector()) {
10308
0
                    (*originTypeList)[member].type->getQualifier().layoutPacking = qualifier.layoutPacking;
10309
0
                }
10310
0
            } else {
10311
0
                if ((*tmpTypeList)[member].type->getQualifier().layoutPacking == ElpNone &&
10312
0
                    !(*tmpTypeList)[member].type->isScalarOrVector()) {
10313
0
                    (*tmpTypeList)[member].type->getQualifier().layoutPacking = qualifier.layoutPacking;
10314
0
                }
10315
0
            }
10316
0
        }
10317
10318
10.1k
        if ((*originTypeList)[member].type->getBasicType() == EbtStruct) {
10319
            // Deep copy the type in pool.
10320
            // Because, struct use in different block may have different layout qualifier.
10321
            // We have to new a object to distinguish between them.
10322
0
            const TType* tmpType = tmpTypeList == nullptr ?
10323
0
                (*originTypeList)[member].type->clone() : (*tmpTypeList)[member].type;
10324
10325
0
            fixBlockUniformLayoutPacking(qualifier, (*originTypeList)[member].type->getWritableStruct(),
10326
0
                                         tmpType->getWritableStruct());
10327
10328
0
            const TTypeList* structure = recordStructCopy(packingFixRecord, (*originTypeList)[member].type, tmpType);
10329
10330
0
            if (tmpTypeList == nullptr) {
10331
0
                (*originTypeList)[member].type->setStruct(const_cast<TTypeList*>(structure));
10332
0
            }
10333
0
            if (tmpTypeList != nullptr) {
10334
0
                (*tmpTypeList)[member].type->setStruct(const_cast<TTypeList*>(structure));
10335
0
            }
10336
0
        }
10337
10.1k
    }
10338
1.91k
}
10339
10340
// For an identifier that is already declared, add more qualification to it.
10341
void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier)
10342
0
{
10343
0
    TSymbol* symbol = symbolTable.find(identifier);
10344
10345
    // A forward declaration of a block reference looks to the grammar like adding
10346
    // a qualifier to an existing symbol. Detect this and create the block reference
10347
    // type with an empty type list, which will be filled in later in
10348
    // TParseContext::declareBlock.
10349
0
    if (!symbol && qualifier.hasBufferReference()) {
10350
        // The layout qualifiers are ignored in forward declaration, give warning for the most probable to be seen
10351
0
        if (qualifier.hasBufferReferenceAlign()) {
10352
0
            warn(loc, "the buffer_reference_align layout is ignored when defined in forward declaration",
10353
0
                 identifier.c_str(), "");
10354
0
        }
10355
0
        if (qualifier.hasPacking()) {
10356
0
            warn(loc, "the packing layout (scalar, std430, etc) is ignored when defined in forward declaration",
10357
0
                 identifier.c_str(), "");
10358
0
        }
10359
0
        TTypeList typeList;
10360
0
        TType blockType(&typeList, identifier, qualifier);
10361
0
        TType blockNameType(EbtReference, blockType, identifier);
10362
0
        TVariable* blockNameVar = new TVariable(&identifier, blockNameType, true);
10363
0
        if (! symbolTable.insert(*blockNameVar)) {
10364
0
            error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
10365
0
        }
10366
0
        return;
10367
0
    }
10368
10369
0
    if (! symbol) {
10370
0
        error(loc, "identifier not previously declared", identifier.c_str(), "");
10371
0
        return;
10372
0
    }
10373
0
    if (symbol->getAsFunction()) {
10374
0
        error(loc, "cannot re-qualify a function name", identifier.c_str(), "");
10375
0
        return;
10376
0
    }
10377
10378
0
    if (qualifier.isAuxiliary() ||
10379
0
        qualifier.isMemory() ||
10380
0
        qualifier.isInterpolation() ||
10381
0
        qualifier.hasLayout() ||
10382
0
        qualifier.storage != EvqTemporary ||
10383
0
        qualifier.precision != EpqNone) {
10384
0
        error(loc, "cannot add storage, auxiliary, memory, interpolation, layout, or precision qualifier to an existing variable", identifier.c_str(), "");
10385
0
        return;
10386
0
    }
10387
10388
    // For read-only built-ins, add a new symbol for holding the modified qualifier.
10389
    // This will bring up an entire block, if a block type has to be modified (e.g., gl_Position inside a block)
10390
0
    if (symbol->isReadOnly())
10391
0
        symbol = symbolTable.copyUp(symbol);
10392
10393
0
    if (qualifier.invariant) {
10394
0
        if (intermediate.inIoAccessed(identifier))
10395
0
            error(loc, "cannot change qualification after use", "invariant", "");
10396
0
        symbol->getWritableType().getQualifier().invariant = true;
10397
0
        invariantCheck(loc, symbol->getType().getQualifier());
10398
0
    } else if (qualifier.isNoContraction()) {
10399
0
        if (intermediate.inIoAccessed(identifier))
10400
0
            error(loc, "cannot change qualification after use", "precise", "");
10401
0
        symbol->getWritableType().getQualifier().setNoContraction();
10402
0
    } else if (qualifier.specConstant) {
10403
0
        symbol->getWritableType().getQualifier().makeSpecConstant();
10404
0
        if (qualifier.hasSpecConstantId())
10405
0
            symbol->getWritableType().getQualifier().layoutSpecConstantId = qualifier.layoutSpecConstantId;
10406
0
    } else
10407
0
        warn(loc, "unknown requalification", "", "");
10408
0
}
10409
10410
void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, TIdentifierList& identifiers)
10411
0
{
10412
0
    for (unsigned int i = 0; i < identifiers.size(); ++i)
10413
0
        addQualifierToExisting(loc, qualifier, *identifiers[i]);
10414
0
}
10415
10416
// Make sure 'invariant' isn't being applied to a non-allowed object.
10417
void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qualifier)
10418
281k
{
10419
281k
    if (! qualifier.invariant)
10420
281k
        return;
10421
10422
0
    bool pipeOut = qualifier.isPipeOutput();
10423
0
    bool pipeIn = qualifier.isPipeInput();
10424
0
    if ((version >= 300 && isEsProfile()) || (!isEsProfile() && version >= 420)) {
10425
0
        if (! pipeOut)
10426
0
            error(loc, "can only apply to an output", "invariant", "");
10427
0
    } else {
10428
0
        if ((language == EShLangVertex && pipeIn) || (! pipeOut && ! pipeIn))
10429
0
            error(loc, "can only apply to an output, or to an input in a non-vertex stage\n", "invariant", "");
10430
0
    }
10431
0
}
10432
10433
//
10434
// Updating default qualifier for the case of a declaration with just a qualifier,
10435
// no type, block, or identifier.
10436
//
10437
void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType)
10438
0
{
10439
0
    if (publicType.shaderQualifiers.vertices != TQualifier::layoutNotSet) {
10440
0
        assert(language == EShLangTessControl || language == EShLangGeometry || language == EShLangMesh);
10441
0
        const char* id = (language == EShLangTessControl) ? "vertices" : "max_vertices";
10442
10443
0
        if (publicType.qualifier.storage != EvqVaryingOut)
10444
0
            error(loc, "can only apply to 'out'", id, "");
10445
0
        if (! intermediate.setVertices(publicType.shaderQualifiers.vertices))
10446
0
            error(loc, "cannot change previously set layout value", id, "");
10447
10448
0
        if (language == EShLangTessControl)
10449
0
            checkIoArraysConsistency(loc);
10450
0
    }
10451
0
    if (publicType.shaderQualifiers.primitives != TQualifier::layoutNotSet) {
10452
0
        assert(language == EShLangMesh);
10453
0
        const char* id = "max_primitives";
10454
10455
0
        if (publicType.qualifier.storage != EvqVaryingOut)
10456
0
            error(loc, "can only apply to 'out'", id, "");
10457
0
        if (! intermediate.setPrimitives(publicType.shaderQualifiers.primitives))
10458
0
            error(loc, "cannot change previously set layout value", id, "");
10459
0
    }
10460
0
    if (publicType.shaderQualifiers.invocations != TQualifier::layoutNotSet) {
10461
0
        if (publicType.qualifier.storage != EvqVaryingIn)
10462
0
            error(loc, "can only apply to 'in'", "invocations", "");
10463
0
        if (! intermediate.setInvocations(publicType.shaderQualifiers.invocations))
10464
0
            error(loc, "cannot change previously set layout value", "invocations", "");
10465
0
    }
10466
0
    if (publicType.shaderQualifiers.geometry != ElgNone) {
10467
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10468
0
            switch (publicType.shaderQualifiers.geometry) {
10469
0
            case ElgPoints:
10470
0
            case ElgLines:
10471
0
            case ElgLinesAdjacency:
10472
0
            case ElgTriangles:
10473
0
            case ElgTrianglesAdjacency:
10474
0
            case ElgQuads:
10475
0
            case ElgIsolines:
10476
0
                if (language == EShLangMesh) {
10477
0
                    error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10478
0
                    break;
10479
0
                }
10480
0
                if (intermediate.setInputPrimitive(publicType.shaderQualifiers.geometry)) {
10481
0
                    if (language == EShLangGeometry)
10482
0
                        checkIoArraysConsistency(loc);
10483
0
                } else
10484
0
                    error(loc, "cannot change previously set input primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10485
0
                break;
10486
0
            default:
10487
0
                error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10488
0
            }
10489
0
        } else if (publicType.qualifier.storage == EvqVaryingOut) {
10490
0
            switch (publicType.shaderQualifiers.geometry) {
10491
0
            case ElgLines:
10492
0
            case ElgTriangles:
10493
0
                if (language != EShLangMesh) {
10494
0
                    error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10495
0
                    break;
10496
0
                }
10497
0
                [[fallthrough]];
10498
0
            case ElgPoints:
10499
0
            case ElgLineStrip:
10500
0
            case ElgTriangleStrip:
10501
0
                if (! intermediate.setOutputPrimitive(publicType.shaderQualifiers.geometry))
10502
0
                    error(loc, "cannot change previously set output primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10503
0
                break;
10504
0
            default:
10505
0
                error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
10506
0
            }
10507
0
        } else
10508
0
            error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
10509
0
    }
10510
0
    if (publicType.shaderQualifiers.spacing != EvsNone) {
10511
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10512
0
            if (! intermediate.setVertexSpacing(publicType.shaderQualifiers.spacing))
10513
0
                error(loc, "cannot change previously set vertex spacing", TQualifier::getVertexSpacingString(publicType.shaderQualifiers.spacing), "");
10514
0
        } else
10515
0
            error(loc, "can only apply to 'in'", TQualifier::getVertexSpacingString(publicType.shaderQualifiers.spacing), "");
10516
0
    }
10517
0
    if (publicType.shaderQualifiers.order != EvoNone) {
10518
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10519
0
            if (! intermediate.setVertexOrder(publicType.shaderQualifiers.order))
10520
0
                error(loc, "cannot change previously set vertex order", TQualifier::getVertexOrderString(publicType.shaderQualifiers.order), "");
10521
0
        } else
10522
0
            error(loc, "can only apply to 'in'", TQualifier::getVertexOrderString(publicType.shaderQualifiers.order), "");
10523
0
    }
10524
0
    if (publicType.shaderQualifiers.pointMode) {
10525
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10526
0
            intermediate.setPointMode();
10527
0
        else
10528
0
            error(loc, "can only apply to 'in'", "point_mode", "");
10529
0
    }
10530
10531
0
    for (int i = 0; i < 3; ++i) {
10532
0
        if (publicType.shaderQualifiers.localSizeNotDefault[i]) {
10533
0
            if (publicType.qualifier.storage == EvqVaryingIn) {
10534
0
                if (! intermediate.setLocalSize(i, publicType.shaderQualifiers.localSize[i]))
10535
0
                    error(loc, "cannot change previously set size", "local_size", "");
10536
0
                else {
10537
0
                    int max = 0;
10538
0
                    if (language == EShLangCompute) {
10539
0
                        switch (i) {
10540
0
                        case 0: max = resources.maxComputeWorkGroupSizeX; break;
10541
0
                        case 1: max = resources.maxComputeWorkGroupSizeY; break;
10542
0
                        case 2: max = resources.maxComputeWorkGroupSizeZ; break;
10543
0
                        default: break;
10544
0
                        }
10545
0
                        if (intermediate.getLocalSize(i) > (unsigned int)max)
10546
0
                            error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
10547
0
                    } else if (language == EShLangMesh) {
10548
0
                        switch (i) {
10549
0
                        case 0:
10550
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10551
0
                                    resources.maxMeshWorkGroupSizeX_EXT :
10552
0
                                    resources.maxMeshWorkGroupSizeX_NV;
10553
0
                            break;
10554
0
                        case 1:
10555
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10556
0
                                    resources.maxMeshWorkGroupSizeY_EXT :
10557
0
                                    resources.maxMeshWorkGroupSizeY_NV ;
10558
0
                            break;
10559
0
                        case 2:
10560
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10561
0
                                    resources.maxMeshWorkGroupSizeZ_EXT :
10562
0
                                    resources.maxMeshWorkGroupSizeZ_NV ;
10563
0
                            break;
10564
0
                        default: break;
10565
0
                        }
10566
0
                        if (intermediate.getLocalSize(i) > (unsigned int)max) {
10567
0
                            TString maxsErrtring = "too large, see ";
10568
0
                            maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10569
0
                                                    "gl_MaxMeshWorkGroupSizeEXT" : "gl_MaxMeshWorkGroupSizeNV");
10570
0
                            error(loc, maxsErrtring.c_str(), "local_size", "");
10571
0
                        }
10572
0
                    } else if (language == EShLangTask) {
10573
0
                        switch (i) {
10574
0
                        case 0:
10575
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10576
0
                                    resources.maxTaskWorkGroupSizeX_EXT :
10577
0
                                    resources.maxTaskWorkGroupSizeX_NV;
10578
0
                            break;
10579
0
                        case 1:
10580
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10581
0
                                    resources.maxTaskWorkGroupSizeY_EXT:
10582
0
                                    resources.maxTaskWorkGroupSizeY_NV;
10583
0
                            break;
10584
0
                        case 2:
10585
0
                            max = extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10586
0
                                    resources.maxTaskWorkGroupSizeZ_EXT:
10587
0
                                    resources.maxTaskWorkGroupSizeZ_NV;
10588
0
                            break;
10589
0
                        default: break;
10590
0
                        }
10591
0
                        if (intermediate.getLocalSize(i) > (unsigned int)max) {
10592
0
                            TString maxsErrtring = "too large, see ";
10593
0
                            maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ?
10594
0
                                                    "gl_MaxTaskWorkGroupSizeEXT" : "gl_MaxTaskWorkGroupSizeNV");
10595
0
                            error(loc, maxsErrtring.c_str(), "local_size", "");
10596
0
                        }
10597
0
                    } else {
10598
0
                        assert(0);
10599
0
                    }
10600
10601
                    // Fix the existing constant gl_WorkGroupSize with this new information.
10602
0
                    TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
10603
0
                    if (workGroupSize != nullptr)
10604
0
                        workGroupSize->getWritableConstArray()[i].setUConst(intermediate.getLocalSize(i));
10605
0
                }
10606
0
            } else
10607
0
                error(loc, "can only apply to 'in'", "local_size", "");
10608
0
        }
10609
0
        if (publicType.shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) {
10610
0
            if (publicType.qualifier.storage == EvqVaryingIn) {
10611
0
                if (! intermediate.setLocalSizeSpecId(i, publicType.shaderQualifiers.localSizeSpecId[i]))
10612
0
                    error(loc, "cannot change previously set size", "local_size", "");
10613
0
            } else
10614
0
                error(loc, "can only apply to 'in'", "local_size id", "");
10615
            // Set the workgroup built-in variable as a specialization constant
10616
0
            TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
10617
0
            if (workGroupSize != nullptr)
10618
0
                workGroupSize->getWritableType().getQualifier().specConstant = true;
10619
0
        }
10620
0
    }
10621
10622
0
    if (publicType.shaderQualifiers.earlyFragmentTests) {
10623
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10624
0
            intermediate.setEarlyFragmentTests();
10625
0
        else
10626
0
            error(loc, "can only apply to 'in'", "early_fragment_tests", "");
10627
0
    }
10628
0
    if (publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD) {
10629
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10630
0
            intermediate.setEarlyAndLateFragmentTestsAMD();
10631
0
        else
10632
0
            error(loc, "can only apply to 'in'", "early_and_late_fragment_tests_amd", "");
10633
0
    }
10634
0
    if (publicType.shaderQualifiers.postDepthCoverage) {
10635
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10636
0
            intermediate.setPostDepthCoverage();
10637
0
        else
10638
0
            error(loc, "can only apply to 'in'", "post_coverage_coverage", "");
10639
0
    }
10640
0
    if (publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT) {
10641
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10642
0
            intermediate.setNonCoherentColorAttachmentReadEXT();
10643
0
        else
10644
0
            error(loc, "can only apply to 'in'", "non_coherent_color_attachment_readEXT", "");
10645
0
    }
10646
0
    if (publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT) {
10647
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10648
0
            intermediate.setNonCoherentDepthAttachmentReadEXT();
10649
0
        else
10650
0
            error(loc, "can only apply to 'in'", "non_coherent_depth_attachment_readEXT", "");
10651
0
    }
10652
0
    if (publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT) {
10653
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10654
0
            intermediate.setNonCoherentStencilAttachmentReadEXT();
10655
0
        else
10656
0
            error(loc, "can only apply to 'in'", "non_coherent_stencil_attachment_readEXT", "");
10657
0
    }
10658
0
    if (publicType.shaderQualifiers.layoutNonCoherentTileAttachmentReadQCOM) {
10659
0
        if (publicType.qualifier.storage == EvqVaryingIn)
10660
0
            intermediate.setNonCoherentTileAttachmentReadQCOM();
10661
0
        else
10662
0
            error(loc, "can only apply to 'in'", "non_coherent_attachment_readQCOM", "");
10663
0
    }
10664
0
    if (publicType.shaderQualifiers.hasBlendEquation()) {
10665
0
        if (publicType.qualifier.storage != EvqVaryingOut)
10666
0
            error(loc, "can only apply to 'out'", "blend equation", "");
10667
0
    }
10668
0
    if (publicType.shaderQualifiers.interlockOrdering) {
10669
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10670
0
            if (!intermediate.setInterlockOrdering(publicType.shaderQualifiers.interlockOrdering))
10671
0
                error(loc, "cannot change previously set fragment shader interlock ordering", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), "");
10672
0
        }
10673
0
        else
10674
0
            error(loc, "can only apply to 'in'", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), "");
10675
0
    }
10676
10677
0
    if (publicType.shaderQualifiers.layoutDerivativeGroupQuads &&
10678
0
        publicType.shaderQualifiers.layoutDerivativeGroupLinear) {
10679
0
        error(loc, "cannot be both specified", "derivative_group_quadsNV and derivative_group_linearNV", "");
10680
0
    }
10681
10682
0
    if (publicType.shaderQualifiers.layoutDerivativeGroupQuads) {
10683
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10684
0
            if ((intermediate.getLocalSizeSpecId(0) == TQualifier::layoutNotSet && (intermediate.getLocalSize(0) & 1)) ||
10685
0
                (intermediate.getLocalSizeSpecId(1) == TQualifier::layoutNotSet && (intermediate.getLocalSize(1) & 1)))
10686
0
                error(loc, "requires local_size_x and local_size_y to be multiple of two", "derivative_group_quadsNV", "");
10687
0
            else
10688
0
                intermediate.setLayoutDerivativeMode(LayoutDerivativeGroupQuads);
10689
0
        }
10690
0
        else
10691
0
            error(loc, "can only apply to 'in'", "derivative_group_quadsNV", "");
10692
0
    }
10693
0
    if (publicType.shaderQualifiers.layoutDerivativeGroupLinear) {
10694
0
        if (publicType.qualifier.storage == EvqVaryingIn) {
10695
0
            if (intermediate.getLocalSizeSpecId(0) == TQualifier::layoutNotSet &&
10696
0
                intermediate.getLocalSizeSpecId(1) == TQualifier::layoutNotSet &&
10697
0
                intermediate.getLocalSizeSpecId(2) == TQualifier::layoutNotSet &&
10698
0
                (intermediate.getLocalSize(0) *
10699
0
                intermediate.getLocalSize(1) *
10700
0
                intermediate.getLocalSize(2)) % 4 != 0)
10701
0
                error(loc, "requires total group size to be multiple of four", "derivative_group_linearNV", "");
10702
0
            else
10703
0
                intermediate.setLayoutDerivativeMode(LayoutDerivativeGroupLinear);
10704
0
        }
10705
0
        else
10706
0
            error(loc, "can only apply to 'in'", "derivative_group_linearNV", "");
10707
0
    }
10708
    // Check mesh out array sizes, once all the necessary out qualifiers are defined.
10709
0
    if ((language == EShLangMesh) &&
10710
0
        (intermediate.getVertices() != TQualifier::layoutNotSet) &&
10711
0
        (intermediate.getPrimitives() != TQualifier::layoutNotSet) &&
10712
0
        (intermediate.getOutputPrimitive() != ElgNone))
10713
0
    {
10714
0
        checkIoArraysConsistency(loc);
10715
0
    }
10716
10717
0
    if (publicType.shaderQualifiers.layoutPrimitiveCulling) {
10718
0
        if (publicType.qualifier.storage != EvqTemporary)
10719
0
            error(loc, "layout qualifier cannot have storage qualifiers", "primitive_culling", "", "");
10720
0
        else {
10721
0
            intermediate.setLayoutPrimitiveCulling();
10722
0
        }
10723
        // Exit early as further checks are not valid
10724
0
        return;
10725
0
    }
10726
10727
0
    for (int i = 0; i < 3; ++i) {
10728
0
        if (publicType.shaderQualifiers.layoutTileShadingRateQCOMNotDefault[i]) {
10729
0
            if (publicType.qualifier.storage == EvqVaryingIn) {
10730
0
                if (! intermediate.setTileShadingRateQCOM(i, publicType.shaderQualifiers.layoutTileShadingRateQCOM[i]))
10731
0
                    error(loc, "cannot change previously set size", (i==0?"shading_rate_xQCOM":(i==1?"shading_rate_yQCOM":"shading_rate_zQCOM")), "");
10732
0
            } else
10733
0
                error(loc, "can only apply to 'in'", (i==0?"shading_rate_xQCOM":(i==1?"shading_rate_yQCOM":"shading_rate_zQCOM")), "");
10734
0
        }
10735
0
    }
10736
10737
0
    const TQualifier& qualifier = publicType.qualifier;
10738
10739
0
    if (qualifier.isAuxiliary() ||
10740
0
        qualifier.isMemory() ||
10741
0
        qualifier.isInterpolation() ||
10742
0
        qualifier.precision != EpqNone)
10743
0
        error(loc, "cannot use auxiliary, memory, interpolation, or precision qualifier in a default qualifier declaration (declaration with no type)", "qualifier", "");
10744
10745
    // "The offset qualifier can only be used on block members of blocks..."
10746
    // "The align qualifier can only be used on blocks or block members..."
10747
0
    if (qualifier.hasOffset() ||
10748
0
        qualifier.hasAlign())
10749
0
        error(loc, "cannot use offset or align qualifiers in a default qualifier declaration (declaration with no type)", "layout qualifier", "");
10750
10751
0
    layoutQualifierCheck(loc, qualifier);
10752
10753
0
    switch (qualifier.storage) {
10754
0
    case EvqUniform:
10755
0
        if (qualifier.hasMatrix())
10756
0
            globalUniformDefaults.layoutMatrix = qualifier.layoutMatrix;
10757
0
        if (qualifier.hasPacking())
10758
0
            globalUniformDefaults.layoutPacking = qualifier.layoutPacking;
10759
0
        break;
10760
0
    case EvqBuffer:
10761
0
        if (qualifier.hasMatrix())
10762
0
            globalBufferDefaults.layoutMatrix = qualifier.layoutMatrix;
10763
0
        if (qualifier.hasPacking())
10764
0
            globalBufferDefaults.layoutPacking = qualifier.layoutPacking;
10765
0
        break;
10766
0
    case EvqVaryingIn:
10767
0
        break;
10768
0
    case EvqVaryingOut:
10769
0
        if (qualifier.hasStream())
10770
0
            globalOutputDefaults.layoutStream = qualifier.layoutStream;
10771
0
        if (qualifier.hasXfbBuffer())
10772
0
            globalOutputDefaults.layoutXfbBuffer = qualifier.layoutXfbBuffer;
10773
0
        if (globalOutputDefaults.hasXfbBuffer() && qualifier.hasXfbStride()) {
10774
0
            if (! intermediate.setXfbBufferStride(globalOutputDefaults.layoutXfbBuffer, qualifier.layoutXfbStride))
10775
0
                error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
10776
0
        }
10777
0
        break;
10778
0
    case EvqShared:
10779
0
        if (qualifier.hasMatrix())
10780
0
            globalSharedDefaults.layoutMatrix = qualifier.layoutMatrix;
10781
0
        if (qualifier.hasPacking())
10782
0
            globalSharedDefaults.layoutPacking = qualifier.layoutPacking;
10783
0
        break;
10784
0
    default:
10785
0
        error(loc, "default qualifier requires 'uniform', 'buffer', 'in', 'out' or 'shared' storage qualification", "", "");
10786
0
        return;
10787
0
    }
10788
10789
0
    if (qualifier.hasBinding())
10790
0
        error(loc, "cannot declare a default, include a type or full declaration", "binding", "");
10791
0
    if (qualifier.hasAnyLocation())
10792
0
        error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
10793
0
    if (qualifier.hasXfbOffset())
10794
0
        error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
10795
0
    if (qualifier.isPushConstant())
10796
0
        error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
10797
0
    if (qualifier.hasBufferReference())
10798
0
        error(loc, "cannot declare a default, can only be used on a block", "buffer_reference", "");
10799
0
    if (qualifier.hasSpecConstantId())
10800
0
        error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
10801
0
    if (qualifier.isShaderRecord())
10802
0
        error(loc, "cannot declare a default, can only be used on a block", "shaderRecordNV", "");
10803
0
}
10804
10805
//
10806
// Take the sequence of statements that has been built up since the last case/default,
10807
// put it on the list of top-level nodes for the current (inner-most) switch statement,
10808
// and follow that by the case/default we are on now.  (See switch topology comment on
10809
// TIntermSwitch.)
10810
//
10811
void TParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode)
10812
0
{
10813
0
    TIntermSequence* switchSequence = switchSequenceStack.back();
10814
10815
0
    if (statements) {
10816
0
        if (switchSequence->size() == 0)
10817
0
            error(statements->getLoc(), "cannot have statements before first case/default label", "switch", "");
10818
0
        statements->setOperator(EOpSequence);
10819
0
        switchSequence->push_back(statements);
10820
0
    }
10821
0
    if (branchNode) {
10822
        // check all previous cases for the same label (or both are 'default')
10823
0
        for (unsigned int s = 0; s < switchSequence->size(); ++s) {
10824
0
            TIntermBranch* prevBranch = (*switchSequence)[s]->getAsBranchNode();
10825
0
            if (prevBranch) {
10826
0
                TIntermTyped* prevExpression = prevBranch->getExpression();
10827
0
                TIntermTyped* newExpression = branchNode->getAsBranchNode()->getExpression();
10828
0
                if (prevExpression == nullptr && newExpression == nullptr)
10829
0
                    error(branchNode->getLoc(), "duplicate label", "default", "");
10830
0
                else if (prevExpression != nullptr &&
10831
0
                          newExpression != nullptr &&
10832
0
                         prevExpression->getAsConstantUnion() &&
10833
0
                          newExpression->getAsConstantUnion() &&
10834
0
                         prevExpression->getAsConstantUnion()->getConstArray()[0].getIConst() ==
10835
0
                          newExpression->getAsConstantUnion()->getConstArray()[0].getIConst())
10836
0
                    error(branchNode->getLoc(), "duplicated value", "case", "");
10837
0
            }
10838
0
        }
10839
0
        switchSequence->push_back(branchNode);
10840
0
    }
10841
0
}
10842
10843
//
10844
// Turn the top-level node sequence built up of wrapupSwitchSubsequence9)
10845
// into a switch node.
10846
//
10847
TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression, TIntermAggregate* lastStatements)
10848
0
{
10849
0
    profileRequires(loc, EEsProfile, 300, nullptr, "switch statements");
10850
0
    profileRequires(loc, ENoProfile, 130, nullptr, "switch statements");
10851
10852
0
    wrapupSwitchSubsequence(lastStatements, nullptr);
10853
10854
0
    if (expression == nullptr ||
10855
0
        (expression->getBasicType() != EbtInt && expression->getBasicType() != EbtUint) ||
10856
0
        expression->getType().isArray() || expression->getType().isMatrix() || expression->getType().isVector())
10857
0
            error(loc, "condition must be a scalar integer expression", "switch", "");
10858
10859
    // If there is nothing to do, drop the switch but still execute the expression
10860
0
    TIntermSequence* switchSequence = switchSequenceStack.back();
10861
0
    if (switchSequence->size() == 0)
10862
0
        return expression;
10863
10864
0
    if (lastStatements == nullptr) {
10865
        // This was originally an ERRROR, because early versions of the specification said
10866
        // "it is an error to have no statement between a label and the end of the switch statement."
10867
        // The specifications were updated to remove this (being ill-defined what a "statement" was),
10868
        // so, this became a warning.  However, 3.0 tests still check for the error.
10869
0
        if (isEsProfile() && (version <= 300 || version >= 320) && ! relaxedErrors())
10870
0
            error(loc, "last case/default label not followed by statements", "switch", "");
10871
0
        else if (!isEsProfile() && (version <= 430 || version >= 460))
10872
0
            error(loc, "last case/default label not followed by statements", "switch", "");
10873
0
        else
10874
0
            warn(loc, "last case/default label not followed by statements", "switch", "");
10875
10876
10877
        // emulate a break for error recovery
10878
0
        lastStatements = intermediate.makeAggregate(intermediate.addBranch(EOpBreak, loc));
10879
0
        lastStatements->setOperator(EOpSequence);
10880
0
        switchSequence->push_back(lastStatements);
10881
0
    }
10882
10883
0
    TIntermAggregate* body = new TIntermAggregate(EOpSequence);
10884
0
    body->getSequence() = *switchSequenceStack.back();
10885
0
    body->setLoc(loc);
10886
10887
0
    TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
10888
0
    switchNode->setLoc(loc);
10889
10890
0
    return switchNode;
10891
0
}
10892
10893
//
10894
// When a struct used in block, and has it's own layout packing, layout matrix,
10895
// record the origin structure of a struct to map, and Record the structure copy to the copy table,
10896
//
10897
const TTypeList* TParseContext::recordStructCopy(TStructRecord& record, const TType* originType, const TType* tmpType)
10898
0
{
10899
0
    size_t memberCount = tmpType->getStruct()->size();
10900
0
    size_t originHash = 0, tmpHash = 0;
10901
0
    std::hash<size_t> hasher;
10902
0
    for (size_t i = 0; i < memberCount; i++) {
10903
0
        size_t originMemberHash = hasher(originType->getStruct()->at(i).type->getQualifier().layoutPacking +
10904
0
                                         originType->getStruct()->at(i).type->getQualifier().layoutMatrix);
10905
0
        size_t tmpMemberHash = hasher(tmpType->getStruct()->at(i).type->getQualifier().layoutPacking +
10906
0
                                      tmpType->getStruct()->at(i).type->getQualifier().layoutMatrix);
10907
0
        originHash = hasher((originHash ^ originMemberHash) << 1);
10908
0
        tmpHash = hasher((tmpHash ^ tmpMemberHash) << 1);
10909
0
    }
10910
0
    const TTypeList* originStruct = originType->getStruct();
10911
0
    const TTypeList* tmpStruct = tmpType->getStruct();
10912
0
    if (originHash != tmpHash) {
10913
0
        auto fixRecords = record.find(originStruct);
10914
0
        if (fixRecords != record.end()) {
10915
0
            auto fixRecord = fixRecords->second.find(tmpHash);
10916
0
            if (fixRecord != fixRecords->second.end()) {
10917
0
                return fixRecord->second;
10918
0
            } else {
10919
0
                record[originStruct][tmpHash] = tmpStruct;
10920
0
                return tmpStruct;
10921
0
            }
10922
0
        } else {
10923
0
            record[originStruct] = std::map<size_t, const TTypeList*>();
10924
0
            record[originStruct][tmpHash] = tmpStruct;
10925
0
            return tmpStruct;
10926
0
        }
10927
0
    }
10928
0
    return originStruct;
10929
0
}
10930
10931
TLayoutFormat TParseContext::mapLegacyLayoutFormat(TLayoutFormat legacyLayoutFormat, TBasicType imageType)
10932
0
{
10933
0
    TLayoutFormat layoutFormat = ElfNone;
10934
0
    if (imageType == EbtFloat) {
10935
0
        switch (legacyLayoutFormat) {
10936
0
        case ElfSize1x16: layoutFormat = ElfR16f; break;
10937
0
        case ElfSize1x32: layoutFormat = ElfR32f; break;
10938
0
        case ElfSize2x32: layoutFormat = ElfRg32f; break;
10939
0
        case ElfSize4x32: layoutFormat = ElfRgba32f; break;
10940
0
        default: break;
10941
0
        }
10942
0
    } else if (imageType == EbtUint) {
10943
0
        switch (legacyLayoutFormat) {
10944
0
        case ElfSize1x8: layoutFormat = ElfR8ui; break;
10945
0
        case ElfSize1x16: layoutFormat = ElfR16ui; break;
10946
0
        case ElfSize1x32: layoutFormat = ElfR32ui; break;
10947
0
        case ElfSize2x32: layoutFormat = ElfRg32ui; break;
10948
0
        case ElfSize4x32: layoutFormat = ElfRgba32ui; break;
10949
0
        default: break;
10950
0
        }
10951
0
    } else if (imageType == EbtInt) {
10952
0
        switch (legacyLayoutFormat) {
10953
0
        case ElfSize1x8: layoutFormat = ElfR8i; break;
10954
0
        case ElfSize1x16: layoutFormat = ElfR16i; break;
10955
0
        case ElfSize1x32: layoutFormat = ElfR32i; break;
10956
0
        case ElfSize2x32: layoutFormat = ElfRg32i; break;
10957
0
        case ElfSize4x32: layoutFormat = ElfRgba32i; break;
10958
0
        default: break;
10959
0
        }
10960
0
    }
10961
10962
0
    return layoutFormat;
10963
0
}
10964
10965
} // end namespace glslang