Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | // |
michael@0 | 2 | // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. |
michael@0 | 3 | // Use of this source code is governed by a BSD-style license that can be |
michael@0 | 4 | // found in the LICENSE file. |
michael@0 | 5 | // |
michael@0 | 6 | |
michael@0 | 7 | // |
michael@0 | 8 | // Build the intermediate representation. |
michael@0 | 9 | // |
michael@0 | 10 | |
michael@0 | 11 | #include <float.h> |
michael@0 | 12 | #include <limits.h> |
michael@0 | 13 | #include <algorithm> |
michael@0 | 14 | |
michael@0 | 15 | #include "compiler/HashNames.h" |
michael@0 | 16 | #include "compiler/localintermediate.h" |
michael@0 | 17 | #include "compiler/QualifierAlive.h" |
michael@0 | 18 | #include "compiler/RemoveTree.h" |
michael@0 | 19 | |
michael@0 | 20 | bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); |
michael@0 | 21 | |
michael@0 | 22 | static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ |
michael@0 | 23 | return left > right ? left : right; |
michael@0 | 24 | } |
michael@0 | 25 | |
michael@0 | 26 | const char* getOperatorString(TOperator op) { |
michael@0 | 27 | switch (op) { |
michael@0 | 28 | case EOpInitialize: return "="; |
michael@0 | 29 | case EOpAssign: return "="; |
michael@0 | 30 | case EOpAddAssign: return "+="; |
michael@0 | 31 | case EOpSubAssign: return "-="; |
michael@0 | 32 | case EOpDivAssign: return "/="; |
michael@0 | 33 | |
michael@0 | 34 | // Fall-through. |
michael@0 | 35 | case EOpMulAssign: |
michael@0 | 36 | case EOpVectorTimesMatrixAssign: |
michael@0 | 37 | case EOpVectorTimesScalarAssign: |
michael@0 | 38 | case EOpMatrixTimesScalarAssign: |
michael@0 | 39 | case EOpMatrixTimesMatrixAssign: return "*="; |
michael@0 | 40 | |
michael@0 | 41 | // Fall-through. |
michael@0 | 42 | case EOpIndexDirect: |
michael@0 | 43 | case EOpIndexIndirect: return "[]"; |
michael@0 | 44 | |
michael@0 | 45 | case EOpIndexDirectStruct: return "."; |
michael@0 | 46 | case EOpVectorSwizzle: return "."; |
michael@0 | 47 | case EOpAdd: return "+"; |
michael@0 | 48 | case EOpSub: return "-"; |
michael@0 | 49 | case EOpMul: return "*"; |
michael@0 | 50 | case EOpDiv: return "/"; |
michael@0 | 51 | case EOpMod: UNIMPLEMENTED(); break; |
michael@0 | 52 | case EOpEqual: return "=="; |
michael@0 | 53 | case EOpNotEqual: return "!="; |
michael@0 | 54 | case EOpLessThan: return "<"; |
michael@0 | 55 | case EOpGreaterThan: return ">"; |
michael@0 | 56 | case EOpLessThanEqual: return "<="; |
michael@0 | 57 | case EOpGreaterThanEqual: return ">="; |
michael@0 | 58 | |
michael@0 | 59 | // Fall-through. |
michael@0 | 60 | case EOpVectorTimesScalar: |
michael@0 | 61 | case EOpVectorTimesMatrix: |
michael@0 | 62 | case EOpMatrixTimesVector: |
michael@0 | 63 | case EOpMatrixTimesScalar: |
michael@0 | 64 | case EOpMatrixTimesMatrix: return "*"; |
michael@0 | 65 | |
michael@0 | 66 | case EOpLogicalOr: return "||"; |
michael@0 | 67 | case EOpLogicalXor: return "^^"; |
michael@0 | 68 | case EOpLogicalAnd: return "&&"; |
michael@0 | 69 | case EOpNegative: return "-"; |
michael@0 | 70 | case EOpVectorLogicalNot: return "not"; |
michael@0 | 71 | case EOpLogicalNot: return "!"; |
michael@0 | 72 | case EOpPostIncrement: return "++"; |
michael@0 | 73 | case EOpPostDecrement: return "--"; |
michael@0 | 74 | case EOpPreIncrement: return "++"; |
michael@0 | 75 | case EOpPreDecrement: return "--"; |
michael@0 | 76 | |
michael@0 | 77 | // Fall-through. |
michael@0 | 78 | case EOpConvIntToBool: |
michael@0 | 79 | case EOpConvFloatToBool: return "bool"; |
michael@0 | 80 | |
michael@0 | 81 | // Fall-through. |
michael@0 | 82 | case EOpConvBoolToFloat: |
michael@0 | 83 | case EOpConvIntToFloat: return "float"; |
michael@0 | 84 | |
michael@0 | 85 | // Fall-through. |
michael@0 | 86 | case EOpConvFloatToInt: |
michael@0 | 87 | case EOpConvBoolToInt: return "int"; |
michael@0 | 88 | |
michael@0 | 89 | case EOpRadians: return "radians"; |
michael@0 | 90 | case EOpDegrees: return "degrees"; |
michael@0 | 91 | case EOpSin: return "sin"; |
michael@0 | 92 | case EOpCos: return "cos"; |
michael@0 | 93 | case EOpTan: return "tan"; |
michael@0 | 94 | case EOpAsin: return "asin"; |
michael@0 | 95 | case EOpAcos: return "acos"; |
michael@0 | 96 | case EOpAtan: return "atan"; |
michael@0 | 97 | case EOpExp: return "exp"; |
michael@0 | 98 | case EOpLog: return "log"; |
michael@0 | 99 | case EOpExp2: return "exp2"; |
michael@0 | 100 | case EOpLog2: return "log2"; |
michael@0 | 101 | case EOpSqrt: return "sqrt"; |
michael@0 | 102 | case EOpInverseSqrt: return "inversesqrt"; |
michael@0 | 103 | case EOpAbs: return "abs"; |
michael@0 | 104 | case EOpSign: return "sign"; |
michael@0 | 105 | case EOpFloor: return "floor"; |
michael@0 | 106 | case EOpCeil: return "ceil"; |
michael@0 | 107 | case EOpFract: return "fract"; |
michael@0 | 108 | case EOpLength: return "length"; |
michael@0 | 109 | case EOpNormalize: return "normalize"; |
michael@0 | 110 | case EOpDFdx: return "dFdx"; |
michael@0 | 111 | case EOpDFdy: return "dFdy"; |
michael@0 | 112 | case EOpFwidth: return "fwidth"; |
michael@0 | 113 | case EOpAny: return "any"; |
michael@0 | 114 | case EOpAll: return "all"; |
michael@0 | 115 | |
michael@0 | 116 | default: break; |
michael@0 | 117 | } |
michael@0 | 118 | return ""; |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | //////////////////////////////////////////////////////////////////////////// |
michael@0 | 122 | // |
michael@0 | 123 | // First set of functions are to help build the intermediate representation. |
michael@0 | 124 | // These functions are not member functions of the nodes. |
michael@0 | 125 | // They are called from parser productions. |
michael@0 | 126 | // |
michael@0 | 127 | ///////////////////////////////////////////////////////////////////////////// |
michael@0 | 128 | |
michael@0 | 129 | // |
michael@0 | 130 | // Add a terminal node for an identifier in an expression. |
michael@0 | 131 | // |
michael@0 | 132 | // Returns the added node. |
michael@0 | 133 | // |
michael@0 | 134 | TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line) |
michael@0 | 135 | { |
michael@0 | 136 | TIntermSymbol* node = new TIntermSymbol(id, name, type); |
michael@0 | 137 | node->setLine(line); |
michael@0 | 138 | |
michael@0 | 139 | return node; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | // |
michael@0 | 143 | // Connect two nodes with a new parent that does a binary operation on the nodes. |
michael@0 | 144 | // |
michael@0 | 145 | // Returns the added node. |
michael@0 | 146 | // |
michael@0 | 147 | TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable) |
michael@0 | 148 | { |
michael@0 | 149 | switch (op) { |
michael@0 | 150 | case EOpEqual: |
michael@0 | 151 | case EOpNotEqual: |
michael@0 | 152 | if (left->isArray()) |
michael@0 | 153 | return 0; |
michael@0 | 154 | break; |
michael@0 | 155 | case EOpLessThan: |
michael@0 | 156 | case EOpGreaterThan: |
michael@0 | 157 | case EOpLessThanEqual: |
michael@0 | 158 | case EOpGreaterThanEqual: |
michael@0 | 159 | if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { |
michael@0 | 160 | return 0; |
michael@0 | 161 | } |
michael@0 | 162 | break; |
michael@0 | 163 | case EOpLogicalOr: |
michael@0 | 164 | case EOpLogicalXor: |
michael@0 | 165 | case EOpLogicalAnd: |
michael@0 | 166 | if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { |
michael@0 | 167 | return 0; |
michael@0 | 168 | } |
michael@0 | 169 | break; |
michael@0 | 170 | case EOpAdd: |
michael@0 | 171 | case EOpSub: |
michael@0 | 172 | case EOpDiv: |
michael@0 | 173 | case EOpMul: |
michael@0 | 174 | if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) |
michael@0 | 175 | return 0; |
michael@0 | 176 | default: break; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | // |
michael@0 | 180 | // First try converting the children to compatible types. |
michael@0 | 181 | // |
michael@0 | 182 | if (left->getType().getStruct() && right->getType().getStruct()) { |
michael@0 | 183 | if (left->getType() != right->getType()) |
michael@0 | 184 | return 0; |
michael@0 | 185 | } else { |
michael@0 | 186 | TIntermTyped* child = addConversion(op, left->getType(), right); |
michael@0 | 187 | if (child) |
michael@0 | 188 | right = child; |
michael@0 | 189 | else { |
michael@0 | 190 | child = addConversion(op, right->getType(), left); |
michael@0 | 191 | if (child) |
michael@0 | 192 | left = child; |
michael@0 | 193 | else |
michael@0 | 194 | return 0; |
michael@0 | 195 | } |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | // |
michael@0 | 199 | // Need a new node holding things together then. Make |
michael@0 | 200 | // one and promote it to the right type. |
michael@0 | 201 | // |
michael@0 | 202 | TIntermBinary* node = new TIntermBinary(op); |
michael@0 | 203 | node->setLine(line); |
michael@0 | 204 | |
michael@0 | 205 | node->setLeft(left); |
michael@0 | 206 | node->setRight(right); |
michael@0 | 207 | if (!node->promote(infoSink)) |
michael@0 | 208 | return 0; |
michael@0 | 209 | |
michael@0 | 210 | // |
michael@0 | 211 | // See if we can fold constants. |
michael@0 | 212 | // |
michael@0 | 213 | TIntermTyped* typedReturnNode = 0; |
michael@0 | 214 | TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); |
michael@0 | 215 | TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); |
michael@0 | 216 | if (leftTempConstant && rightTempConstant) { |
michael@0 | 217 | typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); |
michael@0 | 218 | |
michael@0 | 219 | if (typedReturnNode) |
michael@0 | 220 | return typedReturnNode; |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | return node; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | // |
michael@0 | 227 | // Connect two nodes through an assignment. |
michael@0 | 228 | // |
michael@0 | 229 | // Returns the added node. |
michael@0 | 230 | // |
michael@0 | 231 | TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) |
michael@0 | 232 | { |
michael@0 | 233 | // |
michael@0 | 234 | // Like adding binary math, except the conversion can only go |
michael@0 | 235 | // from right to left. |
michael@0 | 236 | // |
michael@0 | 237 | TIntermBinary* node = new TIntermBinary(op); |
michael@0 | 238 | node->setLine(line); |
michael@0 | 239 | |
michael@0 | 240 | TIntermTyped* child = addConversion(op, left->getType(), right); |
michael@0 | 241 | if (child == 0) |
michael@0 | 242 | return 0; |
michael@0 | 243 | |
michael@0 | 244 | node->setLeft(left); |
michael@0 | 245 | node->setRight(child); |
michael@0 | 246 | if (! node->promote(infoSink)) |
michael@0 | 247 | return 0; |
michael@0 | 248 | |
michael@0 | 249 | return node; |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | // |
michael@0 | 253 | // Connect two nodes through an index operator, where the left node is the base |
michael@0 | 254 | // of an array or struct, and the right node is a direct or indirect offset. |
michael@0 | 255 | // |
michael@0 | 256 | // Returns the added node. |
michael@0 | 257 | // The caller should set the type of the returned node. |
michael@0 | 258 | // |
michael@0 | 259 | TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line) |
michael@0 | 260 | { |
michael@0 | 261 | TIntermBinary* node = new TIntermBinary(op); |
michael@0 | 262 | node->setLine(line); |
michael@0 | 263 | node->setLeft(base); |
michael@0 | 264 | node->setRight(index); |
michael@0 | 265 | |
michael@0 | 266 | // caller should set the type |
michael@0 | 267 | |
michael@0 | 268 | return node; |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | // |
michael@0 | 272 | // Add one node as the parent of another that it operates on. |
michael@0 | 273 | // |
michael@0 | 274 | // Returns the added node. |
michael@0 | 275 | // |
michael@0 | 276 | TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable) |
michael@0 | 277 | { |
michael@0 | 278 | TIntermUnary* node; |
michael@0 | 279 | TIntermTyped* child = childNode->getAsTyped(); |
michael@0 | 280 | |
michael@0 | 281 | if (child == 0) { |
michael@0 | 282 | infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); |
michael@0 | 283 | return 0; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | switch (op) { |
michael@0 | 287 | case EOpLogicalNot: |
michael@0 | 288 | if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { |
michael@0 | 289 | return 0; |
michael@0 | 290 | } |
michael@0 | 291 | break; |
michael@0 | 292 | |
michael@0 | 293 | case EOpPostIncrement: |
michael@0 | 294 | case EOpPreIncrement: |
michael@0 | 295 | case EOpPostDecrement: |
michael@0 | 296 | case EOpPreDecrement: |
michael@0 | 297 | case EOpNegative: |
michael@0 | 298 | if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) |
michael@0 | 299 | return 0; |
michael@0 | 300 | default: break; |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | // |
michael@0 | 304 | // Do we need to promote the operand? |
michael@0 | 305 | // |
michael@0 | 306 | // Note: Implicit promotions were removed from the language. |
michael@0 | 307 | // |
michael@0 | 308 | TBasicType newType = EbtVoid; |
michael@0 | 309 | switch (op) { |
michael@0 | 310 | case EOpConstructInt: newType = EbtInt; break; |
michael@0 | 311 | case EOpConstructBool: newType = EbtBool; break; |
michael@0 | 312 | case EOpConstructFloat: newType = EbtFloat; break; |
michael@0 | 313 | default: break; |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | if (newType != EbtVoid) { |
michael@0 | 317 | child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, |
michael@0 | 318 | child->getNominalSize(), |
michael@0 | 319 | child->isMatrix(), |
michael@0 | 320 | child->isArray()), |
michael@0 | 321 | child); |
michael@0 | 322 | if (child == 0) |
michael@0 | 323 | return 0; |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | // |
michael@0 | 327 | // For constructors, we are now done, it's all in the conversion. |
michael@0 | 328 | // |
michael@0 | 329 | switch (op) { |
michael@0 | 330 | case EOpConstructInt: |
michael@0 | 331 | case EOpConstructBool: |
michael@0 | 332 | case EOpConstructFloat: |
michael@0 | 333 | return child; |
michael@0 | 334 | default: break; |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | TIntermConstantUnion *childTempConstant = 0; |
michael@0 | 338 | if (child->getAsConstantUnion()) |
michael@0 | 339 | childTempConstant = child->getAsConstantUnion(); |
michael@0 | 340 | |
michael@0 | 341 | // |
michael@0 | 342 | // Make a new node for the operator. |
michael@0 | 343 | // |
michael@0 | 344 | node = new TIntermUnary(op); |
michael@0 | 345 | node->setLine(line); |
michael@0 | 346 | node->setOperand(child); |
michael@0 | 347 | |
michael@0 | 348 | if (! node->promote(infoSink)) |
michael@0 | 349 | return 0; |
michael@0 | 350 | |
michael@0 | 351 | if (childTempConstant) { |
michael@0 | 352 | TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); |
michael@0 | 353 | |
michael@0 | 354 | if (newChild) |
michael@0 | 355 | return newChild; |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | return node; |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | // |
michael@0 | 362 | // This is the safe way to change the operator on an aggregate, as it |
michael@0 | 363 | // does lots of error checking and fixing. Especially for establishing |
michael@0 | 364 | // a function call's operation on it's set of parameters. Sequences |
michael@0 | 365 | // of instructions are also aggregates, but they just direnctly set |
michael@0 | 366 | // their operator to EOpSequence. |
michael@0 | 367 | // |
michael@0 | 368 | // Returns an aggregate node, which could be the one passed in if |
michael@0 | 369 | // it was already an aggregate but no operator was set. |
michael@0 | 370 | // |
michael@0 | 371 | TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line) |
michael@0 | 372 | { |
michael@0 | 373 | TIntermAggregate* aggNode; |
michael@0 | 374 | |
michael@0 | 375 | // |
michael@0 | 376 | // Make sure we have an aggregate. If not turn it into one. |
michael@0 | 377 | // |
michael@0 | 378 | if (node) { |
michael@0 | 379 | aggNode = node->getAsAggregate(); |
michael@0 | 380 | if (aggNode == 0 || aggNode->getOp() != EOpNull) { |
michael@0 | 381 | // |
michael@0 | 382 | // Make an aggregate containing this node. |
michael@0 | 383 | // |
michael@0 | 384 | aggNode = new TIntermAggregate(); |
michael@0 | 385 | aggNode->getSequence().push_back(node); |
michael@0 | 386 | } |
michael@0 | 387 | } else |
michael@0 | 388 | aggNode = new TIntermAggregate(); |
michael@0 | 389 | |
michael@0 | 390 | // |
michael@0 | 391 | // Set the operator. |
michael@0 | 392 | // |
michael@0 | 393 | aggNode->setOp(op); |
michael@0 | 394 | aggNode->setLine(line); |
michael@0 | 395 | |
michael@0 | 396 | return aggNode; |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | // |
michael@0 | 400 | // Convert one type to another. |
michael@0 | 401 | // |
michael@0 | 402 | // Returns the node representing the conversion, which could be the same |
michael@0 | 403 | // node passed in if no conversion was needed. |
michael@0 | 404 | // |
michael@0 | 405 | // Return 0 if a conversion can't be done. |
michael@0 | 406 | // |
michael@0 | 407 | TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) |
michael@0 | 408 | { |
michael@0 | 409 | // |
michael@0 | 410 | // Does the base type allow operation? |
michael@0 | 411 | // |
michael@0 | 412 | switch (node->getBasicType()) { |
michael@0 | 413 | case EbtVoid: |
michael@0 | 414 | case EbtSampler2D: |
michael@0 | 415 | case EbtSamplerCube: |
michael@0 | 416 | return 0; |
michael@0 | 417 | default: break; |
michael@0 | 418 | } |
michael@0 | 419 | |
michael@0 | 420 | // |
michael@0 | 421 | // Otherwise, if types are identical, no problem |
michael@0 | 422 | // |
michael@0 | 423 | if (type == node->getType()) |
michael@0 | 424 | return node; |
michael@0 | 425 | |
michael@0 | 426 | // |
michael@0 | 427 | // If one's a structure, then no conversions. |
michael@0 | 428 | // |
michael@0 | 429 | if (type.getStruct() || node->getType().getStruct()) |
michael@0 | 430 | return 0; |
michael@0 | 431 | |
michael@0 | 432 | // |
michael@0 | 433 | // If one's an array, then no conversions. |
michael@0 | 434 | // |
michael@0 | 435 | if (type.isArray() || node->getType().isArray()) |
michael@0 | 436 | return 0; |
michael@0 | 437 | |
michael@0 | 438 | TBasicType promoteTo; |
michael@0 | 439 | |
michael@0 | 440 | switch (op) { |
michael@0 | 441 | // |
michael@0 | 442 | // Explicit conversions |
michael@0 | 443 | // |
michael@0 | 444 | case EOpConstructBool: |
michael@0 | 445 | promoteTo = EbtBool; |
michael@0 | 446 | break; |
michael@0 | 447 | case EOpConstructFloat: |
michael@0 | 448 | promoteTo = EbtFloat; |
michael@0 | 449 | break; |
michael@0 | 450 | case EOpConstructInt: |
michael@0 | 451 | promoteTo = EbtInt; |
michael@0 | 452 | break; |
michael@0 | 453 | default: |
michael@0 | 454 | // |
michael@0 | 455 | // implicit conversions were removed from the language. |
michael@0 | 456 | // |
michael@0 | 457 | if (type.getBasicType() != node->getType().getBasicType()) |
michael@0 | 458 | return 0; |
michael@0 | 459 | // |
michael@0 | 460 | // Size and structure could still differ, but that's |
michael@0 | 461 | // handled by operator promotion. |
michael@0 | 462 | // |
michael@0 | 463 | return node; |
michael@0 | 464 | } |
michael@0 | 465 | |
michael@0 | 466 | if (node->getAsConstantUnion()) { |
michael@0 | 467 | |
michael@0 | 468 | return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); |
michael@0 | 469 | } else { |
michael@0 | 470 | |
michael@0 | 471 | // |
michael@0 | 472 | // Add a new newNode for the conversion. |
michael@0 | 473 | // |
michael@0 | 474 | TIntermUnary* newNode = 0; |
michael@0 | 475 | |
michael@0 | 476 | TOperator newOp = EOpNull; |
michael@0 | 477 | switch (promoteTo) { |
michael@0 | 478 | case EbtFloat: |
michael@0 | 479 | switch (node->getBasicType()) { |
michael@0 | 480 | case EbtInt: newOp = EOpConvIntToFloat; break; |
michael@0 | 481 | case EbtBool: newOp = EOpConvBoolToFloat; break; |
michael@0 | 482 | default: |
michael@0 | 483 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); |
michael@0 | 484 | return 0; |
michael@0 | 485 | } |
michael@0 | 486 | break; |
michael@0 | 487 | case EbtBool: |
michael@0 | 488 | switch (node->getBasicType()) { |
michael@0 | 489 | case EbtInt: newOp = EOpConvIntToBool; break; |
michael@0 | 490 | case EbtFloat: newOp = EOpConvFloatToBool; break; |
michael@0 | 491 | default: |
michael@0 | 492 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); |
michael@0 | 493 | return 0; |
michael@0 | 494 | } |
michael@0 | 495 | break; |
michael@0 | 496 | case EbtInt: |
michael@0 | 497 | switch (node->getBasicType()) { |
michael@0 | 498 | case EbtBool: newOp = EOpConvBoolToInt; break; |
michael@0 | 499 | case EbtFloat: newOp = EOpConvFloatToInt; break; |
michael@0 | 500 | default: |
michael@0 | 501 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); |
michael@0 | 502 | return 0; |
michael@0 | 503 | } |
michael@0 | 504 | break; |
michael@0 | 505 | default: |
michael@0 | 506 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); |
michael@0 | 507 | return 0; |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); |
michael@0 | 511 | newNode = new TIntermUnary(newOp, type); |
michael@0 | 512 | newNode->setLine(node->getLine()); |
michael@0 | 513 | newNode->setOperand(node); |
michael@0 | 514 | |
michael@0 | 515 | return newNode; |
michael@0 | 516 | } |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | // |
michael@0 | 520 | // Safe way to combine two nodes into an aggregate. Works with null pointers, |
michael@0 | 521 | // a node that's not a aggregate yet, etc. |
michael@0 | 522 | // |
michael@0 | 523 | // Returns the resulting aggregate, unless 0 was passed in for |
michael@0 | 524 | // both existing nodes. |
michael@0 | 525 | // |
michael@0 | 526 | TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) |
michael@0 | 527 | { |
michael@0 | 528 | if (left == 0 && right == 0) |
michael@0 | 529 | return 0; |
michael@0 | 530 | |
michael@0 | 531 | TIntermAggregate* aggNode = 0; |
michael@0 | 532 | if (left) |
michael@0 | 533 | aggNode = left->getAsAggregate(); |
michael@0 | 534 | if (!aggNode || aggNode->getOp() != EOpNull) { |
michael@0 | 535 | aggNode = new TIntermAggregate; |
michael@0 | 536 | if (left) |
michael@0 | 537 | aggNode->getSequence().push_back(left); |
michael@0 | 538 | } |
michael@0 | 539 | |
michael@0 | 540 | if (right) |
michael@0 | 541 | aggNode->getSequence().push_back(right); |
michael@0 | 542 | |
michael@0 | 543 | aggNode->setLine(line); |
michael@0 | 544 | |
michael@0 | 545 | return aggNode; |
michael@0 | 546 | } |
michael@0 | 547 | |
michael@0 | 548 | // |
michael@0 | 549 | // Turn an existing node into an aggregate. |
michael@0 | 550 | // |
michael@0 | 551 | // Returns an aggregate, unless 0 was passed in for the existing node. |
michael@0 | 552 | // |
michael@0 | 553 | TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) |
michael@0 | 554 | { |
michael@0 | 555 | if (node == 0) |
michael@0 | 556 | return 0; |
michael@0 | 557 | |
michael@0 | 558 | TIntermAggregate* aggNode = new TIntermAggregate; |
michael@0 | 559 | aggNode->getSequence().push_back(node); |
michael@0 | 560 | aggNode->setLine(line); |
michael@0 | 561 | |
michael@0 | 562 | return aggNode; |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | // |
michael@0 | 566 | // For "if" test nodes. There are three children; a condition, |
michael@0 | 567 | // a true path, and a false path. The two paths are in the |
michael@0 | 568 | // nodePair. |
michael@0 | 569 | // |
michael@0 | 570 | // Returns the selection node created. |
michael@0 | 571 | // |
michael@0 | 572 | TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line) |
michael@0 | 573 | { |
michael@0 | 574 | // |
michael@0 | 575 | // For compile time constant selections, prune the code and |
michael@0 | 576 | // test now. |
michael@0 | 577 | // |
michael@0 | 578 | |
michael@0 | 579 | if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { |
michael@0 | 580 | if (cond->getAsConstantUnion()->getBConst(0) == true) |
michael@0 | 581 | return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; |
michael@0 | 582 | else |
michael@0 | 583 | return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; |
michael@0 | 584 | } |
michael@0 | 585 | |
michael@0 | 586 | TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); |
michael@0 | 587 | node->setLine(line); |
michael@0 | 588 | |
michael@0 | 589 | return node; |
michael@0 | 590 | } |
michael@0 | 591 | |
michael@0 | 592 | |
michael@0 | 593 | TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) |
michael@0 | 594 | { |
michael@0 | 595 | if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { |
michael@0 | 596 | return right; |
michael@0 | 597 | } else { |
michael@0 | 598 | TIntermTyped *commaAggregate = growAggregate(left, right, line); |
michael@0 | 599 | commaAggregate->getAsAggregate()->setOp(EOpComma); |
michael@0 | 600 | commaAggregate->setType(right->getType()); |
michael@0 | 601 | commaAggregate->getTypePointer()->setQualifier(EvqTemporary); |
michael@0 | 602 | return commaAggregate; |
michael@0 | 603 | } |
michael@0 | 604 | } |
michael@0 | 605 | |
michael@0 | 606 | // |
michael@0 | 607 | // For "?:" test nodes. There are three children; a condition, |
michael@0 | 608 | // a true path, and a false path. The two paths are specified |
michael@0 | 609 | // as separate parameters. |
michael@0 | 610 | // |
michael@0 | 611 | // Returns the selection node created, or 0 if one could not be. |
michael@0 | 612 | // |
michael@0 | 613 | TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line) |
michael@0 | 614 | { |
michael@0 | 615 | // |
michael@0 | 616 | // Get compatible types. |
michael@0 | 617 | // |
michael@0 | 618 | TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); |
michael@0 | 619 | if (child) |
michael@0 | 620 | falseBlock = child; |
michael@0 | 621 | else { |
michael@0 | 622 | child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); |
michael@0 | 623 | if (child) |
michael@0 | 624 | trueBlock = child; |
michael@0 | 625 | else |
michael@0 | 626 | return 0; |
michael@0 | 627 | } |
michael@0 | 628 | |
michael@0 | 629 | // |
michael@0 | 630 | // See if all the operands are constant, then fold it otherwise not. |
michael@0 | 631 | // |
michael@0 | 632 | |
michael@0 | 633 | if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { |
michael@0 | 634 | if (cond->getAsConstantUnion()->getBConst(0)) |
michael@0 | 635 | return trueBlock; |
michael@0 | 636 | else |
michael@0 | 637 | return falseBlock; |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | // |
michael@0 | 641 | // Make a selection node. |
michael@0 | 642 | // |
michael@0 | 643 | TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); |
michael@0 | 644 | node->getTypePointer()->setQualifier(EvqTemporary); |
michael@0 | 645 | node->setLine(line); |
michael@0 | 646 | |
michael@0 | 647 | return node; |
michael@0 | 648 | } |
michael@0 | 649 | |
michael@0 | 650 | // |
michael@0 | 651 | // Constant terminal nodes. Has a union that contains bool, float or int constants |
michael@0 | 652 | // |
michael@0 | 653 | // Returns the constant union node created. |
michael@0 | 654 | // |
michael@0 | 655 | |
michael@0 | 656 | TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line) |
michael@0 | 657 | { |
michael@0 | 658 | TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); |
michael@0 | 659 | node->setLine(line); |
michael@0 | 660 | |
michael@0 | 661 | return node; |
michael@0 | 662 | } |
michael@0 | 663 | |
michael@0 | 664 | TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line) |
michael@0 | 665 | { |
michael@0 | 666 | |
michael@0 | 667 | TIntermAggregate* node = new TIntermAggregate(EOpSequence); |
michael@0 | 668 | |
michael@0 | 669 | node->setLine(line); |
michael@0 | 670 | TIntermConstantUnion* constIntNode; |
michael@0 | 671 | TIntermSequence &sequenceVector = node->getSequence(); |
michael@0 | 672 | ConstantUnion* unionArray; |
michael@0 | 673 | |
michael@0 | 674 | for (int i = 0; i < fields.num; i++) { |
michael@0 | 675 | unionArray = new ConstantUnion[1]; |
michael@0 | 676 | unionArray->setIConst(fields.offsets[i]); |
michael@0 | 677 | constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); |
michael@0 | 678 | sequenceVector.push_back(constIntNode); |
michael@0 | 679 | } |
michael@0 | 680 | |
michael@0 | 681 | return node; |
michael@0 | 682 | } |
michael@0 | 683 | |
michael@0 | 684 | // |
michael@0 | 685 | // Create loop nodes. |
michael@0 | 686 | // |
michael@0 | 687 | TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line) |
michael@0 | 688 | { |
michael@0 | 689 | TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); |
michael@0 | 690 | node->setLine(line); |
michael@0 | 691 | |
michael@0 | 692 | return node; |
michael@0 | 693 | } |
michael@0 | 694 | |
michael@0 | 695 | // |
michael@0 | 696 | // Add branches. |
michael@0 | 697 | // |
michael@0 | 698 | TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line) |
michael@0 | 699 | { |
michael@0 | 700 | return addBranch(branchOp, 0, line); |
michael@0 | 701 | } |
michael@0 | 702 | |
michael@0 | 703 | TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line) |
michael@0 | 704 | { |
michael@0 | 705 | TIntermBranch* node = new TIntermBranch(branchOp, expression); |
michael@0 | 706 | node->setLine(line); |
michael@0 | 707 | |
michael@0 | 708 | return node; |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | // |
michael@0 | 712 | // This is to be executed once the final root is put on top by the parsing |
michael@0 | 713 | // process. |
michael@0 | 714 | // |
michael@0 | 715 | bool TIntermediate::postProcess(TIntermNode* root) |
michael@0 | 716 | { |
michael@0 | 717 | if (root == 0) |
michael@0 | 718 | return true; |
michael@0 | 719 | |
michael@0 | 720 | // |
michael@0 | 721 | // First, finish off the top level sequence, if any |
michael@0 | 722 | // |
michael@0 | 723 | TIntermAggregate* aggRoot = root->getAsAggregate(); |
michael@0 | 724 | if (aggRoot && aggRoot->getOp() == EOpNull) |
michael@0 | 725 | aggRoot->setOp(EOpSequence); |
michael@0 | 726 | |
michael@0 | 727 | return true; |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | // |
michael@0 | 731 | // This deletes the tree. |
michael@0 | 732 | // |
michael@0 | 733 | void TIntermediate::remove(TIntermNode* root) |
michael@0 | 734 | { |
michael@0 | 735 | if (root) |
michael@0 | 736 | RemoveAllTreeNodes(root); |
michael@0 | 737 | } |
michael@0 | 738 | |
michael@0 | 739 | //////////////////////////////////////////////////////////////// |
michael@0 | 740 | // |
michael@0 | 741 | // Member functions of the nodes used for building the tree. |
michael@0 | 742 | // |
michael@0 | 743 | //////////////////////////////////////////////////////////////// |
michael@0 | 744 | |
michael@0 | 745 | // |
michael@0 | 746 | // Say whether or not an operation node changes the value of a variable. |
michael@0 | 747 | // |
michael@0 | 748 | // Returns true if state is modified. |
michael@0 | 749 | // |
michael@0 | 750 | bool TIntermOperator::modifiesState() const |
michael@0 | 751 | { |
michael@0 | 752 | switch (op) { |
michael@0 | 753 | case EOpPostIncrement: |
michael@0 | 754 | case EOpPostDecrement: |
michael@0 | 755 | case EOpPreIncrement: |
michael@0 | 756 | case EOpPreDecrement: |
michael@0 | 757 | case EOpAssign: |
michael@0 | 758 | case EOpAddAssign: |
michael@0 | 759 | case EOpSubAssign: |
michael@0 | 760 | case EOpMulAssign: |
michael@0 | 761 | case EOpVectorTimesMatrixAssign: |
michael@0 | 762 | case EOpVectorTimesScalarAssign: |
michael@0 | 763 | case EOpMatrixTimesScalarAssign: |
michael@0 | 764 | case EOpMatrixTimesMatrixAssign: |
michael@0 | 765 | case EOpDivAssign: |
michael@0 | 766 | return true; |
michael@0 | 767 | default: |
michael@0 | 768 | return false; |
michael@0 | 769 | } |
michael@0 | 770 | } |
michael@0 | 771 | |
michael@0 | 772 | // |
michael@0 | 773 | // returns true if the operator is for one of the constructors |
michael@0 | 774 | // |
michael@0 | 775 | bool TIntermOperator::isConstructor() const |
michael@0 | 776 | { |
michael@0 | 777 | switch (op) { |
michael@0 | 778 | case EOpConstructVec2: |
michael@0 | 779 | case EOpConstructVec3: |
michael@0 | 780 | case EOpConstructVec4: |
michael@0 | 781 | case EOpConstructMat2: |
michael@0 | 782 | case EOpConstructMat3: |
michael@0 | 783 | case EOpConstructMat4: |
michael@0 | 784 | case EOpConstructFloat: |
michael@0 | 785 | case EOpConstructIVec2: |
michael@0 | 786 | case EOpConstructIVec3: |
michael@0 | 787 | case EOpConstructIVec4: |
michael@0 | 788 | case EOpConstructInt: |
michael@0 | 789 | case EOpConstructBVec2: |
michael@0 | 790 | case EOpConstructBVec3: |
michael@0 | 791 | case EOpConstructBVec4: |
michael@0 | 792 | case EOpConstructBool: |
michael@0 | 793 | case EOpConstructStruct: |
michael@0 | 794 | return true; |
michael@0 | 795 | default: |
michael@0 | 796 | return false; |
michael@0 | 797 | } |
michael@0 | 798 | } |
michael@0 | 799 | // |
michael@0 | 800 | // Make sure the type of a unary operator is appropriate for its |
michael@0 | 801 | // combination of operation and operand type. |
michael@0 | 802 | // |
michael@0 | 803 | // Returns false in nothing makes sense. |
michael@0 | 804 | // |
michael@0 | 805 | bool TIntermUnary::promote(TInfoSink&) |
michael@0 | 806 | { |
michael@0 | 807 | switch (op) { |
michael@0 | 808 | case EOpLogicalNot: |
michael@0 | 809 | if (operand->getBasicType() != EbtBool) |
michael@0 | 810 | return false; |
michael@0 | 811 | break; |
michael@0 | 812 | case EOpNegative: |
michael@0 | 813 | case EOpPostIncrement: |
michael@0 | 814 | case EOpPostDecrement: |
michael@0 | 815 | case EOpPreIncrement: |
michael@0 | 816 | case EOpPreDecrement: |
michael@0 | 817 | if (operand->getBasicType() == EbtBool) |
michael@0 | 818 | return false; |
michael@0 | 819 | break; |
michael@0 | 820 | |
michael@0 | 821 | // operators for built-ins are already type checked against their prototype |
michael@0 | 822 | case EOpAny: |
michael@0 | 823 | case EOpAll: |
michael@0 | 824 | case EOpVectorLogicalNot: |
michael@0 | 825 | return true; |
michael@0 | 826 | |
michael@0 | 827 | default: |
michael@0 | 828 | if (operand->getBasicType() != EbtFloat) |
michael@0 | 829 | return false; |
michael@0 | 830 | } |
michael@0 | 831 | |
michael@0 | 832 | setType(operand->getType()); |
michael@0 | 833 | type.setQualifier(EvqTemporary); |
michael@0 | 834 | |
michael@0 | 835 | return true; |
michael@0 | 836 | } |
michael@0 | 837 | |
michael@0 | 838 | // |
michael@0 | 839 | // Establishes the type of the resultant operation, as well as |
michael@0 | 840 | // makes the operator the correct one for the operands. |
michael@0 | 841 | // |
michael@0 | 842 | // Returns false if operator can't work on operands. |
michael@0 | 843 | // |
michael@0 | 844 | bool TIntermBinary::promote(TInfoSink& infoSink) |
michael@0 | 845 | { |
michael@0 | 846 | // This function only handles scalars, vectors, and matrices. |
michael@0 | 847 | if (left->isArray() || right->isArray()) { |
michael@0 | 848 | infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); |
michael@0 | 849 | return false; |
michael@0 | 850 | } |
michael@0 | 851 | |
michael@0 | 852 | // GLSL ES 2.0 does not support implicit type casting. |
michael@0 | 853 | // So the basic type should always match. |
michael@0 | 854 | if (left->getBasicType() != right->getBasicType()) |
michael@0 | 855 | return false; |
michael@0 | 856 | |
michael@0 | 857 | // |
michael@0 | 858 | // Base assumption: just make the type the same as the left |
michael@0 | 859 | // operand. Then only deviations from this need be coded. |
michael@0 | 860 | // |
michael@0 | 861 | setType(left->getType()); |
michael@0 | 862 | |
michael@0 | 863 | // The result gets promoted to the highest precision. |
michael@0 | 864 | TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); |
michael@0 | 865 | getTypePointer()->setPrecision(higherPrecision); |
michael@0 | 866 | |
michael@0 | 867 | // Binary operations results in temporary variables unless both |
michael@0 | 868 | // operands are const. |
michael@0 | 869 | if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { |
michael@0 | 870 | getTypePointer()->setQualifier(EvqTemporary); |
michael@0 | 871 | } |
michael@0 | 872 | |
michael@0 | 873 | int size = std::max(left->getNominalSize(), right->getNominalSize()); |
michael@0 | 874 | |
michael@0 | 875 | // |
michael@0 | 876 | // All scalars. Code after this test assumes this case is removed! |
michael@0 | 877 | // |
michael@0 | 878 | if (size == 1) { |
michael@0 | 879 | switch (op) { |
michael@0 | 880 | // |
michael@0 | 881 | // Promote to conditional |
michael@0 | 882 | // |
michael@0 | 883 | case EOpEqual: |
michael@0 | 884 | case EOpNotEqual: |
michael@0 | 885 | case EOpLessThan: |
michael@0 | 886 | case EOpGreaterThan: |
michael@0 | 887 | case EOpLessThanEqual: |
michael@0 | 888 | case EOpGreaterThanEqual: |
michael@0 | 889 | setType(TType(EbtBool, EbpUndefined)); |
michael@0 | 890 | break; |
michael@0 | 891 | |
michael@0 | 892 | // |
michael@0 | 893 | // And and Or operate on conditionals |
michael@0 | 894 | // |
michael@0 | 895 | case EOpLogicalAnd: |
michael@0 | 896 | case EOpLogicalOr: |
michael@0 | 897 | // Both operands must be of type bool. |
michael@0 | 898 | if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) |
michael@0 | 899 | return false; |
michael@0 | 900 | setType(TType(EbtBool, EbpUndefined)); |
michael@0 | 901 | break; |
michael@0 | 902 | |
michael@0 | 903 | default: |
michael@0 | 904 | break; |
michael@0 | 905 | } |
michael@0 | 906 | return true; |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | // If we reach here, at least one of the operands is vector or matrix. |
michael@0 | 910 | // The other operand could be a scalar, vector, or matrix. |
michael@0 | 911 | // Are the sizes compatible? |
michael@0 | 912 | // |
michael@0 | 913 | if (left->getNominalSize() != right->getNominalSize()) { |
michael@0 | 914 | // If the nominal size of operands do not match: |
michael@0 | 915 | // One of them must be scalar. |
michael@0 | 916 | if (left->getNominalSize() != 1 && right->getNominalSize() != 1) |
michael@0 | 917 | return false; |
michael@0 | 918 | // Operator cannot be of type pure assignment. |
michael@0 | 919 | if (op == EOpAssign || op == EOpInitialize) |
michael@0 | 920 | return false; |
michael@0 | 921 | } |
michael@0 | 922 | |
michael@0 | 923 | // |
michael@0 | 924 | // Can these two operands be combined? |
michael@0 | 925 | // |
michael@0 | 926 | TBasicType basicType = left->getBasicType(); |
michael@0 | 927 | switch (op) { |
michael@0 | 928 | case EOpMul: |
michael@0 | 929 | if (!left->isMatrix() && right->isMatrix()) { |
michael@0 | 930 | if (left->isVector()) |
michael@0 | 931 | op = EOpVectorTimesMatrix; |
michael@0 | 932 | else { |
michael@0 | 933 | op = EOpMatrixTimesScalar; |
michael@0 | 934 | setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); |
michael@0 | 935 | } |
michael@0 | 936 | } else if (left->isMatrix() && !right->isMatrix()) { |
michael@0 | 937 | if (right->isVector()) { |
michael@0 | 938 | op = EOpMatrixTimesVector; |
michael@0 | 939 | setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); |
michael@0 | 940 | } else { |
michael@0 | 941 | op = EOpMatrixTimesScalar; |
michael@0 | 942 | } |
michael@0 | 943 | } else if (left->isMatrix() && right->isMatrix()) { |
michael@0 | 944 | op = EOpMatrixTimesMatrix; |
michael@0 | 945 | } else if (!left->isMatrix() && !right->isMatrix()) { |
michael@0 | 946 | if (left->isVector() && right->isVector()) { |
michael@0 | 947 | // leave as component product |
michael@0 | 948 | } else if (left->isVector() || right->isVector()) { |
michael@0 | 949 | op = EOpVectorTimesScalar; |
michael@0 | 950 | setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); |
michael@0 | 951 | } |
michael@0 | 952 | } else { |
michael@0 | 953 | infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); |
michael@0 | 954 | return false; |
michael@0 | 955 | } |
michael@0 | 956 | break; |
michael@0 | 957 | case EOpMulAssign: |
michael@0 | 958 | if (!left->isMatrix() && right->isMatrix()) { |
michael@0 | 959 | if (left->isVector()) |
michael@0 | 960 | op = EOpVectorTimesMatrixAssign; |
michael@0 | 961 | else { |
michael@0 | 962 | return false; |
michael@0 | 963 | } |
michael@0 | 964 | } else if (left->isMatrix() && !right->isMatrix()) { |
michael@0 | 965 | if (right->isVector()) { |
michael@0 | 966 | return false; |
michael@0 | 967 | } else { |
michael@0 | 968 | op = EOpMatrixTimesScalarAssign; |
michael@0 | 969 | } |
michael@0 | 970 | } else if (left->isMatrix() && right->isMatrix()) { |
michael@0 | 971 | op = EOpMatrixTimesMatrixAssign; |
michael@0 | 972 | } else if (!left->isMatrix() && !right->isMatrix()) { |
michael@0 | 973 | if (left->isVector() && right->isVector()) { |
michael@0 | 974 | // leave as component product |
michael@0 | 975 | } else if (left->isVector() || right->isVector()) { |
michael@0 | 976 | if (! left->isVector()) |
michael@0 | 977 | return false; |
michael@0 | 978 | op = EOpVectorTimesScalarAssign; |
michael@0 | 979 | setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); |
michael@0 | 980 | } |
michael@0 | 981 | } else { |
michael@0 | 982 | infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); |
michael@0 | 983 | return false; |
michael@0 | 984 | } |
michael@0 | 985 | break; |
michael@0 | 986 | |
michael@0 | 987 | case EOpAssign: |
michael@0 | 988 | case EOpInitialize: |
michael@0 | 989 | case EOpAdd: |
michael@0 | 990 | case EOpSub: |
michael@0 | 991 | case EOpDiv: |
michael@0 | 992 | case EOpAddAssign: |
michael@0 | 993 | case EOpSubAssign: |
michael@0 | 994 | case EOpDivAssign: |
michael@0 | 995 | if ((left->isMatrix() && right->isVector()) || |
michael@0 | 996 | (left->isVector() && right->isMatrix())) |
michael@0 | 997 | return false; |
michael@0 | 998 | setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); |
michael@0 | 999 | break; |
michael@0 | 1000 | |
michael@0 | 1001 | case EOpEqual: |
michael@0 | 1002 | case EOpNotEqual: |
michael@0 | 1003 | case EOpLessThan: |
michael@0 | 1004 | case EOpGreaterThan: |
michael@0 | 1005 | case EOpLessThanEqual: |
michael@0 | 1006 | case EOpGreaterThanEqual: |
michael@0 | 1007 | if ((left->isMatrix() && right->isVector()) || |
michael@0 | 1008 | (left->isVector() && right->isMatrix())) |
michael@0 | 1009 | return false; |
michael@0 | 1010 | setType(TType(EbtBool, EbpUndefined)); |
michael@0 | 1011 | break; |
michael@0 | 1012 | |
michael@0 | 1013 | default: |
michael@0 | 1014 | return false; |
michael@0 | 1015 | } |
michael@0 | 1016 | |
michael@0 | 1017 | return true; |
michael@0 | 1018 | } |
michael@0 | 1019 | |
michael@0 | 1020 | bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) |
michael@0 | 1021 | { |
michael@0 | 1022 | const TFieldList& fields = leftNodeType.getStruct()->fields(); |
michael@0 | 1023 | |
michael@0 | 1024 | size_t structSize = fields.size(); |
michael@0 | 1025 | size_t index = 0; |
michael@0 | 1026 | |
michael@0 | 1027 | for (size_t j = 0; j < structSize; j++) { |
michael@0 | 1028 | size_t size = fields[j]->type()->getObjectSize(); |
michael@0 | 1029 | for (size_t i = 0; i < size; i++) { |
michael@0 | 1030 | if (fields[j]->type()->getBasicType() == EbtStruct) { |
michael@0 | 1031 | if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index])) |
michael@0 | 1032 | return false; |
michael@0 | 1033 | } else { |
michael@0 | 1034 | if (leftUnionArray[index] != rightUnionArray[index]) |
michael@0 | 1035 | return false; |
michael@0 | 1036 | index++; |
michael@0 | 1037 | } |
michael@0 | 1038 | } |
michael@0 | 1039 | } |
michael@0 | 1040 | return true; |
michael@0 | 1041 | } |
michael@0 | 1042 | |
michael@0 | 1043 | bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) |
michael@0 | 1044 | { |
michael@0 | 1045 | if (leftNodeType.isArray()) { |
michael@0 | 1046 | TType typeWithoutArrayness = leftNodeType; |
michael@0 | 1047 | typeWithoutArrayness.clearArrayness(); |
michael@0 | 1048 | |
michael@0 | 1049 | size_t arraySize = leftNodeType.getArraySize(); |
michael@0 | 1050 | |
michael@0 | 1051 | for (size_t i = 0; i < arraySize; ++i) { |
michael@0 | 1052 | size_t offset = typeWithoutArrayness.getObjectSize() * i; |
michael@0 | 1053 | if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) |
michael@0 | 1054 | return false; |
michael@0 | 1055 | } |
michael@0 | 1056 | } else |
michael@0 | 1057 | return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); |
michael@0 | 1058 | |
michael@0 | 1059 | return true; |
michael@0 | 1060 | } |
michael@0 | 1061 | |
michael@0 | 1062 | // |
michael@0 | 1063 | // The fold functions see if an operation on a constant can be done in place, |
michael@0 | 1064 | // without generating run-time code. |
michael@0 | 1065 | // |
michael@0 | 1066 | // Returns the node to keep using, which may or may not be the node passed in. |
michael@0 | 1067 | // |
michael@0 | 1068 | |
michael@0 | 1069 | TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) |
michael@0 | 1070 | { |
michael@0 | 1071 | ConstantUnion *unionArray = getUnionArrayPointer(); |
michael@0 | 1072 | size_t objectSize = getType().getObjectSize(); |
michael@0 | 1073 | |
michael@0 | 1074 | if (constantNode) { // binary operations |
michael@0 | 1075 | TIntermConstantUnion *node = constantNode->getAsConstantUnion(); |
michael@0 | 1076 | ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); |
michael@0 | 1077 | TType returnType = getType(); |
michael@0 | 1078 | |
michael@0 | 1079 | // for a case like float f = 1.2 + vec4(2,3,4,5); |
michael@0 | 1080 | if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { |
michael@0 | 1081 | rightUnionArray = new ConstantUnion[objectSize]; |
michael@0 | 1082 | for (size_t i = 0; i < objectSize; ++i) |
michael@0 | 1083 | rightUnionArray[i] = *node->getUnionArrayPointer(); |
michael@0 | 1084 | returnType = getType(); |
michael@0 | 1085 | } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { |
michael@0 | 1086 | // for a case like float f = vec4(2,3,4,5) + 1.2; |
michael@0 | 1087 | unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; |
michael@0 | 1088 | for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) |
michael@0 | 1089 | unionArray[i] = *getUnionArrayPointer(); |
michael@0 | 1090 | returnType = node->getType(); |
michael@0 | 1091 | objectSize = constantNode->getType().getObjectSize(); |
michael@0 | 1092 | } |
michael@0 | 1093 | |
michael@0 | 1094 | ConstantUnion* tempConstArray = 0; |
michael@0 | 1095 | TIntermConstantUnion *tempNode; |
michael@0 | 1096 | |
michael@0 | 1097 | bool boolNodeFlag = false; |
michael@0 | 1098 | switch(op) { |
michael@0 | 1099 | case EOpAdd: |
michael@0 | 1100 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1101 | {// support MSVC++6.0 |
michael@0 | 1102 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1103 | tempConstArray[i] = unionArray[i] + rightUnionArray[i]; |
michael@0 | 1104 | } |
michael@0 | 1105 | break; |
michael@0 | 1106 | case EOpSub: |
michael@0 | 1107 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1108 | {// support MSVC++6.0 |
michael@0 | 1109 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1110 | tempConstArray[i] = unionArray[i] - rightUnionArray[i]; |
michael@0 | 1111 | } |
michael@0 | 1112 | break; |
michael@0 | 1113 | |
michael@0 | 1114 | case EOpMul: |
michael@0 | 1115 | case EOpVectorTimesScalar: |
michael@0 | 1116 | case EOpMatrixTimesScalar: |
michael@0 | 1117 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1118 | {// support MSVC++6.0 |
michael@0 | 1119 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1120 | tempConstArray[i] = unionArray[i] * rightUnionArray[i]; |
michael@0 | 1121 | } |
michael@0 | 1122 | break; |
michael@0 | 1123 | case EOpMatrixTimesMatrix: |
michael@0 | 1124 | if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { |
michael@0 | 1125 | infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); |
michael@0 | 1126 | return 0; |
michael@0 | 1127 | } |
michael@0 | 1128 | {// support MSVC++6.0 |
michael@0 | 1129 | int size = getNominalSize(); |
michael@0 | 1130 | tempConstArray = new ConstantUnion[size*size]; |
michael@0 | 1131 | for (int row = 0; row < size; row++) { |
michael@0 | 1132 | for (int column = 0; column < size; column++) { |
michael@0 | 1133 | tempConstArray[size * column + row].setFConst(0.0f); |
michael@0 | 1134 | for (int i = 0; i < size; i++) { |
michael@0 | 1135 | tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); |
michael@0 | 1136 | } |
michael@0 | 1137 | } |
michael@0 | 1138 | } |
michael@0 | 1139 | } |
michael@0 | 1140 | break; |
michael@0 | 1141 | case EOpDiv: |
michael@0 | 1142 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1143 | {// support MSVC++6.0 |
michael@0 | 1144 | for (size_t i = 0; i < objectSize; i++) { |
michael@0 | 1145 | switch (getType().getBasicType()) { |
michael@0 | 1146 | case EbtFloat: |
michael@0 | 1147 | if (rightUnionArray[i] == 0.0f) { |
michael@0 | 1148 | infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); |
michael@0 | 1149 | tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); |
michael@0 | 1150 | } else |
michael@0 | 1151 | tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); |
michael@0 | 1152 | break; |
michael@0 | 1153 | |
michael@0 | 1154 | case EbtInt: |
michael@0 | 1155 | if (rightUnionArray[i] == 0) { |
michael@0 | 1156 | infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); |
michael@0 | 1157 | tempConstArray[i].setIConst(INT_MAX); |
michael@0 | 1158 | } else |
michael@0 | 1159 | tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); |
michael@0 | 1160 | break; |
michael@0 | 1161 | default: |
michael@0 | 1162 | infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); |
michael@0 | 1163 | return 0; |
michael@0 | 1164 | } |
michael@0 | 1165 | } |
michael@0 | 1166 | } |
michael@0 | 1167 | break; |
michael@0 | 1168 | |
michael@0 | 1169 | case EOpMatrixTimesVector: |
michael@0 | 1170 | if (node->getBasicType() != EbtFloat) { |
michael@0 | 1171 | infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); |
michael@0 | 1172 | return 0; |
michael@0 | 1173 | } |
michael@0 | 1174 | tempConstArray = new ConstantUnion[getNominalSize()]; |
michael@0 | 1175 | |
michael@0 | 1176 | {// support MSVC++6.0 |
michael@0 | 1177 | for (int size = getNominalSize(), i = 0; i < size; i++) { |
michael@0 | 1178 | tempConstArray[i].setFConst(0.0f); |
michael@0 | 1179 | for (int j = 0; j < size; j++) { |
michael@0 | 1180 | tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); |
michael@0 | 1181 | } |
michael@0 | 1182 | } |
michael@0 | 1183 | } |
michael@0 | 1184 | |
michael@0 | 1185 | tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); |
michael@0 | 1186 | tempNode->setLine(getLine()); |
michael@0 | 1187 | |
michael@0 | 1188 | return tempNode; |
michael@0 | 1189 | |
michael@0 | 1190 | case EOpVectorTimesMatrix: |
michael@0 | 1191 | if (getType().getBasicType() != EbtFloat) { |
michael@0 | 1192 | infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); |
michael@0 | 1193 | return 0; |
michael@0 | 1194 | } |
michael@0 | 1195 | |
michael@0 | 1196 | tempConstArray = new ConstantUnion[getNominalSize()]; |
michael@0 | 1197 | {// support MSVC++6.0 |
michael@0 | 1198 | for (int size = getNominalSize(), i = 0; i < size; i++) { |
michael@0 | 1199 | tempConstArray[i].setFConst(0.0f); |
michael@0 | 1200 | for (int j = 0; j < size; j++) { |
michael@0 | 1201 | tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); |
michael@0 | 1202 | } |
michael@0 | 1203 | } |
michael@0 | 1204 | } |
michael@0 | 1205 | break; |
michael@0 | 1206 | |
michael@0 | 1207 | case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently |
michael@0 | 1208 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1209 | {// support MSVC++6.0 |
michael@0 | 1210 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1211 | tempConstArray[i] = unionArray[i] && rightUnionArray[i]; |
michael@0 | 1212 | } |
michael@0 | 1213 | break; |
michael@0 | 1214 | |
michael@0 | 1215 | case EOpLogicalOr: // this code is written for possible future use, will not get executed currently |
michael@0 | 1216 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1217 | {// support MSVC++6.0 |
michael@0 | 1218 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1219 | tempConstArray[i] = unionArray[i] || rightUnionArray[i]; |
michael@0 | 1220 | } |
michael@0 | 1221 | break; |
michael@0 | 1222 | |
michael@0 | 1223 | case EOpLogicalXor: |
michael@0 | 1224 | tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1225 | {// support MSVC++6.0 |
michael@0 | 1226 | for (size_t i = 0; i < objectSize; i++) |
michael@0 | 1227 | switch (getType().getBasicType()) { |
michael@0 | 1228 | case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; |
michael@0 | 1229 | default: assert(false && "Default missing"); |
michael@0 | 1230 | } |
michael@0 | 1231 | } |
michael@0 | 1232 | break; |
michael@0 | 1233 | |
michael@0 | 1234 | case EOpLessThan: |
michael@0 | 1235 | assert(objectSize == 1); |
michael@0 | 1236 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1237 | tempConstArray->setBConst(*unionArray < *rightUnionArray); |
michael@0 | 1238 | returnType = TType(EbtBool, EbpUndefined, EvqConst); |
michael@0 | 1239 | break; |
michael@0 | 1240 | case EOpGreaterThan: |
michael@0 | 1241 | assert(objectSize == 1); |
michael@0 | 1242 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1243 | tempConstArray->setBConst(*unionArray > *rightUnionArray); |
michael@0 | 1244 | returnType = TType(EbtBool, EbpUndefined, EvqConst); |
michael@0 | 1245 | break; |
michael@0 | 1246 | case EOpLessThanEqual: |
michael@0 | 1247 | { |
michael@0 | 1248 | assert(objectSize == 1); |
michael@0 | 1249 | ConstantUnion constant; |
michael@0 | 1250 | constant.setBConst(*unionArray > *rightUnionArray); |
michael@0 | 1251 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1252 | tempConstArray->setBConst(!constant.getBConst()); |
michael@0 | 1253 | returnType = TType(EbtBool, EbpUndefined, EvqConst); |
michael@0 | 1254 | break; |
michael@0 | 1255 | } |
michael@0 | 1256 | case EOpGreaterThanEqual: |
michael@0 | 1257 | { |
michael@0 | 1258 | assert(objectSize == 1); |
michael@0 | 1259 | ConstantUnion constant; |
michael@0 | 1260 | constant.setBConst(*unionArray < *rightUnionArray); |
michael@0 | 1261 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1262 | tempConstArray->setBConst(!constant.getBConst()); |
michael@0 | 1263 | returnType = TType(EbtBool, EbpUndefined, EvqConst); |
michael@0 | 1264 | break; |
michael@0 | 1265 | } |
michael@0 | 1266 | |
michael@0 | 1267 | case EOpEqual: |
michael@0 | 1268 | if (getType().getBasicType() == EbtStruct) { |
michael@0 | 1269 | if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) |
michael@0 | 1270 | boolNodeFlag = true; |
michael@0 | 1271 | } else { |
michael@0 | 1272 | for (size_t i = 0; i < objectSize; i++) { |
michael@0 | 1273 | if (unionArray[i] != rightUnionArray[i]) { |
michael@0 | 1274 | boolNodeFlag = true; |
michael@0 | 1275 | break; // break out of for loop |
michael@0 | 1276 | } |
michael@0 | 1277 | } |
michael@0 | 1278 | } |
michael@0 | 1279 | |
michael@0 | 1280 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1281 | if (!boolNodeFlag) { |
michael@0 | 1282 | tempConstArray->setBConst(true); |
michael@0 | 1283 | } |
michael@0 | 1284 | else { |
michael@0 | 1285 | tempConstArray->setBConst(false); |
michael@0 | 1286 | } |
michael@0 | 1287 | |
michael@0 | 1288 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); |
michael@0 | 1289 | tempNode->setLine(getLine()); |
michael@0 | 1290 | |
michael@0 | 1291 | return tempNode; |
michael@0 | 1292 | |
michael@0 | 1293 | case EOpNotEqual: |
michael@0 | 1294 | if (getType().getBasicType() == EbtStruct) { |
michael@0 | 1295 | if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) |
michael@0 | 1296 | boolNodeFlag = true; |
michael@0 | 1297 | } else { |
michael@0 | 1298 | for (size_t i = 0; i < objectSize; i++) { |
michael@0 | 1299 | if (unionArray[i] == rightUnionArray[i]) { |
michael@0 | 1300 | boolNodeFlag = true; |
michael@0 | 1301 | break; // break out of for loop |
michael@0 | 1302 | } |
michael@0 | 1303 | } |
michael@0 | 1304 | } |
michael@0 | 1305 | |
michael@0 | 1306 | tempConstArray = new ConstantUnion[1]; |
michael@0 | 1307 | if (!boolNodeFlag) { |
michael@0 | 1308 | tempConstArray->setBConst(true); |
michael@0 | 1309 | } |
michael@0 | 1310 | else { |
michael@0 | 1311 | tempConstArray->setBConst(false); |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); |
michael@0 | 1315 | tempNode->setLine(getLine()); |
michael@0 | 1316 | |
michael@0 | 1317 | return tempNode; |
michael@0 | 1318 | |
michael@0 | 1319 | default: |
michael@0 | 1320 | infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding"); |
michael@0 | 1321 | return 0; |
michael@0 | 1322 | } |
michael@0 | 1323 | tempNode = new TIntermConstantUnion(tempConstArray, returnType); |
michael@0 | 1324 | tempNode->setLine(getLine()); |
michael@0 | 1325 | |
michael@0 | 1326 | return tempNode; |
michael@0 | 1327 | } else { |
michael@0 | 1328 | // |
michael@0 | 1329 | // Do unary operations |
michael@0 | 1330 | // |
michael@0 | 1331 | TIntermConstantUnion *newNode = 0; |
michael@0 | 1332 | ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; |
michael@0 | 1333 | for (size_t i = 0; i < objectSize; i++) { |
michael@0 | 1334 | switch(op) { |
michael@0 | 1335 | case EOpNegative: |
michael@0 | 1336 | switch (getType().getBasicType()) { |
michael@0 | 1337 | case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; |
michael@0 | 1338 | case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; |
michael@0 | 1339 | default: |
michael@0 | 1340 | infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); |
michael@0 | 1341 | return 0; |
michael@0 | 1342 | } |
michael@0 | 1343 | break; |
michael@0 | 1344 | case EOpLogicalNot: // this code is written for possible future use, will not get executed currently |
michael@0 | 1345 | switch (getType().getBasicType()) { |
michael@0 | 1346 | case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; |
michael@0 | 1347 | default: |
michael@0 | 1348 | infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); |
michael@0 | 1349 | return 0; |
michael@0 | 1350 | } |
michael@0 | 1351 | break; |
michael@0 | 1352 | default: |
michael@0 | 1353 | return 0; |
michael@0 | 1354 | } |
michael@0 | 1355 | } |
michael@0 | 1356 | newNode = new TIntermConstantUnion(tempConstArray, getType()); |
michael@0 | 1357 | newNode->setLine(getLine()); |
michael@0 | 1358 | return newNode; |
michael@0 | 1359 | } |
michael@0 | 1360 | } |
michael@0 | 1361 | |
michael@0 | 1362 | TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) |
michael@0 | 1363 | { |
michael@0 | 1364 | size_t size = node->getType().getObjectSize(); |
michael@0 | 1365 | |
michael@0 | 1366 | ConstantUnion *leftUnionArray = new ConstantUnion[size]; |
michael@0 | 1367 | |
michael@0 | 1368 | for (size_t i = 0; i < size; i++) { |
michael@0 | 1369 | |
michael@0 | 1370 | switch (promoteTo) { |
michael@0 | 1371 | case EbtFloat: |
michael@0 | 1372 | switch (node->getType().getBasicType()) { |
michael@0 | 1373 | case EbtInt: |
michael@0 | 1374 | leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i))); |
michael@0 | 1375 | break; |
michael@0 | 1376 | case EbtBool: |
michael@0 | 1377 | leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i))); |
michael@0 | 1378 | break; |
michael@0 | 1379 | case EbtFloat: |
michael@0 | 1380 | leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i))); |
michael@0 | 1381 | break; |
michael@0 | 1382 | default: |
michael@0 | 1383 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); |
michael@0 | 1384 | return 0; |
michael@0 | 1385 | } |
michael@0 | 1386 | break; |
michael@0 | 1387 | case EbtInt: |
michael@0 | 1388 | switch (node->getType().getBasicType()) { |
michael@0 | 1389 | case EbtInt: |
michael@0 | 1390 | leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i))); |
michael@0 | 1391 | break; |
michael@0 | 1392 | case EbtBool: |
michael@0 | 1393 | leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i))); |
michael@0 | 1394 | break; |
michael@0 | 1395 | case EbtFloat: |
michael@0 | 1396 | leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i))); |
michael@0 | 1397 | break; |
michael@0 | 1398 | default: |
michael@0 | 1399 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); |
michael@0 | 1400 | return 0; |
michael@0 | 1401 | } |
michael@0 | 1402 | break; |
michael@0 | 1403 | case EbtBool: |
michael@0 | 1404 | switch (node->getType().getBasicType()) { |
michael@0 | 1405 | case EbtInt: |
michael@0 | 1406 | leftUnionArray[i].setBConst(node->getIConst(i) != 0); |
michael@0 | 1407 | break; |
michael@0 | 1408 | case EbtBool: |
michael@0 | 1409 | leftUnionArray[i].setBConst(node->getBConst(i)); |
michael@0 | 1410 | break; |
michael@0 | 1411 | case EbtFloat: |
michael@0 | 1412 | leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); |
michael@0 | 1413 | break; |
michael@0 | 1414 | default: |
michael@0 | 1415 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); |
michael@0 | 1416 | return 0; |
michael@0 | 1417 | } |
michael@0 | 1418 | |
michael@0 | 1419 | break; |
michael@0 | 1420 | default: |
michael@0 | 1421 | infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found"); |
michael@0 | 1422 | return 0; |
michael@0 | 1423 | } |
michael@0 | 1424 | |
michael@0 | 1425 | } |
michael@0 | 1426 | |
michael@0 | 1427 | const TType& t = node->getType(); |
michael@0 | 1428 | |
michael@0 | 1429 | return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); |
michael@0 | 1430 | } |
michael@0 | 1431 | |
michael@0 | 1432 | // static |
michael@0 | 1433 | TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction) |
michael@0 | 1434 | { |
michael@0 | 1435 | if (hashFunction == NULL || name.empty()) |
michael@0 | 1436 | return name; |
michael@0 | 1437 | khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); |
michael@0 | 1438 | TStringStream stream; |
michael@0 | 1439 | stream << HASHED_NAME_PREFIX << std::hex << number; |
michael@0 | 1440 | TString hashedName = stream.str(); |
michael@0 | 1441 | return hashedName; |
michael@0 | 1442 | } |