2 // Copyright (c) 2002-2014 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.
8 // Build the intermediate representation.
15 #include "compiler/translator/HashNames.h"
16 #include "compiler/translator/IntermNode.h"
17 #include "compiler/translator/SymbolTable.h"
22 TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
24 return left > right ? left : right;
27 bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
33 return left.getNominalSize() == right.getNominalSize() &&
34 left.getSecondarySize() == right.getSecondarySize();
35 case EOpVectorTimesScalar:
36 case EOpVectorTimesScalarAssign:
38 case EOpVectorTimesMatrix:
39 return left.getNominalSize() == right.getRows();
40 case EOpVectorTimesMatrixAssign:
41 return left.getNominalSize() == right.getRows() &&
42 left.getNominalSize() == right.getCols();
43 case EOpMatrixTimesVector:
44 return left.getCols() == right.getNominalSize();
45 case EOpMatrixTimesScalar:
46 case EOpMatrixTimesScalarAssign:
48 case EOpMatrixTimesMatrix:
49 return left.getCols() == right.getRows();
50 case EOpMatrixTimesMatrixAssign:
51 return left.getCols() == right.getCols() &&
52 left.getRows() == right.getRows();
60 bool CompareStructure(const TType& leftNodeType,
61 ConstantUnion *rightUnionArray,
62 ConstantUnion *leftUnionArray);
64 bool CompareStruct(const TType &leftNodeType,
65 ConstantUnion *rightUnionArray,
66 ConstantUnion *leftUnionArray)
68 const TFieldList &fields = leftNodeType.getStruct()->fields();
70 size_t structSize = fields.size();
73 for (size_t j = 0; j < structSize; j++)
75 size_t size = fields[j]->type()->getObjectSize();
76 for (size_t i = 0; i < size; i++)
78 if (fields[j]->type()->getBasicType() == EbtStruct)
80 if (!CompareStructure(*fields[j]->type(),
81 &rightUnionArray[index],
82 &leftUnionArray[index]))
89 if (leftUnionArray[index] != rightUnionArray[index])
98 bool CompareStructure(const TType &leftNodeType,
99 ConstantUnion *rightUnionArray,
100 ConstantUnion *leftUnionArray)
102 if (leftNodeType.isArray())
104 TType typeWithoutArrayness = leftNodeType;
105 typeWithoutArrayness.clearArrayness();
107 size_t arraySize = leftNodeType.getArraySize();
109 for (size_t i = 0; i < arraySize; ++i)
111 size_t offset = typeWithoutArrayness.getObjectSize() * i;
112 if (!CompareStruct(typeWithoutArrayness,
113 &rightUnionArray[offset],
114 &leftUnionArray[offset]))
122 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
127 } // namespace anonymous
130 ////////////////////////////////////////////////////////////////
132 // Member functions of the nodes used for building the tree.
134 ////////////////////////////////////////////////////////////////
136 #define REPLACE_IF_IS(node, type, original, replacement) \
137 if (node == original) { \
138 node = static_cast<type *>(replacement); \
142 bool TIntermLoop::replaceChildNode(
143 TIntermNode *original, TIntermNode *replacement)
145 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
146 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
147 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
148 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
152 void TIntermLoop::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
156 nodeQueue->push(mInit);
160 nodeQueue->push(mCond);
164 nodeQueue->push(mExpr);
168 nodeQueue->push(mBody);
172 bool TIntermBranch::replaceChildNode(
173 TIntermNode *original, TIntermNode *replacement)
175 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
179 void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
183 nodeQueue->push(mExpression);
187 bool TIntermBinary::replaceChildNode(
188 TIntermNode *original, TIntermNode *replacement)
190 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
191 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
195 void TIntermBinary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
199 nodeQueue->push(mLeft);
203 nodeQueue->push(mRight);
207 bool TIntermUnary::replaceChildNode(
208 TIntermNode *original, TIntermNode *replacement)
210 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
214 void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
218 nodeQueue->push(mOperand);
222 bool TIntermAggregate::replaceChildNode(
223 TIntermNode *original, TIntermNode *replacement)
225 for (size_t ii = 0; ii < mSequence.size(); ++ii)
227 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
232 void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
234 for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++)
236 nodeQueue->push(mSequence[childIndex]);
240 bool TIntermSelection::replaceChildNode(
241 TIntermNode *original, TIntermNode *replacement)
243 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
244 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
245 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
249 void TIntermSelection::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
253 nodeQueue->push(mCondition);
257 nodeQueue->push(mTrueBlock);
261 nodeQueue->push(mFalseBlock);
266 // Say whether or not an operation node changes the value of a variable.
268 bool TIntermOperator::isAssignment() const
272 case EOpPostIncrement:
273 case EOpPostDecrement:
274 case EOpPreIncrement:
275 case EOpPreDecrement:
280 case EOpVectorTimesMatrixAssign:
281 case EOpVectorTimesScalarAssign:
282 case EOpMatrixTimesScalarAssign:
283 case EOpMatrixTimesMatrixAssign:
292 // returns true if the operator is for one of the constructors
294 bool TIntermOperator::isConstructor() const
298 case EOpConstructVec2:
299 case EOpConstructVec3:
300 case EOpConstructVec4:
301 case EOpConstructMat2:
302 case EOpConstructMat3:
303 case EOpConstructMat4:
304 case EOpConstructFloat:
305 case EOpConstructIVec2:
306 case EOpConstructIVec3:
307 case EOpConstructIVec4:
308 case EOpConstructInt:
309 case EOpConstructUVec2:
310 case EOpConstructUVec3:
311 case EOpConstructUVec4:
312 case EOpConstructUInt:
313 case EOpConstructBVec2:
314 case EOpConstructBVec3:
315 case EOpConstructBVec4:
316 case EOpConstructBool:
317 case EOpConstructStruct:
325 // Make sure the type of a unary operator is appropriate for its
326 // combination of operation and operand type.
328 // Returns false in nothing makes sense.
330 bool TIntermUnary::promote(TInfoSink &)
335 if (mOperand->getBasicType() != EbtBool)
339 case EOpPostIncrement:
340 case EOpPostDecrement:
341 case EOpPreIncrement:
342 case EOpPreDecrement:
343 if (mOperand->getBasicType() == EbtBool)
347 // operators for built-ins are already type checked against their prototype
350 case EOpVectorLogicalNot:
354 if (mOperand->getBasicType() != EbtFloat)
358 setType(mOperand->getType());
359 mType.setQualifier(EvqTemporary);
365 // Establishes the type of the resultant operation, as well as
366 // makes the operator the correct one for the operands.
368 // Returns false if operator can't work on operands.
370 bool TIntermBinary::promote(TInfoSink &infoSink)
372 // This function only handles scalars, vectors, and matrices.
373 if (mLeft->isArray() || mRight->isArray())
375 infoSink.info.message(EPrefixInternalError, getLine(),
376 "Invalid operation for arrays");
380 // GLSL ES 2.0 does not support implicit type casting.
381 // So the basic type should always match.
382 if (mLeft->getBasicType() != mRight->getBasicType())
388 // Base assumption: just make the type the same as the left
389 // operand. Then only deviations from this need be coded.
391 setType(mLeft->getType());
393 // The result gets promoted to the highest precision.
394 TPrecision higherPrecision = GetHigherPrecision(
395 mLeft->getPrecision(), mRight->getPrecision());
396 getTypePointer()->setPrecision(higherPrecision);
398 // Binary operations results in temporary variables unless both
399 // operands are const.
400 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
402 getTypePointer()->setQualifier(EvqTemporary);
405 const int nominalSize =
406 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
409 // All scalars or structs. Code after this test assumes this case is removed!
411 if (nominalSize == 1)
416 // Promote to conditional
422 case EOpLessThanEqual:
423 case EOpGreaterThanEqual:
424 setType(TType(EbtBool, EbpUndefined));
428 // And and Or operate on conditionals
432 // Both operands must be of type bool.
433 if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
437 setType(TType(EbtBool, EbpUndefined));
446 // If we reach here, at least one of the operands is vector or matrix.
447 // The other operand could be a scalar, vector, or matrix.
448 // Can these two operands be combined?
450 TBasicType basicType = mLeft->getBasicType();
454 if (!mLeft->isMatrix() && mRight->isMatrix())
456 if (mLeft->isVector())
458 mOp = EOpVectorTimesMatrix;
459 setType(TType(basicType, higherPrecision, EvqTemporary,
460 mRight->getCols(), 1));
464 mOp = EOpMatrixTimesScalar;
465 setType(TType(basicType, higherPrecision, EvqTemporary,
466 mRight->getCols(), mRight->getRows()));
469 else if (mLeft->isMatrix() && !mRight->isMatrix())
471 if (mRight->isVector())
473 mOp = EOpMatrixTimesVector;
474 setType(TType(basicType, higherPrecision, EvqTemporary,
475 mLeft->getRows(), 1));
479 mOp = EOpMatrixTimesScalar;
482 else if (mLeft->isMatrix() && mRight->isMatrix())
484 mOp = EOpMatrixTimesMatrix;
485 setType(TType(basicType, higherPrecision, EvqTemporary,
486 mRight->getCols(), mLeft->getRows()));
488 else if (!mLeft->isMatrix() && !mRight->isMatrix())
490 if (mLeft->isVector() && mRight->isVector())
492 // leave as component product
494 else if (mLeft->isVector() || mRight->isVector())
496 mOp = EOpVectorTimesScalar;
497 setType(TType(basicType, higherPrecision, EvqTemporary,
503 infoSink.info.message(EPrefixInternalError, getLine(),
508 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
515 if (!mLeft->isMatrix() && mRight->isMatrix())
517 if (mLeft->isVector())
519 mOp = EOpVectorTimesMatrixAssign;
526 else if (mLeft->isMatrix() && !mRight->isMatrix())
528 if (mRight->isVector())
534 mOp = EOpMatrixTimesScalarAssign;
537 else if (mLeft->isMatrix() && mRight->isMatrix())
539 mOp = EOpMatrixTimesMatrixAssign;
540 setType(TType(basicType, higherPrecision, EvqTemporary,
541 mRight->getCols(), mLeft->getRows()));
543 else if (!mLeft->isMatrix() && !mRight->isMatrix())
545 if (mLeft->isVector() && mRight->isVector())
547 // leave as component product
549 else if (mLeft->isVector() || mRight->isVector())
551 if (!mLeft->isVector())
553 mOp = EOpVectorTimesScalarAssign;
554 setType(TType(basicType, higherPrecision, EvqTemporary,
555 mLeft->getNominalSize(), 1));
560 infoSink.info.message(EPrefixInternalError, getLine(),
565 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
579 if ((mLeft->isMatrix() && mRight->isVector()) ||
580 (mLeft->isVector() && mRight->isMatrix()))
585 // Are the sizes compatible?
586 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
587 mLeft->getSecondarySize() != mRight->getSecondarySize())
589 // If the nominal size of operands do not match:
590 // One of them must be scalar.
591 if (!mLeft->isScalar() && !mRight->isScalar())
594 // Operator cannot be of type pure assignment.
595 if (mOp == EOpAssign || mOp == EOpInitialize)
600 const int secondarySize = std::max(
601 mLeft->getSecondarySize(), mRight->getSecondarySize());
602 setType(TType(basicType, higherPrecision, EvqTemporary,
603 nominalSize, secondarySize));
611 case EOpLessThanEqual:
612 case EOpGreaterThanEqual:
613 if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
614 (mLeft->getSecondarySize() != mRight->getSecondarySize()))
618 setType(TType(EbtBool, EbpUndefined));
628 // The fold functions see if an operation on a constant can be done in place,
629 // without generating run-time code.
631 // Returns the node to keep using, which may or may not be the node passed in.
633 TIntermTyped *TIntermConstantUnion::fold(
634 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
636 ConstantUnion *unionArray = getUnionArrayPointer();
641 size_t objectSize = getType().getObjectSize();
646 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
647 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
648 TType returnType = getType();
650 if (!rightUnionArray)
653 // for a case like float f = 1.2 + vec4(2,3,4,5);
654 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
656 rightUnionArray = new ConstantUnion[objectSize];
657 for (size_t i = 0; i < objectSize; ++i)
659 rightUnionArray[i] = *node->getUnionArrayPointer();
661 returnType = getType();
663 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
665 // for a case like float f = vec4(2,3,4,5) + 1.2;
666 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
667 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
669 unionArray[i] = *getUnionArrayPointer();
671 returnType = node->getType();
672 objectSize = constantNode->getType().getObjectSize();
675 ConstantUnion *tempConstArray = NULL;
676 TIntermConstantUnion *tempNode;
678 bool boolNodeFlag = false;
682 tempConstArray = new ConstantUnion[objectSize];
683 for (size_t i = 0; i < objectSize; i++)
684 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
687 tempConstArray = new ConstantUnion[objectSize];
688 for (size_t i = 0; i < objectSize; i++)
689 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
693 case EOpVectorTimesScalar:
694 case EOpMatrixTimesScalar:
695 tempConstArray = new ConstantUnion[objectSize];
696 for (size_t i = 0; i < objectSize; i++)
697 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
700 case EOpMatrixTimesMatrix:
702 if (getType().getBasicType() != EbtFloat ||
703 node->getBasicType() != EbtFloat)
705 infoSink.info.message(
706 EPrefixInternalError, getLine(),
707 "Constant Folding cannot be done for matrix multiply");
711 const int leftCols = getCols();
712 const int leftRows = getRows();
713 const int rightCols = constantNode->getType().getCols();
714 const int rightRows = constantNode->getType().getRows();
715 const int resultCols = rightCols;
716 const int resultRows = leftRows;
718 tempConstArray = new ConstantUnion[resultCols*resultRows];
719 for (int row = 0; row < resultRows; row++)
721 for (int column = 0; column < resultCols; column++)
723 tempConstArray[resultRows * column + row].setFConst(0.0f);
724 for (int i = 0; i < leftCols; i++)
726 tempConstArray[resultRows * column + row].setFConst(
727 tempConstArray[resultRows * column + row].getFConst() +
728 unionArray[i * leftRows + row].getFConst() *
729 rightUnionArray[column * rightRows + i].getFConst());
734 // update return type for matrix product
735 returnType.setPrimarySize(resultCols);
736 returnType.setSecondarySize(resultRows);
742 tempConstArray = new ConstantUnion[objectSize];
743 for (size_t i = 0; i < objectSize; i++)
745 switch (getType().getBasicType())
748 if (rightUnionArray[i] == 0.0f)
750 infoSink.info.message(
751 EPrefixWarning, getLine(),
752 "Divide by zero error during constant folding");
753 tempConstArray[i].setFConst(
754 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
758 tempConstArray[i].setFConst(
759 unionArray[i].getFConst() /
760 rightUnionArray[i].getFConst());
765 if (rightUnionArray[i] == 0)
767 infoSink.info.message(
768 EPrefixWarning, getLine(),
769 "Divide by zero error during constant folding");
770 tempConstArray[i].setIConst(INT_MAX);
774 tempConstArray[i].setIConst(
775 unionArray[i].getIConst() /
776 rightUnionArray[i].getIConst());
781 if (rightUnionArray[i] == 0)
783 infoSink.info.message(
784 EPrefixWarning, getLine(),
785 "Divide by zero error during constant folding");
786 tempConstArray[i].setUConst(UINT_MAX);
790 tempConstArray[i].setUConst(
791 unionArray[i].getUConst() /
792 rightUnionArray[i].getUConst());
797 infoSink.info.message(
798 EPrefixInternalError, getLine(),
799 "Constant folding cannot be done for \"/\"");
806 case EOpMatrixTimesVector:
808 if (node->getBasicType() != EbtFloat)
810 infoSink.info.message(
811 EPrefixInternalError, getLine(),
812 "Constant Folding cannot be done for matrix times vector");
816 const int matrixCols = getCols();
817 const int matrixRows = getRows();
819 tempConstArray = new ConstantUnion[matrixRows];
821 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
823 tempConstArray[matrixRow].setFConst(0.0f);
824 for (int col = 0; col < matrixCols; col++)
826 tempConstArray[matrixRow].setFConst(
827 tempConstArray[matrixRow].getFConst() +
828 unionArray[col * matrixRows + matrixRow].getFConst() *
829 rightUnionArray[col].getFConst());
833 returnType = node->getType();
834 returnType.setPrimarySize(matrixRows);
836 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
837 tempNode->setLine(getLine());
842 case EOpVectorTimesMatrix:
844 if (getType().getBasicType() != EbtFloat)
846 infoSink.info.message(
847 EPrefixInternalError, getLine(),
848 "Constant Folding cannot be done for vector times matrix");
852 const int matrixCols = constantNode->getType().getCols();
853 const int matrixRows = constantNode->getType().getRows();
855 tempConstArray = new ConstantUnion[matrixCols];
857 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
859 tempConstArray[matrixCol].setFConst(0.0f);
860 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
862 tempConstArray[matrixCol].setFConst(
863 tempConstArray[matrixCol].getFConst() +
864 unionArray[matrixRow].getFConst() *
865 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
869 returnType.setPrimarySize(matrixCols);
874 // this code is written for possible future use,
875 // will not get executed currently
877 tempConstArray = new ConstantUnion[objectSize];
878 for (size_t i = 0; i < objectSize; i++)
880 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
886 // this code is written for possible future use,
887 // will not get executed currently
889 tempConstArray = new ConstantUnion[objectSize];
890 for (size_t i = 0; i < objectSize; i++)
892 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
899 tempConstArray = new ConstantUnion[objectSize];
900 for (size_t i = 0; i < objectSize; i++)
902 switch (getType().getBasicType())
905 tempConstArray[i].setBConst(
906 unionArray[i] == rightUnionArray[i] ? false : true);
917 ASSERT(objectSize == 1);
918 tempConstArray = new ConstantUnion[1];
919 tempConstArray->setBConst(*unionArray < *rightUnionArray);
920 returnType = TType(EbtBool, EbpUndefined, EvqConst);
924 ASSERT(objectSize == 1);
925 tempConstArray = new ConstantUnion[1];
926 tempConstArray->setBConst(*unionArray > *rightUnionArray);
927 returnType = TType(EbtBool, EbpUndefined, EvqConst);
930 case EOpLessThanEqual:
932 ASSERT(objectSize == 1);
933 ConstantUnion constant;
934 constant.setBConst(*unionArray > *rightUnionArray);
935 tempConstArray = new ConstantUnion[1];
936 tempConstArray->setBConst(!constant.getBConst());
937 returnType = TType(EbtBool, EbpUndefined, EvqConst);
941 case EOpGreaterThanEqual:
943 ASSERT(objectSize == 1);
944 ConstantUnion constant;
945 constant.setBConst(*unionArray < *rightUnionArray);
946 tempConstArray = new ConstantUnion[1];
947 tempConstArray->setBConst(!constant.getBConst());
948 returnType = TType(EbtBool, EbpUndefined, EvqConst);
953 if (getType().getBasicType() == EbtStruct)
955 if (!CompareStructure(node->getType(),
956 node->getUnionArrayPointer(),
964 for (size_t i = 0; i < objectSize; i++)
966 if (unionArray[i] != rightUnionArray[i])
969 break; // break out of for loop
974 tempConstArray = new ConstantUnion[1];
977 tempConstArray->setBConst(true);
981 tempConstArray->setBConst(false);
984 tempNode = new TIntermConstantUnion(
985 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
986 tempNode->setLine(getLine());
991 if (getType().getBasicType() == EbtStruct)
993 if (CompareStructure(node->getType(),
994 node->getUnionArrayPointer(),
1002 for (size_t i = 0; i < objectSize; i++)
1004 if (unionArray[i] == rightUnionArray[i])
1006 boolNodeFlag = true;
1007 break; // break out of for loop
1012 tempConstArray = new ConstantUnion[1];
1015 tempConstArray->setBConst(true);
1019 tempConstArray->setBConst(false);
1022 tempNode = new TIntermConstantUnion(
1023 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1024 tempNode->setLine(getLine());
1029 infoSink.info.message(
1030 EPrefixInternalError, getLine(),
1031 "Invalid operator for constant folding");
1034 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1035 tempNode->setLine(getLine());
1042 // Do unary operations
1044 TIntermConstantUnion *newNode = 0;
1045 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1046 for (size_t i = 0; i < objectSize; i++)
1051 switch (getType().getBasicType())
1054 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1057 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1060 tempConstArray[i].setUConst(static_cast<unsigned int>(
1061 -static_cast<int>(unionArray[i].getUConst())));
1064 infoSink.info.message(
1065 EPrefixInternalError, getLine(),
1066 "Unary operation not folded into constant");
1072 // this code is written for possible future use,
1073 // will not get executed currently
1074 switch (getType().getBasicType())
1077 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1080 infoSink.info.message(
1081 EPrefixInternalError, getLine(),
1082 "Unary operation not folded into constant");
1091 newNode = new TIntermConstantUnion(tempConstArray, getType());
1092 newNode->setLine(getLine());
1098 TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
1100 if (hashFunction == NULL || name.empty())
1102 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1103 TStringStream stream;
1104 stream << HASHED_NAME_PREFIX << std::hex << number;
1105 TString hashedName = stream.str();