1 //
2 // Copyright 2020 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 // ValidateBarrierFunctionCalls:
7 //   Runs compilation checks related to the "barrier built-in function.
8 
9 #include "compiler/translator/ValidateBarrierFunctionCall.h"
10 
11 #include "compiler/translator/Diagnostics.h"
12 #include "compiler/translator/SymbolTable.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14 
15 namespace sh
16 {
17 namespace
18 {
19 class Traverser : public TIntermTraverser
20 {
21   public:
Traverser(TDiagnostics * diagnostics)22     Traverser(TDiagnostics *diagnostics)
23         : TIntermTraverser(true, false, true), mDiagnostics(diagnostics)
24     {}
25 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)26     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
27     {
28         if (!node->getFunction()->isMain())
29         {
30             return false;
31         }
32 
33         mInMain = visit == PreVisit;
34         return true;
35     }
36 
visitBranch(Visit visit,TIntermBranch * branch)37     bool visitBranch(Visit visit, TIntermBranch *branch) override
38     {
39         if (branch->getFlowOp() == EOpReturn)
40         {
41             mSeenReturn = true;
42         }
43 
44         return true;
45     }
46 
visitAggregate(Visit visit,TIntermAggregate * node)47     bool visitAggregate(Visit visit, TIntermAggregate *node) override
48     {
49         if (node->getOp() != EOpBarrier)
50         {
51             return true;
52         }
53 
54         if (mSeenReturn)
55         {
56             mDiagnostics->error(node->getLine(),
57                                 "barrier() may not be called at any point after a return statement "
58                                 "in the function main().",
59                                 "barrier");
60             mValid = false;
61             return false;
62         }
63 
64         // TODO(anglebug.com/5557): Determine if we should check loops as well.
65         if (mBranchCount > 0)
66         {
67             mDiagnostics->error(
68                 node->getLine(),
69                 "barrier() may not be called in potentially divergent flow control.", "barrier");
70             mValid = false;
71             return false;
72         }
73 
74         return true;
75     }
76 
visitIfElse(Visit visit,TIntermIfElse * node)77     bool visitIfElse(Visit visit, TIntermIfElse *node) override
78     {
79         mBranchCount += ((visit == PreVisit) ? 1 : -1);
80         return true;
81     }
82 
valid() const83     bool valid() const { return mValid; }
84 
85   private:
86     TDiagnostics *mDiagnostics = nullptr;
87     bool mInMain               = false;
88     bool mSeenReturn           = false;
89     bool mValid                = true;
90     uint32_t mBranchCount      = 0;
91 };
92 }  // anonymous namespace
93 
ValidateBarrierFunctionCall(TIntermBlock * root,TDiagnostics * diagnostics)94 bool ValidateBarrierFunctionCall(TIntermBlock *root, TDiagnostics *diagnostics)
95 {
96     Traverser traverser(diagnostics);
97     root->traverse(&traverser);
98     return traverser.valid();
99 }
100 }  // namespace sh
101