// // 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() != EOpBarrierTCS) { 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