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