gfx/angle/src/compiler/Intermediate.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/angle/src/compiler/Intermediate.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1442 @@
     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 +//
    1.11 +// Build the intermediate representation.
    1.12 +//
    1.13 +
    1.14 +#include <float.h>
    1.15 +#include <limits.h>
    1.16 +#include <algorithm>
    1.17 +
    1.18 +#include "compiler/HashNames.h"
    1.19 +#include "compiler/localintermediate.h"
    1.20 +#include "compiler/QualifierAlive.h"
    1.21 +#include "compiler/RemoveTree.h"
    1.22 +
    1.23 +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
    1.24 +
    1.25 +static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
    1.26 +    return left > right ? left : right;
    1.27 +}
    1.28 +
    1.29 +const char* getOperatorString(TOperator op) {
    1.30 +    switch (op) {
    1.31 +      case EOpInitialize: return "=";
    1.32 +      case EOpAssign: return "=";
    1.33 +      case EOpAddAssign: return "+=";
    1.34 +      case EOpSubAssign: return "-=";
    1.35 +      case EOpDivAssign: return "/=";
    1.36 +
    1.37 +      // Fall-through.
    1.38 +      case EOpMulAssign: 
    1.39 +      case EOpVectorTimesMatrixAssign:
    1.40 +      case EOpVectorTimesScalarAssign:
    1.41 +      case EOpMatrixTimesScalarAssign:
    1.42 +      case EOpMatrixTimesMatrixAssign: return "*=";
    1.43 +
    1.44 +      // Fall-through.
    1.45 +      case EOpIndexDirect:
    1.46 +      case EOpIndexIndirect: return "[]";
    1.47 +
    1.48 +      case EOpIndexDirectStruct: return ".";
    1.49 +      case EOpVectorSwizzle: return ".";
    1.50 +      case EOpAdd: return "+";
    1.51 +      case EOpSub: return "-";
    1.52 +      case EOpMul: return "*";
    1.53 +      case EOpDiv: return "/";
    1.54 +      case EOpMod: UNIMPLEMENTED(); break;
    1.55 +      case EOpEqual: return "==";
    1.56 +      case EOpNotEqual: return "!=";
    1.57 +      case EOpLessThan: return "<";
    1.58 +      case EOpGreaterThan: return ">";
    1.59 +      case EOpLessThanEqual: return "<=";
    1.60 +      case EOpGreaterThanEqual: return ">=";
    1.61 +
    1.62 +      // Fall-through.
    1.63 +      case EOpVectorTimesScalar:
    1.64 +      case EOpVectorTimesMatrix:
    1.65 +      case EOpMatrixTimesVector:
    1.66 +      case EOpMatrixTimesScalar:
    1.67 +      case EOpMatrixTimesMatrix: return "*";
    1.68 +
    1.69 +      case EOpLogicalOr: return "||";
    1.70 +      case EOpLogicalXor: return "^^";
    1.71 +      case EOpLogicalAnd: return "&&";
    1.72 +      case EOpNegative: return "-";
    1.73 +      case EOpVectorLogicalNot: return "not";
    1.74 +      case EOpLogicalNot: return "!";
    1.75 +      case EOpPostIncrement: return "++";
    1.76 +      case EOpPostDecrement: return "--";
    1.77 +      case EOpPreIncrement: return "++";
    1.78 +      case EOpPreDecrement: return "--";
    1.79 +
    1.80 +      // Fall-through.
    1.81 +      case EOpConvIntToBool:
    1.82 +      case EOpConvFloatToBool: return "bool";
    1.83 + 
    1.84 +      // Fall-through.
    1.85 +      case EOpConvBoolToFloat:
    1.86 +      case EOpConvIntToFloat: return "float";
    1.87 + 
    1.88 +      // Fall-through.
    1.89 +      case EOpConvFloatToInt:
    1.90 +      case EOpConvBoolToInt: return "int";
    1.91 +
    1.92 +      case EOpRadians: return "radians";
    1.93 +      case EOpDegrees: return "degrees";
    1.94 +      case EOpSin: return "sin";
    1.95 +      case EOpCos: return "cos";
    1.96 +      case EOpTan: return "tan";
    1.97 +      case EOpAsin: return "asin";
    1.98 +      case EOpAcos: return "acos";
    1.99 +      case EOpAtan: return "atan";
   1.100 +      case EOpExp: return "exp";
   1.101 +      case EOpLog: return "log";
   1.102 +      case EOpExp2: return "exp2";
   1.103 +      case EOpLog2: return "log2";
   1.104 +      case EOpSqrt: return "sqrt";
   1.105 +      case EOpInverseSqrt: return "inversesqrt";
   1.106 +      case EOpAbs: return "abs";
   1.107 +      case EOpSign: return "sign";
   1.108 +      case EOpFloor: return "floor";
   1.109 +      case EOpCeil: return "ceil";
   1.110 +      case EOpFract: return "fract";
   1.111 +      case EOpLength: return "length";
   1.112 +      case EOpNormalize: return "normalize";
   1.113 +      case EOpDFdx: return "dFdx";
   1.114 +      case EOpDFdy: return "dFdy";
   1.115 +      case EOpFwidth: return "fwidth";
   1.116 +      case EOpAny: return "any";
   1.117 +      case EOpAll: return "all";
   1.118 +
   1.119 +      default: break;
   1.120 +    }
   1.121 +    return "";
   1.122 +}
   1.123 +
   1.124 +////////////////////////////////////////////////////////////////////////////
   1.125 +//
   1.126 +// First set of functions are to help build the intermediate representation.
   1.127 +// These functions are not member functions of the nodes.
   1.128 +// They are called from parser productions.
   1.129 +//
   1.130 +/////////////////////////////////////////////////////////////////////////////
   1.131 +
   1.132 +//
   1.133 +// Add a terminal node for an identifier in an expression.
   1.134 +//
   1.135 +// Returns the added node.
   1.136 +//
   1.137 +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
   1.138 +{
   1.139 +    TIntermSymbol* node = new TIntermSymbol(id, name, type);
   1.140 +    node->setLine(line);
   1.141 +
   1.142 +    return node;
   1.143 +}
   1.144 +
   1.145 +//
   1.146 +// Connect two nodes with a new parent that does a binary operation on the nodes.
   1.147 +//
   1.148 +// Returns the added node.
   1.149 +//
   1.150 +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable)
   1.151 +{
   1.152 +    switch (op) {
   1.153 +        case EOpEqual:
   1.154 +        case EOpNotEqual:
   1.155 +            if (left->isArray())
   1.156 +                return 0;
   1.157 +            break;
   1.158 +        case EOpLessThan:
   1.159 +        case EOpGreaterThan:
   1.160 +        case EOpLessThanEqual:
   1.161 +        case EOpGreaterThanEqual:
   1.162 +            if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
   1.163 +                return 0;
   1.164 +            }
   1.165 +            break;
   1.166 +        case EOpLogicalOr:
   1.167 +        case EOpLogicalXor:
   1.168 +        case EOpLogicalAnd:
   1.169 +            if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
   1.170 +                return 0;
   1.171 +            }
   1.172 +            break;
   1.173 +        case EOpAdd:
   1.174 +        case EOpSub:
   1.175 +        case EOpDiv:
   1.176 +        case EOpMul:
   1.177 +            if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
   1.178 +                return 0;
   1.179 +        default: break;
   1.180 +    }
   1.181 +
   1.182 +    //
   1.183 +    // First try converting the children to compatible types.
   1.184 +    //
   1.185 +    if (left->getType().getStruct() && right->getType().getStruct()) {
   1.186 +        if (left->getType() != right->getType())
   1.187 +            return 0;
   1.188 +    } else {
   1.189 +        TIntermTyped* child = addConversion(op, left->getType(), right);
   1.190 +        if (child)
   1.191 +            right = child;
   1.192 +        else {
   1.193 +            child = addConversion(op, right->getType(), left);
   1.194 +            if (child)
   1.195 +                left = child;
   1.196 +            else
   1.197 +                return 0;
   1.198 +        }
   1.199 +    }
   1.200 +
   1.201 +    //
   1.202 +    // Need a new node holding things together then.  Make
   1.203 +    // one and promote it to the right type.
   1.204 +    //
   1.205 +    TIntermBinary* node = new TIntermBinary(op);
   1.206 +    node->setLine(line);
   1.207 +
   1.208 +    node->setLeft(left);
   1.209 +    node->setRight(right);
   1.210 +    if (!node->promote(infoSink))
   1.211 +        return 0;
   1.212 +
   1.213 +    //
   1.214 +    // See if we can fold constants.
   1.215 +    //
   1.216 +    TIntermTyped* typedReturnNode = 0;
   1.217 +    TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
   1.218 +    TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
   1.219 +    if (leftTempConstant && rightTempConstant) {
   1.220 +        typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
   1.221 +
   1.222 +        if (typedReturnNode)
   1.223 +            return typedReturnNode;
   1.224 +    }
   1.225 +
   1.226 +    return node;
   1.227 +}
   1.228 +
   1.229 +//
   1.230 +// Connect two nodes through an assignment.
   1.231 +//
   1.232 +// Returns the added node.
   1.233 +//
   1.234 +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
   1.235 +{
   1.236 +    //
   1.237 +    // Like adding binary math, except the conversion can only go
   1.238 +    // from right to left.
   1.239 +    //
   1.240 +    TIntermBinary* node = new TIntermBinary(op);
   1.241 +    node->setLine(line);
   1.242 +
   1.243 +    TIntermTyped* child = addConversion(op, left->getType(), right);
   1.244 +    if (child == 0)
   1.245 +        return 0;
   1.246 +
   1.247 +    node->setLeft(left);
   1.248 +    node->setRight(child);
   1.249 +    if (! node->promote(infoSink))
   1.250 +        return 0;
   1.251 +
   1.252 +    return node;
   1.253 +}
   1.254 +
   1.255 +//
   1.256 +// Connect two nodes through an index operator, where the left node is the base
   1.257 +// of an array or struct, and the right node is a direct or indirect offset.
   1.258 +//
   1.259 +// Returns the added node.
   1.260 +// The caller should set the type of the returned node.
   1.261 +//
   1.262 +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
   1.263 +{
   1.264 +    TIntermBinary* node = new TIntermBinary(op);
   1.265 +    node->setLine(line);
   1.266 +    node->setLeft(base);
   1.267 +    node->setRight(index);
   1.268 +
   1.269 +    // caller should set the type
   1.270 +
   1.271 +    return node;
   1.272 +}
   1.273 +
   1.274 +//
   1.275 +// Add one node as the parent of another that it operates on.
   1.276 +//
   1.277 +// Returns the added node.
   1.278 +//
   1.279 +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable)
   1.280 +{
   1.281 +    TIntermUnary* node;
   1.282 +    TIntermTyped* child = childNode->getAsTyped();
   1.283 +
   1.284 +    if (child == 0) {
   1.285 +        infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
   1.286 +        return 0;
   1.287 +    }
   1.288 +
   1.289 +    switch (op) {
   1.290 +        case EOpLogicalNot:
   1.291 +            if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
   1.292 +                return 0;
   1.293 +            }
   1.294 +            break;
   1.295 +
   1.296 +        case EOpPostIncrement:
   1.297 +        case EOpPreIncrement:
   1.298 +        case EOpPostDecrement:
   1.299 +        case EOpPreDecrement:
   1.300 +        case EOpNegative:
   1.301 +            if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
   1.302 +                return 0;
   1.303 +        default: break;
   1.304 +    }
   1.305 +
   1.306 +    //
   1.307 +    // Do we need to promote the operand?
   1.308 +    //
   1.309 +    // Note: Implicit promotions were removed from the language.
   1.310 +    //
   1.311 +    TBasicType newType = EbtVoid;
   1.312 +    switch (op) {
   1.313 +        case EOpConstructInt:   newType = EbtInt;   break;
   1.314 +        case EOpConstructBool:  newType = EbtBool;  break;
   1.315 +        case EOpConstructFloat: newType = EbtFloat; break;
   1.316 +        default: break;
   1.317 +    }
   1.318 +
   1.319 +    if (newType != EbtVoid) {
   1.320 +        child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
   1.321 +            child->getNominalSize(),
   1.322 +            child->isMatrix(),
   1.323 +            child->isArray()),
   1.324 +            child);
   1.325 +        if (child == 0)
   1.326 +            return 0;
   1.327 +    }
   1.328 +
   1.329 +    //
   1.330 +    // For constructors, we are now done, it's all in the conversion.
   1.331 +    //
   1.332 +    switch (op) {
   1.333 +        case EOpConstructInt:
   1.334 +        case EOpConstructBool:
   1.335 +        case EOpConstructFloat:
   1.336 +            return child;
   1.337 +        default: break;
   1.338 +    }
   1.339 +
   1.340 +    TIntermConstantUnion *childTempConstant = 0;
   1.341 +    if (child->getAsConstantUnion())
   1.342 +        childTempConstant = child->getAsConstantUnion();
   1.343 +
   1.344 +    //
   1.345 +    // Make a new node for the operator.
   1.346 +    //
   1.347 +    node = new TIntermUnary(op);
   1.348 +    node->setLine(line);
   1.349 +    node->setOperand(child);
   1.350 +
   1.351 +    if (! node->promote(infoSink))
   1.352 +        return 0;
   1.353 +
   1.354 +    if (childTempConstant)  {
   1.355 +        TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
   1.356 +
   1.357 +        if (newChild)
   1.358 +            return newChild;
   1.359 +    }
   1.360 +
   1.361 +    return node;
   1.362 +}
   1.363 +
   1.364 +//
   1.365 +// This is the safe way to change the operator on an aggregate, as it
   1.366 +// does lots of error checking and fixing.  Especially for establishing
   1.367 +// a function call's operation on it's set of parameters.  Sequences
   1.368 +// of instructions are also aggregates, but they just direnctly set
   1.369 +// their operator to EOpSequence.
   1.370 +//
   1.371 +// Returns an aggregate node, which could be the one passed in if
   1.372 +// it was already an aggregate but no operator was set.
   1.373 +//
   1.374 +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
   1.375 +{
   1.376 +    TIntermAggregate* aggNode;
   1.377 +
   1.378 +    //
   1.379 +    // Make sure we have an aggregate.  If not turn it into one.
   1.380 +    //
   1.381 +    if (node) {
   1.382 +        aggNode = node->getAsAggregate();
   1.383 +        if (aggNode == 0 || aggNode->getOp() != EOpNull) {
   1.384 +            //
   1.385 +            // Make an aggregate containing this node.
   1.386 +            //
   1.387 +            aggNode = new TIntermAggregate();
   1.388 +            aggNode->getSequence().push_back(node);
   1.389 +        }
   1.390 +    } else
   1.391 +        aggNode = new TIntermAggregate();
   1.392 +
   1.393 +    //
   1.394 +    // Set the operator.
   1.395 +    //
   1.396 +    aggNode->setOp(op);
   1.397 +    aggNode->setLine(line);
   1.398 +
   1.399 +    return aggNode;
   1.400 +}
   1.401 +
   1.402 +//
   1.403 +// Convert one type to another.
   1.404 +//
   1.405 +// Returns the node representing the conversion, which could be the same
   1.406 +// node passed in if no conversion was needed.
   1.407 +//
   1.408 +// Return 0 if a conversion can't be done.
   1.409 +//
   1.410 +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
   1.411 +{
   1.412 +    //
   1.413 +    // Does the base type allow operation?
   1.414 +    //
   1.415 +    switch (node->getBasicType()) {
   1.416 +        case EbtVoid:
   1.417 +        case EbtSampler2D:
   1.418 +        case EbtSamplerCube:
   1.419 +            return 0;
   1.420 +        default: break;
   1.421 +    }
   1.422 +
   1.423 +    //
   1.424 +    // Otherwise, if types are identical, no problem
   1.425 +    //
   1.426 +    if (type == node->getType())
   1.427 +        return node;
   1.428 +
   1.429 +    //
   1.430 +    // If one's a structure, then no conversions.
   1.431 +    //
   1.432 +    if (type.getStruct() || node->getType().getStruct())
   1.433 +        return 0;
   1.434 +
   1.435 +    //
   1.436 +    // If one's an array, then no conversions.
   1.437 +    //
   1.438 +    if (type.isArray() || node->getType().isArray())
   1.439 +        return 0;
   1.440 +
   1.441 +    TBasicType promoteTo;
   1.442 +
   1.443 +    switch (op) {
   1.444 +        //
   1.445 +        // Explicit conversions
   1.446 +        //
   1.447 +        case EOpConstructBool:
   1.448 +            promoteTo = EbtBool;
   1.449 +            break;
   1.450 +        case EOpConstructFloat:
   1.451 +            promoteTo = EbtFloat;
   1.452 +            break;
   1.453 +        case EOpConstructInt:
   1.454 +            promoteTo = EbtInt;
   1.455 +            break;
   1.456 +        default:
   1.457 +            //
   1.458 +            // implicit conversions were removed from the language.
   1.459 +            //
   1.460 +            if (type.getBasicType() != node->getType().getBasicType())
   1.461 +                return 0;
   1.462 +            //
   1.463 +            // Size and structure could still differ, but that's
   1.464 +            // handled by operator promotion.
   1.465 +            //
   1.466 +            return node;
   1.467 +    }
   1.468 +
   1.469 +    if (node->getAsConstantUnion()) {
   1.470 +
   1.471 +        return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
   1.472 +    } else {
   1.473 +
   1.474 +        //
   1.475 +        // Add a new newNode for the conversion.
   1.476 +        //
   1.477 +        TIntermUnary* newNode = 0;
   1.478 +
   1.479 +        TOperator newOp = EOpNull;
   1.480 +        switch (promoteTo) {
   1.481 +            case EbtFloat:
   1.482 +                switch (node->getBasicType()) {
   1.483 +                    case EbtInt:   newOp = EOpConvIntToFloat;  break;
   1.484 +                    case EbtBool:  newOp = EOpConvBoolToFloat; break;
   1.485 +                    default:
   1.486 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
   1.487 +                        return 0;
   1.488 +                }
   1.489 +                break;
   1.490 +            case EbtBool:
   1.491 +                switch (node->getBasicType()) {
   1.492 +                    case EbtInt:   newOp = EOpConvIntToBool;   break;
   1.493 +                    case EbtFloat: newOp = EOpConvFloatToBool; break;
   1.494 +                    default:
   1.495 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
   1.496 +                        return 0;
   1.497 +                }
   1.498 +                break;
   1.499 +            case EbtInt:
   1.500 +                switch (node->getBasicType()) {
   1.501 +                    case EbtBool:   newOp = EOpConvBoolToInt;  break;
   1.502 +                    case EbtFloat:  newOp = EOpConvFloatToInt; break;
   1.503 +                    default:
   1.504 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
   1.505 +                        return 0;
   1.506 +                }
   1.507 +                break;
   1.508 +            default:
   1.509 +                infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
   1.510 +                return 0;
   1.511 +        }
   1.512 +
   1.513 +        TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
   1.514 +        newNode = new TIntermUnary(newOp, type);
   1.515 +        newNode->setLine(node->getLine());
   1.516 +        newNode->setOperand(node);
   1.517 +
   1.518 +        return newNode;
   1.519 +    }
   1.520 +}
   1.521 +
   1.522 +//
   1.523 +// Safe way to combine two nodes into an aggregate.  Works with null pointers,
   1.524 +// a node that's not a aggregate yet, etc.
   1.525 +//
   1.526 +// Returns the resulting aggregate, unless 0 was passed in for
   1.527 +// both existing nodes.
   1.528 +//
   1.529 +TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
   1.530 +{
   1.531 +    if (left == 0 && right == 0)
   1.532 +        return 0;
   1.533 +
   1.534 +    TIntermAggregate* aggNode = 0;
   1.535 +    if (left)
   1.536 +        aggNode = left->getAsAggregate();
   1.537 +    if (!aggNode || aggNode->getOp() != EOpNull) {
   1.538 +        aggNode = new TIntermAggregate;
   1.539 +        if (left)
   1.540 +            aggNode->getSequence().push_back(left);
   1.541 +    }
   1.542 +
   1.543 +    if (right)
   1.544 +        aggNode->getSequence().push_back(right);
   1.545 +
   1.546 +    aggNode->setLine(line);
   1.547 +
   1.548 +    return aggNode;
   1.549 +}
   1.550 +
   1.551 +//
   1.552 +// Turn an existing node into an aggregate.
   1.553 +//
   1.554 +// Returns an aggregate, unless 0 was passed in for the existing node.
   1.555 +//
   1.556 +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
   1.557 +{
   1.558 +    if (node == 0)
   1.559 +        return 0;
   1.560 +
   1.561 +    TIntermAggregate* aggNode = new TIntermAggregate;
   1.562 +    aggNode->getSequence().push_back(node);
   1.563 +    aggNode->setLine(line);
   1.564 +
   1.565 +    return aggNode;
   1.566 +}
   1.567 +
   1.568 +//
   1.569 +// For "if" test nodes.  There are three children; a condition,
   1.570 +// a true path, and a false path.  The two paths are in the
   1.571 +// nodePair.
   1.572 +//
   1.573 +// Returns the selection node created.
   1.574 +//
   1.575 +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
   1.576 +{
   1.577 +    //
   1.578 +    // For compile time constant selections, prune the code and
   1.579 +    // test now.
   1.580 +    //
   1.581 +
   1.582 +    if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
   1.583 +        if (cond->getAsConstantUnion()->getBConst(0) == true)
   1.584 +            return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
   1.585 +        else
   1.586 +            return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
   1.587 +    }
   1.588 +
   1.589 +    TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
   1.590 +    node->setLine(line);
   1.591 +
   1.592 +    return node;
   1.593 +}
   1.594 +
   1.595 +
   1.596 +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
   1.597 +{
   1.598 +    if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
   1.599 +        return right;
   1.600 +    } else {
   1.601 +        TIntermTyped *commaAggregate = growAggregate(left, right, line);
   1.602 +        commaAggregate->getAsAggregate()->setOp(EOpComma);
   1.603 +        commaAggregate->setType(right->getType());
   1.604 +        commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
   1.605 +        return commaAggregate;
   1.606 +    }
   1.607 +}
   1.608 +
   1.609 +//
   1.610 +// For "?:" test nodes.  There are three children; a condition,
   1.611 +// a true path, and a false path.  The two paths are specified
   1.612 +// as separate parameters.
   1.613 +//
   1.614 +// Returns the selection node created, or 0 if one could not be.
   1.615 +//
   1.616 +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
   1.617 +{
   1.618 +    //
   1.619 +    // Get compatible types.
   1.620 +    //
   1.621 +    TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
   1.622 +    if (child)
   1.623 +        falseBlock = child;
   1.624 +    else {
   1.625 +        child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
   1.626 +        if (child)
   1.627 +            trueBlock = child;
   1.628 +        else
   1.629 +            return 0;
   1.630 +    }
   1.631 +
   1.632 +    //
   1.633 +    // See if all the operands are constant, then fold it otherwise not.
   1.634 +    //
   1.635 +
   1.636 +    if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
   1.637 +        if (cond->getAsConstantUnion()->getBConst(0))
   1.638 +            return trueBlock;
   1.639 +        else
   1.640 +            return falseBlock;
   1.641 +    }
   1.642 +
   1.643 +    //
   1.644 +    // Make a selection node.
   1.645 +    //
   1.646 +    TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
   1.647 +    node->getTypePointer()->setQualifier(EvqTemporary);
   1.648 +    node->setLine(line);
   1.649 +
   1.650 +    return node;
   1.651 +}
   1.652 +
   1.653 +//
   1.654 +// Constant terminal nodes.  Has a union that contains bool, float or int constants
   1.655 +//
   1.656 +// Returns the constant union node created.
   1.657 +//
   1.658 +
   1.659 +TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
   1.660 +{
   1.661 +    TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
   1.662 +    node->setLine(line);
   1.663 +
   1.664 +    return node;
   1.665 +}
   1.666 +
   1.667 +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
   1.668 +{
   1.669 +
   1.670 +    TIntermAggregate* node = new TIntermAggregate(EOpSequence);
   1.671 +
   1.672 +    node->setLine(line);
   1.673 +    TIntermConstantUnion* constIntNode;
   1.674 +    TIntermSequence &sequenceVector = node->getSequence();
   1.675 +    ConstantUnion* unionArray;
   1.676 +
   1.677 +    for (int i = 0; i < fields.num; i++) {
   1.678 +        unionArray = new ConstantUnion[1];
   1.679 +        unionArray->setIConst(fields.offsets[i]);
   1.680 +        constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
   1.681 +        sequenceVector.push_back(constIntNode);
   1.682 +    }
   1.683 +
   1.684 +    return node;
   1.685 +}
   1.686 +
   1.687 +//
   1.688 +// Create loop nodes.
   1.689 +//
   1.690 +TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
   1.691 +{
   1.692 +    TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
   1.693 +    node->setLine(line);
   1.694 +
   1.695 +    return node;
   1.696 +}
   1.697 +
   1.698 +//
   1.699 +// Add branches.
   1.700 +//
   1.701 +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
   1.702 +{
   1.703 +    return addBranch(branchOp, 0, line);
   1.704 +}
   1.705 +
   1.706 +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
   1.707 +{
   1.708 +    TIntermBranch* node = new TIntermBranch(branchOp, expression);
   1.709 +    node->setLine(line);
   1.710 +
   1.711 +    return node;
   1.712 +}
   1.713 +
   1.714 +//
   1.715 +// This is to be executed once the final root is put on top by the parsing
   1.716 +// process.
   1.717 +//
   1.718 +bool TIntermediate::postProcess(TIntermNode* root)
   1.719 +{
   1.720 +    if (root == 0)
   1.721 +        return true;
   1.722 +
   1.723 +    //
   1.724 +    // First, finish off the top level sequence, if any
   1.725 +    //
   1.726 +    TIntermAggregate* aggRoot = root->getAsAggregate();
   1.727 +    if (aggRoot && aggRoot->getOp() == EOpNull)
   1.728 +        aggRoot->setOp(EOpSequence);
   1.729 +
   1.730 +    return true;
   1.731 +}
   1.732 +
   1.733 +//
   1.734 +// This deletes the tree.
   1.735 +//
   1.736 +void TIntermediate::remove(TIntermNode* root)
   1.737 +{
   1.738 +    if (root)
   1.739 +        RemoveAllTreeNodes(root);
   1.740 +}
   1.741 +
   1.742 +////////////////////////////////////////////////////////////////
   1.743 +//
   1.744 +// Member functions of the nodes used for building the tree.
   1.745 +//
   1.746 +////////////////////////////////////////////////////////////////
   1.747 +
   1.748 +//
   1.749 +// Say whether or not an operation node changes the value of a variable.
   1.750 +//
   1.751 +// Returns true if state is modified.
   1.752 +//
   1.753 +bool TIntermOperator::modifiesState() const
   1.754 +{
   1.755 +    switch (op) {
   1.756 +        case EOpPostIncrement:
   1.757 +        case EOpPostDecrement:
   1.758 +        case EOpPreIncrement:
   1.759 +        case EOpPreDecrement:
   1.760 +        case EOpAssign:
   1.761 +        case EOpAddAssign:
   1.762 +        case EOpSubAssign:
   1.763 +        case EOpMulAssign:
   1.764 +        case EOpVectorTimesMatrixAssign:
   1.765 +        case EOpVectorTimesScalarAssign:
   1.766 +        case EOpMatrixTimesScalarAssign:
   1.767 +        case EOpMatrixTimesMatrixAssign:
   1.768 +        case EOpDivAssign:
   1.769 +            return true;
   1.770 +        default:
   1.771 +            return false;
   1.772 +    }
   1.773 +}
   1.774 +
   1.775 +//
   1.776 +// returns true if the operator is for one of the constructors
   1.777 +//
   1.778 +bool TIntermOperator::isConstructor() const
   1.779 +{
   1.780 +    switch (op) {
   1.781 +        case EOpConstructVec2:
   1.782 +        case EOpConstructVec3:
   1.783 +        case EOpConstructVec4:
   1.784 +        case EOpConstructMat2:
   1.785 +        case EOpConstructMat3:
   1.786 +        case EOpConstructMat4:
   1.787 +        case EOpConstructFloat:
   1.788 +        case EOpConstructIVec2:
   1.789 +        case EOpConstructIVec3:
   1.790 +        case EOpConstructIVec4:
   1.791 +        case EOpConstructInt:
   1.792 +        case EOpConstructBVec2:
   1.793 +        case EOpConstructBVec3:
   1.794 +        case EOpConstructBVec4:
   1.795 +        case EOpConstructBool:
   1.796 +        case EOpConstructStruct:
   1.797 +            return true;
   1.798 +        default:
   1.799 +            return false;
   1.800 +    }
   1.801 +}
   1.802 +//
   1.803 +// Make sure the type of a unary operator is appropriate for its
   1.804 +// combination of operation and operand type.
   1.805 +//
   1.806 +// Returns false in nothing makes sense.
   1.807 +//
   1.808 +bool TIntermUnary::promote(TInfoSink&)
   1.809 +{
   1.810 +    switch (op) {
   1.811 +        case EOpLogicalNot:
   1.812 +            if (operand->getBasicType() != EbtBool)
   1.813 +                return false;
   1.814 +            break;
   1.815 +        case EOpNegative:
   1.816 +        case EOpPostIncrement:
   1.817 +        case EOpPostDecrement:
   1.818 +        case EOpPreIncrement:
   1.819 +        case EOpPreDecrement:
   1.820 +            if (operand->getBasicType() == EbtBool)
   1.821 +                return false;
   1.822 +            break;
   1.823 +
   1.824 +            // operators for built-ins are already type checked against their prototype
   1.825 +        case EOpAny:
   1.826 +        case EOpAll:
   1.827 +        case EOpVectorLogicalNot:
   1.828 +            return true;
   1.829 +
   1.830 +        default:
   1.831 +            if (operand->getBasicType() != EbtFloat)
   1.832 +                return false;
   1.833 +    }
   1.834 +
   1.835 +    setType(operand->getType());
   1.836 +    type.setQualifier(EvqTemporary);
   1.837 +
   1.838 +    return true;
   1.839 +}
   1.840 +
   1.841 +//
   1.842 +// Establishes the type of the resultant operation, as well as
   1.843 +// makes the operator the correct one for the operands.
   1.844 +//
   1.845 +// Returns false if operator can't work on operands.
   1.846 +//
   1.847 +bool TIntermBinary::promote(TInfoSink& infoSink)
   1.848 +{
   1.849 +    // This function only handles scalars, vectors, and matrices.
   1.850 +    if (left->isArray() || right->isArray()) {
   1.851 +        infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
   1.852 +        return false;
   1.853 +    }
   1.854 +
   1.855 +    // GLSL ES 2.0 does not support implicit type casting.
   1.856 +    // So the basic type should always match.
   1.857 +    if (left->getBasicType() != right->getBasicType())
   1.858 +        return false;
   1.859 +
   1.860 +    //
   1.861 +    // Base assumption:  just make the type the same as the left
   1.862 +    // operand.  Then only deviations from this need be coded.
   1.863 +    //
   1.864 +    setType(left->getType());
   1.865 +
   1.866 +    // The result gets promoted to the highest precision.
   1.867 +    TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
   1.868 +    getTypePointer()->setPrecision(higherPrecision);
   1.869 +
   1.870 +    // Binary operations results in temporary variables unless both
   1.871 +    // operands are const.
   1.872 +    if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
   1.873 +        getTypePointer()->setQualifier(EvqTemporary);
   1.874 +    }
   1.875 +
   1.876 +    int size = std::max(left->getNominalSize(), right->getNominalSize());
   1.877 +
   1.878 +    //
   1.879 +    // All scalars. Code after this test assumes this case is removed!
   1.880 +    //
   1.881 +    if (size == 1) {
   1.882 +        switch (op) {
   1.883 +            //
   1.884 +            // Promote to conditional
   1.885 +            //
   1.886 +            case EOpEqual:
   1.887 +            case EOpNotEqual:
   1.888 +            case EOpLessThan:
   1.889 +            case EOpGreaterThan:
   1.890 +            case EOpLessThanEqual:
   1.891 +            case EOpGreaterThanEqual:
   1.892 +                setType(TType(EbtBool, EbpUndefined));
   1.893 +                break;
   1.894 +
   1.895 +            //
   1.896 +            // And and Or operate on conditionals
   1.897 +            //
   1.898 +            case EOpLogicalAnd:
   1.899 +            case EOpLogicalOr:
   1.900 +                // Both operands must be of type bool.
   1.901 +                if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
   1.902 +                    return false;
   1.903 +                setType(TType(EbtBool, EbpUndefined));
   1.904 +                break;
   1.905 +
   1.906 +            default:
   1.907 +                break;
   1.908 +        }
   1.909 +        return true;
   1.910 +    }
   1.911 +
   1.912 +    // If we reach here, at least one of the operands is vector or matrix.
   1.913 +    // The other operand could be a scalar, vector, or matrix.
   1.914 +    // Are the sizes compatible?
   1.915 +    //
   1.916 +    if (left->getNominalSize() != right->getNominalSize()) {
   1.917 +        // If the nominal size of operands do not match:
   1.918 +        // One of them must be scalar.
   1.919 +        if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
   1.920 +            return false;
   1.921 +        // Operator cannot be of type pure assignment.
   1.922 +        if (op == EOpAssign || op == EOpInitialize)
   1.923 +            return false;
   1.924 +    }
   1.925 +
   1.926 +    //
   1.927 +    // Can these two operands be combined?
   1.928 +    //
   1.929 +    TBasicType basicType = left->getBasicType();
   1.930 +    switch (op) {
   1.931 +        case EOpMul:
   1.932 +            if (!left->isMatrix() && right->isMatrix()) {
   1.933 +                if (left->isVector())
   1.934 +                    op = EOpVectorTimesMatrix;
   1.935 +                else {
   1.936 +                    op = EOpMatrixTimesScalar;
   1.937 +                    setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
   1.938 +                }
   1.939 +            } else if (left->isMatrix() && !right->isMatrix()) {
   1.940 +                if (right->isVector()) {
   1.941 +                    op = EOpMatrixTimesVector;
   1.942 +                    setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
   1.943 +                } else {
   1.944 +                    op = EOpMatrixTimesScalar;
   1.945 +                }
   1.946 +            } else if (left->isMatrix() && right->isMatrix()) {
   1.947 +                op = EOpMatrixTimesMatrix;
   1.948 +            } else if (!left->isMatrix() && !right->isMatrix()) {
   1.949 +                if (left->isVector() && right->isVector()) {
   1.950 +                    // leave as component product
   1.951 +                } else if (left->isVector() || right->isVector()) {
   1.952 +                    op = EOpVectorTimesScalar;
   1.953 +                    setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
   1.954 +                }
   1.955 +            } else {
   1.956 +                infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
   1.957 +                return false;
   1.958 +            }
   1.959 +            break;
   1.960 +        case EOpMulAssign:
   1.961 +            if (!left->isMatrix() && right->isMatrix()) {
   1.962 +                if (left->isVector())
   1.963 +                    op = EOpVectorTimesMatrixAssign;
   1.964 +                else {
   1.965 +                    return false;
   1.966 +                }
   1.967 +            } else if (left->isMatrix() && !right->isMatrix()) {
   1.968 +                if (right->isVector()) {
   1.969 +                    return false;
   1.970 +                } else {
   1.971 +                    op = EOpMatrixTimesScalarAssign;
   1.972 +                }
   1.973 +            } else if (left->isMatrix() && right->isMatrix()) {
   1.974 +                op = EOpMatrixTimesMatrixAssign;
   1.975 +            } else if (!left->isMatrix() && !right->isMatrix()) {
   1.976 +                if (left->isVector() && right->isVector()) {
   1.977 +                    // leave as component product
   1.978 +                } else if (left->isVector() || right->isVector()) {
   1.979 +                    if (! left->isVector())
   1.980 +                        return false;
   1.981 +                    op = EOpVectorTimesScalarAssign;
   1.982 +                    setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
   1.983 +                }
   1.984 +            } else {
   1.985 +                infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
   1.986 +                return false;
   1.987 +            }
   1.988 +            break;
   1.989 +
   1.990 +        case EOpAssign:
   1.991 +        case EOpInitialize:
   1.992 +        case EOpAdd:
   1.993 +        case EOpSub:
   1.994 +        case EOpDiv:
   1.995 +        case EOpAddAssign:
   1.996 +        case EOpSubAssign:
   1.997 +        case EOpDivAssign:
   1.998 +            if ((left->isMatrix() && right->isVector()) ||
   1.999 +                (left->isVector() && right->isMatrix()))
  1.1000 +                return false;
  1.1001 +            setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
  1.1002 +            break;
  1.1003 +
  1.1004 +        case EOpEqual:
  1.1005 +        case EOpNotEqual:
  1.1006 +        case EOpLessThan:
  1.1007 +        case EOpGreaterThan:
  1.1008 +        case EOpLessThanEqual:
  1.1009 +        case EOpGreaterThanEqual:
  1.1010 +            if ((left->isMatrix() && right->isVector()) ||
  1.1011 +                (left->isVector() && right->isMatrix()))
  1.1012 +                return false;
  1.1013 +            setType(TType(EbtBool, EbpUndefined));
  1.1014 +            break;
  1.1015 +
  1.1016 +        default:
  1.1017 +            return false;
  1.1018 +    }
  1.1019 +    
  1.1020 +    return true;
  1.1021 +}
  1.1022 +
  1.1023 +bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
  1.1024 +{
  1.1025 +    const TFieldList& fields = leftNodeType.getStruct()->fields();
  1.1026 +
  1.1027 +    size_t structSize = fields.size();
  1.1028 +    size_t index = 0;
  1.1029 +
  1.1030 +    for (size_t j = 0; j < structSize; j++) {
  1.1031 +        size_t size = fields[j]->type()->getObjectSize();
  1.1032 +        for (size_t i = 0; i < size; i++) {
  1.1033 +            if (fields[j]->type()->getBasicType() == EbtStruct) {
  1.1034 +                if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
  1.1035 +                    return false;
  1.1036 +            } else {
  1.1037 +                if (leftUnionArray[index] != rightUnionArray[index])
  1.1038 +                    return false;
  1.1039 +                index++;
  1.1040 +            }
  1.1041 +        }
  1.1042 +    }
  1.1043 +    return true;
  1.1044 +}
  1.1045 +
  1.1046 +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
  1.1047 +{
  1.1048 +    if (leftNodeType.isArray()) {
  1.1049 +        TType typeWithoutArrayness = leftNodeType;
  1.1050 +        typeWithoutArrayness.clearArrayness();
  1.1051 +
  1.1052 +        size_t arraySize = leftNodeType.getArraySize();
  1.1053 +
  1.1054 +        for (size_t i = 0; i < arraySize; ++i) {
  1.1055 +            size_t offset = typeWithoutArrayness.getObjectSize() * i;
  1.1056 +            if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
  1.1057 +                return false;
  1.1058 +        }
  1.1059 +    } else
  1.1060 +        return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
  1.1061 +
  1.1062 +    return true;
  1.1063 +}
  1.1064 +
  1.1065 +//
  1.1066 +// The fold functions see if an operation on a constant can be done in place,
  1.1067 +// without generating run-time code.
  1.1068 +//
  1.1069 +// Returns the node to keep using, which may or may not be the node passed in.
  1.1070 +//
  1.1071 +
  1.1072 +TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
  1.1073 +{
  1.1074 +    ConstantUnion *unionArray = getUnionArrayPointer();
  1.1075 +    size_t objectSize = getType().getObjectSize();
  1.1076 +
  1.1077 +    if (constantNode) {  // binary operations
  1.1078 +        TIntermConstantUnion *node = constantNode->getAsConstantUnion();
  1.1079 +        ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
  1.1080 +        TType returnType = getType();
  1.1081 +
  1.1082 +        // for a case like float f = 1.2 + vec4(2,3,4,5);
  1.1083 +        if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
  1.1084 +            rightUnionArray = new ConstantUnion[objectSize];
  1.1085 +            for (size_t i = 0; i < objectSize; ++i)
  1.1086 +                rightUnionArray[i] = *node->getUnionArrayPointer();
  1.1087 +            returnType = getType();
  1.1088 +        } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
  1.1089 +            // for a case like float f = vec4(2,3,4,5) + 1.2;
  1.1090 +            unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
  1.1091 +            for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
  1.1092 +                unionArray[i] = *getUnionArrayPointer();
  1.1093 +            returnType = node->getType();
  1.1094 +            objectSize = constantNode->getType().getObjectSize();
  1.1095 +        }
  1.1096 +
  1.1097 +        ConstantUnion* tempConstArray = 0;
  1.1098 +        TIntermConstantUnion *tempNode;
  1.1099 +
  1.1100 +        bool boolNodeFlag = false;
  1.1101 +        switch(op) {
  1.1102 +            case EOpAdd:
  1.1103 +                tempConstArray = new ConstantUnion[objectSize];
  1.1104 +                {// support MSVC++6.0
  1.1105 +                    for (size_t i = 0; i < objectSize; i++)
  1.1106 +                        tempConstArray[i] = unionArray[i] + rightUnionArray[i];
  1.1107 +                }
  1.1108 +                break;
  1.1109 +            case EOpSub:
  1.1110 +                tempConstArray = new ConstantUnion[objectSize];
  1.1111 +                {// support MSVC++6.0
  1.1112 +                    for (size_t i = 0; i < objectSize; i++)
  1.1113 +                        tempConstArray[i] = unionArray[i] - rightUnionArray[i];
  1.1114 +                }
  1.1115 +                break;
  1.1116 +
  1.1117 +            case EOpMul:
  1.1118 +            case EOpVectorTimesScalar:
  1.1119 +            case EOpMatrixTimesScalar:
  1.1120 +                tempConstArray = new ConstantUnion[objectSize];
  1.1121 +                {// support MSVC++6.0
  1.1122 +                    for (size_t i = 0; i < objectSize; i++)
  1.1123 +                        tempConstArray[i] = unionArray[i] * rightUnionArray[i];
  1.1124 +                }
  1.1125 +                break;
  1.1126 +            case EOpMatrixTimesMatrix:
  1.1127 +                if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
  1.1128 +                    infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
  1.1129 +                    return 0;
  1.1130 +                }
  1.1131 +                {// support MSVC++6.0
  1.1132 +                    int size = getNominalSize();
  1.1133 +                    tempConstArray = new ConstantUnion[size*size];
  1.1134 +                    for (int row = 0; row < size; row++) {
  1.1135 +                        for (int column = 0; column < size; column++) {
  1.1136 +                            tempConstArray[size * column + row].setFConst(0.0f);
  1.1137 +                            for (int i = 0; i < size; i++) {
  1.1138 +                                tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
  1.1139 +                            }
  1.1140 +                        }
  1.1141 +                    }
  1.1142 +                }
  1.1143 +                break;
  1.1144 +            case EOpDiv:
  1.1145 +                tempConstArray = new ConstantUnion[objectSize];
  1.1146 +                {// support MSVC++6.0
  1.1147 +                    for (size_t i = 0; i < objectSize; i++) {
  1.1148 +                        switch (getType().getBasicType()) {
  1.1149 +            case EbtFloat:
  1.1150 +                if (rightUnionArray[i] == 0.0f) {
  1.1151 +                    infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
  1.1152 +                    tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
  1.1153 +                } else
  1.1154 +                    tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
  1.1155 +                break;
  1.1156 +
  1.1157 +            case EbtInt:
  1.1158 +                if (rightUnionArray[i] == 0) {
  1.1159 +                    infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
  1.1160 +                    tempConstArray[i].setIConst(INT_MAX);
  1.1161 +                } else
  1.1162 +                    tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
  1.1163 +                break;
  1.1164 +            default:
  1.1165 +                infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
  1.1166 +                return 0;
  1.1167 +                        }
  1.1168 +                    }
  1.1169 +                }
  1.1170 +                break;
  1.1171 +
  1.1172 +            case EOpMatrixTimesVector:
  1.1173 +                if (node->getBasicType() != EbtFloat) {
  1.1174 +                    infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
  1.1175 +                    return 0;
  1.1176 +                }
  1.1177 +                tempConstArray = new ConstantUnion[getNominalSize()];
  1.1178 +
  1.1179 +                {// support MSVC++6.0
  1.1180 +                    for (int size = getNominalSize(), i = 0; i < size; i++) {
  1.1181 +                        tempConstArray[i].setFConst(0.0f);
  1.1182 +                        for (int j = 0; j < size; j++) {
  1.1183 +                            tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
  1.1184 +                        }
  1.1185 +                    }
  1.1186 +                }
  1.1187 +
  1.1188 +                tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
  1.1189 +                tempNode->setLine(getLine());
  1.1190 +
  1.1191 +                return tempNode;
  1.1192 +
  1.1193 +            case EOpVectorTimesMatrix:
  1.1194 +                if (getType().getBasicType() != EbtFloat) {
  1.1195 +                    infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
  1.1196 +                    return 0;
  1.1197 +                }
  1.1198 +
  1.1199 +                tempConstArray = new ConstantUnion[getNominalSize()];
  1.1200 +                {// support MSVC++6.0
  1.1201 +                    for (int size = getNominalSize(), i = 0; i < size; i++) {
  1.1202 +                        tempConstArray[i].setFConst(0.0f);
  1.1203 +                        for (int j = 0; j < size; j++) {
  1.1204 +                            tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
  1.1205 +                        }
  1.1206 +                    }
  1.1207 +                }
  1.1208 +                break;
  1.1209 +
  1.1210 +            case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
  1.1211 +                tempConstArray = new ConstantUnion[objectSize];
  1.1212 +                {// support MSVC++6.0
  1.1213 +                    for (size_t i = 0; i < objectSize; i++)
  1.1214 +                        tempConstArray[i] = unionArray[i] && rightUnionArray[i];
  1.1215 +                }
  1.1216 +                break;
  1.1217 +
  1.1218 +            case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
  1.1219 +                tempConstArray = new ConstantUnion[objectSize];
  1.1220 +                {// support MSVC++6.0
  1.1221 +                    for (size_t i = 0; i < objectSize; i++)
  1.1222 +                        tempConstArray[i] = unionArray[i] || rightUnionArray[i];
  1.1223 +                }
  1.1224 +                break;
  1.1225 +
  1.1226 +            case EOpLogicalXor:
  1.1227 +                tempConstArray = new ConstantUnion[objectSize];
  1.1228 +                {// support MSVC++6.0
  1.1229 +                    for (size_t i = 0; i < objectSize; i++)
  1.1230 +                        switch (getType().getBasicType()) {
  1.1231 +            case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
  1.1232 +            default: assert(false && "Default missing");
  1.1233 +                    }
  1.1234 +                }
  1.1235 +                break;
  1.1236 +
  1.1237 +            case EOpLessThan:
  1.1238 +                assert(objectSize == 1);
  1.1239 +                tempConstArray = new ConstantUnion[1];
  1.1240 +                tempConstArray->setBConst(*unionArray < *rightUnionArray);
  1.1241 +                returnType = TType(EbtBool, EbpUndefined, EvqConst);
  1.1242 +                break;
  1.1243 +            case EOpGreaterThan:
  1.1244 +                assert(objectSize == 1);
  1.1245 +                tempConstArray = new ConstantUnion[1];
  1.1246 +                tempConstArray->setBConst(*unionArray > *rightUnionArray);
  1.1247 +                returnType = TType(EbtBool, EbpUndefined, EvqConst);
  1.1248 +                break;
  1.1249 +            case EOpLessThanEqual:
  1.1250 +                {
  1.1251 +                    assert(objectSize == 1);
  1.1252 +                    ConstantUnion constant;
  1.1253 +                    constant.setBConst(*unionArray > *rightUnionArray);
  1.1254 +                    tempConstArray = new ConstantUnion[1];
  1.1255 +                    tempConstArray->setBConst(!constant.getBConst());
  1.1256 +                    returnType = TType(EbtBool, EbpUndefined, EvqConst);
  1.1257 +                    break;
  1.1258 +                }
  1.1259 +            case EOpGreaterThanEqual:
  1.1260 +                {
  1.1261 +                    assert(objectSize == 1);
  1.1262 +                    ConstantUnion constant;
  1.1263 +                    constant.setBConst(*unionArray < *rightUnionArray);
  1.1264 +                    tempConstArray = new ConstantUnion[1];
  1.1265 +                    tempConstArray->setBConst(!constant.getBConst());
  1.1266 +                    returnType = TType(EbtBool, EbpUndefined, EvqConst);
  1.1267 +                    break;
  1.1268 +                }
  1.1269 +
  1.1270 +            case EOpEqual:
  1.1271 +                if (getType().getBasicType() == EbtStruct) {
  1.1272 +                    if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
  1.1273 +                        boolNodeFlag = true;
  1.1274 +                } else {
  1.1275 +                    for (size_t i = 0; i < objectSize; i++) {
  1.1276 +                        if (unionArray[i] != rightUnionArray[i]) {
  1.1277 +                            boolNodeFlag = true;
  1.1278 +                            break;  // break out of for loop
  1.1279 +                        }
  1.1280 +                    }
  1.1281 +                }
  1.1282 +
  1.1283 +                tempConstArray = new ConstantUnion[1];
  1.1284 +                if (!boolNodeFlag) {
  1.1285 +                    tempConstArray->setBConst(true);
  1.1286 +                }
  1.1287 +                else {
  1.1288 +                    tempConstArray->setBConst(false);
  1.1289 +                }
  1.1290 +
  1.1291 +                tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
  1.1292 +                tempNode->setLine(getLine());
  1.1293 +
  1.1294 +                return tempNode;
  1.1295 +
  1.1296 +            case EOpNotEqual:
  1.1297 +                if (getType().getBasicType() == EbtStruct) {
  1.1298 +                    if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
  1.1299 +                        boolNodeFlag = true;
  1.1300 +                } else {
  1.1301 +                    for (size_t i = 0; i < objectSize; i++) {
  1.1302 +                        if (unionArray[i] == rightUnionArray[i]) {
  1.1303 +                            boolNodeFlag = true;
  1.1304 +                            break;  // break out of for loop
  1.1305 +                        }
  1.1306 +                    }
  1.1307 +                }
  1.1308 +
  1.1309 +                tempConstArray = new ConstantUnion[1];
  1.1310 +                if (!boolNodeFlag) {
  1.1311 +                    tempConstArray->setBConst(true);
  1.1312 +                }
  1.1313 +                else {
  1.1314 +                    tempConstArray->setBConst(false);
  1.1315 +                }
  1.1316 +
  1.1317 +                tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
  1.1318 +                tempNode->setLine(getLine());
  1.1319 +
  1.1320 +                return tempNode;
  1.1321 +
  1.1322 +            default:
  1.1323 +                infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
  1.1324 +                return 0;
  1.1325 +        }
  1.1326 +        tempNode = new TIntermConstantUnion(tempConstArray, returnType);
  1.1327 +        tempNode->setLine(getLine());
  1.1328 +
  1.1329 +        return tempNode;
  1.1330 +    } else {
  1.1331 +        //
  1.1332 +        // Do unary operations
  1.1333 +        //
  1.1334 +        TIntermConstantUnion *newNode = 0;
  1.1335 +        ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
  1.1336 +        for (size_t i = 0; i < objectSize; i++) {
  1.1337 +            switch(op) {
  1.1338 +                case EOpNegative:
  1.1339 +                    switch (getType().getBasicType()) {
  1.1340 +                        case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
  1.1341 +                        case EbtInt:   tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
  1.1342 +                        default:
  1.1343 +                            infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
  1.1344 +                            return 0;
  1.1345 +                    }
  1.1346 +                    break;
  1.1347 +                case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
  1.1348 +                    switch (getType().getBasicType()) {
  1.1349 +                        case EbtBool:  tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
  1.1350 +                        default:
  1.1351 +                            infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
  1.1352 +                            return 0;
  1.1353 +                    }
  1.1354 +                    break;
  1.1355 +                default:
  1.1356 +                    return 0;
  1.1357 +            }
  1.1358 +        }
  1.1359 +        newNode = new TIntermConstantUnion(tempConstArray, getType());
  1.1360 +        newNode->setLine(getLine());
  1.1361 +        return newNode;
  1.1362 +    }
  1.1363 +}
  1.1364 +
  1.1365 +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
  1.1366 +{
  1.1367 +    size_t size = node->getType().getObjectSize();
  1.1368 +
  1.1369 +    ConstantUnion *leftUnionArray = new ConstantUnion[size];
  1.1370 +
  1.1371 +    for (size_t i = 0; i < size; i++) {
  1.1372 +
  1.1373 +        switch (promoteTo) {
  1.1374 +            case EbtFloat:
  1.1375 +                switch (node->getType().getBasicType()) {
  1.1376 +                    case EbtInt:
  1.1377 +                        leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
  1.1378 +                        break;
  1.1379 +                    case EbtBool:
  1.1380 +                        leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
  1.1381 +                        break;
  1.1382 +                    case EbtFloat:
  1.1383 +                        leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
  1.1384 +                        break;
  1.1385 +                    default:
  1.1386 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
  1.1387 +                        return 0;
  1.1388 +                }
  1.1389 +                break;
  1.1390 +            case EbtInt:
  1.1391 +                switch (node->getType().getBasicType()) {
  1.1392 +                    case EbtInt:
  1.1393 +                        leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
  1.1394 +                        break;
  1.1395 +                    case EbtBool:
  1.1396 +                        leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
  1.1397 +                        break;
  1.1398 +                    case EbtFloat:
  1.1399 +                        leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
  1.1400 +                        break;
  1.1401 +                    default:
  1.1402 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
  1.1403 +                        return 0;
  1.1404 +                }
  1.1405 +                break;
  1.1406 +            case EbtBool:
  1.1407 +                switch (node->getType().getBasicType()) {
  1.1408 +                    case EbtInt:
  1.1409 +                        leftUnionArray[i].setBConst(node->getIConst(i) != 0);
  1.1410 +                        break;
  1.1411 +                    case EbtBool:
  1.1412 +                        leftUnionArray[i].setBConst(node->getBConst(i));
  1.1413 +                        break;
  1.1414 +                    case EbtFloat:
  1.1415 +                        leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
  1.1416 +                        break;
  1.1417 +                    default:
  1.1418 +                        infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
  1.1419 +                        return 0;
  1.1420 +                }
  1.1421 +
  1.1422 +                break;
  1.1423 +            default:
  1.1424 +                infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
  1.1425 +                return 0;
  1.1426 +        }
  1.1427 +
  1.1428 +    }
  1.1429 +
  1.1430 +    const TType& t = node->getType();
  1.1431 +
  1.1432 +    return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
  1.1433 +}
  1.1434 +
  1.1435 +// static
  1.1436 +TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
  1.1437 +{
  1.1438 +    if (hashFunction == NULL || name.empty())
  1.1439 +        return name;
  1.1440 +    khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
  1.1441 +    TStringStream stream;
  1.1442 +    stream << HASHED_NAME_PREFIX << std::hex << number;
  1.1443 +    TString hashedName = stream.str();
  1.1444 +    return hashedName;
  1.1445 +}

mercurial