Path: blob/main_old/src/compiler/translator/ConstantUnion.cpp
1693 views
//1// Copyright 2016 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// ConstantUnion: Constant folding helper class.67#include "compiler/translator/ConstantUnion.h"89#include "common/mathutil.h"10#include "compiler/translator/Diagnostics.h"11#include "compiler/translator/util.h"1213namespace sh14{1516namespace17{1819float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)20{21float result = lhs + rhs;22if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))23{24diag->warning(line, "Constant folded undefined addition generated NaN", "+");25}26else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))27{28diag->warning(line, "Constant folded addition overflowed to infinity", "+");29}30return result;31}3233float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)34{35float result = lhs - rhs;36if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))37{38diag->warning(line, "Constant folded undefined subtraction generated NaN", "-");39}40else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))41{42diag->warning(line, "Constant folded subtraction overflowed to infinity", "-");43}44return result;45}4647float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)48{49float result = lhs * rhs;50if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))51{52diag->warning(line, "Constant folded undefined multiplication generated NaN", "*");53}54else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))55{56diag->warning(line, "Constant folded multiplication overflowed to infinity", "*");57}58return result;59}6061bool IsValidShiftOffset(const TConstantUnion &rhs)62{63return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) ||64(rhs.getType() == EbtUInt && rhs.getUConst() <= 31u);65}6667} // anonymous namespace6869TConstantUnion::TConstantUnion() : iConst(0), type(EbtVoid) {}7071TConstantUnion::TConstantUnion(int i) : iConst(i), type(EbtInt) {}7273TConstantUnion::TConstantUnion(unsigned int u) : uConst(u), type(EbtUInt) {}7475TConstantUnion::TConstantUnion(float f) : fConst(f), type(EbtFloat) {}7677TConstantUnion::TConstantUnion(bool b) : bConst(b), type(EbtBool) {}7879int TConstantUnion::getIConst() const80{81ASSERT(type == EbtInt);82return iConst;83}8485unsigned int TConstantUnion::getUConst() const86{87ASSERT(type == EbtUInt);88return uConst;89}9091float TConstantUnion::getFConst() const92{93switch (type)94{95case EbtInt:96return static_cast<float>(iConst);97case EbtUInt:98return static_cast<float>(uConst);99default:100ASSERT(type == EbtFloat);101return fConst;102}103}104105bool TConstantUnion::getBConst() const106{107ASSERT(type == EbtBool);108return bConst;109}110111bool TConstantUnion::isZero() const112{113switch (type)114{115case EbtInt:116return getIConst() == 0;117case EbtUInt:118return getUConst() == 0;119case EbtFloat:120return getFConst() == 0.0f;121case EbtBool:122return getBConst() == false;123default:124return false;125}126}127128TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const129{130ASSERT(type == EbtYuvCscStandardEXT);131return yuvCscStandardEXTConst;132}133134bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)135{136switch (newType)137{138case EbtFloat:139switch (constant.type)140{141case EbtInt:142setFConst(static_cast<float>(constant.getIConst()));143break;144case EbtUInt:145setFConst(static_cast<float>(constant.getUConst()));146break;147case EbtBool:148setFConst(static_cast<float>(constant.getBConst()));149break;150case EbtFloat:151setFConst(static_cast<float>(constant.getFConst()));152break;153default:154return false;155}156break;157case EbtInt:158switch (constant.type)159{160case EbtInt:161setIConst(static_cast<int>(constant.getIConst()));162break;163case EbtUInt:164setIConst(static_cast<int>(constant.getUConst()));165break;166case EbtBool:167setIConst(static_cast<int>(constant.getBConst()));168break;169case EbtFloat:170setIConst(static_cast<int>(constant.getFConst()));171break;172default:173return false;174}175break;176case EbtUInt:177switch (constant.type)178{179case EbtInt:180setUConst(static_cast<unsigned int>(constant.getIConst()));181break;182case EbtUInt:183setUConst(static_cast<unsigned int>(constant.getUConst()));184break;185case EbtBool:186setUConst(static_cast<unsigned int>(constant.getBConst()));187break;188case EbtFloat:189if (constant.getFConst() < 0.0f)190{191// Avoid undefined behavior in C++ by first casting to signed int.192setUConst(193static_cast<unsigned int>(static_cast<int>(constant.getFConst())));194}195else196{197setUConst(static_cast<unsigned int>(constant.getFConst()));198}199break;200default:201return false;202}203break;204case EbtBool:205switch (constant.type)206{207case EbtInt:208setBConst(constant.getIConst() != 0);209break;210case EbtUInt:211setBConst(constant.getUConst() != 0);212break;213case EbtBool:214setBConst(constant.getBConst());215break;216case EbtFloat:217setBConst(constant.getFConst() != 0.0f);218break;219default:220return false;221}222break;223case EbtStruct: // Struct fields don't get cast224switch (constant.type)225{226case EbtInt:227setIConst(constant.getIConst());228break;229case EbtUInt:230setUConst(constant.getUConst());231break;232case EbtBool:233setBConst(constant.getBConst());234break;235case EbtFloat:236setFConst(constant.getFConst());237break;238default:239return false;240}241break;242default:243return false;244}245246return true;247}248249bool TConstantUnion::operator==(const int i) const250{251switch (type)252{253case EbtFloat:254return static_cast<float>(i) == fConst;255default:256return i == iConst;257}258}259260bool TConstantUnion::operator==(const unsigned int u) const261{262switch (type)263{264case EbtFloat:265return static_cast<float>(u) == fConst;266default:267return u == uConst;268}269}270271bool TConstantUnion::operator==(const float f) const272{273switch (type)274{275case EbtInt:276return f == static_cast<float>(iConst);277case EbtUInt:278return f == static_cast<float>(uConst);279default:280return f == fConst;281}282}283284bool TConstantUnion::operator==(const bool b) const285{286return b == bConst;287}288289bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const290{291return s == yuvCscStandardEXTConst;292}293294bool TConstantUnion::operator==(const TConstantUnion &constant) const295{296ImplicitTypeConversion conversion = GetConversion(constant.type, type);297if (conversion == ImplicitTypeConversion::Same)298{299switch (type)300{301case EbtInt:302return constant.iConst == iConst;303case EbtUInt:304return constant.uConst == uConst;305case EbtFloat:306return constant.fConst == fConst;307case EbtBool:308return constant.bConst == bConst;309case EbtYuvCscStandardEXT:310return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst;311default:312return false;313}314}315else if (conversion == ImplicitTypeConversion::Invalid)316{317return false;318}319else320{321return constant.getFConst() == getFConst();322}323}324325bool TConstantUnion::operator!=(const int i) const326{327return !operator==(i);328}329330bool TConstantUnion::operator!=(const unsigned int u) const331{332return !operator==(u);333}334335bool TConstantUnion::operator!=(const float f) const336{337return !operator==(f);338}339340bool TConstantUnion::operator!=(const bool b) const341{342return !operator==(b);343}344345bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const346{347return !operator==(s);348}349350bool TConstantUnion::operator!=(const TConstantUnion &constant) const351{352return !operator==(constant);353}354355bool TConstantUnion::operator>(const TConstantUnion &constant) const356{357358ImplicitTypeConversion conversion = GetConversion(constant.type, type);359if (conversion == ImplicitTypeConversion::Same)360{361switch (type)362{363case EbtInt:364return iConst > constant.iConst;365case EbtUInt:366return uConst > constant.uConst;367case EbtFloat:368return fConst > constant.fConst;369default:370return false; // Invalid operation, handled at semantic analysis371}372}373else374{375ASSERT(conversion != ImplicitTypeConversion::Invalid);376return getFConst() > constant.getFConst();377}378}379380bool TConstantUnion::operator<(const TConstantUnion &constant) const381{382ImplicitTypeConversion conversion = GetConversion(constant.type, type);383if (conversion == ImplicitTypeConversion::Same)384{385switch (type)386{387case EbtInt:388return iConst < constant.iConst;389case EbtUInt:390return uConst < constant.uConst;391case EbtFloat:392return fConst < constant.fConst;393default:394return false; // Invalid operation, handled at semantic analysis395}396}397else398{399ASSERT(conversion != ImplicitTypeConversion::Invalid);400return getFConst() < constant.getFConst();401}402}403404// static405TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,406const TConstantUnion &rhs,407TDiagnostics *diag,408const TSourceLoc &line)409{410TConstantUnion returnValue;411412ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);413if (conversion == ImplicitTypeConversion::Same)414{415switch (lhs.type)416{417case EbtInt:418returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));419break;420case EbtUInt:421returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));422break;423case EbtFloat:424returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));425break;426default:427UNREACHABLE();428}429}430else431{432ASSERT(conversion != ImplicitTypeConversion::Invalid);433returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line));434}435436return returnValue;437}438439// static440TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,441const TConstantUnion &rhs,442TDiagnostics *diag,443const TSourceLoc &line)444{445TConstantUnion returnValue;446447ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);448if (conversion == ImplicitTypeConversion::Same)449{450switch (lhs.type)451{452case EbtInt:453returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));454break;455case EbtUInt:456returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));457break;458case EbtFloat:459returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));460break;461default:462UNREACHABLE();463}464}465else466{467ASSERT(conversion != ImplicitTypeConversion::Invalid);468returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line));469}470471return returnValue;472}473474// static475TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,476const TConstantUnion &rhs,477TDiagnostics *diag,478const TSourceLoc &line)479{480TConstantUnion returnValue;481482ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type);483if (conversion == ImplicitTypeConversion::Same)484{485switch (lhs.type)486{487case EbtInt:488returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));489break;490case EbtUInt:491// Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely492// on that to implement wrapping multiplication.493returnValue.setUConst(lhs.uConst * rhs.uConst);494break;495case EbtFloat:496returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));497break;498default:499UNREACHABLE();500}501}502else503{504ASSERT(conversion != ImplicitTypeConversion::Invalid);505returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line));506}507508return returnValue;509}510511TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const512{513TConstantUnion returnValue;514ASSERT(type == constant.type);515switch (type)516{517case EbtInt:518returnValue.setIConst(iConst % constant.iConst);519break;520case EbtUInt:521returnValue.setUConst(uConst % constant.uConst);522break;523default:524UNREACHABLE();525}526527return returnValue;528}529530// static531TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,532const TConstantUnion &rhs,533TDiagnostics *diag,534const TSourceLoc &line)535{536TConstantUnion returnValue;537ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);538ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);539if (!IsValidShiftOffset(rhs))540{541diag->warning(line, "Undefined shift (operand out of range)", ">>");542switch (lhs.type)543{544case EbtInt:545returnValue.setIConst(0);546break;547case EbtUInt:548returnValue.setUConst(0u);549break;550default:551UNREACHABLE();552}553return returnValue;554}555556switch (lhs.type)557{558case EbtInt:559{560unsigned int shiftOffset = 0;561switch (rhs.type)562{563case EbtInt:564shiftOffset = static_cast<unsigned int>(rhs.iConst);565break;566case EbtUInt:567shiftOffset = rhs.uConst;568break;569default:570UNREACHABLE();571}572if (shiftOffset > 0)573{574// ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend575// the sign bit." In C++ shifting negative integers is undefined, so we implement576// extending the sign bit manually.577int lhsSafe = lhs.iConst;578if (lhsSafe == std::numeric_limits<int>::min())579{580// The min integer needs special treatment because only bit it has set is the581// sign bit, which we clear later to implement safe right shift of negative582// numbers.583lhsSafe = -0x40000000;584--shiftOffset;585}586if (shiftOffset > 0)587{588bool extendSignBit = false;589if (lhsSafe < 0)590{591extendSignBit = true;592// Clear the sign bit so that bitshift right is defined in C++.593lhsSafe &= 0x7fffffff;594ASSERT(lhsSafe > 0);595}596returnValue.setIConst(lhsSafe >> shiftOffset);597598// Manually fill in the extended sign bit if necessary.599if (extendSignBit)600{601int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));602returnValue.setIConst(returnValue.getIConst() | extendedSignBit);603}604}605else606{607returnValue.setIConst(lhsSafe);608}609}610else611{612returnValue.setIConst(lhs.iConst);613}614break;615}616case EbtUInt:617switch (rhs.type)618{619case EbtInt:620returnValue.setUConst(lhs.uConst >> rhs.iConst);621break;622case EbtUInt:623returnValue.setUConst(lhs.uConst >> rhs.uConst);624break;625default:626UNREACHABLE();627}628break;629630default:631UNREACHABLE();632}633return returnValue;634}635636// static637TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,638const TConstantUnion &rhs,639TDiagnostics *diag,640const TSourceLoc &line)641{642TConstantUnion returnValue;643ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);644ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);645if (!IsValidShiftOffset(rhs))646{647diag->warning(line, "Undefined shift (operand out of range)", "<<");648switch (lhs.type)649{650case EbtInt:651returnValue.setIConst(0);652break;653case EbtUInt:654returnValue.setUConst(0u);655break;656default:657UNREACHABLE();658}659return returnValue;660}661662switch (lhs.type)663{664case EbtInt:665switch (rhs.type)666{667// Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that668// lhs is "interpreted as a bit pattern". This also avoids the possibility of signed669// integer overflow or undefined shift of a negative integer.670case EbtInt:671returnValue.setIConst(672static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));673break;674case EbtUInt:675returnValue.setIConst(676static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));677break;678default:679UNREACHABLE();680}681break;682683case EbtUInt:684switch (rhs.type)685{686case EbtInt:687returnValue.setUConst(lhs.uConst << rhs.iConst);688break;689case EbtUInt:690returnValue.setUConst(lhs.uConst << rhs.uConst);691break;692default:693UNREACHABLE();694}695break;696697default:698UNREACHABLE();699}700return returnValue;701}702703TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const704{705TConstantUnion returnValue;706ASSERT(constant.type == EbtInt || constant.type == EbtUInt);707switch (type)708{709case EbtInt:710returnValue.setIConst(iConst & constant.iConst);711break;712case EbtUInt:713returnValue.setUConst(uConst & constant.uConst);714break;715default:716UNREACHABLE();717}718719return returnValue;720}721722TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const723{724TConstantUnion returnValue;725ASSERT(type == constant.type);726switch (type)727{728case EbtInt:729returnValue.setIConst(iConst | constant.iConst);730break;731case EbtUInt:732returnValue.setUConst(uConst | constant.uConst);733break;734default:735UNREACHABLE();736}737738return returnValue;739}740741TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const742{743TConstantUnion returnValue;744ASSERT(type == constant.type);745switch (type)746{747case EbtInt:748returnValue.setIConst(iConst ^ constant.iConst);749break;750case EbtUInt:751returnValue.setUConst(uConst ^ constant.uConst);752break;753default:754UNREACHABLE();755}756757return returnValue;758}759760TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const761{762TConstantUnion returnValue;763ASSERT(type == constant.type);764switch (type)765{766case EbtBool:767returnValue.setBConst(bConst && constant.bConst);768break;769default:770UNREACHABLE();771}772773return returnValue;774}775776TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const777{778TConstantUnion returnValue;779ASSERT(type == constant.type);780switch (type)781{782case EbtBool:783returnValue.setBConst(bConst || constant.bConst);784break;785default:786UNREACHABLE();787}788789return returnValue;790}791792} // namespace sh793794795