• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 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/ValidateAST.h"
8 
9 #include "common/utilities.h"
10 #include "compiler/translator/Diagnostics.h"
11 #include "compiler/translator/ImmutableStringBuilder.h"
12 #include "compiler/translator/Symbol.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14 #include "compiler/translator/tree_util/SpecializationConstant.h"
15 #include "compiler/translator/util.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
23 class ValidateAST : public TIntermTraverser
24 {
25   public:
26     static bool validate(TIntermNode *root,
27                          TDiagnostics *diagnostics,
28                          const ValidateASTOptions &options);
29 
30     void visitSymbol(TIntermSymbol *node) override;
31     void visitConstantUnion(TIntermConstantUnion *node) override;
32     bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
33     bool visitBinary(Visit visit, TIntermBinary *node) override;
34     bool visitUnary(Visit visit, TIntermUnary *node) override;
35     bool visitTernary(Visit visit, TIntermTernary *node) override;
36     bool visitIfElse(Visit visit, TIntermIfElse *node) override;
37     bool visitSwitch(Visit visit, TIntermSwitch *node) override;
38     bool visitCase(Visit visit, TIntermCase *node) override;
39     void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
40     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
41     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
42     bool visitBlock(Visit visit, TIntermBlock *node) override;
43     bool visitGlobalQualifierDeclaration(Visit visit,
44                                          TIntermGlobalQualifierDeclaration *node) override;
45     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
46     bool visitLoop(Visit visit, TIntermLoop *node) override;
47     bool visitBranch(Visit visit, TIntermBranch *node) override;
48     void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
49 
50   private:
51     ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
52 
53     // Visit as a generic node
54     void visitNode(Visit visit, TIntermNode *node);
55     // Visit a structure or interface block, and recursively visit its fields of structure type.
56     void visitStructOrInterfaceBlockDeclaration(const TType &type, const TSourceLoc &location);
57     void visitStructUsage(const TType &type, const TSourceLoc &location);
58     // Visit a unary or aggregate node and validate its built-in op against its built-in function.
59     void visitBuiltInFunction(TIntermOperator *op, const TFunction *function);
60     // Visit an aggregate node and validate its function call is to one that's already defined.
61     void visitFunctionCall(TIntermAggregate *node);
62     // Visit a binary node and validate its type against its operands.
63     void validateExpressionTypeBinary(TIntermBinary *node);
64     // Visit a switch node and validate its selector type is integer.
65     void validateExpressionTypeSwitch(TIntermSwitch *node);
66     // Visit a symbol node and validate it's declared previously.
67     void visitVariableNeedingDeclaration(TIntermSymbol *node);
68     // Visit a built-in symbol node and validate it's consistently used across the tree.
69     void visitBuiltInVariable(TIntermSymbol *node);
70 
71     void scope(Visit visit);
72     bool isVariableDeclared(const TVariable *variable);
73     bool variableNeedsDeclaration(const TVariable *variable);
74     const TFieldListCollection *getStructOrInterfaceBlock(const TType &type,
75                                                           ImmutableString *typeNameOut);
76 
77     void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count);
78 
79     bool validateInternal();
80 
81     ValidateASTOptions mOptions;
82     TDiagnostics *mDiagnostics;
83 
84     // For validateSingleParent:
85     std::map<TIntermNode *, TIntermNode *> mParent;
86     bool mSingleParentFailed = false;
87 
88     // For validateVariableReferences:
89     std::vector<std::set<const TVariable *>> mDeclaredVariables;
90     std::set<const TInterfaceBlock *> mNamelessInterfaceBlocks;
91     std::map<ImmutableString, const TVariable *> mReferencedBuiltIns;
92     bool mVariableReferencesFailed = false;
93 
94     // For validateOps:
95     bool mOpsFailed = false;
96 
97     // For validateBuiltInOps:
98     bool mBuiltInOpsFailed = false;
99 
100     // For validateFunctionCall:
101     std::set<const TFunction *> mDeclaredFunctions;
102     bool mFunctionCallFailed = false;
103 
104     // For validateNoRawFunctionCalls:
105     bool mNoRawFunctionCallsFailed = false;
106 
107     // For validateNullNodes:
108     bool mNullNodesFailed = false;
109 
110     // For validateQualifiers:
111     bool mQualifiersFailed = false;
112 
113     // For validatePrecision:
114     bool mPrecisionFailed = false;
115 
116     // For validateStructUsage:
117     std::vector<std::map<ImmutableString, const TFieldListCollection *>> mStructsAndBlocksByName;
118     std::set<const TFunction *> mStructUsageProcessedFunctions;
119     bool mStructUsageFailed = false;
120 
121     // For validateExpressionTypes:
122     bool mExpressionTypesFailed = false;
123 
124     // For validateMultiDeclarations:
125     bool mMultiDeclarationsFailed = false;
126 
127     // For validateNoSwizzleOfSwizzle:
128     bool mNoSwizzleOfSwizzleFailed = false;
129 
130     // For validateNoQualifiersOnConstructors:
131     bool mNoQualifiersOnConstructorsFailed = false;
132 
133     // For validateNoStatementsAfterBranch:
134     bool mIsBranchVisitedInBlock        = false;
135     bool mNoStatementsAfterBranchFailed = false;
136 };
137 
IsSameType(const TType & a,const TType & b)138 bool IsSameType(const TType &a, const TType &b)
139 {
140     return a.getBasicType() == b.getBasicType() && a.getNominalSize() == b.getNominalSize() &&
141            a.getSecondarySize() == b.getSecondarySize() && a.getArraySizes() == b.getArraySizes() &&
142            a.getStruct() == b.getStruct() &&
143            (!a.isInterfaceBlock() || a.getInterfaceBlock() == b.getInterfaceBlock());
144 }
145 
IsUnaryOp(TOperator op)146 bool IsUnaryOp(TOperator op)
147 {
148     switch (op)
149     {
150         case EOpNegative:
151         case EOpPositive:
152         case EOpLogicalNot:
153         case EOpBitwiseNot:
154         case EOpPostIncrement:
155         case EOpPostDecrement:
156         case EOpPreIncrement:
157         case EOpPreDecrement:
158         case EOpArrayLength:
159             return true;
160         default:
161             return false;
162     }
163 }
164 
IsBinaryOp(TOperator op)165 bool IsBinaryOp(TOperator op)
166 {
167     switch (op)
168     {
169         case EOpAdd:
170         case EOpSub:
171         case EOpMul:
172         case EOpDiv:
173         case EOpIMod:
174         case EOpEqual:
175         case EOpNotEqual:
176         case EOpLessThan:
177         case EOpGreaterThan:
178         case EOpLessThanEqual:
179         case EOpGreaterThanEqual:
180         case EOpComma:
181         case EOpVectorTimesScalar:
182         case EOpVectorTimesMatrix:
183         case EOpMatrixTimesVector:
184         case EOpMatrixTimesScalar:
185         case EOpMatrixTimesMatrix:
186         case EOpLogicalOr:
187         case EOpLogicalXor:
188         case EOpLogicalAnd:
189         case EOpBitShiftLeft:
190         case EOpBitShiftRight:
191         case EOpBitwiseAnd:
192         case EOpBitwiseXor:
193         case EOpBitwiseOr:
194         case EOpIndexDirect:
195         case EOpIndexIndirect:
196         case EOpIndexDirectStruct:
197         case EOpIndexDirectInterfaceBlock:
198         case EOpAssign:
199         case EOpInitialize:
200         case EOpAddAssign:
201         case EOpSubAssign:
202         case EOpMulAssign:
203         case EOpVectorTimesMatrixAssign:
204         case EOpVectorTimesScalarAssign:
205         case EOpMatrixTimesScalarAssign:
206         case EOpMatrixTimesMatrixAssign:
207         case EOpDivAssign:
208         case EOpIModAssign:
209         case EOpBitShiftLeftAssign:
210         case EOpBitShiftRightAssign:
211         case EOpBitwiseAndAssign:
212         case EOpBitwiseXorAssign:
213         case EOpBitwiseOrAssign:
214             return true;
215         default:
216             return false;
217     }
218 }
219 
IsBranchOp(TOperator op)220 bool IsBranchOp(TOperator op)
221 {
222     switch (op)
223     {
224         case EOpKill:
225         case EOpReturn:
226         case EOpBreak:
227         case EOpContinue:
228             return true;
229         default:
230             return false;
231     }
232 }
233 
validate(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)234 bool ValidateAST::validate(TIntermNode *root,
235                            TDiagnostics *diagnostics,
236                            const ValidateASTOptions &options)
237 {
238     ValidateAST validate(root, diagnostics, options);
239     root->traverse(&validate);
240     return validate.validateInternal();
241 }
242 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)243 ValidateAST::ValidateAST(TIntermNode *root,
244                          TDiagnostics *diagnostics,
245                          const ValidateASTOptions &options)
246     : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
247 {
248     bool isTreeRoot = root->getAsBlock() && root->getAsBlock()->isTreeRoot();
249 
250     // Some validations are not applicable unless run on the entire tree.
251     if (!isTreeRoot)
252     {
253         mOptions.validateVariableReferences = false;
254         mOptions.validateFunctionCall       = false;
255         mOptions.validateStructUsage        = false;
256     }
257 
258     if (mOptions.validateSingleParent)
259     {
260         mParent[root] = nullptr;
261     }
262 }
263 
visitNode(Visit visit,TIntermNode * node)264 void ValidateAST::visitNode(Visit visit, TIntermNode *node)
265 {
266     if (visit == PreVisit && mOptions.validateSingleParent)
267     {
268         size_t childCount = node->getChildCount();
269         for (size_t i = 0; i < childCount; ++i)
270         {
271             TIntermNode *child = node->getChildNode(i);
272             if (mParent.find(child) != mParent.end())
273             {
274                 // If child is visited twice but through the same parent, the problem is in one of
275                 // the ancestors.
276                 if (mParent[child] != node)
277                 {
278                     mDiagnostics->error(node->getLine(), "Found child with two parents",
279                                         "<validateSingleParent>");
280                     mSingleParentFailed = true;
281                 }
282             }
283 
284             mParent[child] = node;
285         }
286     }
287 
288     if (visit == PreVisit && mOptions.validateNoStatementsAfterBranch)
289     {
290         // If a branch has already been visited in this block, there should be no statements that
291         // follow.  Only expected node visit should be PostVisit of the block.
292         if (mIsBranchVisitedInBlock)
293         {
294             mDiagnostics->error(node->getLine(), "Found dead code after branch",
295                                 "<validateNoStatementsAfterBranch>");
296             mNoStatementsAfterBranchFailed = true;
297         }
298     }
299 }
300 
visitStructOrInterfaceBlockDeclaration(const TType & type,const TSourceLoc & location)301 void ValidateAST::visitStructOrInterfaceBlockDeclaration(const TType &type,
302                                                          const TSourceLoc &location)
303 {
304     if (type.getStruct() == nullptr && type.getInterfaceBlock() == nullptr)
305     {
306         return;
307     }
308 
309     // Make sure the structure or interface block is not doubly defined.
310     ImmutableString typeName("");
311     const TFieldListCollection *namedStructOrBlock = getStructOrInterfaceBlock(type, &typeName);
312 
313     // Recurse the fields of the structure or interface block and check members of structure type.
314     // This is done before visiting the struct itself, because if the fields refer to a struct with
315     // the same name, they would be referencing the struct declared in an outer scope.
316     {
317         // Note that structOrBlock was previously only set for named structures, so make sure
318         // nameless structs are also recursed.
319         const TFieldListCollection *structOrBlock = namedStructOrBlock;
320         if (structOrBlock == nullptr)
321         {
322             structOrBlock = type.getStruct();
323         }
324         ASSERT(structOrBlock != nullptr);
325 
326         for (const TField *field : structOrBlock->fields())
327         {
328             visitStructUsage(*field->type(), field->line());
329         }
330     }
331 
332     if (namedStructOrBlock)
333     {
334         ASSERT(!typeName.empty());
335         // Structures are not allowed to be doubly defined
336         if (type.getStruct() == nullptr)
337         {
338             // Allow interfaces to be doubly-defined.
339             std::string name(typeName.data());
340 
341             if (IsShaderIn(type.getQualifier()))
342             {
343                 typeName = ImmutableString(name + "<input>");
344             }
345             else if (IsShaderOut(type.getQualifier()))
346             {
347                 typeName = ImmutableString(name + "<output>");
348             }
349             else if (IsStorageBuffer(type.getQualifier()))
350             {
351                 typeName = ImmutableString(name + "<buffer>");
352             }
353             else if (type.getQualifier() == EvqUniform)
354             {
355                 typeName = ImmutableString(name + "<uniform>");
356             }
357         }
358 
359         if (mStructsAndBlocksByName.back().find(typeName) != mStructsAndBlocksByName.back().end())
360         {
361             mDiagnostics->error(location,
362                                 "Found redeclaration of struct or interface block with the same "
363                                 "name in the same scope <validateStructUsage>",
364                                 typeName.data());
365             mStructUsageFailed = true;
366         }
367         else
368         {
369             // First encounter.
370             mStructsAndBlocksByName.back()[typeName] = namedStructOrBlock;
371         }
372     }
373 }
374 
visitStructUsage(const TType & type,const TSourceLoc & location)375 void ValidateAST::visitStructUsage(const TType &type, const TSourceLoc &location)
376 {
377     if (type.getStruct() == nullptr)
378     {
379         return;
380     }
381 
382     // Make sure the structure being referenced has the same pointer as the closest (in scope)
383     // definition.
384     const TStructure *structure     = type.getStruct();
385     const ImmutableString &typeName = structure->name();
386 
387     bool foundDeclaration = false;
388     for (size_t scopeIndex = mStructsAndBlocksByName.size(); scopeIndex > 0; --scopeIndex)
389     {
390         const std::map<ImmutableString, const TFieldListCollection *> &scopeDecls =
391             mStructsAndBlocksByName[scopeIndex - 1];
392 
393         auto iter = scopeDecls.find(typeName);
394         if (iter != scopeDecls.end())
395         {
396             foundDeclaration = true;
397 
398             if (iter->second != structure)
399             {
400                 mDiagnostics->error(location,
401                                     "Found reference to struct or interface block with doubly "
402                                     "created type <validateStructUsage>",
403                                     typeName.data());
404                 mStructUsageFailed = true;
405             }
406 
407             break;
408         }
409     }
410 
411     if (!foundDeclaration)
412     {
413         mDiagnostics->error(location,
414                             "Found reference to struct or interface block with no declaration "
415                             "<validateStructUsage>",
416                             typeName.data());
417         mStructUsageFailed = true;
418     }
419 }
420 
visitBuiltInFunction(TIntermOperator * node,const TFunction * function)421 void ValidateAST::visitBuiltInFunction(TIntermOperator *node, const TFunction *function)
422 {
423     const TOperator op = node->getOp();
424     if (!BuiltInGroup::IsBuiltIn(op))
425     {
426         return;
427     }
428 
429     ImmutableStringBuilder opValueBuilder(16);
430     opValueBuilder << "op: ";
431     opValueBuilder.appendDecimal(op);
432 
433     ImmutableString opValue = opValueBuilder;
434 
435     if (function == nullptr)
436     {
437         mDiagnostics->error(node->getLine(),
438                             "Found node calling built-in without a reference to the built-in "
439                             "function <validateBuiltInOps>",
440                             opValue.data());
441         mVariableReferencesFailed = true;
442     }
443     else if (function->getBuiltInOp() != op)
444     {
445         mDiagnostics->error(node->getLine(),
446                             "Found node calling built-in with a reference to a different function "
447                             "<validateBuiltInOps>",
448                             opValue.data());
449         mVariableReferencesFailed = true;
450     }
451 }
452 
visitFunctionCall(TIntermAggregate * node)453 void ValidateAST::visitFunctionCall(TIntermAggregate *node)
454 {
455     if (node->getOp() != EOpCallFunctionInAST)
456     {
457         return;
458     }
459 
460     const TFunction *function = node->getFunction();
461 
462     if (function == nullptr)
463     {
464         mDiagnostics->error(node->getLine(),
465                             "Found node calling function without a reference to it",
466                             "<validateFunctionCall>");
467         mFunctionCallFailed = true;
468     }
469     else if (mDeclaredFunctions.find(function) == mDeclaredFunctions.end())
470     {
471         mDiagnostics->error(node->getLine(),
472                             "Found node calling previously undeclared function "
473                             "<validateFunctionCall>",
474                             function->name().data());
475         mFunctionCallFailed = true;
476     }
477 }
478 
validateExpressionTypeBinary(TIntermBinary * node)479 void ValidateAST::validateExpressionTypeBinary(TIntermBinary *node)
480 {
481     switch (node->getOp())
482     {
483         case EOpIndexDirect:
484         case EOpIndexIndirect:
485         {
486             TType expectedType(node->getLeft()->getType());
487             if (!expectedType.isArray())
488             {
489                 // TODO: Validate matrix column selection and vector component selection.
490                 // http://anglebug.com/2733
491                 break;
492             }
493 
494             expectedType.toArrayElementType();
495 
496             if (!IsSameType(node->getType(), expectedType))
497             {
498                 const TSymbol *symbol = expectedType.getStruct();
499                 if (symbol == nullptr)
500                 {
501                     symbol = expectedType.getInterfaceBlock();
502                 }
503                 const char *name = nullptr;
504                 if (symbol)
505                 {
506                     name = symbol->name().data();
507                 }
508                 else if (expectedType.isScalar())
509                 {
510                     name = "<scalar array>";
511                 }
512                 else if (expectedType.isVector())
513                 {
514                     name = "<vector array>";
515                 }
516                 else
517                 {
518                     ASSERT(expectedType.isMatrix());
519                     name = "<matrix array>";
520                 }
521 
522                 mDiagnostics->error(
523                     node->getLine(),
524                     "Found index node with type that is inconsistent with the array being indexed "
525                     "<validateExpressionTypes>",
526                     name);
527                 mExpressionTypesFailed = true;
528             }
529         }
530         break;
531         default:
532             // TODO: Validate other expressions. http://anglebug.com/2733
533             break;
534     }
535 
536     switch (node->getOp())
537     {
538         case EOpIndexDirect:
539         case EOpIndexDirectStruct:
540         case EOpIndexDirectInterfaceBlock:
541             if (node->getRight()->getAsConstantUnion() == nullptr)
542             {
543                 mDiagnostics->error(node->getLine(),
544                                     "Found direct index node with a non-constant index",
545                                     "<validateExpressionTypes>");
546                 mExpressionTypesFailed = true;
547             }
548             break;
549         default:
550             break;
551     }
552 }
553 
validateExpressionTypeSwitch(TIntermSwitch * node)554 void ValidateAST::validateExpressionTypeSwitch(TIntermSwitch *node)
555 {
556     const TType &selectorType = node->getInit()->getType();
557 
558     if (selectorType.getBasicType() != EbtYuvCscStandardEXT &&
559         selectorType.getBasicType() != EbtInt && selectorType.getBasicType() != EbtUInt)
560     {
561         mDiagnostics->error(node->getLine(), "Found switch selector expression that is not integer",
562                             "<validateExpressionTypes>");
563         mExpressionTypesFailed = true;
564     }
565     else if (!selectorType.isScalar())
566     {
567         mDiagnostics->error(node->getLine(), "Found switch selector expression that is not scalar",
568                             "<validateExpressionTypes>");
569         mExpressionTypesFailed = true;
570     }
571 }
572 
visitVariableNeedingDeclaration(TIntermSymbol * node)573 void ValidateAST::visitVariableNeedingDeclaration(TIntermSymbol *node)
574 {
575     const TVariable *variable = &node->variable();
576     const TType &type         = node->getType();
577 
578     // If it's a reference to a field of a nameless interface block, match it by index and name.
579     if (type.getInterfaceBlock() && !type.isInterfaceBlock())
580     {
581         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
582         const TFieldList &fieldList           = interfaceBlock->fields();
583         const size_t fieldIndex               = type.getInterfaceBlockFieldIndex();
584 
585         if (mNamelessInterfaceBlocks.count(interfaceBlock) == 0)
586         {
587             mDiagnostics->error(node->getLine(),
588                                 "Found reference to undeclared or inconsistenly transformed "
589                                 "nameless interface block <validateVariableReferences>",
590                                 node->getName().data());
591             mVariableReferencesFailed = true;
592         }
593         else if (fieldIndex >= fieldList.size() || node->getName() != fieldList[fieldIndex]->name())
594         {
595             mDiagnostics->error(node->getLine(),
596                                 "Found reference to inconsistenly transformed nameless "
597                                 "interface block field <validateVariableReferences>",
598                                 node->getName().data());
599             mVariableReferencesFailed = true;
600         }
601         return;
602     }
603 
604     const bool isStructDeclaration =
605         type.isStructSpecifier() && variable->symbolType() == SymbolType::Empty;
606 
607     if (!isStructDeclaration && !isVariableDeclared(variable))
608     {
609         mDiagnostics->error(node->getLine(),
610                             "Found reference to undeclared or inconsistently transformed "
611                             "variable <validateVariableReferences>",
612                             node->getName().data());
613         mVariableReferencesFailed = true;
614     }
615 }
616 
visitBuiltInVariable(TIntermSymbol * node)617 void ValidateAST::visitBuiltInVariable(TIntermSymbol *node)
618 {
619     const TVariable *variable = &node->variable();
620     ImmutableString name      = variable->name();
621 
622     if (mOptions.validateVariableReferences)
623     {
624         auto iter = mReferencedBuiltIns.find(name);
625         if (iter == mReferencedBuiltIns.end())
626         {
627             mReferencedBuiltIns[name] = variable;
628             return;
629         }
630 
631         if (variable != iter->second)
632         {
633             mDiagnostics->error(
634                 node->getLine(),
635                 "Found inconsistent references to built-in variable <validateVariableReferences>",
636                 name.data());
637             mVariableReferencesFailed = true;
638         }
639     }
640 
641     if (mOptions.validateQualifiers)
642     {
643         TQualifier qualifier = variable->getType().getQualifier();
644 
645         if ((name == "gl_ClipDistance" && qualifier != EvqClipDistance) ||
646             (name == "gl_CullDistance" && qualifier != EvqCullDistance) ||
647             (name == "gl_FragDepth" && qualifier != EvqFragDepth) ||
648             (name == "gl_LastFragData" && qualifier != EvqLastFragData) ||
649             (name == "gl_LastFragColorARM" && qualifier != EvqLastFragColor))
650         {
651             mDiagnostics->error(
652                 node->getLine(),
653                 "Incorrect qualifier applied to redeclared built-in <validateQualifiers>",
654                 name.data());
655             mQualifiersFailed = true;
656         }
657     }
658 }
659 
scope(Visit visit)660 void ValidateAST::scope(Visit visit)
661 {
662     if (mOptions.validateVariableReferences)
663     {
664         if (visit == PreVisit)
665         {
666             mDeclaredVariables.push_back({});
667         }
668         else if (visit == PostVisit)
669         {
670             mDeclaredVariables.pop_back();
671         }
672     }
673 
674     if (mOptions.validateStructUsage)
675     {
676         if (visit == PreVisit)
677         {
678             mStructsAndBlocksByName.push_back({});
679         }
680         else if (visit == PostVisit)
681         {
682             mStructsAndBlocksByName.pop_back();
683         }
684     }
685 }
686 
isVariableDeclared(const TVariable * variable)687 bool ValidateAST::isVariableDeclared(const TVariable *variable)
688 {
689     ASSERT(mOptions.validateVariableReferences);
690 
691     for (const std::set<const TVariable *> &scopeVariables : mDeclaredVariables)
692     {
693         if (scopeVariables.count(variable) > 0)
694         {
695             return true;
696         }
697     }
698 
699     return false;
700 }
701 
variableNeedsDeclaration(const TVariable * variable)702 bool ValidateAST::variableNeedsDeclaration(const TVariable *variable)
703 {
704     // Don't expect declaration for built-in variables.
705     if (gl::IsBuiltInName(variable->name().data()))
706     {
707         return false;
708     }
709 
710     // Additionally, don't expect declaration for Vulkan specialization constants if not enabled.
711     // The declaration of these variables is deferred.
712     if (variable->getType().getQualifier() == EvqSpecConst)
713     {
714         return mOptions.validateSpecConstReferences;
715     }
716 
717     return true;
718 }
719 
getStructOrInterfaceBlock(const TType & type,ImmutableString * typeNameOut)720 const TFieldListCollection *ValidateAST::getStructOrInterfaceBlock(const TType &type,
721                                                                    ImmutableString *typeNameOut)
722 {
723     const TStructure *structure           = type.getStruct();
724     const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
725 
726     ASSERT(structure != nullptr || interfaceBlock != nullptr);
727 
728     // Make sure the structure or interface block is not doubly defined.
729     const TFieldListCollection *structOrBlock = nullptr;
730     if (structure != nullptr && structure->symbolType() != SymbolType::Empty)
731     {
732         structOrBlock = structure;
733         *typeNameOut  = structure->name();
734     }
735     else if (interfaceBlock != nullptr)
736     {
737         structOrBlock = interfaceBlock;
738         *typeNameOut  = interfaceBlock->name();
739     }
740 
741     return structOrBlock;
742 }
743 
expectNonNullChildren(Visit visit,TIntermNode * node,size_t least_count)744 void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
745 {
746     if (visit == PreVisit && mOptions.validateNullNodes)
747     {
748         size_t childCount = node->getChildCount();
749         if (childCount < least_count)
750         {
751             mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
752             mNullNodesFailed = true;
753         }
754 
755         for (size_t i = 0; i < childCount; ++i)
756         {
757             if (node->getChildNode(i) == nullptr)
758             {
759                 mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>");
760                 mNullNodesFailed = true;
761             }
762         }
763     }
764 }
765 
visitSymbol(TIntermSymbol * node)766 void ValidateAST::visitSymbol(TIntermSymbol *node)
767 {
768     visitNode(PreVisit, node);
769 
770     const TVariable *variable = &node->variable();
771 
772     if (mOptions.validateVariableReferences)
773     {
774         if (variableNeedsDeclaration(variable))
775         {
776             visitVariableNeedingDeclaration(node);
777         }
778     }
779 
780     const bool isBuiltIn = gl::IsBuiltInName(variable->name().data());
781     if (isBuiltIn)
782     {
783         visitBuiltInVariable(node);
784     }
785 
786     if (mOptions.validatePrecision)
787     {
788         if (!isBuiltIn && IsPrecisionApplicableToType(node->getBasicType()) &&
789             node->getType().getPrecision() == EbpUndefined)
790         {
791             // Note that some built-ins don't have a precision.
792             mDiagnostics->error(node->getLine(),
793                                 "Found symbol with undefined precision <validatePrecision>",
794                                 variable->name().data());
795             mPrecisionFailed = true;
796         }
797     }
798 }
799 
visitConstantUnion(TIntermConstantUnion * node)800 void ValidateAST::visitConstantUnion(TIntermConstantUnion *node)
801 {
802     visitNode(PreVisit, node);
803 }
804 
visitSwizzle(Visit visit,TIntermSwizzle * node)805 bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node)
806 {
807     visitNode(visit, node);
808 
809     if (mOptions.validateNoSwizzleOfSwizzle)
810     {
811         if (node->getOperand()->getAsSwizzleNode() != nullptr)
812         {
813             mDiagnostics->error(node->getLine(), "Found swizzle applied to swizzle",
814                                 "<validateNoSwizzleOfSwizzle>");
815             mNoSwizzleOfSwizzleFailed = true;
816         }
817     }
818 
819     return true;
820 }
821 
visitBinary(Visit visit,TIntermBinary * node)822 bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node)
823 {
824     visitNode(visit, node);
825 
826     if (visit == PreVisit && mOptions.validateOps)
827     {
828         const bool hasParent = getParentNode() != nullptr;
829         const bool isInDeclaration =
830             hasParent && getParentNode()->getAsDeclarationNode() != nullptr;
831         const TOperator op = node->getOp();
832         if (!BuiltInGroup::IsBuiltIn(op) && !IsBinaryOp(op))
833         {
834             mDiagnostics->error(node->getLine(),
835                                 "Found binary node with non-binary op <validateOps>",
836                                 GetOperatorString(op));
837             mOpsFailed = true;
838         }
839         else if (op == EOpInitialize && hasParent && !isInDeclaration)
840         {
841             mDiagnostics->error(node->getLine(),
842                                 "Found EOpInitialize node outside declaration <validateOps>",
843                                 GetOperatorString(op));
844             mOpsFailed = true;
845         }
846         else if (op == EOpAssign && hasParent && isInDeclaration)
847         {
848             mDiagnostics->error(node->getLine(),
849                                 "Found EOpAssign node inside declaration <validateOps>",
850                                 GetOperatorString(op));
851             mOpsFailed = true;
852         }
853     }
854     if (mOptions.validateExpressionTypes && visit == PreVisit)
855     {
856         validateExpressionTypeBinary(node);
857     }
858 
859     return true;
860 }
861 
visitUnary(Visit visit,TIntermUnary * node)862 bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node)
863 {
864     visitNode(visit, node);
865 
866     if (visit == PreVisit && mOptions.validateOps)
867     {
868         const TOperator op = node->getOp();
869         if (!BuiltInGroup::IsBuiltIn(op) && !IsUnaryOp(op))
870         {
871             mDiagnostics->error(node->getLine(), "Found unary node with non-unary op <validateOps>",
872                                 GetOperatorString(op));
873             mOpsFailed = true;
874         }
875     }
876     if (visit == PreVisit && mOptions.validateBuiltInOps)
877     {
878         visitBuiltInFunction(node, node->getFunction());
879     }
880 
881     return true;
882 }
883 
visitTernary(Visit visit,TIntermTernary * node)884 bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node)
885 {
886     visitNode(visit, node);
887     return true;
888 }
889 
visitIfElse(Visit visit,TIntermIfElse * node)890 bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node)
891 {
892     visitNode(visit, node);
893     return true;
894 }
895 
visitSwitch(Visit visit,TIntermSwitch * node)896 bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node)
897 {
898     visitNode(visit, node);
899 
900     if (mOptions.validateExpressionTypes && visit == PreVisit)
901     {
902         validateExpressionTypeSwitch(node);
903     }
904 
905     return true;
906 }
907 
visitCase(Visit visit,TIntermCase * node)908 bool ValidateAST::visitCase(Visit visit, TIntermCase *node)
909 {
910     // Case is allowed to come after a branch, and for dead-code-elimination purposes acts as if a
911     // new block is started.
912     mIsBranchVisitedInBlock = false;
913 
914     visitNode(visit, node);
915 
916     return true;
917 }
918 
visitFunctionPrototype(TIntermFunctionPrototype * node)919 void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node)
920 {
921     visitNode(PreVisit, node);
922 
923     if (mOptions.validateFunctionCall)
924     {
925         const TFunction *function = node->getFunction();
926         mDeclaredFunctions.insert(function);
927     }
928 
929     const TFunction *function = node->getFunction();
930     const TType &returnType   = function->getReturnType();
931     if (mOptions.validatePrecision && IsPrecisionApplicableToType(returnType.getBasicType()) &&
932         returnType.getPrecision() == EbpUndefined)
933     {
934         mDiagnostics->error(
935             node->getLine(),
936             "Found function with undefined precision on return value <validatePrecision>",
937             function->name().data());
938         mPrecisionFailed = true;
939     }
940 
941     if (mOptions.validateStructUsage)
942     {
943         bool needsProcessing =
944             mStructUsageProcessedFunctions.find(function) == mStructUsageProcessedFunctions.end();
945         if (needsProcessing && returnType.isStructSpecifier())
946         {
947             visitStructOrInterfaceBlockDeclaration(returnType, node->getLine());
948             mStructUsageProcessedFunctions.insert(function);
949         }
950         else
951         {
952             visitStructUsage(returnType, node->getLine());
953         }
954     }
955 
956     for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
957     {
958         const TVariable *param = function->getParam(paramIndex);
959         const TType &paramType = param->getType();
960 
961         if (mOptions.validateStructUsage)
962         {
963             visitStructUsage(paramType, node->getLine());
964         }
965 
966         if (mOptions.validateQualifiers)
967         {
968             TQualifier qualifier = paramType.getQualifier();
969             if (qualifier != EvqParamIn && qualifier != EvqParamOut && qualifier != EvqParamInOut &&
970                 qualifier != EvqParamConst)
971             {
972                 mDiagnostics->error(node->getLine(),
973                                     "Found function prototype with an invalid qualifier "
974                                     "<validateQualifiers>",
975                                     param->name().data());
976                 mQualifiersFailed = true;
977             }
978 
979             if (IsOpaqueType(paramType.getBasicType()) && qualifier != EvqParamIn)
980             {
981                 mDiagnostics->error(
982                     node->getLine(),
983                     "Found function prototype with an invalid qualifier on opaque parameter "
984                     "<validateQualifiers>",
985                     param->name().data());
986                 mQualifiersFailed = true;
987             }
988         }
989 
990         if (mOptions.validatePrecision && IsPrecisionApplicableToType(paramType.getBasicType()) &&
991             paramType.getPrecision() == EbpUndefined)
992         {
993             mDiagnostics->error(
994                 node->getLine(),
995                 "Found function parameter with undefined precision <validatePrecision>",
996                 param->name().data());
997             mPrecisionFailed = true;
998         }
999     }
1000 }
1001 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)1002 bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1003 {
1004     visitNode(visit, node);
1005 
1006     if (mOptions.validateVariableReferences && visit == PreVisit)
1007     {
1008         const TFunction *function = node->getFunction();
1009 
1010         size_t paramCount = function->getParamCount();
1011         for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
1012         {
1013             const TVariable *variable = function->getParam(paramIndex);
1014 
1015             if (isVariableDeclared(variable))
1016             {
1017                 mDiagnostics->error(node->getLine(),
1018                                     "Found two declarations of the same function argument "
1019                                     "<validateVariableReferences>",
1020                                     variable->name().data());
1021                 mVariableReferencesFailed = true;
1022                 break;
1023             }
1024 
1025             mDeclaredVariables.back().insert(variable);
1026         }
1027     }
1028 
1029     return true;
1030 }
1031 
visitAggregate(Visit visit,TIntermAggregate * node)1032 bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node)
1033 {
1034     visitNode(visit, node);
1035     expectNonNullChildren(visit, node, 0);
1036 
1037     if (visit == PreVisit && mOptions.validateBuiltInOps)
1038     {
1039         visitBuiltInFunction(node, node->getFunction());
1040     }
1041 
1042     if (visit == PreVisit && mOptions.validateFunctionCall)
1043     {
1044         visitFunctionCall(node);
1045     }
1046 
1047     if (visit == PreVisit && mOptions.validateNoRawFunctionCalls)
1048     {
1049         if (node->getOp() == EOpCallInternalRawFunction)
1050         {
1051             mDiagnostics->error(node->getLine(),
1052                                 "Found node calling a raw function (deprecated) "
1053                                 "<validateNoRawFunctionCalls>",
1054                                 node->getFunction()->name().data());
1055             mNoRawFunctionCallsFailed = true;
1056         }
1057     }
1058 
1059     if (visit == PreVisit && mOptions.validateNoQualifiersOnConstructors)
1060     {
1061         if (node->getOp() == EOpConstruct)
1062         {
1063             if (node->getType().isInvariant())
1064             {
1065                 mDiagnostics->error(node->getLine(), "Found constructor node with invariant type",
1066                                     "<validateNoQualifiersOnConstructors>");
1067                 mNoQualifiersOnConstructorsFailed = true;
1068             }
1069             if (node->getType().isPrecise())
1070             {
1071                 mDiagnostics->error(node->getLine(), "Found constructor node with precise type",
1072                                     "<validateNoQualifiersOnConstructors>");
1073                 mNoQualifiersOnConstructorsFailed = true;
1074             }
1075             if (node->getType().isInterpolant())
1076             {
1077                 mDiagnostics->error(node->getLine(), "Found constructor node with interpolant type",
1078                                     "<validateNoQualifiersOnConstructors>");
1079                 mNoQualifiersOnConstructorsFailed = true;
1080             }
1081             if (!node->getType().getMemoryQualifier().isEmpty())
1082             {
1083                 mDiagnostics->error(node->getLine(),
1084                                     "Found constructor node whose type has a memory qualifier",
1085                                     "<validateNoQualifiersOnConstructors>");
1086                 mNoQualifiersOnConstructorsFailed = true;
1087             }
1088             if (node->getType().getInterfaceBlock() != nullptr)
1089             {
1090                 mDiagnostics->error(
1091                     node->getLine(),
1092                     "Found constructor node whose type references an interface block",
1093                     "<validateNoQualifiersOnConstructors>");
1094                 mNoQualifiersOnConstructorsFailed = true;
1095             }
1096             if (!node->getType().getLayoutQualifier().isEmpty())
1097             {
1098                 mDiagnostics->error(node->getLine(),
1099                                     "Found constructor node whose type has a layout qualifier",
1100                                     "<validateNoQualifiersOnConstructors>");
1101                 mNoQualifiersOnConstructorsFailed = true;
1102             }
1103         }
1104     }
1105 
1106     return true;
1107 }
1108 
visitBlock(Visit visit,TIntermBlock * node)1109 bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node)
1110 {
1111     visitNode(visit, node);
1112     scope(visit);
1113     expectNonNullChildren(visit, node, 0);
1114 
1115     if (visit == PostVisit)
1116     {
1117         // If the parent is a block and mIsBranchVisitedInBlock is set, this is a nested block
1118         // without any condition (like if, loop or switch), so the rest of the parent block is also
1119         // dead code.  Otherwise the parent block can contain code after this.
1120         if (getParentNode() == nullptr || getParentNode()->getAsBlock() == nullptr)
1121         {
1122             mIsBranchVisitedInBlock = false;
1123         }
1124     }
1125 
1126     return true;
1127 }
1128 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)1129 bool ValidateAST::visitGlobalQualifierDeclaration(Visit visit,
1130                                                   TIntermGlobalQualifierDeclaration *node)
1131 {
1132     visitNode(visit, node);
1133 
1134     const TVariable *variable = &node->getSymbol()->variable();
1135 
1136     if (mOptions.validateVariableReferences && variableNeedsDeclaration(variable))
1137     {
1138         if (!isVariableDeclared(variable))
1139         {
1140             mDiagnostics->error(node->getLine(),
1141                                 "Found reference to undeclared or inconsistently transformed "
1142                                 "variable <validateVariableReferences>",
1143                                 variable->name().data());
1144             mVariableReferencesFailed = true;
1145         }
1146     }
1147     return true;
1148 }
1149 
visitDeclaration(Visit visit,TIntermDeclaration * node)1150 bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node)
1151 {
1152     visitNode(visit, node);
1153     expectNonNullChildren(visit, node, 0);
1154 
1155     const TIntermSequence &sequence = *(node->getSequence());
1156 
1157     if (mOptions.validateMultiDeclarations && sequence.size() > 1)
1158     {
1159         TIntermSymbol *symbol = sequence[1]->getAsSymbolNode();
1160         if (symbol == nullptr)
1161         {
1162             TIntermBinary *init = sequence[1]->getAsBinaryNode();
1163             ASSERT(init && init->getOp() == EOpInitialize);
1164             symbol = init->getLeft()->getAsSymbolNode();
1165         }
1166         ASSERT(symbol);
1167 
1168         mDiagnostics->error(node->getLine(),
1169                             "Found multiple declarations where SeparateDeclarations should have "
1170                             "separated them <validateMultiDeclarations>",
1171                             symbol->variable().name().data());
1172         mMultiDeclarationsFailed = true;
1173     }
1174 
1175     if (visit == PreVisit)
1176     {
1177         bool validateStructUsage = mOptions.validateStructUsage;
1178 
1179         for (TIntermNode *instance : sequence)
1180         {
1181             TIntermSymbol *symbol = instance->getAsSymbolNode();
1182             if (symbol == nullptr)
1183             {
1184                 TIntermBinary *init = instance->getAsBinaryNode();
1185                 ASSERT(init && init->getOp() == EOpInitialize);
1186                 symbol = init->getLeft()->getAsSymbolNode();
1187             }
1188             ASSERT(symbol);
1189 
1190             const TVariable *variable = &symbol->variable();
1191             const TType &type         = variable->getType();
1192 
1193             if (mOptions.validateVariableReferences)
1194             {
1195                 if (isVariableDeclared(variable))
1196                 {
1197                     mDiagnostics->error(
1198                         node->getLine(),
1199                         "Found two declarations of the same variable <validateVariableReferences>",
1200                         variable->name().data());
1201                     mVariableReferencesFailed = true;
1202                     break;
1203                 }
1204 
1205                 mDeclaredVariables.back().insert(variable);
1206 
1207                 const TInterfaceBlock *interfaceBlock = variable->getType().getInterfaceBlock();
1208 
1209                 if (variable->symbolType() == SymbolType::Empty && interfaceBlock != nullptr)
1210                 {
1211                     // Nameless interface blocks can only be declared at the top level.  Their
1212                     // fields are matched by field index, and then verified to match by name.
1213                     // Conflict in names should have already generated a compile error.
1214                     ASSERT(mDeclaredVariables.size() == 1);
1215                     ASSERT(mNamelessInterfaceBlocks.count(interfaceBlock) == 0);
1216 
1217                     mNamelessInterfaceBlocks.insert(interfaceBlock);
1218                 }
1219             }
1220 
1221             if (validateStructUsage)
1222             {
1223                 // Only declare and/or validate the struct once.
1224                 validateStructUsage = false;
1225 
1226                 if (type.isStructSpecifier() || type.isInterfaceBlock())
1227                 {
1228                     visitStructOrInterfaceBlockDeclaration(type, node->getLine());
1229                 }
1230                 else
1231                 {
1232                     visitStructUsage(type, node->getLine());
1233                 }
1234             }
1235 
1236             if (gl::IsBuiltInName(variable->name().data()))
1237             {
1238                 visitBuiltInVariable(symbol);
1239             }
1240 
1241             if (mOptions.validatePrecision && (type.isStructSpecifier() || type.isInterfaceBlock()))
1242             {
1243                 const TFieldListCollection *structOrBlock = type.getStruct();
1244                 if (structOrBlock == nullptr)
1245                 {
1246                     structOrBlock = type.getInterfaceBlock();
1247                 }
1248 
1249                 for (const TField *field : structOrBlock->fields())
1250                 {
1251                     const TType *fieldType = field->type();
1252                     if (IsPrecisionApplicableToType(fieldType->getBasicType()) &&
1253                         fieldType->getPrecision() == EbpUndefined)
1254                     {
1255                         mDiagnostics->error(
1256                             node->getLine(),
1257                             "Found block field with undefined precision <validatePrecision>",
1258                             field->name().data());
1259                         mPrecisionFailed = true;
1260                     }
1261                 }
1262             }
1263         }
1264     }
1265 
1266     return true;
1267 }
1268 
visitLoop(Visit visit,TIntermLoop * node)1269 bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node)
1270 {
1271     visitNode(visit, node);
1272     return true;
1273 }
1274 
visitBranch(Visit visit,TIntermBranch * node)1275 bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node)
1276 {
1277     visitNode(visit, node);
1278 
1279     if (visit == PreVisit && mOptions.validateOps)
1280     {
1281         const TOperator op = node->getFlowOp();
1282         if (!IsBranchOp(op))
1283         {
1284             mDiagnostics->error(node->getLine(),
1285                                 "Found branch node with non-branch op <validateOps>",
1286                                 GetOperatorString(op));
1287             mOpsFailed = true;
1288         }
1289     }
1290     if (visit == PostVisit)
1291     {
1292         mIsBranchVisitedInBlock = true;
1293     }
1294 
1295     return true;
1296 }
1297 
visitPreprocessorDirective(TIntermPreprocessorDirective * node)1298 void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1299 {
1300     visitNode(PreVisit, node);
1301 }
1302 
validateInternal()1303 bool ValidateAST::validateInternal()
1304 {
1305     return !mSingleParentFailed && !mVariableReferencesFailed && !mOpsFailed &&
1306            !mBuiltInOpsFailed && !mFunctionCallFailed && !mNoRawFunctionCallsFailed &&
1307            !mNullNodesFailed && !mQualifiersFailed && !mPrecisionFailed && !mStructUsageFailed &&
1308            !mExpressionTypesFailed && !mMultiDeclarationsFailed && !mNoSwizzleOfSwizzleFailed &&
1309            !mNoQualifiersOnConstructorsFailed && !mNoStatementsAfterBranchFailed;
1310 }
1311 
1312 }  // anonymous namespace
1313 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)1314 bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options)
1315 {
1316     // ValidateAST is called after transformations, so if |validateNoMoreTransformations| is set,
1317     // it's immediately an error.
1318     if (options.validateNoMoreTransformations)
1319     {
1320         diagnostics->error(kNoSourceLoc, "Unexpected transformation after AST post-processing",
1321                            "<validateNoMoreTransformations>");
1322         return false;
1323     }
1324 
1325     return ValidateAST::validate(root, diagnostics, options);
1326 }
1327 
1328 }  // namespace sh
1329