summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp
new file mode 100644
index 0000000000..23479906e1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateBarrierFunctionCall.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright 2020 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ValidateBarrierFunctionCalls:
+// Runs compilation checks related to the "barrier built-in function.
+
+#include "compiler/translator/ValidateBarrierFunctionCall.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+namespace
+{
+class Traverser : public TIntermTraverser
+{
+ public:
+ Traverser(TDiagnostics *diagnostics)
+ : TIntermTraverser(true, false, true), mDiagnostics(diagnostics)
+ {}
+
+ bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
+ {
+ if (!node->getFunction()->isMain())
+ {
+ return false;
+ }
+
+ mInMain = visit == PreVisit;
+ return true;
+ }
+
+ bool visitBranch(Visit visit, TIntermBranch *branch) override
+ {
+ if (branch->getFlowOp() == EOpReturn)
+ {
+ mSeenReturn = true;
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (node->getOp() != EOpBarrier)
+ {
+ return true;
+ }
+
+ if (mSeenReturn)
+ {
+ mDiagnostics->error(node->getLine(),
+ "barrier() may not be called at any point after a return statement "
+ "in the function main().",
+ "barrier");
+ mValid = false;
+ return false;
+ }
+
+ // TODO(anglebug.com/5557): Determine if we should check loops as well.
+ if (mBranchCount > 0)
+ {
+ mDiagnostics->error(
+ node->getLine(),
+ "barrier() may not be called in potentially divergent flow control.", "barrier");
+ mValid = false;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool visitIfElse(Visit visit, TIntermIfElse *node) override
+ {
+ mBranchCount += ((visit == PreVisit) ? 1 : -1);
+ return true;
+ }
+
+ bool valid() const { return mValid; }
+
+ private:
+ TDiagnostics *mDiagnostics = nullptr;
+ bool mInMain = false;
+ bool mSeenReturn = false;
+ bool mValid = true;
+ uint32_t mBranchCount = 0;
+};
+} // anonymous namespace
+
+bool ValidateBarrierFunctionCall(TIntermBlock *root, TDiagnostics *diagnostics)
+{
+ Traverser traverser(diagnostics);
+ root->traverse(&traverser);
+ return traverser.valid();
+}
+} // namespace sh