summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
new file mode 100644
index 0000000000..ea15ab7844
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
@@ -0,0 +1,119 @@
+//
+// Copyright 2002 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.
+//
+// During parsing, all constant expressions are folded to constant union nodes. The expressions that
+// have been folded may have had precision qualifiers, which should affect the precision of the
+// consuming operation. If the folded constant union nodes are written to output as such they won't
+// have any precision qualifiers, and their effect on the precision of the consuming operation is
+// lost.
+//
+// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants
+// and hoists the constants outside the containing expression as precision qualified named variables
+// in case that is required for correct precision propagation.
+//
+
+#include "compiler/translator/tree_ops/RecordConstantPrecision.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class RecordConstantPrecisionTraverser : public TIntermTraverser
+{
+ public:
+ RecordConstantPrecisionTraverser(TSymbolTable *symbolTable);
+
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+
+ protected:
+ bool operandAffectsParentOperationPrecision(TIntermTyped *operand);
+};
+
+RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, true, symbolTable)
+{}
+
+bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand)
+{
+ if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock())
+ {
+ return false;
+ }
+
+ if (operand->getBasicType() == EbtBool || operand->getBasicType() == EbtStruct)
+ {
+ return false;
+ }
+
+ const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode();
+ if (parentAsBinary != nullptr)
+ {
+ // If the constant is assigned or is used to initialize a variable, or if it's an index,
+ // its precision has no effect.
+ switch (parentAsBinary->getOp())
+ {
+ case EOpInitialize:
+ case EOpAssign:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexIndirect:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ TIntermAggregate *parentAsAggregate = getParentNode()->getAsAggregate();
+ if (parentAsAggregate != nullptr)
+ {
+ // The precision of an aggregate is derived from children only in the following conditions:
+ //
+ // - Built-in math operations
+ // - Constructors
+ //
+ return parentAsAggregate->isConstructor() ||
+ BuiltInGroup::IsMath(parentAsAggregate->getOp());
+ }
+
+ return true;
+}
+
+void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ // If the constant has lowp or undefined precision, it can't increase the precision of consuming
+ // operations.
+ if (node->getPrecision() < EbpMedium)
+ return;
+
+ // It's possible the node has no effect on the precision of the consuming expression, depending
+ // on the consuming expression, and the precision of the other parameters of the expression.
+ if (!operandAffectsParentOperationPrecision(node))
+ return;
+
+ // Make the constant a precision-qualified named variable to make sure it affects the precision
+ // of the consuming expression.
+ TIntermDeclaration *variableDeclaration = nullptr;
+ TVariable *variable = DeclareTempVariable(mSymbolTable, node, EvqConst, &variableDeclaration);
+ insertStatementInParentBlock(variableDeclaration);
+ queueReplacement(CreateTempSymbolNode(variable), OriginalNode::IS_DROPPED);
+}
+
+} // namespace
+
+bool RecordConstantPrecision(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
+{
+ RecordConstantPrecisionTraverser traverser(symbolTable);
+ root->traverse(&traverser);
+ return traverser.updateTree(compiler, root);
+}
+
+} // namespace sh