xref: /aosp_15_r20/external/angle/src/compiler/translator/QualifierTypes.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/QualifierTypes.h"
8 
9 #include "compiler/translator/Diagnostics.h"
10 #include "compiler/translator/ImmutableStringBuilder.h"
11 
12 #include <algorithm>
13 
14 namespace sh
15 {
16 
17 namespace
18 {
19 
20 constexpr const ImmutableString kSpecifiedMultipleTimes(" specified multiple times");
21 constexpr const ImmutableString kInvariantMultipleTimes(
22     "The invariant qualifier specified multiple times.");
23 constexpr const ImmutableString kPreciseMultipleTimes(
24     "The precise qualifier specified multiple times.");
25 constexpr const ImmutableString kPrecisionMultipleTimes(
26     "The precision qualifier specified multiple times.");
27 constexpr const ImmutableString kLayoutMultipleTimes(
28     "The layout qualifier specified multiple times.");
29 constexpr const ImmutableString kLayoutAndInvariantDisallowed(
30     "The layout qualifier and invariant qualifier cannot coexist in the same "
31     "declaration according to the grammar.");
32 constexpr const ImmutableString kInterpolationMultipleTimes(
33     "The interpolation qualifier specified multiple times.");
34 constexpr const ImmutableString kOutputLayoutMultipleTimes(
35     "Output layout location specified multiple times.");
36 constexpr const ImmutableString kInvariantQualifierFirst(
37     "The invariant qualifier has to be first in the expression.");
38 constexpr const ImmutableString kStorageAfterInterpolation(
39     "Storage qualifiers have to be after interpolation qualifiers.");
40 constexpr const ImmutableString kPrecisionAfterInterpolation(
41     "Precision qualifiers have to be after interpolation qualifiers.");
42 constexpr const ImmutableString kStorageAfterLayout(
43     "Storage qualifiers have to be after layout qualifiers.");
44 constexpr const ImmutableString kPrecisionAfterLayout(
45     "Precision qualifiers have to be after layout qualifiers.");
46 constexpr const ImmutableString kPrecisionAfterStorage(
47     "Precision qualifiers have to be after storage qualifiers.");
48 constexpr const ImmutableString kPrecisionAfterMemory(
49     "Precision qualifiers have to be after memory qualifiers.");
50 
51 // GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout
52 // declarations.
53 // GLSL ES 3.10 Revision 4, 4.10 Order of Qualification
AreTypeQualifierChecksRelaxed(int shaderVersion)54 bool AreTypeQualifierChecksRelaxed(int shaderVersion)
55 {
56     return shaderVersion >= 310;
57 }
58 
IsScopeQualifier(TQualifier qualifier)59 bool IsScopeQualifier(TQualifier qualifier)
60 {
61     return qualifier == EvqGlobal || qualifier == EvqTemporary;
62 }
63 
IsScopeQualifierWrapper(const TQualifierWrapperBase * qualifier)64 bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier)
65 {
66     if (qualifier->getType() != QtStorage)
67         return false;
68     const TStorageQualifierWrapper *storageQualifier =
69         static_cast<const TStorageQualifierWrapper *>(qualifier);
70     TQualifier q = storageQualifier->getQualifier();
71     return IsScopeQualifier(q);
72 }
73 
74 // Returns true if the invariant/precise for the qualifier sequence holds
IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence & qualifiers)75 bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers)
76 {
77     // We should have at least one qualifier.
78     // The first qualifier always tells the scope.
79     return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]);
80 }
81 
QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString & qualifierString)82 ImmutableString QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString &qualifierString)
83 {
84     ImmutableStringBuilder errorMsg(qualifierString.length() + kSpecifiedMultipleTimes.length());
85     errorMsg << qualifierString << kSpecifiedMultipleTimes;
86     return errorMsg;
87 }
88 
89 // Returns true if there are qualifiers which have been specified multiple times
90 // If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed.
HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence & qualifiers,bool areQualifierChecksRelaxed,ImmutableString * errorMessage)91 bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
92                             bool areQualifierChecksRelaxed,
93                             ImmutableString *errorMessage)
94 {
95     bool invariantFound     = false;
96     bool preciseFound       = false;
97     bool precisionFound     = false;
98     bool layoutFound        = false;
99     bool interpolationFound = false;
100 
101     unsigned int locationsSpecified = 0;
102     bool isOut                      = false;
103 
104     // The iteration starts from one since the first qualifier only reveals the scope of the
105     // expression. It is inserted first whenever the sequence gets created.
106     for (size_t i = 1; i < qualifiers.size(); ++i)
107     {
108         switch (qualifiers[i]->getType())
109         {
110             case QtInvariant:
111             {
112                 if (invariantFound)
113                 {
114                     *errorMessage = kInvariantMultipleTimes;
115                     return true;
116                 }
117                 invariantFound = true;
118                 break;
119             }
120             case QtPrecise:
121             {
122                 if (preciseFound)
123                 {
124                     *errorMessage = kPreciseMultipleTimes;
125                     return true;
126                 }
127                 preciseFound = true;
128                 break;
129             }
130             case QtPrecision:
131             {
132                 if (precisionFound)
133                 {
134                     *errorMessage = kPrecisionMultipleTimes;
135                     return true;
136                 }
137                 precisionFound = true;
138                 break;
139             }
140             case QtLayout:
141             {
142                 if (layoutFound && !areQualifierChecksRelaxed)
143                 {
144                     *errorMessage = kLayoutMultipleTimes;
145                     return true;
146                 }
147                 if (invariantFound && !areQualifierChecksRelaxed)
148                 {
149                     // This combination is not correct according to the syntax specified in the
150                     // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have
151                     // a similar restriction.
152                     *errorMessage = kLayoutAndInvariantDisallowed;
153                     return true;
154                 }
155                 layoutFound = true;
156                 const TLayoutQualifier &currentQualifier =
157                     static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier();
158                 locationsSpecified += currentQualifier.locationsSpecified;
159                 break;
160             }
161             case QtInterpolation:
162             {
163                 // 'centroid' and 'sample' are treated as storage qualifiers
164                 // 'flat centroid' and 'flat sample' will be squashed to 'flat'
165                 // 'smooth centroid' will be squashed to 'centroid'
166                 // 'smooth sample' will be squashed to 'sample'
167                 if (interpolationFound)
168                 {
169                     *errorMessage = kInterpolationMultipleTimes;
170                     return true;
171                 }
172                 interpolationFound = true;
173                 break;
174             }
175             case QtStorage:
176             {
177                 // Go over all of the storage qualifiers up until the current one and check for
178                 // repetitions.
179                 TQualifier currentQualifier =
180                     static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier();
181                 if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut ||
182                     currentQualifier == EvqFragmentInOut)
183                 {
184                     isOut = true;
185                 }
186                 for (size_t j = 1; j < i; ++j)
187                 {
188                     if (qualifiers[j]->getType() == QtStorage)
189                     {
190                         const TStorageQualifierWrapper *previousQualifierWrapper =
191                             static_cast<const TStorageQualifierWrapper *>(qualifiers[j]);
192                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
193                         if (currentQualifier == previousQualifier)
194                         {
195                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
196                                 previousQualifierWrapper->getQualifierString());
197                             return true;
198                         }
199                     }
200                 }
201                 break;
202             }
203             case QtMemory:
204             {
205                 // Go over all of the memory qualifiers up until the current one and check for
206                 // repetitions.
207                 // Having both readonly and writeonly in a sequence is valid.
208                 // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
209                 TQualifier currentQualifier =
210                     static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier();
211                 for (size_t j = 1; j < i; ++j)
212                 {
213                     if (qualifiers[j]->getType() == QtMemory)
214                     {
215                         const TMemoryQualifierWrapper *previousQualifierWrapper =
216                             static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]);
217                         TQualifier previousQualifier = previousQualifierWrapper->getQualifier();
218                         if (currentQualifier == previousQualifier)
219                         {
220                             *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage(
221                                 previousQualifierWrapper->getQualifierString());
222                             return true;
223                         }
224                     }
225                 }
226                 break;
227             }
228             default:
229                 UNREACHABLE();
230         }
231     }
232 
233     if (locationsSpecified > 1 && isOut)
234     {
235         // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers
236         // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers
237         // "The qualifier may appear at most once within a declaration."
238         *errorMessage = kOutputLayoutMultipleTimes;
239         return true;
240     }
241 
242     return false;
243 }
244 
245 // GLSL ES 3.00_6, 4.7 Order of Qualification
246 // The correct order of qualifiers is:
247 // invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier
248 // layout-qualifier has to be before storage-qualifier.
249 //
250 // GLSL ES 3.1 relaxes the order of qualification:
251 // When multiple qualifiers are present in a declaration, they may appear in any order, but they
252 // must all appear before the type.
AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence & qualifiers,int shaderVersion,ImmutableString * errorMessage)253 bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers,
254                           int shaderVersion,
255                           ImmutableString *errorMessage)
256 {
257     if (shaderVersion >= 310)
258     {
259         return true;
260     }
261 
262     bool foundInterpolation = false;
263     bool foundStorage       = false;
264     bool foundPrecision     = false;
265     for (size_t i = 1; i < qualifiers.size(); ++i)
266     {
267         switch (qualifiers[i]->getType())
268         {
269             case QtInvariant:
270                 if (foundInterpolation || foundStorage || foundPrecision)
271                 {
272                     *errorMessage = kInvariantQualifierFirst;
273                     return false;
274                 }
275                 break;
276             case QtInterpolation:
277                 if (foundStorage)
278                 {
279                     *errorMessage = kStorageAfterInterpolation;
280                     return false;
281                 }
282                 else if (foundPrecision)
283                 {
284                     *errorMessage = kPrecisionAfterInterpolation;
285                     return false;
286                 }
287                 foundInterpolation = true;
288                 break;
289             case QtLayout:
290                 if (foundStorage)
291                 {
292                     *errorMessage = kStorageAfterLayout;
293                     return false;
294                 }
295                 else if (foundPrecision)
296                 {
297                     *errorMessage = kPrecisionAfterLayout;
298                     return false;
299                 }
300                 break;
301             case QtStorage:
302                 if (foundPrecision)
303                 {
304                     *errorMessage = kPrecisionAfterStorage;
305                     return false;
306                 }
307                 foundStorage = true;
308                 break;
309             case QtMemory:
310                 if (foundPrecision)
311                 {
312                     *errorMessage = kPrecisionAfterMemory;
313                     return false;
314                 }
315                 break;
316             case QtPrecision:
317                 foundPrecision = true;
318                 break;
319             case QtPrecise:
320                 // This keyword is available in ES3.1 (with extension) or in ES3.2, but the function
321                 // should early-out in such a case as the spec doesn't require a particular order to
322                 // the qualifiers.
323                 UNREACHABLE();
324                 break;
325             default:
326                 UNREACHABLE();
327         }
328     }
329     return true;
330 }
331 
332 struct QualifierComparator
333 {
operator ()sh::__anonc724bd5f0111::QualifierComparator334     bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2)
335     {
336         return q1->getRank() < q2->getRank();
337     }
338 };
339 
SortSequence(TTypeQualifierBuilder::QualifierSequence & qualifiers)340 void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers)
341 {
342     // We need a stable sorting algorithm since the order of layout-qualifier declarations matter.
343     // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope
344     // and we always want it to be first.
345     std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator());
346 }
347 
348 // Handles the joining of storage qualifiers for variables.
JoinVariableStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)349 bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
350 {
351     switch (*joinedQualifier)
352     {
353         case EvqGlobal:
354             *joinedQualifier = storageQualifier;
355             break;
356         case EvqTemporary:
357         {
358             switch (storageQualifier)
359             {
360                 case EvqConst:
361                     *joinedQualifier = storageQualifier;
362                     break;
363                 default:
364                     return false;
365             }
366             break;
367         }
368         case EvqSmooth:
369         {
370             switch (storageQualifier)
371             {
372                 case EvqCentroid:
373                     *joinedQualifier = EvqCentroid;
374                     break;
375                 case EvqSample:
376                     *joinedQualifier = EvqSample;
377                     break;
378                 case EvqVertexOut:
379                 case EvqGeometryOut:
380                 case EvqTessControlOut:
381                 case EvqTessEvaluationOut:
382                     *joinedQualifier = EvqSmoothOut;
383                     break;
384                 case EvqFragmentIn:
385                 case EvqGeometryIn:
386                 case EvqTessControlIn:
387                 case EvqTessEvaluationIn:
388                     *joinedQualifier = EvqSmoothIn;
389                     break;
390                 default:
391                     return false;
392             }
393             break;
394         }
395         case EvqFlat:
396         {
397             switch (storageQualifier)
398             {
399                 case EvqCentroid:
400                 case EvqSample:
401                     *joinedQualifier = EvqFlat;
402                     break;
403                 case EvqVertexOut:
404                 case EvqGeometryOut:
405                 case EvqTessControlOut:
406                 case EvqTessEvaluationOut:
407                     *joinedQualifier = EvqFlatOut;
408                     break;
409                 case EvqFragmentIn:
410                 case EvqGeometryIn:
411                 case EvqTessControlIn:
412                 case EvqTessEvaluationIn:
413                     *joinedQualifier = EvqFlatIn;
414                     break;
415                 default:
416                     return false;
417             }
418             break;
419         }
420         case EvqNoPerspective:
421         {
422             switch (storageQualifier)
423             {
424                 case EvqCentroid:
425                     *joinedQualifier = EvqNoPerspectiveCentroid;
426                     break;
427                 case EvqSample:
428                     *joinedQualifier = EvqNoPerspectiveSample;
429                     break;
430                 case EvqVertexOut:
431                 case EvqGeometryOut:
432                 case EvqTessControlOut:
433                 case EvqTessEvaluationOut:
434                     *joinedQualifier = EvqNoPerspectiveOut;
435                     break;
436                 case EvqFragmentIn:
437                 case EvqGeometryIn:
438                 case EvqTessControlIn:
439                 case EvqTessEvaluationIn:
440                     *joinedQualifier = EvqNoPerspectiveIn;
441                     break;
442                 default:
443                     return false;
444             }
445             break;
446         }
447         case EvqCentroid:
448         {
449             switch (storageQualifier)
450             {
451                 case EvqVertexOut:
452                 case EvqGeometryOut:
453                 case EvqTessControlOut:
454                 case EvqTessEvaluationOut:
455                     *joinedQualifier = EvqCentroidOut;
456                     break;
457                 case EvqFragmentIn:
458                 case EvqGeometryIn:
459                 case EvqTessControlIn:
460                 case EvqTessEvaluationIn:
461                     *joinedQualifier = EvqCentroidIn;
462                     break;
463                 default:
464                     return false;
465             }
466             break;
467         }
468         case EvqSample:
469         {
470             switch (storageQualifier)
471             {
472                 case EvqVertexOut:
473                 case EvqGeometryOut:
474                 case EvqTessControlOut:
475                 case EvqTessEvaluationOut:
476                     *joinedQualifier = EvqSampleOut;
477                     break;
478                 case EvqFragmentIn:
479                 case EvqGeometryIn:
480                 case EvqTessControlIn:
481                 case EvqTessEvaluationIn:
482                     *joinedQualifier = EvqSampleIn;
483                     break;
484                 default:
485                     return false;
486             }
487             break;
488         }
489         case EvqNoPerspectiveCentroid:
490         {
491             switch (storageQualifier)
492             {
493                 case EvqVertexOut:
494                 case EvqGeometryOut:
495                 case EvqTessControlOut:
496                 case EvqTessEvaluationOut:
497                     *joinedQualifier = EvqNoPerspectiveCentroidOut;
498                     break;
499                 case EvqFragmentIn:
500                 case EvqGeometryIn:
501                 case EvqTessControlIn:
502                 case EvqTessEvaluationIn:
503                     *joinedQualifier = EvqNoPerspectiveCentroidIn;
504                     break;
505                 default:
506                     return false;
507             }
508             break;
509         }
510         case EvqNoPerspectiveSample:
511         {
512             switch (storageQualifier)
513             {
514                 case EvqVertexOut:
515                 case EvqGeometryOut:
516                 case EvqTessControlOut:
517                 case EvqTessEvaluationOut:
518                     *joinedQualifier = EvqNoPerspectiveSampleOut;
519                     break;
520                 case EvqFragmentIn:
521                 case EvqGeometryIn:
522                 case EvqTessControlIn:
523                 case EvqTessEvaluationIn:
524                     *joinedQualifier = EvqNoPerspectiveSampleIn;
525                     break;
526                 default:
527                     return false;
528             }
529             break;
530         }
531         case EvqPatch:
532         {
533             switch (storageQualifier)
534             {
535                 case EvqTessControlOut:
536                     *joinedQualifier = EvqPatchOut;
537                     break;
538                 case EvqTessEvaluationIn:
539                     *joinedQualifier = EvqPatchIn;
540                     break;
541                 default:
542                     return false;
543             }
544             break;
545         }
546         default:
547             return false;
548     }
549     return true;
550 }
551 
552 // Handles the joining of storage qualifiers for a parameter in a function.
JoinParameterStorageQualifier(TQualifier * joinedQualifier,TQualifier storageQualifier)553 bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier)
554 {
555     switch (*joinedQualifier)
556     {
557         case EvqTemporary:
558             *joinedQualifier = storageQualifier;
559             break;
560         case EvqConst:
561         {
562             switch (storageQualifier)
563             {
564                 case EvqParamIn:
565                     *joinedQualifier = EvqParamConst;
566                     break;
567                 default:
568                     return false;
569             }
570             break;
571         }
572         default:
573             return false;
574     }
575     return true;
576 }
577 
JoinMemoryQualifier(TMemoryQualifier * joinedMemoryQualifier,TQualifier memoryQualifier)578 bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier)
579 {
580     switch (memoryQualifier)
581     {
582         case EvqReadOnly:
583             joinedMemoryQualifier->readonly = true;
584             break;
585         case EvqWriteOnly:
586             joinedMemoryQualifier->writeonly = true;
587             break;
588         case EvqCoherent:
589             joinedMemoryQualifier->coherent = true;
590             break;
591         case EvqRestrict:
592             joinedMemoryQualifier->restrictQualifier = true;
593             break;
594         case EvqVolatile:
595             // Variables having the volatile qualifier are automatcally treated as coherent as well.
596             // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
597             joinedMemoryQualifier->volatileQualifier = true;
598             joinedMemoryQualifier->coherent          = true;
599             break;
600         default:
601             UNREACHABLE();
602     }
603     return true;
604 }
605 
GetVariableTypeQualifierFromSortedSequence(const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)606 TTypeQualifier GetVariableTypeQualifierFromSortedSequence(
607     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
608     TDiagnostics *diagnostics)
609 {
610     TTypeQualifier typeQualifier(
611         static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(),
612         sortedSequence[0]->getLine());
613     for (size_t i = 1; i < sortedSequence.size(); ++i)
614     {
615         const TQualifierWrapperBase *qualifier = sortedSequence[i];
616         bool isQualifierValid                  = false;
617         switch (qualifier->getType())
618         {
619             case QtInvariant:
620                 isQualifierValid        = true;
621                 typeQualifier.invariant = true;
622                 break;
623             case QtPrecise:
624                 isQualifierValid      = true;
625                 typeQualifier.precise = true;
626                 break;
627             case QtInterpolation:
628             {
629                 switch (typeQualifier.qualifier)
630                 {
631                     case EvqGlobal:
632                         isQualifierValid = true;
633                         typeQualifier.qualifier =
634                             static_cast<const TInterpolationQualifierWrapper *>(qualifier)
635                                 ->getQualifier();
636                         break;
637                     default:
638                         isQualifierValid = false;
639                 }
640                 break;
641             }
642             case QtLayout:
643             {
644                 const TLayoutQualifierWrapper *layoutQualifierWrapper =
645                     static_cast<const TLayoutQualifierWrapper *>(qualifier);
646                 isQualifierValid              = true;
647                 typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers(
648                     typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(),
649                     layoutQualifierWrapper->getLine(), diagnostics);
650                 break;
651             }
652             case QtStorage:
653                 isQualifierValid = JoinVariableStorageQualifier(
654                     &typeQualifier.qualifier,
655                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
656                 break;
657             case QtPrecision:
658                 isQualifierValid = true;
659                 typeQualifier.precision =
660                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
661                 ASSERT(typeQualifier.precision != EbpUndefined);
662                 break;
663             case QtMemory:
664                 isQualifierValid = JoinMemoryQualifier(
665                     &typeQualifier.memoryQualifier,
666                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
667                 break;
668             default:
669                 UNREACHABLE();
670         }
671         if (!isQualifierValid)
672         {
673             const ImmutableString &qualifierString = qualifier->getQualifierString();
674             diagnostics->error(qualifier->getLine(), "invalid qualifier combination",
675                                qualifierString.data());
676             break;
677         }
678     }
679     return typeQualifier;
680 }
681 
GetParameterTypeQualifierFromSortedSequence(TBasicType parameterBasicType,const TTypeQualifierBuilder::QualifierSequence & sortedSequence,TDiagnostics * diagnostics)682 TTypeQualifier GetParameterTypeQualifierFromSortedSequence(
683     TBasicType parameterBasicType,
684     const TTypeQualifierBuilder::QualifierSequence &sortedSequence,
685     TDiagnostics *diagnostics)
686 {
687     TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine());
688     for (size_t i = 1; i < sortedSequence.size(); ++i)
689     {
690         const TQualifierWrapperBase *qualifier = sortedSequence[i];
691         bool isQualifierValid                  = false;
692         switch (qualifier->getType())
693         {
694             case QtInvariant:
695             case QtInterpolation:
696             case QtLayout:
697                 break;
698             case QtMemory:
699                 isQualifierValid = JoinMemoryQualifier(
700                     &typeQualifier.memoryQualifier,
701                     static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier());
702                 break;
703             case QtStorage:
704                 isQualifierValid = JoinParameterStorageQualifier(
705                     &typeQualifier.qualifier,
706                     static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier());
707                 break;
708             case QtPrecision:
709                 isQualifierValid = true;
710                 typeQualifier.precision =
711                     static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier();
712                 ASSERT(typeQualifier.precision != EbpUndefined);
713                 break;
714             case QtPrecise:
715                 isQualifierValid      = true;
716                 typeQualifier.precise = true;
717                 break;
718             default:
719                 UNREACHABLE();
720         }
721         if (!isQualifierValid)
722         {
723             const ImmutableString &qualifierString = qualifier->getQualifierString();
724             diagnostics->error(qualifier->getLine(), "invalid parameter qualifier",
725                                qualifierString.data());
726             break;
727         }
728     }
729 
730     switch (typeQualifier.qualifier)
731     {
732         case EvqParamIn:
733         case EvqParamOut:
734         case EvqParamInOut:
735             break;
736         case EvqParamConst:  // const in
737         case EvqConst:
738             // Opaque parameters can only be |in|.  |const| is allowed, but is meaningless and is
739             // dropped.
740             typeQualifier.qualifier = IsOpaqueType(parameterBasicType) ? EvqParamIn : EvqParamConst;
741             break;
742         case EvqTemporary:
743             // no qualifier has been specified, set it to EvqParamIn which is the default
744             typeQualifier.qualifier = EvqParamIn;
745             break;
746         default:
747             diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ",
748                                getQualifierString(typeQualifier.qualifier));
749     }
750     return typeQualifier;
751 }
752 }  // namespace
753 
JoinLayoutQualifiers(TLayoutQualifier leftQualifier,TLayoutQualifier rightQualifier,const TSourceLoc & rightQualifierLocation,TDiagnostics * diagnostics)754 TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
755                                       TLayoutQualifier rightQualifier,
756                                       const TSourceLoc &rightQualifierLocation,
757                                       TDiagnostics *diagnostics)
758 {
759     TLayoutQualifier joinedQualifier = leftQualifier;
760 
761     if (rightQualifier.location != -1)
762     {
763         joinedQualifier.location = rightQualifier.location;
764         ++joinedQualifier.locationsSpecified;
765     }
766     if (rightQualifier.depth != EdUnspecified)
767     {
768         if (joinedQualifier.depth != EdUnspecified)
769         {
770             diagnostics->error(rightQualifierLocation, "Cannot have multiple depth qualifiers",
771                                getDepthString(rightQualifier.depth));
772         }
773         joinedQualifier.depth = rightQualifier.depth;
774     }
775     if (rightQualifier.yuv != false)
776     {
777         joinedQualifier.yuv = rightQualifier.yuv;
778     }
779     if (rightQualifier.earlyFragmentTests != false)
780     {
781         joinedQualifier.earlyFragmentTests = rightQualifier.earlyFragmentTests;
782     }
783     if (rightQualifier.binding != -1)
784     {
785         joinedQualifier.binding = rightQualifier.binding;
786     }
787     if (rightQualifier.offset != -1)
788     {
789         joinedQualifier.offset = rightQualifier.offset;
790     }
791     if (rightQualifier.matrixPacking != EmpUnspecified)
792     {
793         joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
794     }
795     if (rightQualifier.blockStorage != EbsUnspecified)
796     {
797         joinedQualifier.blockStorage = rightQualifier.blockStorage;
798     }
799     if (rightQualifier.noncoherent != false)
800     {
801         joinedQualifier.noncoherent = rightQualifier.noncoherent;
802     }
803 
804     for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
805     {
806         if (rightQualifier.localSize[i] != -1)
807         {
808             if (joinedQualifier.localSize[i] != -1 &&
809                 joinedQualifier.localSize[i] != rightQualifier.localSize[i])
810             {
811                 diagnostics->error(rightQualifierLocation,
812                                    "Cannot have multiple different work group size specifiers",
813                                    getWorkGroupSizeString(i));
814             }
815             joinedQualifier.localSize[i] = rightQualifier.localSize[i];
816         }
817     }
818 
819     if (rightQualifier.numViews != -1)
820     {
821         joinedQualifier.numViews = rightQualifier.numViews;
822     }
823 
824     if (rightQualifier.imageInternalFormat != EiifUnspecified)
825     {
826         joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
827     }
828 
829     if (rightQualifier.primitiveType != EptUndefined)
830     {
831         if (joinedQualifier.primitiveType != EptUndefined &&
832             joinedQualifier.primitiveType != rightQualifier.primitiveType)
833         {
834             diagnostics->error(rightQualifierLocation,
835                                "Cannot have multiple different primitive specifiers",
836                                getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
837         }
838         joinedQualifier.primitiveType = rightQualifier.primitiveType;
839     }
840 
841     if (rightQualifier.invocations != 0)
842     {
843         if (joinedQualifier.invocations != 0 &&
844             joinedQualifier.invocations != rightQualifier.invocations)
845         {
846             diagnostics->error(rightQualifierLocation,
847                                "Cannot have multiple different invocations specifiers",
848                                "invocations");
849         }
850         joinedQualifier.invocations = rightQualifier.invocations;
851     }
852 
853     if (rightQualifier.maxVertices != -1)
854     {
855         if (joinedQualifier.maxVertices != -1 &&
856             joinedQualifier.maxVertices != rightQualifier.maxVertices)
857         {
858             diagnostics->error(rightQualifierLocation,
859                                "Cannot have multiple different max_vertices specifiers",
860                                "max_vertices");
861         }
862         joinedQualifier.maxVertices = rightQualifier.maxVertices;
863     }
864 
865     if (rightQualifier.tesPrimitiveType != EtetUndefined)
866     {
867         if (joinedQualifier.tesPrimitiveType == EtetUndefined)
868         {
869             joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
870         }
871     }
872 
873     if (rightQualifier.tesVertexSpacingType != EtetUndefined)
874     {
875         if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
876         {
877             joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
878         }
879     }
880 
881     if (rightQualifier.tesOrderingType != EtetUndefined)
882     {
883         if (joinedQualifier.tesOrderingType == EtetUndefined)
884         {
885             joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
886         }
887     }
888 
889     if (rightQualifier.tesPointType != EtetUndefined)
890     {
891         if (joinedQualifier.tesPointType == EtetUndefined)
892         {
893             joinedQualifier.tesPointType = rightQualifier.tesPointType;
894         }
895     }
896 
897     if (rightQualifier.vertices != 0)
898     {
899         if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
900         {
901             diagnostics->error(rightQualifierLocation,
902                                "Cannot have multiple different vertices specifiers", "vertices");
903         }
904         joinedQualifier.vertices = rightQualifier.vertices;
905     }
906 
907     if (rightQualifier.index != -1)
908     {
909         if (joinedQualifier.index != -1)
910         {
911             // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
912             diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
913                                "index");
914         }
915         joinedQualifier.index = rightQualifier.index;
916     }
917 
918     if (rightQualifier.advancedBlendEquations.any())
919     {
920         joinedQualifier.advancedBlendEquations |= rightQualifier.advancedBlendEquations;
921     }
922 
923     return joinedQualifier;
924 }
925 
getRank() const926 unsigned int TInvariantQualifierWrapper::getRank() const
927 {
928     return 0u;
929 }
930 
getRank() const931 unsigned int TPreciseQualifierWrapper::getRank() const
932 {
933     return 1u;
934 }
935 
getRank() const936 unsigned int TInterpolationQualifierWrapper::getRank() const
937 {
938     return 2u;
939 }
940 
getRank() const941 unsigned int TLayoutQualifierWrapper::getRank() const
942 {
943     return 3u;
944 }
945 
getRank() const946 unsigned int TStorageQualifierWrapper::getRank() const
947 {
948     // Force the 'centroid' and 'sample' auxilary storage qualifiers
949     // to be always first among all storage qualifiers.
950     if (mStorageQualifier == EvqCentroid || mStorageQualifier == EvqSample)
951     {
952         return 4u;
953     }
954     else
955     {
956         return 5u;
957     }
958 }
959 
getRank() const960 unsigned int TMemoryQualifierWrapper::getRank() const
961 {
962     return 5u;
963 }
964 
getRank() const965 unsigned int TPrecisionQualifierWrapper::getRank() const
966 {
967     return 6u;
968 }
969 
TTypeQualifier(TQualifier scope,const TSourceLoc & loc)970 TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc)
971     : layoutQualifier(TLayoutQualifier::Create()),
972       memoryQualifier(TMemoryQualifier::Create()),
973       precision(EbpUndefined),
974       qualifier(scope),
975       invariant(false),
976       precise(false),
977       line(loc)
978 {
979     ASSERT(IsScopeQualifier(qualifier));
980 }
981 
TTypeQualifierBuilder(const TStorageQualifierWrapper * scope,int shaderVersion)982 TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope,
983                                              int shaderVersion)
984     : mShaderVersion(shaderVersion)
985 {
986     ASSERT(IsScopeQualifier(scope->getQualifier()));
987     mQualifiers.push_back(scope);
988 }
989 
appendQualifier(const TQualifierWrapperBase * qualifier)990 void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier)
991 {
992     mQualifiers.push_back(qualifier);
993 }
994 
checkSequenceIsValid(TDiagnostics * diagnostics) const995 bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const
996 {
997     bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion);
998     ImmutableString errorMessage("");
999     if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage))
1000     {
1001         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
1002         return false;
1003     }
1004 
1005     if (!areQualifierChecksRelaxed &&
1006         !AreQualifiersInOrder(mQualifiers, mShaderVersion, &errorMessage))
1007     {
1008         diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence");
1009         return false;
1010     }
1011 
1012     return true;
1013 }
1014 
getParameterTypeQualifier(TBasicType parameterBasicType,TDiagnostics * diagnostics) const1015 TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TBasicType parameterBasicType,
1016                                                                 TDiagnostics *diagnostics) const
1017 {
1018     ASSERT(IsInvariantCorrect(mQualifiers));
1019     ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() ==
1020            EvqTemporary);
1021 
1022     if (!checkSequenceIsValid(diagnostics))
1023     {
1024         return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine());
1025     }
1026 
1027     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
1028     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
1029     // combine the qualifiers.
1030     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
1031     {
1032         // Copy the qualifier sequence so that we can sort them.
1033         QualifierSequence sortedQualifierSequence = mQualifiers;
1034         SortSequence(sortedQualifierSequence);
1035         return GetParameterTypeQualifierFromSortedSequence(parameterBasicType,
1036                                                            sortedQualifierSequence, diagnostics);
1037     }
1038     return GetParameterTypeQualifierFromSortedSequence(parameterBasicType, mQualifiers,
1039                                                        diagnostics);
1040 }
1041 
getVariableTypeQualifier(TDiagnostics * diagnostics) const1042 TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const
1043 {
1044     ASSERT(IsInvariantCorrect(mQualifiers));
1045 
1046     if (!checkSequenceIsValid(diagnostics))
1047     {
1048         return TTypeQualifier(
1049             static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(),
1050             mQualifiers[0]->getLine());
1051     }
1052 
1053     // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so
1054     // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to
1055     // combine the qualifiers.
1056     if (AreTypeQualifierChecksRelaxed(mShaderVersion))
1057     {
1058         // Copy the qualifier sequence so that we can sort them.
1059         QualifierSequence sortedQualifierSequence = mQualifiers;
1060         SortSequence(sortedQualifierSequence);
1061         return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics);
1062     }
1063     return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics);
1064 }
1065 
1066 }  // namespace sh
1067