1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/compiler/ForLoopUnroll.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,215 @@ 1.4 +// 1.5 +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +#include "compiler/ForLoopUnroll.h" 1.11 + 1.12 +namespace { 1.13 + 1.14 +class IntegerForLoopUnrollMarker : public TIntermTraverser { 1.15 +public: 1.16 + 1.17 + virtual bool visitLoop(Visit, TIntermLoop* node) 1.18 + { 1.19 + // This is called after ValidateLimitations pass, so all the ASSERT 1.20 + // should never fail. 1.21 + // See ValidateLimitations::validateForLoopInit(). 1.22 + ASSERT(node); 1.23 + ASSERT(node->getType() == ELoopFor); 1.24 + ASSERT(node->getInit()); 1.25 + TIntermAggregate* decl = node->getInit()->getAsAggregate(); 1.26 + ASSERT(decl && decl->getOp() == EOpDeclaration); 1.27 + TIntermSequence& declSeq = decl->getSequence(); 1.28 + ASSERT(declSeq.size() == 1); 1.29 + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); 1.30 + ASSERT(declInit && declInit->getOp() == EOpInitialize); 1.31 + ASSERT(declInit->getLeft()); 1.32 + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); 1.33 + ASSERT(symbol); 1.34 + TBasicType type = symbol->getBasicType(); 1.35 + ASSERT(type == EbtInt || type == EbtFloat); 1.36 + if (type == EbtInt) 1.37 + node->setUnrollFlag(true); 1.38 + return true; 1.39 + } 1.40 + 1.41 +}; 1.42 + 1.43 +} // anonymous namepsace 1.44 + 1.45 +void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info) 1.46 +{ 1.47 + ASSERT(node->getType() == ELoopFor); 1.48 + ASSERT(node->getUnrollFlag()); 1.49 + 1.50 + TIntermNode* init = node->getInit(); 1.51 + ASSERT(init != NULL); 1.52 + TIntermAggregate* decl = init->getAsAggregate(); 1.53 + ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration)); 1.54 + TIntermSequence& declSeq = decl->getSequence(); 1.55 + ASSERT(declSeq.size() == 1); 1.56 + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); 1.57 + ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize)); 1.58 + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); 1.59 + ASSERT(symbol != NULL); 1.60 + ASSERT(symbol->getBasicType() == EbtInt); 1.61 + 1.62 + info.id = symbol->getId(); 1.63 + 1.64 + ASSERT(declInit->getRight() != NULL); 1.65 + TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); 1.66 + ASSERT(initNode != NULL); 1.67 + 1.68 + info.initValue = evaluateIntConstant(initNode); 1.69 + info.currentValue = info.initValue; 1.70 + 1.71 + TIntermNode* cond = node->getCondition(); 1.72 + ASSERT(cond != NULL); 1.73 + TIntermBinary* binOp = cond->getAsBinaryNode(); 1.74 + ASSERT(binOp != NULL); 1.75 + ASSERT(binOp->getRight() != NULL); 1.76 + ASSERT(binOp->getRight()->getAsConstantUnion() != NULL); 1.77 + 1.78 + info.incrementValue = getLoopIncrement(node); 1.79 + info.stopValue = evaluateIntConstant( 1.80 + binOp->getRight()->getAsConstantUnion()); 1.81 + info.op = binOp->getOp(); 1.82 +} 1.83 + 1.84 +void ForLoopUnroll::Step() 1.85 +{ 1.86 + ASSERT(mLoopIndexStack.size() > 0); 1.87 + TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; 1.88 + info.currentValue += info.incrementValue; 1.89 +} 1.90 + 1.91 +bool ForLoopUnroll::SatisfiesLoopCondition() 1.92 +{ 1.93 + ASSERT(mLoopIndexStack.size() > 0); 1.94 + TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; 1.95 + // Relational operator is one of: > >= < <= == or !=. 1.96 + switch (info.op) { 1.97 + case EOpEqual: 1.98 + return (info.currentValue == info.stopValue); 1.99 + case EOpNotEqual: 1.100 + return (info.currentValue != info.stopValue); 1.101 + case EOpLessThan: 1.102 + return (info.currentValue < info.stopValue); 1.103 + case EOpGreaterThan: 1.104 + return (info.currentValue > info.stopValue); 1.105 + case EOpLessThanEqual: 1.106 + return (info.currentValue <= info.stopValue); 1.107 + case EOpGreaterThanEqual: 1.108 + return (info.currentValue >= info.stopValue); 1.109 + default: 1.110 + UNREACHABLE(); 1.111 + } 1.112 + return false; 1.113 +} 1.114 + 1.115 +bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol) 1.116 +{ 1.117 + for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin(); 1.118 + i != mLoopIndexStack.end(); 1.119 + ++i) { 1.120 + if (i->id == symbol->getId()) 1.121 + return true; 1.122 + } 1.123 + return false; 1.124 +} 1.125 + 1.126 +int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol) 1.127 +{ 1.128 + for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin(); 1.129 + i != mLoopIndexStack.end(); 1.130 + ++i) { 1.131 + if (i->id == symbol->getId()) 1.132 + return i->currentValue; 1.133 + } 1.134 + UNREACHABLE(); 1.135 + return false; 1.136 +} 1.137 + 1.138 +void ForLoopUnroll::Push(TLoopIndexInfo& info) 1.139 +{ 1.140 + mLoopIndexStack.push_back(info); 1.141 +} 1.142 + 1.143 +void ForLoopUnroll::Pop() 1.144 +{ 1.145 + mLoopIndexStack.pop_back(); 1.146 +} 1.147 + 1.148 +// static 1.149 +void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling( 1.150 + TIntermNode* root) 1.151 +{ 1.152 + ASSERT(root); 1.153 + 1.154 + IntegerForLoopUnrollMarker marker; 1.155 + root->traverse(&marker); 1.156 +} 1.157 + 1.158 +int ForLoopUnroll::getLoopIncrement(TIntermLoop* node) 1.159 +{ 1.160 + TIntermNode* expr = node->getExpression(); 1.161 + ASSERT(expr != NULL); 1.162 + // for expression has one of the following forms: 1.163 + // loop_index++ 1.164 + // loop_index-- 1.165 + // loop_index += constant_expression 1.166 + // loop_index -= constant_expression 1.167 + // ++loop_index 1.168 + // --loop_index 1.169 + // The last two forms are not specified in the spec, but I am assuming 1.170 + // its an oversight. 1.171 + TIntermUnary* unOp = expr->getAsUnaryNode(); 1.172 + TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); 1.173 + 1.174 + TOperator op = EOpNull; 1.175 + TIntermConstantUnion* incrementNode = NULL; 1.176 + if (unOp != NULL) { 1.177 + op = unOp->getOp(); 1.178 + } else if (binOp != NULL) { 1.179 + op = binOp->getOp(); 1.180 + ASSERT(binOp->getRight() != NULL); 1.181 + incrementNode = binOp->getRight()->getAsConstantUnion(); 1.182 + ASSERT(incrementNode != NULL); 1.183 + } 1.184 + 1.185 + int increment = 0; 1.186 + // The operator is one of: ++ -- += -=. 1.187 + switch (op) { 1.188 + case EOpPostIncrement: 1.189 + case EOpPreIncrement: 1.190 + ASSERT((unOp != NULL) && (binOp == NULL)); 1.191 + increment = 1; 1.192 + break; 1.193 + case EOpPostDecrement: 1.194 + case EOpPreDecrement: 1.195 + ASSERT((unOp != NULL) && (binOp == NULL)); 1.196 + increment = -1; 1.197 + break; 1.198 + case EOpAddAssign: 1.199 + ASSERT((unOp == NULL) && (binOp != NULL)); 1.200 + increment = evaluateIntConstant(incrementNode); 1.201 + break; 1.202 + case EOpSubAssign: 1.203 + ASSERT((unOp == NULL) && (binOp != NULL)); 1.204 + increment = - evaluateIntConstant(incrementNode); 1.205 + break; 1.206 + default: 1.207 + ASSERT(false); 1.208 + } 1.209 + 1.210 + return increment; 1.211 +} 1.212 + 1.213 +int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node) 1.214 +{ 1.215 + ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL)); 1.216 + return node->getIConst(0); 1.217 +} 1.218 +