summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/compiler/translator/Intermediate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/compiler/translator/Intermediate.cpp')
-rwxr-xr-xgfx/angle/src/compiler/translator/Intermediate.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/gfx/angle/src/compiler/translator/Intermediate.cpp b/gfx/angle/src/compiler/translator/Intermediate.cpp
new file mode 100755
index 000000000..9e3e455ae
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/Intermediate.cpp
@@ -0,0 +1,387 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol *TIntermediate::addSymbol(
+ int id, const TString &name, const TType &type, const TSourceLoc &line)
+{
+ TIntermSymbol *node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped *TIntermediate::addIndex(TOperator op,
+ TIntermTyped *base,
+ TIntermTyped *index,
+ const TSourceLoc &line,
+ TDiagnostics *diagnostics)
+{
+ TIntermBinary *node = new TIntermBinary(op, base, index);
+ node->setLine(line);
+
+ TIntermTyped *folded = node->fold(diagnostics);
+ if (folded)
+ {
+ return folded;
+ }
+
+ return node;
+}
+
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate but no operator was set.
+TIntermAggregate *TIntermediate::setAggregateOperator(
+ TIntermNode *node, TOperator op, const TSourceLoc &line)
+{
+ TIntermAggregate *aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node)
+ {
+ aggNode = node->getAsAggregate();
+ if (aggNode == NULL || aggNode->getOp() != EOpNull)
+ {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence()->push_back(node);
+ }
+ }
+ else
+ {
+ aggNode = new TIntermAggregate();
+ }
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate *TIntermediate::growAggregate(
+ TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
+{
+ if (left == NULL && right == NULL)
+ return NULL;
+
+ TIntermAggregate *aggNode = NULL;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull)
+ {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence()->push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence()->push_back(right);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless NULL was passed in for the existing node.
+//
+TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceLoc &line)
+{
+ if (node == nullptr)
+ return nullptr;
+
+ TIntermAggregate *aggNode = new TIntermAggregate;
+ aggNode->getSequence()->push_back(node);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+// If the input node is nullptr, return nullptr.
+// If the input node is a block node, return it.
+// If the input node is not a block node, put it inside a block node and return that.
+TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
+{
+ if (node == nullptr)
+ return nullptr;
+ TIntermBlock *blockNode = node->getAsBlock();
+ if (blockNode != nullptr)
+ return blockNode;
+
+ blockNode = new TIntermBlock();
+ blockNode->setLine(node->getLine());
+ blockNode->getSequence()->push_back(node);
+ return blockNode;
+}
+
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the node created.
+TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
+ TIntermNodePair nodePair,
+ const TSourceLoc &line)
+{
+ // For compile time constant conditions, prune the code now.
+
+ if (cond->getAsConstantUnion())
+ {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ {
+ return EnsureBlock(nodePair.node1);
+ }
+ else
+ {
+ return EnsureBlock(nodePair.node2);
+ }
+ }
+
+ TIntermIfElse *node =
+ new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &line,
+ int shaderVersion)
+{
+ TIntermTyped *commaNode = nullptr;
+ if (!left->hasSideEffects())
+ {
+ commaNode = right;
+ }
+ else
+ {
+ commaNode = new TIntermBinary(EOpComma, left, right);
+ commaNode->setLine(line);
+ }
+ TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
+ commaNode->getTypePointer()->setQualifier(resultQualifier);
+ return commaNode;
+}
+
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
+// could be folded.
+TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line)
+{
+ // Note that the node resulting from here can be a constant union without being qualified as
+ // constant.
+ if (cond->getAsConstantUnion())
+ {
+ TQualifier resultQualifier =
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
+ if (cond->getAsConstantUnion()->getBConst(0))
+ {
+ trueExpression->getTypePointer()->setQualifier(resultQualifier);
+ return trueExpression;
+ }
+ else
+ {
+ falseExpression->getTypePointer()->setQualifier(resultQualifier);
+ return falseExpression;
+ }
+ }
+
+ // Make a ternary node.
+ TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
+ TIntermBlock *statementList,
+ const TSourceLoc &line)
+{
+ TIntermSwitch *node = new TIntermSwitch(init, statementList);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermCase *TIntermediate::addCase(
+ TIntermTyped *condition, const TSourceLoc &line)
+{
+ TIntermCase *node = new TIntermCase(condition);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
+ const TType &type,
+ const TSourceLoc &line)
+{
+ TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
+ const TVectorFields &fields,
+ const TSourceLoc &dotLocation)
+{
+ TVector<int> fieldsVector;
+ for (int i = 0; i < fields.num; ++i)
+ {
+ fieldsVector.push_back(fields.offsets[i]);
+ }
+ TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
+ node->setLine(dotLocation);
+
+ TIntermTyped *folded = node->fold();
+ if (folded)
+ {
+ return folded;
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode *TIntermediate::addLoop(
+ TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
+ TIntermNode *body, const TSourceLoc &line)
+{
+ TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(
+ TOperator branchOp, const TSourceLoc &line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(
+ TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
+{
+ TIntermBranch *node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
+{
+ switch (aggregate->getOp())
+ {
+ case EOpAtan:
+ case EOpPow:
+ case EOpMod:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpMul:
+ case EOpOuterProduct:
+ case EOpLessThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThan:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ return aggregate->fold(diagnostics);
+ default:
+ // TODO: Add support for folding array constructors
+ if (aggregate->isConstructor() && !aggregate->isArray())
+ {
+ return aggregate->fold(diagnostics);
+ }
+ // Constant folding not supported for the built-in.
+ return nullptr;
+ }
+}
+
+} // namespace sh