| // |
| // 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. |
| // |
| |
| #include "compiler/translator/LoopInfo.h" |
| |
| namespace |
| { |
| |
| int EvaluateIntConstant(TIntermConstantUnion *node) |
| { |
| ASSERT(node && node->getUnionArrayPointer()); |
| return node->getIConst(0); |
| } |
| |
| int GetLoopIntIncrement(TIntermLoop *node) |
| { |
| TIntermNode *expr = node->getExpression(); |
| // for expression has one of the following forms: |
| // loop_index++ |
| // loop_index-- |
| // loop_index += constant_expression |
| // loop_index -= constant_expression |
| // ++loop_index |
| // --loop_index |
| // The last two forms are not specified in the spec, but I am assuming |
| // its an oversight. |
| TIntermUnary *unOp = expr->getAsUnaryNode(); |
| TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); |
| |
| TOperator op = EOpNull; |
| TIntermConstantUnion *incrementNode = NULL; |
| if (unOp) |
| { |
| op = unOp->getOp(); |
| } |
| else if (binOp) |
| { |
| op = binOp->getOp(); |
| ASSERT(binOp->getRight()); |
| incrementNode = binOp->getRight()->getAsConstantUnion(); |
| ASSERT(incrementNode); |
| } |
| |
| int increment = 0; |
| // The operator is one of: ++ -- += -=. |
| switch (op) |
| { |
| case EOpPostIncrement: |
| case EOpPreIncrement: |
| ASSERT(unOp && !binOp); |
| increment = 1; |
| break; |
| case EOpPostDecrement: |
| case EOpPreDecrement: |
| ASSERT(unOp && !binOp); |
| increment = -1; |
| break; |
| case EOpAddAssign: |
| ASSERT(!unOp && binOp); |
| increment = EvaluateIntConstant(incrementNode); |
| break; |
| case EOpSubAssign: |
| ASSERT(!unOp && binOp); |
| increment = - EvaluateIntConstant(incrementNode); |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| |
| return increment; |
| } |
| |
| } // namespace anonymous |
| |
| TLoopIndexInfo::TLoopIndexInfo() |
| : mId(-1), |
| mType(EbtVoid), |
| mInitValue(0), |
| mStopValue(0), |
| mIncrementValue(0), |
| mOp(EOpNull), |
| mCurrentValue(0) |
| { |
| } |
| |
| void TLoopIndexInfo::fillInfo(TIntermLoop *node) |
| { |
| if (node == NULL) |
| return; |
| |
| // Here we assume all the operations are valid, because the loop node is |
| // already validated in ValidateLimitations. |
| TIntermSequence &declSeq = |
| node->getInit()->getAsAggregate()->getSequence(); |
| TIntermBinary *declInit = declSeq[0]->getAsBinaryNode(); |
| TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); |
| |
| mId = symbol->getId(); |
| mType = symbol->getBasicType(); |
| |
| if (mType == EbtInt) |
| { |
| TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); |
| mInitValue = EvaluateIntConstant(initNode); |
| mCurrentValue = mInitValue; |
| mIncrementValue = GetLoopIntIncrement(node); |
| |
| TIntermBinary* binOp = node->getCondition()->getAsBinaryNode(); |
| mStopValue = EvaluateIntConstant( |
| binOp->getRight()->getAsConstantUnion()); |
| mOp = binOp->getOp(); |
| } |
| } |
| |
| bool TLoopIndexInfo::satisfiesLoopCondition() const |
| { |
| // Relational operator is one of: > >= < <= == or !=. |
| switch (mOp) |
| { |
| case EOpEqual: |
| return (mCurrentValue == mStopValue); |
| case EOpNotEqual: |
| return (mCurrentValue != mStopValue); |
| case EOpLessThan: |
| return (mCurrentValue < mStopValue); |
| case EOpGreaterThan: |
| return (mCurrentValue > mStopValue); |
| case EOpLessThanEqual: |
| return (mCurrentValue <= mStopValue); |
| case EOpGreaterThanEqual: |
| return (mCurrentValue >= mStopValue); |
| default: |
| UNREACHABLE(); |
| return false; |
| } |
| } |
| |
| TLoopInfo::TLoopInfo() |
| : loop(NULL) |
| { |
| } |
| |
| TLoopInfo::TLoopInfo(TIntermLoop *node) |
| : loop(node) |
| { |
| index.fillInfo(node); |
| } |
| |
| TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol) |
| { |
| if (!symbol) |
| return NULL; |
| for (iterator iter = begin(); iter != end(); ++iter) |
| { |
| if (iter->index.getId() == symbol->getId()) |
| return iter->loop; |
| } |
| return NULL; |
| } |
| |
| TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol) |
| { |
| if (!symbol) |
| return NULL; |
| for (iterator iter = begin(); iter != end(); ++iter) |
| { |
| if (iter->index.getId() == symbol->getId()) |
| return &(iter->index); |
| } |
| return NULL; |
| } |
| |
| void TLoopStack::step() |
| { |
| ASSERT(!empty()); |
| rbegin()->index.step(); |
| } |
| |
| bool TLoopStack::satisfiesLoopCondition() |
| { |
| ASSERT(!empty()); |
| return rbegin()->index.satisfiesLoopCondition(); |
| } |
| |
| bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol) |
| { |
| TIntermLoop *loop = findLoop(symbol); |
| return loop && loop->getUnrollFlag(); |
| } |
| |
| int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol) |
| { |
| TLoopIndexInfo *info = getIndexInfo(symbol); |
| ASSERT(info); |
| return info->getCurrentValue(); |
| } |
| |
| void TLoopStack::push(TIntermLoop *loop) |
| { |
| TLoopInfo info(loop); |
| push_back(info); |
| } |
| |
| void TLoopStack::pop() |
| { |
| pop_back(); |
| } |
| |