ConstantUnion.cpp (23419B)
1 // 2 // Copyright 2016 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // ConstantUnion: Constant folding helper class. 7 8 #include "compiler/translator/ConstantUnion.h" 9 10 #include "common/mathutil.h" 11 #include "compiler/translator/Diagnostics.h" 12 #include "compiler/translator/util.h" 13 14 namespace sh 15 { 16 17 namespace 18 { 19 20 float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) 21 { 22 float result = lhs + rhs; 23 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) 24 { 25 diag->warning(line, "Constant folded undefined addition generated NaN", "+"); 26 } 27 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) 28 { 29 diag->warning(line, "Constant folded addition overflowed to infinity", "+"); 30 } 31 return result; 32 } 33 34 float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) 35 { 36 float result = lhs - rhs; 37 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) 38 { 39 diag->warning(line, "Constant folded undefined subtraction generated NaN", "-"); 40 } 41 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) 42 { 43 diag->warning(line, "Constant folded subtraction overflowed to infinity", "-"); 44 } 45 return result; 46 } 47 48 float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) 49 { 50 float result = lhs * rhs; 51 if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) 52 { 53 diag->warning(line, "Constant folded undefined multiplication generated NaN", "*"); 54 } 55 else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) 56 { 57 diag->warning(line, "Constant folded multiplication overflowed to infinity", "*"); 58 } 59 return result; 60 } 61 62 bool IsValidShiftOffset(const TConstantUnion &rhs) 63 { 64 return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) || 65 (rhs.getType() == EbtUInt && rhs.getUConst() <= 31u); 66 } 67 68 } // anonymous namespace 69 70 TConstantUnion::TConstantUnion() : iConst(0), type(EbtVoid) {} 71 72 TConstantUnion::TConstantUnion(int i) : iConst(i), type(EbtInt) {} 73 74 TConstantUnion::TConstantUnion(unsigned int u) : uConst(u), type(EbtUInt) {} 75 76 TConstantUnion::TConstantUnion(float f) : fConst(f), type(EbtFloat) {} 77 78 TConstantUnion::TConstantUnion(bool b) : bConst(b), type(EbtBool) {} 79 80 int TConstantUnion::getIConst() const 81 { 82 ASSERT(type == EbtInt); 83 return iConst; 84 } 85 86 unsigned int TConstantUnion::getUConst() const 87 { 88 ASSERT(type == EbtUInt); 89 return uConst; 90 } 91 92 float TConstantUnion::getFConst() const 93 { 94 switch (type) 95 { 96 case EbtInt: 97 return static_cast<float>(iConst); 98 case EbtUInt: 99 return static_cast<float>(uConst); 100 default: 101 ASSERT(type == EbtFloat); 102 return fConst; 103 } 104 } 105 106 bool TConstantUnion::getBConst() const 107 { 108 ASSERT(type == EbtBool); 109 return bConst; 110 } 111 112 bool TConstantUnion::isZero() const 113 { 114 switch (type) 115 { 116 case EbtInt: 117 return getIConst() == 0; 118 case EbtUInt: 119 return getUConst() == 0; 120 case EbtFloat: 121 return getFConst() == 0.0f; 122 case EbtBool: 123 return getBConst() == false; 124 default: 125 return false; 126 } 127 } 128 129 TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const 130 { 131 ASSERT(type == EbtYuvCscStandardEXT); 132 return yuvCscStandardEXTConst; 133 } 134 135 bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant) 136 { 137 switch (newType) 138 { 139 case EbtFloat: 140 switch (constant.type) 141 { 142 case EbtInt: 143 setFConst(static_cast<float>(constant.getIConst())); 144 break; 145 case EbtUInt: 146 setFConst(static_cast<float>(constant.getUConst())); 147 break; 148 case EbtBool: 149 setFConst(static_cast<float>(constant.getBConst())); 150 break; 151 case EbtFloat: 152 setFConst(static_cast<float>(constant.getFConst())); 153 break; 154 default: 155 return false; 156 } 157 break; 158 case EbtInt: 159 switch (constant.type) 160 { 161 case EbtInt: 162 setIConst(static_cast<int>(constant.getIConst())); 163 break; 164 case EbtUInt: 165 setIConst(static_cast<int>(constant.getUConst())); 166 break; 167 case EbtBool: 168 setIConst(static_cast<int>(constant.getBConst())); 169 break; 170 case EbtFloat: 171 setIConst(static_cast<int>(constant.getFConst())); 172 break; 173 default: 174 return false; 175 } 176 break; 177 case EbtUInt: 178 switch (constant.type) 179 { 180 case EbtInt: 181 setUConst(static_cast<unsigned int>(constant.getIConst())); 182 break; 183 case EbtUInt: 184 setUConst(static_cast<unsigned int>(constant.getUConst())); 185 break; 186 case EbtBool: 187 setUConst(static_cast<unsigned int>(constant.getBConst())); 188 break; 189 case EbtFloat: 190 if (constant.getFConst() < 0.0f) 191 { 192 // Avoid undefined behavior in C++ by first casting to signed int. 193 setUConst( 194 static_cast<unsigned int>(static_cast<int>(constant.getFConst()))); 195 } 196 else 197 { 198 setUConst(static_cast<unsigned int>(constant.getFConst())); 199 } 200 break; 201 default: 202 return false; 203 } 204 break; 205 case EbtBool: 206 switch (constant.type) 207 { 208 case EbtInt: 209 setBConst(constant.getIConst() != 0); 210 break; 211 case EbtUInt: 212 setBConst(constant.getUConst() != 0); 213 break; 214 case EbtBool: 215 setBConst(constant.getBConst()); 216 break; 217 case EbtFloat: 218 setBConst(constant.getFConst() != 0.0f); 219 break; 220 default: 221 return false; 222 } 223 break; 224 case EbtStruct: // Struct fields don't get cast 225 switch (constant.type) 226 { 227 case EbtInt: 228 setIConst(constant.getIConst()); 229 break; 230 case EbtUInt: 231 setUConst(constant.getUConst()); 232 break; 233 case EbtBool: 234 setBConst(constant.getBConst()); 235 break; 236 case EbtFloat: 237 setFConst(constant.getFConst()); 238 break; 239 default: 240 return false; 241 } 242 break; 243 case EbtYuvCscStandardEXT: 244 switch (constant.type) 245 { 246 case EbtYuvCscStandardEXT: 247 setYuvCscStandardEXTConst(constant.getYuvCscStandardEXTConst()); 248 break; 249 default: 250 return false; 251 } 252 break; 253 default: 254 return false; 255 } 256 257 return true; 258 } 259 260 bool TConstantUnion::operator==(const int i) const 261 { 262 switch (type) 263 { 264 case EbtFloat: 265 return static_cast<float>(i) == fConst; 266 default: 267 return i == iConst; 268 } 269 } 270 271 bool TConstantUnion::operator==(const unsigned int u) const 272 { 273 switch (type) 274 { 275 case EbtFloat: 276 return static_cast<float>(u) == fConst; 277 default: 278 return u == uConst; 279 } 280 } 281 282 bool TConstantUnion::operator==(const float f) const 283 { 284 switch (type) 285 { 286 case EbtInt: 287 return f == static_cast<float>(iConst); 288 case EbtUInt: 289 return f == static_cast<float>(uConst); 290 default: 291 return f == fConst; 292 } 293 } 294 295 bool TConstantUnion::operator==(const bool b) const 296 { 297 return b == bConst; 298 } 299 300 bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const 301 { 302 return s == yuvCscStandardEXTConst; 303 } 304 305 bool TConstantUnion::operator==(const TConstantUnion &constant) const 306 { 307 ImplicitTypeConversion conversion = GetConversion(constant.type, type); 308 if (conversion == ImplicitTypeConversion::Same) 309 { 310 switch (type) 311 { 312 case EbtInt: 313 return constant.iConst == iConst; 314 case EbtUInt: 315 return constant.uConst == uConst; 316 case EbtFloat: 317 return constant.fConst == fConst; 318 case EbtBool: 319 return constant.bConst == bConst; 320 case EbtYuvCscStandardEXT: 321 return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst; 322 default: 323 return false; 324 } 325 } 326 else if (conversion == ImplicitTypeConversion::Invalid) 327 { 328 return false; 329 } 330 else 331 { 332 return constant.getFConst() == getFConst(); 333 } 334 } 335 336 bool TConstantUnion::operator!=(const int i) const 337 { 338 return !operator==(i); 339 } 340 341 bool TConstantUnion::operator!=(const unsigned int u) const 342 { 343 return !operator==(u); 344 } 345 346 bool TConstantUnion::operator!=(const float f) const 347 { 348 return !operator==(f); 349 } 350 351 bool TConstantUnion::operator!=(const bool b) const 352 { 353 return !operator==(b); 354 } 355 356 bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const 357 { 358 return !operator==(s); 359 } 360 361 bool TConstantUnion::operator!=(const TConstantUnion &constant) const 362 { 363 return !operator==(constant); 364 } 365 366 bool TConstantUnion::operator>(const TConstantUnion &constant) const 367 { 368 369 ImplicitTypeConversion conversion = GetConversion(constant.type, type); 370 if (conversion == ImplicitTypeConversion::Same) 371 { 372 switch (type) 373 { 374 case EbtInt: 375 return iConst > constant.iConst; 376 case EbtUInt: 377 return uConst > constant.uConst; 378 case EbtFloat: 379 return fConst > constant.fConst; 380 default: 381 return false; // Invalid operation, handled at semantic analysis 382 } 383 } 384 else 385 { 386 ASSERT(conversion != ImplicitTypeConversion::Invalid); 387 return getFConst() > constant.getFConst(); 388 } 389 } 390 391 bool TConstantUnion::operator<(const TConstantUnion &constant) const 392 { 393 ImplicitTypeConversion conversion = GetConversion(constant.type, type); 394 if (conversion == ImplicitTypeConversion::Same) 395 { 396 switch (type) 397 { 398 case EbtInt: 399 return iConst < constant.iConst; 400 case EbtUInt: 401 return uConst < constant.uConst; 402 case EbtFloat: 403 return fConst < constant.fConst; 404 default: 405 return false; // Invalid operation, handled at semantic analysis 406 } 407 } 408 else 409 { 410 ASSERT(conversion != ImplicitTypeConversion::Invalid); 411 return getFConst() < constant.getFConst(); 412 } 413 } 414 415 // static 416 TConstantUnion TConstantUnion::add(const TConstantUnion &lhs, 417 const TConstantUnion &rhs, 418 TDiagnostics *diag, 419 const TSourceLoc &line) 420 { 421 TConstantUnion returnValue; 422 423 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); 424 if (conversion == ImplicitTypeConversion::Same) 425 { 426 switch (lhs.type) 427 { 428 case EbtInt: 429 returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst)); 430 break; 431 case EbtUInt: 432 returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst)); 433 break; 434 case EbtFloat: 435 returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line)); 436 break; 437 default: 438 UNREACHABLE(); 439 } 440 } 441 else 442 { 443 ASSERT(conversion != ImplicitTypeConversion::Invalid); 444 returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line)); 445 } 446 447 return returnValue; 448 } 449 450 // static 451 TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs, 452 const TConstantUnion &rhs, 453 TDiagnostics *diag, 454 const TSourceLoc &line) 455 { 456 TConstantUnion returnValue; 457 458 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); 459 if (conversion == ImplicitTypeConversion::Same) 460 { 461 switch (lhs.type) 462 { 463 case EbtInt: 464 returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst)); 465 break; 466 case EbtUInt: 467 returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst)); 468 break; 469 case EbtFloat: 470 returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line)); 471 break; 472 default: 473 UNREACHABLE(); 474 } 475 } 476 else 477 { 478 ASSERT(conversion != ImplicitTypeConversion::Invalid); 479 returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line)); 480 } 481 482 return returnValue; 483 } 484 485 // static 486 TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs, 487 const TConstantUnion &rhs, 488 TDiagnostics *diag, 489 const TSourceLoc &line) 490 { 491 TConstantUnion returnValue; 492 493 ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); 494 if (conversion == ImplicitTypeConversion::Same) 495 { 496 switch (lhs.type) 497 { 498 case EbtInt: 499 returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst)); 500 break; 501 case EbtUInt: 502 // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely 503 // on that to implement wrapping multiplication. 504 returnValue.setUConst(lhs.uConst * rhs.uConst); 505 break; 506 case EbtFloat: 507 returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line)); 508 break; 509 default: 510 UNREACHABLE(); 511 } 512 } 513 else 514 { 515 ASSERT(conversion != ImplicitTypeConversion::Invalid); 516 returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line)); 517 } 518 519 return returnValue; 520 } 521 522 TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const 523 { 524 TConstantUnion returnValue; 525 ASSERT(type == constant.type); 526 switch (type) 527 { 528 case EbtInt: 529 returnValue.setIConst(iConst % constant.iConst); 530 break; 531 case EbtUInt: 532 returnValue.setUConst(uConst % constant.uConst); 533 break; 534 default: 535 UNREACHABLE(); 536 } 537 538 return returnValue; 539 } 540 541 // static 542 TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs, 543 const TConstantUnion &rhs, 544 TDiagnostics *diag, 545 const TSourceLoc &line) 546 { 547 TConstantUnion returnValue; 548 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); 549 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); 550 if (!IsValidShiftOffset(rhs)) 551 { 552 diag->warning(line, "Undefined shift (operand out of range)", ">>"); 553 switch (lhs.type) 554 { 555 case EbtInt: 556 returnValue.setIConst(0); 557 break; 558 case EbtUInt: 559 returnValue.setUConst(0u); 560 break; 561 default: 562 UNREACHABLE(); 563 } 564 return returnValue; 565 } 566 567 switch (lhs.type) 568 { 569 case EbtInt: 570 { 571 unsigned int shiftOffset = 0; 572 switch (rhs.type) 573 { 574 case EbtInt: 575 shiftOffset = static_cast<unsigned int>(rhs.iConst); 576 break; 577 case EbtUInt: 578 shiftOffset = rhs.uConst; 579 break; 580 default: 581 UNREACHABLE(); 582 } 583 if (shiftOffset > 0) 584 { 585 // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend 586 // the sign bit." In C++ shifting negative integers is undefined, so we implement 587 // extending the sign bit manually. 588 int lhsSafe = lhs.iConst; 589 if (lhsSafe == std::numeric_limits<int>::min()) 590 { 591 // The min integer needs special treatment because only bit it has set is the 592 // sign bit, which we clear later to implement safe right shift of negative 593 // numbers. 594 lhsSafe = -0x40000000; 595 --shiftOffset; 596 } 597 if (shiftOffset > 0) 598 { 599 bool extendSignBit = false; 600 if (lhsSafe < 0) 601 { 602 extendSignBit = true; 603 // Clear the sign bit so that bitshift right is defined in C++. 604 lhsSafe &= 0x7fffffff; 605 ASSERT(lhsSafe > 0); 606 } 607 returnValue.setIConst(lhsSafe >> shiftOffset); 608 609 // Manually fill in the extended sign bit if necessary. 610 if (extendSignBit) 611 { 612 int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset)); 613 returnValue.setIConst(returnValue.getIConst() | extendedSignBit); 614 } 615 } 616 else 617 { 618 returnValue.setIConst(lhsSafe); 619 } 620 } 621 else 622 { 623 returnValue.setIConst(lhs.iConst); 624 } 625 break; 626 } 627 case EbtUInt: 628 switch (rhs.type) 629 { 630 case EbtInt: 631 returnValue.setUConst(lhs.uConst >> rhs.iConst); 632 break; 633 case EbtUInt: 634 returnValue.setUConst(lhs.uConst >> rhs.uConst); 635 break; 636 default: 637 UNREACHABLE(); 638 } 639 break; 640 641 default: 642 UNREACHABLE(); 643 } 644 return returnValue; 645 } 646 647 // static 648 TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs, 649 const TConstantUnion &rhs, 650 TDiagnostics *diag, 651 const TSourceLoc &line) 652 { 653 TConstantUnion returnValue; 654 ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); 655 ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); 656 if (!IsValidShiftOffset(rhs)) 657 { 658 diag->warning(line, "Undefined shift (operand out of range)", "<<"); 659 switch (lhs.type) 660 { 661 case EbtInt: 662 returnValue.setIConst(0); 663 break; 664 case EbtUInt: 665 returnValue.setUConst(0u); 666 break; 667 default: 668 UNREACHABLE(); 669 } 670 return returnValue; 671 } 672 673 switch (lhs.type) 674 { 675 case EbtInt: 676 switch (rhs.type) 677 { 678 // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that 679 // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed 680 // integer overflow or undefined shift of a negative integer. 681 case EbtInt: 682 returnValue.setIConst( 683 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst)); 684 break; 685 case EbtUInt: 686 returnValue.setIConst( 687 static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst)); 688 break; 689 default: 690 UNREACHABLE(); 691 } 692 break; 693 694 case EbtUInt: 695 switch (rhs.type) 696 { 697 case EbtInt: 698 returnValue.setUConst(lhs.uConst << rhs.iConst); 699 break; 700 case EbtUInt: 701 returnValue.setUConst(lhs.uConst << rhs.uConst); 702 break; 703 default: 704 UNREACHABLE(); 705 } 706 break; 707 708 default: 709 UNREACHABLE(); 710 } 711 return returnValue; 712 } 713 714 TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const 715 { 716 TConstantUnion returnValue; 717 ASSERT(constant.type == EbtInt || constant.type == EbtUInt); 718 switch (type) 719 { 720 case EbtInt: 721 returnValue.setIConst(iConst & constant.iConst); 722 break; 723 case EbtUInt: 724 returnValue.setUConst(uConst & constant.uConst); 725 break; 726 default: 727 UNREACHABLE(); 728 } 729 730 return returnValue; 731 } 732 733 TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const 734 { 735 TConstantUnion returnValue; 736 ASSERT(type == constant.type); 737 switch (type) 738 { 739 case EbtInt: 740 returnValue.setIConst(iConst | constant.iConst); 741 break; 742 case EbtUInt: 743 returnValue.setUConst(uConst | constant.uConst); 744 break; 745 default: 746 UNREACHABLE(); 747 } 748 749 return returnValue; 750 } 751 752 TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const 753 { 754 TConstantUnion returnValue; 755 ASSERT(type == constant.type); 756 switch (type) 757 { 758 case EbtInt: 759 returnValue.setIConst(iConst ^ constant.iConst); 760 break; 761 case EbtUInt: 762 returnValue.setUConst(uConst ^ constant.uConst); 763 break; 764 default: 765 UNREACHABLE(); 766 } 767 768 return returnValue; 769 } 770 771 TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const 772 { 773 TConstantUnion returnValue; 774 ASSERT(type == constant.type); 775 switch (type) 776 { 777 case EbtBool: 778 returnValue.setBConst(bConst && constant.bConst); 779 break; 780 default: 781 UNREACHABLE(); 782 } 783 784 return returnValue; 785 } 786 787 TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const 788 { 789 TConstantUnion returnValue; 790 ASSERT(type == constant.type); 791 switch (type) 792 { 793 case EbtBool: 794 returnValue.setBConst(bConst || constant.bConst); 795 break; 796 default: 797 UNREACHABLE(); 798 } 799 800 return returnValue; 801 } 802 803 } // namespace sh