| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992 |
- //
- // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
- // Copyright (C) 2012-2015 LunarG, Inc.
- // Copyright (C) 2015-2020 Google, Inc.
- // Copyright (C) 2017 ARM Limited.
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- //
- // Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following
- // disclaimer in the documentation and/or other materials provided
- // with the distribution.
- //
- // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
- // contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //
- //
- // Build the intermediate representation.
- //
- #include "localintermediate.h"
- #include "RemoveTree.h"
- #include "SymbolTable.h"
- #include "propagateNoContraction.h"
- #include <cfloat>
- #include <utility>
- #include <tuple>
- namespace glslang {
- ////////////////////////////////////////////////////////////////////////////
- //
- // First set of functions are to help build the intermediate representation.
- // These functions are not member functions of the nodes.
- // They are called from parser productions.
- //
- /////////////////////////////////////////////////////////////////////////////
- //
- // Add a terminal node for an identifier in an expression.
- //
- // Returns the added node.
- //
- TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray,
- TIntermTyped* constSubtree, const TSourceLoc& loc)
- {
- TIntermSymbol* node = new TIntermSymbol(id, name, type);
- node->setLoc(loc);
- node->setConstArray(constArray);
- node->setConstSubtree(constSubtree);
- return node;
- }
- TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol)
- {
- return addSymbol(intermSymbol.getId(),
- intermSymbol.getName(),
- intermSymbol.getType(),
- intermSymbol.getConstArray(),
- intermSymbol.getConstSubtree(),
- intermSymbol.getLoc());
- }
- TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
- {
- glslang::TSourceLoc loc; // just a null location
- loc.init();
- return addSymbol(variable, loc);
- }
- TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
- {
- return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
- }
- TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
- {
- TConstUnionArray unionArray; // just a null constant
- return addSymbol(0, "", type, unionArray, nullptr, loc);
- }
- //
- // Connect two nodes with a new parent that does a binary operation on the nodes.
- //
- // Returns the added node.
- //
- // Returns nullptr if the working conversions and promotions could not be found.
- //
- TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
- {
- // No operations work on blocks
- if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
- return nullptr;
- // Convert "reference +/- int" and "reference - reference" to integer math
- if (op == EOpAdd || op == EOpSub) {
- // No addressing math on struct with unsized array.
- if ((left->isReference() && left->getType().getReferentType()->containsUnsizedArray()) ||
- (right->isReference() && right->getType().getReferentType()->containsUnsizedArray())) {
- return nullptr;
- }
- if (left->isReference() && isTypeInt(right->getBasicType())) {
- const TType& referenceType = left->getType();
- TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
- left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
- right = createConversion(EbtInt64, right);
- right = addBinaryMath(EOpMul, right, size, loc);
- TIntermTyped *node = addBinaryMath(op, left, right, loc);
- node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
- return node;
- }
- }
- if (op == EOpAdd && right->isReference() && isTypeInt(left->getBasicType())) {
- const TType& referenceType = right->getType();
- TIntermConstantUnion* size =
- addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true);
- right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
- left = createConversion(EbtInt64, left);
- left = addBinaryMath(EOpMul, left, size, loc);
- TIntermTyped *node = addBinaryMath(op, left, right, loc);
- node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
- return node;
- }
- if (op == EOpSub && left->isReference() && right->isReference()) {
- TIntermConstantUnion* size =
- addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
- left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
- right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
- left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
- right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
- left = addBinaryMath(EOpSub, left, right, loc);
- TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc);
- return node;
- }
- // No other math operators supported on references
- if (left->isReference() || right->isReference())
- return nullptr;
- // Try converting the children's base types to compatible types.
- auto children = addPairConversion(op, left, right);
- left = std::get<0>(children);
- right = std::get<1>(children);
- if (left == nullptr || right == nullptr)
- return nullptr;
- // Convert the children's type shape to be compatible.
- addBiShapeConversion(op, left, right);
- if (left == nullptr || right == nullptr)
- return nullptr;
- //
- // Need a new node holding things together. Make
- // one and promote it to the right type.
- //
- TIntermBinary* node = addBinaryNode(op, left, right, loc);
- if (! promote(node))
- return nullptr;
- node->updatePrecision();
- //
- // If they are both (non-specialization) constants, they must be folded.
- // (Unless it's the sequence (comma) operator, but that's handled in addComma().)
- //
- TIntermConstantUnion *leftTempConstant = node->getLeft()->getAsConstantUnion();
- TIntermConstantUnion *rightTempConstant = node->getRight()->getAsConstantUnion();
- if (leftTempConstant && rightTempConstant) {
- TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant);
- if (folded)
- return folded;
- }
- // If can propagate spec-constantness and if the operation is an allowed
- // specialization-constant operation, make a spec-constant.
- if (specConstantPropagates(*node->getLeft(), *node->getRight()) && isSpecializationOperation(*node))
- node->getWritableType().getQualifier().makeSpecConstant();
- // If must propagate nonuniform, make a nonuniform.
- if ((node->getLeft()->getQualifier().isNonUniform() || node->getRight()->getQualifier().isNonUniform()) &&
- isNonuniformPropagating(node->getOp()))
- node->getWritableType().getQualifier().nonUniform = true;
- return node;
- }
- //
- // Low level: add binary node (no promotions or other argument modifications)
- //
- TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right,
- const TSourceLoc& loc) const
- {
- // build the node
- TIntermBinary* node = new TIntermBinary(op);
- node->setLoc(loc.line != 0 ? loc : left->getLoc());
- node->setLeft(left);
- node->setRight(right);
- return node;
- }
- //
- // like non-type form, but sets node's type.
- //
- TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right,
- const TSourceLoc& loc, const TType& type) const
- {
- TIntermBinary* node = addBinaryNode(op, left, right, loc);
- node->setType(type);
- return node;
- }
- //
- // Low level: add unary node (no promotions or other argument modifications)
- //
- TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc) const
- {
- TIntermUnary* node = new TIntermUnary(op);
- node->setLoc(loc.line != 0 ? loc : child->getLoc());
- node->setOperand(child);
- return node;
- }
- //
- // like non-type form, but sets node's type.
- //
- TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc, const TType& type)
- const
- {
- TIntermUnary* node = addUnaryNode(op, child, loc);
- node->setType(type);
- return node;
- }
- //
- // Connect two nodes through an assignment.
- //
- // Returns the added node.
- //
- // Returns nullptr if the 'right' type could not be converted to match the 'left' type,
- // or the resulting operation cannot be properly promoted.
- //
- TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right,
- const TSourceLoc& loc)
- {
- // No block assignment
- if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
- return nullptr;
- // Convert "reference += int" to "reference = reference + int". We need this because the
- // "reference + int" calculation involves a cast back to the original type, which makes it
- // not an lvalue.
- if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) {
- if (!(right->getType().isScalar() && right->getType().isIntegerDomain()))
- return nullptr;
- TIntermTyped* node = addBinaryMath(op == EOpAddAssign ? EOpAdd : EOpSub, left, right, loc);
- if (!node)
- return nullptr;
- TIntermSymbol* symbol = left->getAsSymbolNode();
- left = addSymbol(*symbol);
- node = addAssign(EOpAssign, left, node, loc);
- return node;
- }
- //
- // Like adding binary math, except the conversion can only go
- // from right to left.
- //
- // convert base types, nullptr return means not possible
- right = addConversion(op, left->getType(), right);
- if (right == nullptr)
- return nullptr;
- // convert shape
- right = addUniShapeConversion(op, left->getType(), right);
- // build the node
- TIntermBinary* node = addBinaryNode(op, left, right, loc);
- if (! promote(node))
- return nullptr;
- node->updatePrecision();
- return node;
- }
- //
- // Connect two nodes through an index operator, where the left node is the base
- // of an array or struct, and the right node is a direct or indirect offset.
- //
- // Returns the added node.
- // The caller should set the type of the returned node.
- //
- TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index,
- const TSourceLoc& loc)
- {
- // caller should set the type
- return addBinaryNode(op, base, index, loc);
- }
- //
- // Add one node as the parent of another that it operates on.
- //
- // Returns the added node.
- //
- TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child,
- const TSourceLoc& loc)
- {
- if (child == 0)
- return nullptr;
- if (child->getType().getBasicType() == EbtBlock)
- return nullptr;
- switch (op) {
- case EOpLogicalNot:
- if (getSource() == EShSourceHlsl) {
- break; // HLSL can promote logical not
- }
- if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
- return nullptr;
- }
- break;
- case EOpPostIncrement:
- case EOpPreIncrement:
- case EOpPostDecrement:
- case EOpPreDecrement:
- case EOpNegative:
- if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
- return nullptr;
- default: break; // some compilers want this
- }
- //
- // Do we need to promote the operand?
- //
- TBasicType newType = EbtVoid;
- switch (op) {
- case EOpConstructBool: newType = EbtBool; break;
- case EOpConstructFloat: newType = EbtFloat; break;
- case EOpConstructInt: newType = EbtInt; break;
- case EOpConstructUint: newType = EbtUint; break;
- #ifndef GLSLANG_WEB
- case EOpConstructInt8: newType = EbtInt8; break;
- case EOpConstructUint8: newType = EbtUint8; break;
- case EOpConstructInt16: newType = EbtInt16; break;
- case EOpConstructUint16: newType = EbtUint16; break;
- case EOpConstructInt64: newType = EbtInt64; break;
- case EOpConstructUint64: newType = EbtUint64; break;
- case EOpConstructDouble: newType = EbtDouble; break;
- case EOpConstructFloat16: newType = EbtFloat16; break;
- #endif
- default: break; // some compilers want this
- }
- if (newType != EbtVoid) {
- child = addConversion(op, TType(newType, EvqTemporary, child->getVectorSize(),
- child->getMatrixCols(),
- child->getMatrixRows(),
- child->isVector()),
- child);
- if (child == nullptr)
- return nullptr;
- }
- //
- // For constructors, we are now done, it was all in the conversion.
- // TODO: but, did this bypass constant folding?
- //
- switch (op) {
- case EOpConstructInt8:
- case EOpConstructUint8:
- case EOpConstructInt16:
- case EOpConstructUint16:
- case EOpConstructInt:
- case EOpConstructUint:
- case EOpConstructInt64:
- case EOpConstructUint64:
- case EOpConstructBool:
- case EOpConstructFloat:
- case EOpConstructDouble:
- case EOpConstructFloat16:
- return child;
- default: break; // some compilers want this
- }
- //
- // Make a new node for the operator.
- //
- TIntermUnary* node = addUnaryNode(op, child, loc);
- if (! promote(node))
- return nullptr;
- node->updatePrecision();
- // If it's a (non-specialization) constant, it must be folded.
- if (node->getOperand()->getAsConstantUnion())
- return node->getOperand()->getAsConstantUnion()->fold(op, node->getType());
- // If it's a specialization constant, the result is too,
- // if the operation is allowed for specialization constants.
- if (node->getOperand()->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node))
- node->getWritableType().getQualifier().makeSpecConstant();
- // If must propagate nonuniform, make a nonuniform.
- if (node->getOperand()->getQualifier().isNonUniform() && isNonuniformPropagating(node->getOp()))
- node->getWritableType().getQualifier().nonUniform = true;
- return node;
- }
- TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary,
- TIntermNode* childNode, const TType& returnType)
- {
- if (unary) {
- //
- // Treat it like a unary operator.
- // addUnaryMath() should get the type correct on its own;
- // including constness (which would differ from the prototype).
- //
- TIntermTyped* child = childNode->getAsTyped();
- if (child == nullptr)
- return nullptr;
- if (child->getAsConstantUnion()) {
- TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType);
- if (folded)
- return folded;
- }
- return addUnaryNode(op, child, child->getLoc(), returnType);
- } else {
- // setAggregateOperater() calls fold() for constant folding
- TIntermTyped* node = setAggregateOperator(childNode, op, returnType, loc);
- return node;
- }
- }
- //
- // This is the safe way to change the operator on an aggregate, as it
- // does lots of error checking and fixing. Especially for establishing
- // a function call's operation on its set of parameters. Sequences
- // of instructions are also aggregates, but they just directly set
- // their operator to EOpSequence.
- //
- // Returns an aggregate node, which could be the one passed in if
- // it was already an aggregate.
- //
- TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type,
- const TSourceLoc& loc)
- {
- TIntermAggregate* aggNode;
- //
- // Make sure we have an aggregate. If not turn it into one.
- //
- if (node != nullptr) {
- aggNode = node->getAsAggregate();
- if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
- //
- // Make an aggregate containing this node.
- //
- aggNode = new TIntermAggregate();
- aggNode->getSequence().push_back(node);
- }
- } else
- aggNode = new TIntermAggregate();
- //
- // Set the operator.
- //
- aggNode->setOperator(op);
- if (loc.line != 0 || node != nullptr)
- aggNode->setLoc(loc.line != 0 ? loc : node->getLoc());
- aggNode->setType(type);
- return fold(aggNode);
- }
- bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const
- {
- //
- // Does the base type even allow the operation?
- //
- switch (node->getBasicType()) {
- case EbtVoid:
- return false;
- case EbtAtomicUint:
- case EbtSampler:
- case EbtAccStruct:
- // opaque types can be passed to functions
- if (op == EOpFunction)
- break;
- // HLSL can assign samplers directly (no constructor)
- if (getSource() == EShSourceHlsl && node->getBasicType() == EbtSampler)
- break;
- // samplers can get assigned via a sampler constructor
- // (well, not yet, but code in the rest of this function is ready for it)
- if (node->getBasicType() == EbtSampler && op == EOpAssign &&
- node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
- break;
- // otherwise, opaque types can't even be operated on, let alone converted
- return false;
- default:
- break;
- }
- return true;
- }
- bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& newOp) const
- {
- switch (dst) {
- #ifndef GLSLANG_WEB
- case EbtDouble:
- switch (src) {
- case EbtUint: newOp = EOpConvUintToDouble; break;
- case EbtBool: newOp = EOpConvBoolToDouble; break;
- case EbtFloat: newOp = EOpConvFloatToDouble; break;
- case EbtInt: newOp = EOpConvIntToDouble; break;
- case EbtInt8: newOp = EOpConvInt8ToDouble; break;
- case EbtUint8: newOp = EOpConvUint8ToDouble; break;
- case EbtInt16: newOp = EOpConvInt16ToDouble; break;
- case EbtUint16: newOp = EOpConvUint16ToDouble; break;
- case EbtFloat16: newOp = EOpConvFloat16ToDouble; break;
- case EbtInt64: newOp = EOpConvInt64ToDouble; break;
- case EbtUint64: newOp = EOpConvUint64ToDouble; break;
- default:
- return false;
- }
- break;
- #endif
- case EbtFloat:
- switch (src) {
- case EbtInt: newOp = EOpConvIntToFloat; break;
- case EbtUint: newOp = EOpConvUintToFloat; break;
- case EbtBool: newOp = EOpConvBoolToFloat; break;
- #ifndef GLSLANG_WEB
- case EbtDouble: newOp = EOpConvDoubleToFloat; break;
- case EbtInt8: newOp = EOpConvInt8ToFloat; break;
- case EbtUint8: newOp = EOpConvUint8ToFloat; break;
- case EbtInt16: newOp = EOpConvInt16ToFloat; break;
- case EbtUint16: newOp = EOpConvUint16ToFloat; break;
- case EbtFloat16: newOp = EOpConvFloat16ToFloat; break;
- case EbtInt64: newOp = EOpConvInt64ToFloat; break;
- case EbtUint64: newOp = EOpConvUint64ToFloat; break;
- #endif
- default:
- return false;
- }
- break;
- #ifndef GLSLANG_WEB
- case EbtFloat16:
- switch (src) {
- case EbtInt8: newOp = EOpConvInt8ToFloat16; break;
- case EbtUint8: newOp = EOpConvUint8ToFloat16; break;
- case EbtInt16: newOp = EOpConvInt16ToFloat16; break;
- case EbtUint16: newOp = EOpConvUint16ToFloat16; break;
- case EbtInt: newOp = EOpConvIntToFloat16; break;
- case EbtUint: newOp = EOpConvUintToFloat16; break;
- case EbtBool: newOp = EOpConvBoolToFloat16; break;
- case EbtFloat: newOp = EOpConvFloatToFloat16; break;
- case EbtDouble: newOp = EOpConvDoubleToFloat16; break;
- case EbtInt64: newOp = EOpConvInt64ToFloat16; break;
- case EbtUint64: newOp = EOpConvUint64ToFloat16; break;
- default:
- return false;
- }
- break;
- #endif
- case EbtBool:
- switch (src) {
- case EbtInt: newOp = EOpConvIntToBool; break;
- case EbtUint: newOp = EOpConvUintToBool; break;
- case EbtFloat: newOp = EOpConvFloatToBool; break;
- #ifndef GLSLANG_WEB
- case EbtDouble: newOp = EOpConvDoubleToBool; break;
- case EbtInt8: newOp = EOpConvInt8ToBool; break;
- case EbtUint8: newOp = EOpConvUint8ToBool; break;
- case EbtInt16: newOp = EOpConvInt16ToBool; break;
- case EbtUint16: newOp = EOpConvUint16ToBool; break;
- case EbtFloat16: newOp = EOpConvFloat16ToBool; break;
- case EbtInt64: newOp = EOpConvInt64ToBool; break;
- case EbtUint64: newOp = EOpConvUint64ToBool; break;
- #endif
- default:
- return false;
- }
- break;
- #ifndef GLSLANG_WEB
- case EbtInt8:
- switch (src) {
- case EbtUint8: newOp = EOpConvUint8ToInt8; break;
- case EbtInt16: newOp = EOpConvInt16ToInt8; break;
- case EbtUint16: newOp = EOpConvUint16ToInt8; break;
- case EbtInt: newOp = EOpConvIntToInt8; break;
- case EbtUint: newOp = EOpConvUintToInt8; break;
- case EbtInt64: newOp = EOpConvInt64ToInt8; break;
- case EbtUint64: newOp = EOpConvUint64ToInt8; break;
- case EbtBool: newOp = EOpConvBoolToInt8; break;
- case EbtFloat: newOp = EOpConvFloatToInt8; break;
- case EbtDouble: newOp = EOpConvDoubleToInt8; break;
- case EbtFloat16: newOp = EOpConvFloat16ToInt8; break;
- default:
- return false;
- }
- break;
- case EbtUint8:
- switch (src) {
- case EbtInt8: newOp = EOpConvInt8ToUint8; break;
- case EbtInt16: newOp = EOpConvInt16ToUint8; break;
- case EbtUint16: newOp = EOpConvUint16ToUint8; break;
- case EbtInt: newOp = EOpConvIntToUint8; break;
- case EbtUint: newOp = EOpConvUintToUint8; break;
- case EbtInt64: newOp = EOpConvInt64ToUint8; break;
- case EbtUint64: newOp = EOpConvUint64ToUint8; break;
- case EbtBool: newOp = EOpConvBoolToUint8; break;
- case EbtFloat: newOp = EOpConvFloatToUint8; break;
- case EbtDouble: newOp = EOpConvDoubleToUint8; break;
- case EbtFloat16: newOp = EOpConvFloat16ToUint8; break;
- default:
- return false;
- }
- break;
- case EbtInt16:
- switch (src) {
- case EbtUint8: newOp = EOpConvUint8ToInt16; break;
- case EbtInt8: newOp = EOpConvInt8ToInt16; break;
- case EbtUint16: newOp = EOpConvUint16ToInt16; break;
- case EbtInt: newOp = EOpConvIntToInt16; break;
- case EbtUint: newOp = EOpConvUintToInt16; break;
- case EbtInt64: newOp = EOpConvInt64ToInt16; break;
- case EbtUint64: newOp = EOpConvUint64ToInt16; break;
- case EbtBool: newOp = EOpConvBoolToInt16; break;
- case EbtFloat: newOp = EOpConvFloatToInt16; break;
- case EbtDouble: newOp = EOpConvDoubleToInt16; break;
- case EbtFloat16: newOp = EOpConvFloat16ToInt16; break;
- default:
- return false;
- }
- break;
- case EbtUint16:
- switch (src) {
- case EbtInt8: newOp = EOpConvInt8ToUint16; break;
- case EbtUint8: newOp = EOpConvUint8ToUint16; break;
- case EbtInt16: newOp = EOpConvInt16ToUint16; break;
- case EbtInt: newOp = EOpConvIntToUint16; break;
- case EbtUint: newOp = EOpConvUintToUint16; break;
- case EbtInt64: newOp = EOpConvInt64ToUint16; break;
- case EbtUint64: newOp = EOpConvUint64ToUint16; break;
- case EbtBool: newOp = EOpConvBoolToUint16; break;
- case EbtFloat: newOp = EOpConvFloatToUint16; break;
- case EbtDouble: newOp = EOpConvDoubleToUint16; break;
- case EbtFloat16: newOp = EOpConvFloat16ToUint16; break;
- default:
- return false;
- }
- break;
- #endif
- case EbtInt:
- switch (src) {
- case EbtUint: newOp = EOpConvUintToInt; break;
- case EbtBool: newOp = EOpConvBoolToInt; break;
- case EbtFloat: newOp = EOpConvFloatToInt; break;
- #ifndef GLSLANG_WEB
- case EbtInt8: newOp = EOpConvInt8ToInt; break;
- case EbtUint8: newOp = EOpConvUint8ToInt; break;
- case EbtInt16: newOp = EOpConvInt16ToInt; break;
- case EbtUint16: newOp = EOpConvUint16ToInt; break;
- case EbtDouble: newOp = EOpConvDoubleToInt; break;
- case EbtFloat16: newOp = EOpConvFloat16ToInt; break;
- case EbtInt64: newOp = EOpConvInt64ToInt; break;
- case EbtUint64: newOp = EOpConvUint64ToInt; break;
- #endif
- default:
- return false;
- }
- break;
- case EbtUint:
- switch (src) {
- case EbtInt: newOp = EOpConvIntToUint; break;
- case EbtBool: newOp = EOpConvBoolToUint; break;
- case EbtFloat: newOp = EOpConvFloatToUint; break;
- #ifndef GLSLANG_WEB
- case EbtInt8: newOp = EOpConvInt8ToUint; break;
- case EbtUint8: newOp = EOpConvUint8ToUint; break;
- case EbtInt16: newOp = EOpConvInt16ToUint; break;
- case EbtUint16: newOp = EOpConvUint16ToUint; break;
- case EbtDouble: newOp = EOpConvDoubleToUint; break;
- case EbtFloat16: newOp = EOpConvFloat16ToUint; break;
- case EbtInt64: newOp = EOpConvInt64ToUint; break;
- case EbtUint64: newOp = EOpConvUint64ToUint; break;
- #endif
- default:
- return false;
- }
- break;
- #ifndef GLSLANG_WEB
- case EbtInt64:
- switch (src) {
- case EbtInt8: newOp = EOpConvInt8ToInt64; break;
- case EbtUint8: newOp = EOpConvUint8ToInt64; break;
- case EbtInt16: newOp = EOpConvInt16ToInt64; break;
- case EbtUint16: newOp = EOpConvUint16ToInt64; break;
- case EbtInt: newOp = EOpConvIntToInt64; break;
- case EbtUint: newOp = EOpConvUintToInt64; break;
- case EbtBool: newOp = EOpConvBoolToInt64; break;
- case EbtFloat: newOp = EOpConvFloatToInt64; break;
- case EbtDouble: newOp = EOpConvDoubleToInt64; break;
- case EbtFloat16: newOp = EOpConvFloat16ToInt64; break;
- case EbtUint64: newOp = EOpConvUint64ToInt64; break;
- default:
- return false;
- }
- break;
- case EbtUint64:
- switch (src) {
- case EbtInt8: newOp = EOpConvInt8ToUint64; break;
- case EbtUint8: newOp = EOpConvUint8ToUint64; break;
- case EbtInt16: newOp = EOpConvInt16ToUint64; break;
- case EbtUint16: newOp = EOpConvUint16ToUint64; break;
- case EbtInt: newOp = EOpConvIntToUint64; break;
- case EbtUint: newOp = EOpConvUintToUint64; break;
- case EbtBool: newOp = EOpConvBoolToUint64; break;
- case EbtFloat: newOp = EOpConvFloatToUint64; break;
- case EbtDouble: newOp = EOpConvDoubleToUint64; break;
- case EbtFloat16: newOp = EOpConvFloat16ToUint64; break;
- case EbtInt64: newOp = EOpConvInt64ToUint64; break;
- default:
- return false;
- }
- break;
- #endif
- default:
- return false;
- }
- return true;
- }
- // This is 'mechanism' here, it does any conversion told.
- // It is about basic type, not about shape.
- // The policy comes from the shader or the calling code.
- TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped* node) const
- {
- //
- // Add a new newNode for the conversion.
- //
- #ifndef GLSLANG_WEB
- bool convertToIntTypes = (convertTo == EbtInt8 || convertTo == EbtUint8 ||
- convertTo == EbtInt16 || convertTo == EbtUint16 ||
- convertTo == EbtInt || convertTo == EbtUint ||
- convertTo == EbtInt64 || convertTo == EbtUint64);
- bool convertFromIntTypes = (node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8 ||
- node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16 ||
- node->getBasicType() == EbtInt || node->getBasicType() == EbtUint ||
- node->getBasicType() == EbtInt64 || node->getBasicType() == EbtUint64);
- bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtFloat || convertTo == EbtDouble);
- bool convertFromFloatTypes = (node->getBasicType() == EbtFloat16 ||
- node->getBasicType() == EbtFloat ||
- node->getBasicType() == EbtDouble);
- if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) ||
- ((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes)) {
- if (! getArithemeticInt8Enabled()) {
- return nullptr;
- }
- }
- if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) ||
- ((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes)) {
- if (! getArithemeticInt16Enabled()) {
- return nullptr;
- }
- }
- if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) ||
- (node->getBasicType() == EbtFloat16 && ! convertToFloatTypes)) {
- if (! getArithemeticFloat16Enabled()) {
- return nullptr;
- }
- }
- #endif
- TIntermUnary* newNode = nullptr;
- TOperator newOp = EOpNull;
- if (!buildConvertOp(convertTo, node->getBasicType(), newOp)) {
- return nullptr;
- }
- TType newType(convertTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
- newNode = addUnaryNode(newOp, node, node->getLoc(), newType);
- if (node->getAsConstantUnion()) {
- #ifndef GLSLANG_WEB
- // 8/16-bit storage extensions don't support 8/16-bit constants, so don't fold conversions
- // to those types
- if ((getArithemeticInt8Enabled() || !(convertTo == EbtInt8 || convertTo == EbtUint8)) &&
- (getArithemeticInt16Enabled() || !(convertTo == EbtInt16 || convertTo == EbtUint16)) &&
- (getArithemeticFloat16Enabled() || !(convertTo == EbtFloat16)))
- #endif
- {
- TIntermTyped* folded = node->getAsConstantUnion()->fold(newOp, newType);
- if (folded)
- return folded;
- }
- }
- // Propagate specialization-constant-ness, if allowed
- if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode))
- newNode->getWritableType().getQualifier().makeSpecConstant();
- return newNode;
- }
- TIntermTyped* TIntermediate::addConversion(TBasicType convertTo, TIntermTyped* node) const
- {
- return createConversion(convertTo, node);
- }
- // For converting a pair of operands to a binary operation to compatible
- // types with each other, relative to the operation in 'op'.
- // This does not cover assignment operations, which is asymmetric in that the
- // left type is not changeable.
- // See addConversion(op, type, node) for assignments and unary operation
- // conversions.
- //
- // Generally, this is focused on basic type conversion, not shape conversion.
- // See addShapeConversion() for shape conversions.
- //
- // Returns the converted pair of nodes.
- // Returns <nullptr, nullptr> when there is no conversion.
- std::tuple<TIntermTyped*, TIntermTyped*>
- TIntermediate::addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1)
- {
- if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1))
- return std::make_tuple(nullptr, nullptr);
- if (node0->getType() != node1->getType()) {
- // If differing structure, then no conversions.
- if (node0->isStruct() || node1->isStruct())
- return std::make_tuple(nullptr, nullptr);
- // If differing arrays, then no conversions.
- if (node0->getType().isArray() || node1->getType().isArray())
- return std::make_tuple(nullptr, nullptr);
- // No implicit conversions for operations involving cooperative matrices
- if (node0->getType().isCoopMat() || node1->getType().isCoopMat())
- return std::make_tuple(node0, node1);
- }
- auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes);
- switch (op) {
- //
- // List all the binary ops that can implicitly convert one operand to the other's type;
- // This implements the 'policy' for implicit type conversion.
- //
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpEqual:
- case EOpNotEqual:
- case EOpAdd:
- case EOpSub:
- case EOpMul:
- case EOpDiv:
- case EOpMod:
- case EOpVectorTimesScalar:
- case EOpVectorTimesMatrix:
- case EOpMatrixTimesVector:
- case EOpMatrixTimesScalar:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpSequence: // used by ?:
- if (node0->getBasicType() == node1->getBasicType())
- return std::make_tuple(node0, node1);
- promoteTo = getConversionDestinationType(node0->getBasicType(), node1->getBasicType(), op);
- if (std::get<0>(promoteTo) == EbtNumTypes || std::get<1>(promoteTo) == EbtNumTypes)
- return std::make_tuple(nullptr, nullptr);
- break;
- case EOpLogicalAnd:
- case EOpLogicalOr:
- case EOpLogicalXor:
- if (getSource() == EShSourceHlsl)
- promoteTo = std::make_tuple(EbtBool, EbtBool);
- else
- return std::make_tuple(node0, node1);
- break;
- // There are no conversions needed for GLSL; the shift amount just needs to be an
- // integer type, as does the base.
- // HLSL can promote bools to ints to make this work.
- case EOpLeftShift:
- case EOpRightShift:
- if (getSource() == EShSourceHlsl) {
- TBasicType node0BasicType = node0->getBasicType();
- if (node0BasicType == EbtBool)
- node0BasicType = EbtInt;
- if (node1->getBasicType() == EbtBool)
- promoteTo = std::make_tuple(node0BasicType, EbtInt);
- else
- promoteTo = std::make_tuple(node0BasicType, node1->getBasicType());
- } else {
- if (isTypeInt(node0->getBasicType()) && isTypeInt(node1->getBasicType()))
- return std::make_tuple(node0, node1);
- else
- return std::make_tuple(nullptr, nullptr);
- }
- break;
- default:
- if (node0->getType() == node1->getType())
- return std::make_tuple(node0, node1);
- return std::make_tuple(nullptr, nullptr);
- }
- TIntermTyped* newNode0;
- TIntermTyped* newNode1;
- if (std::get<0>(promoteTo) != node0->getType().getBasicType()) {
- if (node0->getAsConstantUnion())
- newNode0 = promoteConstantUnion(std::get<0>(promoteTo), node0->getAsConstantUnion());
- else
- newNode0 = createConversion(std::get<0>(promoteTo), node0);
- } else
- newNode0 = node0;
- if (std::get<1>(promoteTo) != node1->getType().getBasicType()) {
- if (node1->getAsConstantUnion())
- newNode1 = promoteConstantUnion(std::get<1>(promoteTo), node1->getAsConstantUnion());
- else
- newNode1 = createConversion(std::get<1>(promoteTo), node1);
- } else
- newNode1 = node1;
- return std::make_tuple(newNode0, newNode1);
- }
- //
- // Convert the node's type to the given type, as allowed by the operation involved: 'op'.
- // For implicit conversions, 'op' is not the requested conversion, it is the explicit
- // operation requiring the implicit conversion.
- //
- // Binary operation conversions should be handled by addConversion(op, node, node), not here.
- //
- // Returns a node representing the conversion, which could be the same
- // node passed in if no conversion was needed.
- //
- // Generally, this is focused on basic type conversion, not shape conversion.
- // See addShapeConversion() for shape conversions.
- //
- // Return nullptr if a conversion can't be done.
- //
- TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
- {
- if (!isConversionAllowed(op, node))
- return nullptr;
- // Otherwise, if types are identical, no problem
- if (type == node->getType())
- return node;
- // If one's a structure, then no conversions.
- if (type.isStruct() || node->isStruct())
- return nullptr;
- // If one's an array, then no conversions.
- if (type.isArray() || node->getType().isArray())
- return nullptr;
- // Note: callers are responsible for other aspects of shape,
- // like vector and matrix sizes.
- switch (op) {
- //
- // Explicit conversions (unary operations)
- //
- case EOpConstructBool:
- case EOpConstructFloat:
- case EOpConstructInt:
- case EOpConstructUint:
- #ifndef GLSLANG_WEB
- case EOpConstructDouble:
- case EOpConstructFloat16:
- case EOpConstructInt8:
- case EOpConstructUint8:
- case EOpConstructInt16:
- case EOpConstructUint16:
- case EOpConstructInt64:
- case EOpConstructUint64:
- break;
- #endif
- //
- // Implicit conversions
- //
- case EOpLogicalNot:
- case EOpFunctionCall:
- case EOpReturn:
- case EOpAssign:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpMulAssign:
- case EOpVectorTimesScalarAssign:
- case EOpMatrixTimesScalarAssign:
- case EOpDivAssign:
- case EOpModAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpAtan:
- case EOpClamp:
- case EOpCross:
- case EOpDistance:
- case EOpDot:
- case EOpDst:
- case EOpFaceForward:
- case EOpFma:
- case EOpFrexp:
- case EOpLdexp:
- case EOpMix:
- case EOpLit:
- case EOpMax:
- case EOpMin:
- case EOpMod:
- case EOpModf:
- case EOpPow:
- case EOpReflect:
- case EOpRefract:
- case EOpSmoothStep:
- case EOpStep:
- case EOpSequence:
- case EOpConstructStruct:
- case EOpConstructCooperativeMatrix:
- if (type.isReference() || node->getType().isReference()) {
- // types must match to assign a reference
- if (type == node->getType())
- return node;
- else
- return nullptr;
- }
- if (type.getBasicType() == node->getType().getBasicType())
- return node;
- if (! canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op))
- return nullptr;
- break;
- // For GLSL, there are no conversions needed; the shift amount just needs to be an
- // integer type, as do the base/result.
- // HLSL can convert the shift from a bool to an int.
- case EOpLeftShiftAssign:
- case EOpRightShiftAssign:
- {
- if (!(getSource() == EShSourceHlsl && node->getType().getBasicType() == EbtBool)) {
- if (isTypeInt(type.getBasicType()) && isTypeInt(node->getBasicType()))
- return node;
- else
- return nullptr;
- }
- break;
- }
- default:
- // default is to require a match; all exceptions should have case statements above
- if (type.getBasicType() == node->getType().getBasicType())
- return node;
- else
- return nullptr;
- }
- bool canPromoteConstant = true;
- #ifndef GLSLANG_WEB
- // GL_EXT_shader_16bit_storage can't do OpConstantComposite with
- // 16-bit types, so disable promotion for those types.
- // Many issues with this, from JohnK:
- // - this isn't really right to discuss SPIR-V here
- // - this could easily be entirely about scalars, so is overstepping
- // - we should be looking at what the shader asked for, and saying whether or
- // not it can be done, in the parser, by calling requireExtensions(), not
- // changing language sementics on the fly by asking what extensions are in use
- // - at the time of this writing (14-Aug-2020), no test results are changed by this.
- switch (op) {
- case EOpConstructFloat16:
- canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
- break;
- case EOpConstructInt8:
- case EOpConstructUint8:
- canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
- break;
- case EOpConstructInt16:
- case EOpConstructUint16:
- canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
- break;
- default:
- break;
- }
- #endif
- if (canPromoteConstant && node->getAsConstantUnion())
- return promoteConstantUnion(type.getBasicType(), node->getAsConstantUnion());
- //
- // Add a new newNode for the conversion.
- //
- TIntermTyped* newNode = createConversion(type.getBasicType(), node);
- return newNode;
- }
- // Convert the node's shape of type for the given type, as allowed by the
- // operation involved: 'op'. This is for situations where there is only one
- // direction to consider doing the shape conversion.
- //
- // This implements policy, it call addShapeConversion() for the mechanism.
- //
- // Generally, the AST represents allowed GLSL shapes, so this isn't needed
- // for GLSL. Bad shapes are caught in conversion or promotion.
- //
- // Return 'node' if no conversion was done. Promotion handles final shape
- // checking.
- //
- TIntermTyped* TIntermediate::addUniShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
- {
- // some source languages don't do this
- switch (getSource()) {
- case EShSourceHlsl:
- break;
- case EShSourceGlsl:
- default:
- return node;
- }
- // some operations don't do this
- switch (op) {
- case EOpFunctionCall:
- case EOpReturn:
- break;
- case EOpMulAssign:
- // want to support vector *= scalar native ops in AST and lower, not smear, similarly for
- // matrix *= scalar, etc.
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpDivAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpRightShiftAssign:
- case EOpLeftShiftAssign:
- if (node->getVectorSize() == 1)
- return node;
- break;
- case EOpAssign:
- break;
- case EOpMix:
- break;
- default:
- return node;
- }
- return addShapeConversion(type, node);
- }
- // Convert the nodes' shapes to be compatible for the operation 'op'.
- //
- // This implements policy, it call addShapeConversion() for the mechanism.
- //
- // Generally, the AST represents allowed GLSL shapes, so this isn't needed
- // for GLSL. Bad shapes are caught in conversion or promotion.
- //
- void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode)
- {
- // some source languages don't do this
- switch (getSource()) {
- case EShSourceHlsl:
- break;
- case EShSourceGlsl:
- default:
- return;
- }
- // some operations don't do this
- // 'break' will mean attempt bidirectional conversion
- switch (op) {
- case EOpMulAssign:
- case EOpAssign:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpDivAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpRightShiftAssign:
- case EOpLeftShiftAssign:
- // switch to unidirectional conversion (the lhs can't change)
- rhsNode = addUniShapeConversion(op, lhsNode->getType(), rhsNode);
- return;
- case EOpMul:
- // matrix multiply does not change shapes
- if (lhsNode->isMatrix() && rhsNode->isMatrix())
- return;
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- // want to support vector * scalar native ops in AST and lower, not smear, similarly for
- // matrix * vector, etc.
- if (lhsNode->getVectorSize() == 1 || rhsNode->getVectorSize() == 1)
- return;
- break;
- case EOpRightShift:
- case EOpLeftShift:
- // can natively support the right operand being a scalar and the left a vector,
- // but not the reverse
- if (rhsNode->getVectorSize() == 1)
- return;
- break;
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpEqual:
- case EOpNotEqual:
- case EOpLogicalAnd:
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpMix:
- break;
- default:
- return;
- }
- // Do bidirectional conversions
- if (lhsNode->getType().isScalarOrVec1() || rhsNode->getType().isScalarOrVec1()) {
- if (lhsNode->getType().isScalarOrVec1())
- lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
- else
- rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
- }
- lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
- rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
- }
- // Convert the node's shape of type for the given type, as allowed by the
- // operation involved: 'op'.
- //
- // Generally, the AST represents allowed GLSL shapes, so this isn't needed
- // for GLSL. Bad shapes are caught in conversion or promotion.
- //
- // Return 'node' if no conversion was done. Promotion handles final shape
- // checking.
- //
- TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped* node)
- {
- // no conversion needed
- if (node->getType() == type)
- return node;
- // structures and arrays don't change shape, either to or from
- if (node->getType().isStruct() || node->getType().isArray() ||
- type.isStruct() || type.isArray())
- return node;
- // The new node that handles the conversion
- TOperator constructorOp = mapTypeToConstructorOp(type);
- if (getSource() == EShSourceHlsl) {
- // HLSL rules for scalar, vector and matrix conversions:
- // 1) scalar can become anything, initializing every component with its value
- // 2) vector and matrix can become scalar, first element is used (warning: truncation)
- // 3) matrix can become matrix with less rows and/or columns (warning: truncation)
- // 4) vector can become vector with less rows size (warning: truncation)
- // 5a) vector 4 can become 2x2 matrix (special case) (same packing layout, its a reinterpret)
- // 5b) 2x2 matrix can become vector 4 (special case) (same packing layout, its a reinterpret)
- const TType &sourceType = node->getType();
- // rule 1 for scalar to matrix is special
- if (sourceType.isScalarOrVec1() && type.isMatrix()) {
- // HLSL semantics: the scalar (or vec1) is replicated to every component of the matrix. Left to its
- // own devices, the constructor from a scalar would populate the diagonal. This forces replication
- // to every matrix element.
- // Note that if the node is complex (e.g, a function call), we don't want to duplicate it here
- // repeatedly, so we copy it to a temp, then use the temp.
- const int matSize = type.computeNumComponents();
- TIntermAggregate* rhsAggregate = new TIntermAggregate();
- const bool isSimple = (node->getAsSymbolNode() != nullptr) || (node->getAsConstantUnion() != nullptr);
- if (!isSimple) {
- assert(0); // TODO: use node replicator service when available.
- }
- for (int x = 0; x < matSize; ++x)
- rhsAggregate->getSequence().push_back(node);
- return setAggregateOperator(rhsAggregate, constructorOp, type, node->getLoc());
- }
- // rule 1 and 2
- if ((sourceType.isScalar() && !type.isScalar()) || (!sourceType.isScalar() && type.isScalar()))
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- // rule 3 and 5b
- if (sourceType.isMatrix()) {
- // rule 3
- if (type.isMatrix()) {
- if ((sourceType.getMatrixCols() != type.getMatrixCols() || sourceType.getMatrixRows() != type.getMatrixRows()) &&
- sourceType.getMatrixCols() >= type.getMatrixCols() && sourceType.getMatrixRows() >= type.getMatrixRows())
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- // rule 5b
- } else if (type.isVector()) {
- if (type.getVectorSize() == 4 && sourceType.getMatrixCols() == 2 && sourceType.getMatrixRows() == 2)
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- }
- }
- // rule 4 and 5a
- if (sourceType.isVector()) {
- // rule 4
- if (type.isVector())
- {
- if (sourceType.getVectorSize() > type.getVectorSize())
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- // rule 5a
- } else if (type.isMatrix()) {
- if (sourceType.getVectorSize() == 4 && type.getMatrixCols() == 2 && type.getMatrixRows() == 2)
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- }
- }
- }
- // scalar -> vector or vec1 -> vector or
- // vector -> scalar or
- // bigger vector -> smaller vector
- if ((node->getType().isScalarOrVec1() && type.isVector()) ||
- (node->getType().isVector() && type.isScalar()) ||
- (node->isVector() && type.isVector() && node->getVectorSize() > type.getVectorSize()))
- return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
- return node;
- }
- bool TIntermediate::isIntegralPromotion(TBasicType from, TBasicType to) const
- {
- // integral promotions
- if (to == EbtInt) {
- switch(from) {
- case EbtInt8:
- case EbtInt16:
- case EbtUint8:
- case EbtUint16:
- return true;
- default:
- break;
- }
- }
- return false;
- }
- bool TIntermediate::isFPPromotion(TBasicType from, TBasicType to) const
- {
- // floating-point promotions
- if (to == EbtDouble) {
- switch(from) {
- case EbtFloat16:
- case EbtFloat:
- return true;
- default:
- break;
- }
- }
- return false;
- }
- bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const
- {
- #ifdef GLSLANG_WEB
- return false;
- #endif
- switch (from) {
- case EbtInt:
- switch(to) {
- case EbtUint:
- return version >= 400 || getSource() == EShSourceHlsl;
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtUint:
- switch(to) {
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtInt8:
- switch (to) {
- case EbtUint8:
- case EbtInt16:
- case EbtUint16:
- case EbtUint:
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtUint8:
- switch (to) {
- case EbtInt16:
- case EbtUint16:
- case EbtUint:
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtInt16:
- switch(to) {
- case EbtUint16:
- case EbtUint:
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtUint16:
- switch(to) {
- case EbtUint:
- case EbtInt64:
- case EbtUint64:
- return true;
- default:
- break;
- }
- break;
- case EbtInt64:
- if (to == EbtUint64) {
- return true;
- }
- break;
- default:
- break;
- }
- return false;
- }
- bool TIntermediate::isFPConversion(TBasicType from, TBasicType to) const
- {
- #ifdef GLSLANG_WEB
- return false;
- #endif
- if (to == EbtFloat && from == EbtFloat16) {
- return true;
- } else {
- return false;
- }
- }
- bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const
- {
- switch (from) {
- case EbtInt:
- case EbtUint:
- switch(to) {
- case EbtFloat:
- case EbtDouble:
- return true;
- default:
- break;
- }
- break;
- #ifndef GLSLANG_WEB
- case EbtInt8:
- case EbtUint8:
- case EbtInt16:
- case EbtUint16:
- switch (to) {
- case EbtFloat16:
- case EbtFloat:
- case EbtDouble:
- return true;
- default:
- break;
- }
- break;
- case EbtInt64:
- case EbtUint64:
- if (to == EbtDouble) {
- return true;
- }
- break;
- #endif
- default:
- break;
- }
- return false;
- }
- //
- // See if the 'from' type is allowed to be implicitly converted to the
- // 'to' type. This is not about vector/array/struct, only about basic type.
- //
- bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const
- {
- return (from == to); // godlike: Because I like explicitness
- if ((isEsProfile() && version < 310 ) || version == 110)
- return false;
- if (from == to)
- return true;
- // TODO: Move more policies into language-specific handlers.
- // Some languages allow more general (or potentially, more specific) conversions under some conditions.
- if (getSource() == EShSourceHlsl) {
- const bool fromConvertable = (from == EbtFloat || from == EbtDouble || from == EbtInt || from == EbtUint || from == EbtBool);
- const bool toConvertable = (to == EbtFloat || to == EbtDouble || to == EbtInt || to == EbtUint || to == EbtBool);
- if (fromConvertable && toConvertable) {
- switch (op) {
- case EOpAndAssign: // assignments can perform arbitrary conversions
- case EOpInclusiveOrAssign: // ...
- case EOpExclusiveOrAssign: // ...
- case EOpAssign: // ...
- case EOpAddAssign: // ...
- case EOpSubAssign: // ...
- case EOpMulAssign: // ...
- case EOpVectorTimesScalarAssign: // ...
- case EOpMatrixTimesScalarAssign: // ...
- case EOpDivAssign: // ...
- case EOpModAssign: // ...
- case EOpReturn: // function returns can also perform arbitrary conversions
- case EOpFunctionCall: // conversion of a calling parameter
- case EOpLogicalNot:
- case EOpLogicalAnd:
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpConstructStruct:
- return true;
- default:
- break;
- }
- }
- }
- if (getSource() == EShSourceHlsl) {
- // HLSL
- if (from == EbtBool && (to == EbtInt || to == EbtUint || to == EbtFloat))
- return true;
- } else {
- // GLSL
- if (isIntegralPromotion(from, to) ||
- isFPPromotion(from, to) ||
- isIntegralConversion(from, to) ||
- isFPConversion(from, to) ||
- isFPIntegralConversion(from, to)) {
- if (numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int32) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int64) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float32) ||
- numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float64)) {
- return true;
- }
- }
- }
- if (isEsProfile()) {
- switch (to) {
- case EbtFloat:
- switch (from) {
- case EbtInt:
- case EbtUint:
- return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions);
- default:
- return false;
- }
- case EbtUint:
- switch (from) {
- case EbtInt:
- return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions);
- default:
- return false;
- }
- default:
- return false;
- }
- } else {
- switch (to) {
- case EbtDouble:
- switch (from) {
- case EbtInt:
- case EbtUint:
- case EbtInt64:
- case EbtUint64:
- case EbtFloat:
- return version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64);
- case EbtInt16:
- case EbtUint16:
- return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
- numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- case EbtFloat16:
- return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
- numericFeatures.contains(TNumericFeatures::gpu_shader_half_float);
- default:
- return false;
- }
- case EbtFloat:
- switch (from) {
- case EbtInt:
- case EbtUint:
- return true;
- case EbtBool:
- return getSource() == EShSourceHlsl;
- case EbtInt16:
- case EbtUint16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- case EbtFloat16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
- getSource() == EShSourceHlsl;
- default:
- return false;
- }
- case EbtUint:
- switch (from) {
- case EbtInt:
- return version >= 400 || getSource() == EShSourceHlsl;
- case EbtBool:
- return getSource() == EShSourceHlsl;
- case EbtInt16:
- case EbtUint16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- return false;
- }
- case EbtInt:
- switch (from) {
- case EbtBool:
- return getSource() == EShSourceHlsl;
- case EbtInt16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- return false;
- }
- case EbtUint64:
- switch (from) {
- case EbtInt:
- case EbtUint:
- case EbtInt64:
- return true;
- case EbtInt16:
- case EbtUint16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- return false;
- }
- case EbtInt64:
- switch (from) {
- case EbtInt:
- return true;
- case EbtInt16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- return false;
- }
- case EbtFloat16:
- switch (from) {
- case EbtInt16:
- case EbtUint16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- break;
- }
- return false;
- case EbtUint16:
- switch (from) {
- case EbtInt16:
- return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
- default:
- break;
- }
- return false;
- default:
- return false;
- }
- }
- return false;
- }
- static bool canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType, TBasicType uintType)
- {
- #ifdef GLSLANG_WEB
- return false;
- #endif
- switch(sintType) {
- case EbtInt8:
- switch(uintType) {
- case EbtUint8:
- case EbtUint16:
- case EbtUint:
- case EbtUint64:
- return false;
- default:
- assert(false);
- return false;
- }
- break;
- case EbtInt16:
- switch(uintType) {
- case EbtUint8:
- return true;
- case EbtUint16:
- case EbtUint:
- case EbtUint64:
- return false;
- default:
- assert(false);
- return false;
- }
- break;
- case EbtInt:
- switch(uintType) {
- case EbtUint8:
- case EbtUint16:
- return true;
- case EbtUint:
- return false;
- default:
- assert(false);
- return false;
- }
- break;
- case EbtInt64:
- switch(uintType) {
- case EbtUint8:
- case EbtUint16:
- case EbtUint:
- return true;
- case EbtUint64:
- return false;
- default:
- assert(false);
- return false;
- }
- break;
- default:
- assert(false);
- return false;
- }
- }
- static TBasicType getCorrespondingUnsignedType(TBasicType type)
- {
- #ifdef GLSLANG_WEB
- assert(type == EbtInt);
- return EbtUint;
- #endif
- switch(type) {
- case EbtInt8:
- return EbtUint8;
- case EbtInt16:
- return EbtUint16;
- case EbtInt:
- return EbtUint;
- case EbtInt64:
- return EbtUint64;
- default:
- assert(false);
- return EbtNumTypes;
- }
- }
- // Implements the following rules
- // - If either operand has type float64_t or derived from float64_t,
- // the other shall be converted to float64_t or derived type.
- // - Otherwise, if either operand has type float32_t or derived from
- // float32_t, the other shall be converted to float32_t or derived type.
- // - Otherwise, if either operand has type float16_t or derived from
- // float16_t, the other shall be converted to float16_t or derived type.
- // - Otherwise, if both operands have integer types the following rules
- // shall be applied to the operands:
- // - If both operands have the same type, no further conversion
- // is needed.
- // - Otherwise, if both operands have signed integer types or both
- // have unsigned integer types, the operand with the type of lesser
- // integer conversion rank shall be converted to the type of the
- // operand with greater rank.
- // - Otherwise, if the operand that has unsigned integer type has rank
- // greater than or equal to the rank of the type of the other
- // operand, the operand with signed integer type shall be converted
- // to the type of the operand with unsigned integer type.
- // - Otherwise, if the type of the operand with signed integer type can
- // represent all of the values of the type of the operand with
- // unsigned integer type, the operand with unsigned integer type
- // shall be converted to the type of the operand with signed
- // integer type.
- // - Otherwise, both operands shall be converted to the unsigned
- // integer type corresponding to the type of the operand with signed
- // integer type.
- std::tuple<TBasicType, TBasicType> TIntermediate::getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const
- {
- TBasicType res0 = EbtNumTypes;
- TBasicType res1 = EbtNumTypes;
- if ((isEsProfile() &&
- (version < 310 || !numericFeatures.contains(TNumericFeatures::shader_implicit_conversions))) ||
- version == 110)
- return std::make_tuple(res0, res1);
- if (getSource() == EShSourceHlsl) {
- if (canImplicitlyPromote(type1, type0, op)) {
- res0 = type0;
- res1 = type0;
- } else if (canImplicitlyPromote(type0, type1, op)) {
- res0 = type1;
- res1 = type1;
- }
- return std::make_tuple(res0, res1);
- }
- if ((type0 == EbtDouble && canImplicitlyPromote(type1, EbtDouble, op)) ||
- (type1 == EbtDouble && canImplicitlyPromote(type0, EbtDouble, op)) ) {
- res0 = EbtDouble;
- res1 = EbtDouble;
- } else if ((type0 == EbtFloat && canImplicitlyPromote(type1, EbtFloat, op)) ||
- (type1 == EbtFloat && canImplicitlyPromote(type0, EbtFloat, op)) ) {
- res0 = EbtFloat;
- res1 = EbtFloat;
- } else if ((type0 == EbtFloat16 && canImplicitlyPromote(type1, EbtFloat16, op)) ||
- (type1 == EbtFloat16 && canImplicitlyPromote(type0, EbtFloat16, op)) ) {
- res0 = EbtFloat16;
- res1 = EbtFloat16;
- } else if (isTypeInt(type0) && isTypeInt(type1) &&
- (canImplicitlyPromote(type0, type1, op) || canImplicitlyPromote(type1, type0, op))) {
- if ((isTypeSignedInt(type0) && isTypeSignedInt(type1)) ||
- (isTypeUnsignedInt(type0) && isTypeUnsignedInt(type1))) {
- if (getTypeRank(type0) < getTypeRank(type1)) {
- res0 = type1;
- res1 = type1;
- } else {
- res0 = type0;
- res1 = type0;
- }
- } else if (isTypeUnsignedInt(type0) && (getTypeRank(type0) > getTypeRank(type1))) {
- res0 = type0;
- res1 = type0;
- } else if (isTypeUnsignedInt(type1) && (getTypeRank(type1) > getTypeRank(type0))) {
- res0 = type1;
- res1 = type1;
- } else if (isTypeSignedInt(type0)) {
- if (canSignedIntTypeRepresentAllUnsignedValues(type0, type1)) {
- res0 = type0;
- res1 = type0;
- } else {
- res0 = getCorrespondingUnsignedType(type0);
- res1 = getCorrespondingUnsignedType(type0);
- }
- } else if (isTypeSignedInt(type1)) {
- if (canSignedIntTypeRepresentAllUnsignedValues(type1, type0)) {
- res0 = type1;
- res1 = type1;
- } else {
- res0 = getCorrespondingUnsignedType(type1);
- res1 = getCorrespondingUnsignedType(type1);
- }
- }
- }
- return std::make_tuple(res0, res1);
- }
- //
- // Given a type, find what operation would fully construct it.
- //
- TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
- {
- TOperator op = EOpNull;
- if (type.getQualifier().isNonUniform())
- return EOpConstructNonuniform;
- if (type.isCoopMat())
- return EOpConstructCooperativeMatrix;
- switch (type.getBasicType()) {
- case EbtStruct:
- op = EOpConstructStruct;
- break;
- case EbtSampler:
- if (type.getSampler().isCombined())
- op = EOpConstructTextureSampler;
- break;
- case EbtFloat:
- if (type.isMatrix()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructMat2x2; break;
- case 3: op = EOpConstructMat2x3; break;
- case 4: op = EOpConstructMat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructMat3x2; break;
- case 3: op = EOpConstructMat3x3; break;
- case 4: op = EOpConstructMat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructMat4x2; break;
- case 3: op = EOpConstructMat4x3; break;
- case 4: op = EOpConstructMat4x4; break;
- default: break; // some compilers want this
- }
- break;
- default: break; // some compilers want this
- }
- } else {
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructFloat; break;
- case 2: op = EOpConstructVec2; break;
- case 3: op = EOpConstructVec3; break;
- case 4: op = EOpConstructVec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- case EbtInt:
- if (type.getMatrixCols()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructIMat2x2; break;
- case 3: op = EOpConstructIMat2x3; break;
- case 4: op = EOpConstructIMat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructIMat3x2; break;
- case 3: op = EOpConstructIMat3x3; break;
- case 4: op = EOpConstructIMat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructIMat4x2; break;
- case 3: op = EOpConstructIMat4x3; break;
- case 4: op = EOpConstructIMat4x4; break;
- default: break; // some compilers want this
- }
- break;
- }
- } else {
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructInt; break;
- case 2: op = EOpConstructIVec2; break;
- case 3: op = EOpConstructIVec3; break;
- case 4: op = EOpConstructIVec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- case EbtUint:
- if (type.getMatrixCols()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructUMat2x2; break;
- case 3: op = EOpConstructUMat2x3; break;
- case 4: op = EOpConstructUMat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructUMat3x2; break;
- case 3: op = EOpConstructUMat3x3; break;
- case 4: op = EOpConstructUMat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructUMat4x2; break;
- case 3: op = EOpConstructUMat4x3; break;
- case 4: op = EOpConstructUMat4x4; break;
- default: break; // some compilers want this
- }
- break;
- }
- } else {
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructUint; break;
- case 2: op = EOpConstructUVec2; break;
- case 3: op = EOpConstructUVec3; break;
- case 4: op = EOpConstructUVec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- case EbtBool:
- if (type.getMatrixCols()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructBMat2x2; break;
- case 3: op = EOpConstructBMat2x3; break;
- case 4: op = EOpConstructBMat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructBMat3x2; break;
- case 3: op = EOpConstructBMat3x3; break;
- case 4: op = EOpConstructBMat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructBMat4x2; break;
- case 3: op = EOpConstructBMat4x3; break;
- case 4: op = EOpConstructBMat4x4; break;
- default: break; // some compilers want this
- }
- break;
- }
- } else {
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructBool; break;
- case 2: op = EOpConstructBVec2; break;
- case 3: op = EOpConstructBVec3; break;
- case 4: op = EOpConstructBVec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- #ifndef GLSLANG_WEB
- case EbtDouble:
- if (type.getMatrixCols()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructDMat2x2; break;
- case 3: op = EOpConstructDMat2x3; break;
- case 4: op = EOpConstructDMat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructDMat3x2; break;
- case 3: op = EOpConstructDMat3x3; break;
- case 4: op = EOpConstructDMat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructDMat4x2; break;
- case 3: op = EOpConstructDMat4x3; break;
- case 4: op = EOpConstructDMat4x4; break;
- default: break; // some compilers want this
- }
- break;
- }
- } else {
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructDouble; break;
- case 2: op = EOpConstructDVec2; break;
- case 3: op = EOpConstructDVec3; break;
- case 4: op = EOpConstructDVec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- case EbtFloat16:
- if (type.getMatrixCols()) {
- switch (type.getMatrixCols()) {
- case 2:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructF16Mat2x2; break;
- case 3: op = EOpConstructF16Mat2x3; break;
- case 4: op = EOpConstructF16Mat2x4; break;
- default: break; // some compilers want this
- }
- break;
- case 3:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructF16Mat3x2; break;
- case 3: op = EOpConstructF16Mat3x3; break;
- case 4: op = EOpConstructF16Mat3x4; break;
- default: break; // some compilers want this
- }
- break;
- case 4:
- switch (type.getMatrixRows()) {
- case 2: op = EOpConstructF16Mat4x2; break;
- case 3: op = EOpConstructF16Mat4x3; break;
- case 4: op = EOpConstructF16Mat4x4; break;
- default: break; // some compilers want this
- }
- break;
- }
- }
- else {
- switch (type.getVectorSize()) {
- case 1: op = EOpConstructFloat16; break;
- case 2: op = EOpConstructF16Vec2; break;
- case 3: op = EOpConstructF16Vec3; break;
- case 4: op = EOpConstructF16Vec4; break;
- default: break; // some compilers want this
- }
- }
- break;
- case EbtInt8:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructInt8; break;
- case 2: op = EOpConstructI8Vec2; break;
- case 3: op = EOpConstructI8Vec3; break;
- case 4: op = EOpConstructI8Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtUint8:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructUint8; break;
- case 2: op = EOpConstructU8Vec2; break;
- case 3: op = EOpConstructU8Vec3; break;
- case 4: op = EOpConstructU8Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtInt16:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructInt16; break;
- case 2: op = EOpConstructI16Vec2; break;
- case 3: op = EOpConstructI16Vec3; break;
- case 4: op = EOpConstructI16Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtUint16:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructUint16; break;
- case 2: op = EOpConstructU16Vec2; break;
- case 3: op = EOpConstructU16Vec3; break;
- case 4: op = EOpConstructU16Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtInt64:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructInt64; break;
- case 2: op = EOpConstructI64Vec2; break;
- case 3: op = EOpConstructI64Vec3; break;
- case 4: op = EOpConstructI64Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtUint64:
- switch(type.getVectorSize()) {
- case 1: op = EOpConstructUint64; break;
- case 2: op = EOpConstructU64Vec2; break;
- case 3: op = EOpConstructU64Vec3; break;
- case 4: op = EOpConstructU64Vec4; break;
- default: break; // some compilers want this
- }
- break;
- case EbtReference:
- op = EOpConstructReference;
- break;
- case EbtAccStruct:
- op = EOpConstructAccStruct;
- break;
- #endif
- default:
- break;
- }
- return op;
- }
- //
- // Safe way to combine two nodes into an aggregate. Works with null pointers,
- // a node that's not a aggregate yet, etc.
- //
- // Returns the resulting aggregate, unless nullptr was passed in for
- // both existing nodes.
- //
- TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right)
- {
- if (left == nullptr && right == nullptr)
- return nullptr;
- TIntermAggregate* aggNode = nullptr;
- if (left != nullptr)
- aggNode = left->getAsAggregate();
- if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
- aggNode = new TIntermAggregate;
- if (left != nullptr)
- aggNode->getSequence().push_back(left);
- }
- if (right != nullptr)
- aggNode->getSequence().push_back(right);
- return aggNode;
- }
- TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& loc)
- {
- TIntermAggregate* aggNode = growAggregate(left, right);
- if (aggNode)
- aggNode->setLoc(loc);
- return aggNode;
- }
- //
- // Turn an existing node into an aggregate.
- //
- // Returns an aggregate, unless nullptr was passed in for the existing node.
- //
- TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node)
- {
- if (node == nullptr)
- return nullptr;
- TIntermAggregate* aggNode = new TIntermAggregate;
- aggNode->getSequence().push_back(node);
- aggNode->setLoc(node->getLoc());
- return aggNode;
- }
- TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& loc)
- {
- if (node == nullptr)
- return nullptr;
- TIntermAggregate* aggNode = new TIntermAggregate;
- aggNode->getSequence().push_back(node);
- aggNode->setLoc(loc);
- return aggNode;
- }
- //
- // Make an aggregate with an empty sequence.
- //
- TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
- {
- TIntermAggregate* aggNode = new TIntermAggregate;
- aggNode->setLoc(loc);
- return aggNode;
- }
- //
- // For "if" test nodes. There are three children; a condition,
- // a true path, and a false path. The two paths are in the
- // nodePair.
- //
- // Returns the selection node created.
- //
- TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
- {
- //
- // Don't prune the false path for compile-time constants; it's needed
- // for static access analysis.
- //
- TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
- node->setLoc(loc);
- return node;
- }
- TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
- {
- // However, the lowest precedence operators of the sequence operator ( , ) and the assignment operators
- // ... are not included in the operators that can create a constant expression.
- //
- // if (left->getType().getQualifier().storage == EvqConst &&
- // right->getType().getQualifier().storage == EvqConst) {
- // return right;
- //}
- TIntermTyped *commaAggregate = growAggregate(left, right, loc);
- commaAggregate->getAsAggregate()->setOperator(EOpComma);
- commaAggregate->setType(right->getType());
- commaAggregate->getWritableType().getQualifier().makeTemporary();
- return commaAggregate;
- }
- TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type, const TString* name, const TSourceLoc& loc)
- {
- TIntermMethod* method = new TIntermMethod(object, type, *name);
- method->setLoc(loc);
- return method;
- }
- //
- // For "?:" test nodes. There are three children; a condition,
- // a true path, and a false path. The two paths are specified
- // as separate parameters. For vector 'cond', the true and false
- // are not paths, but vectors to mix.
- //
- // Specialization constant operations include
- // - The ternary operator ( ? : )
- //
- // Returns the selection node created, or nullptr if one could not be.
- //
- TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock,
- const TSourceLoc& loc)
- {
- // If it's void, go to the if-then-else selection()
- if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
- TIntermNodePair pair = { trueBlock, falseBlock };
- TIntermSelection* selection = addSelection(cond, pair, loc);
- if (getSource() == EShSourceHlsl)
- selection->setNoShortCircuit();
- return selection;
- }
- //
- // Get compatible types.
- //
- auto children = addPairConversion(EOpSequence, trueBlock, falseBlock);
- trueBlock = std::get<0>(children);
- falseBlock = std::get<1>(children);
- if (trueBlock == nullptr || falseBlock == nullptr)
- return nullptr;
- // Handle a vector condition as a mix
- if (!cond->getType().isScalarOrVec1()) {
- TType targetVectorType(trueBlock->getType().getBasicType(), EvqTemporary,
- cond->getType().getVectorSize());
- // smear true/false operands as needed
- trueBlock = addUniShapeConversion(EOpMix, targetVectorType, trueBlock);
- falseBlock = addUniShapeConversion(EOpMix, targetVectorType, falseBlock);
- // After conversion, types have to match.
- if (falseBlock->getType() != trueBlock->getType())
- return nullptr;
- // make the mix operation
- TIntermAggregate* mix = makeAggregate(loc);
- mix = growAggregate(mix, falseBlock);
- mix = growAggregate(mix, trueBlock);
- mix = growAggregate(mix, cond);
- mix->setType(targetVectorType);
- mix->setOp(EOpMix);
- return mix;
- }
- // Now have a scalar condition...
- // Convert true and false expressions to matching types
- addBiShapeConversion(EOpMix, trueBlock, falseBlock);
- // After conversion, types have to match.
- if (falseBlock->getType() != trueBlock->getType())
- return nullptr;
- // Eliminate the selection when the condition is a scalar and all operands are constant.
- if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
- if (cond->getAsConstantUnion()->getConstArray()[0].getBConst())
- return trueBlock;
- else
- return falseBlock;
- }
- //
- // Make a selection node.
- //
- TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
- node->setLoc(loc);
- node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
- if ((cond->getQualifier().isConstant() && specConstantPropagates(*trueBlock, *falseBlock)) ||
- (cond->getQualifier().isSpecConstant() && trueBlock->getQualifier().isConstant() &&
- falseBlock->getQualifier().isConstant()))
- node->getQualifier().makeSpecConstant();
- else
- node->getQualifier().makeTemporary();
- if (getSource() == EShSourceHlsl)
- node->setNoShortCircuit();
- return node;
- }
- //
- // Constant terminal nodes. Has a union that contains bool, float or int constants
- //
- // Returns the constant union node created.
- //
- TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, const TSourceLoc& loc, bool literal) const
- {
- TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
- node->getQualifier().storage = EvqConst;
- node->setLoc(loc);
- if (literal)
- node->setLiteral();
- return node;
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(signed char i8, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setI8Const(i8);
- return addConstantUnion(unionArray, TType(EbtInt8, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned char u8, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setUConst(u8);
- return addConstantUnion(unionArray, TType(EbtUint8, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(signed short i16, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setI16Const(i16);
- return addConstantUnion(unionArray, TType(EbtInt16, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned short u16, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setU16Const(u16);
- return addConstantUnion(unionArray, TType(EbtUint16, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(int i, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setIConst(i);
- return addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned int u, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setUConst(u);
- return addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(long long i64, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setI64Const(i64);
- return addConstantUnion(unionArray, TType(EbtInt64, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned long long u64, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setU64Const(u64);
- return addConstantUnion(unionArray, TType(EbtUint64, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(bool b, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setBConst(b);
- return addConstantUnion(unionArray, TType(EbtBool, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseType, const TSourceLoc& loc, bool literal) const
- {
- assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16);
- TConstUnionArray unionArray(1);
- unionArray[0].setDConst(d);
- return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
- }
- TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const
- {
- TConstUnionArray unionArray(1);
- unionArray[0].setSConst(s);
- return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal);
- }
- // Put vector swizzle selectors onto the given sequence
- void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
- {
- TIntermConstantUnion* constIntNode = addConstantUnion(selector, loc);
- sequence.push_back(constIntNode);
- }
- // Put matrix swizzle selectors onto the given sequence
- void TIntermediate::pushSelector(TIntermSequence& sequence, const TMatrixSelector& selector, const TSourceLoc& loc)
- {
- TIntermConstantUnion* constIntNode = addConstantUnion(selector.coord1, loc);
- sequence.push_back(constIntNode);
- constIntNode = addConstantUnion(selector.coord2, loc);
- sequence.push_back(constIntNode);
- }
- // Make an aggregate node that has a sequence of all selectors.
- template TIntermTyped* TIntermediate::addSwizzle<TVectorSelector>(TSwizzleSelectors<TVectorSelector>& selector, const TSourceLoc& loc);
- template TIntermTyped* TIntermediate::addSwizzle<TMatrixSelector>(TSwizzleSelectors<TMatrixSelector>& selector, const TSourceLoc& loc);
- template<typename selectorType>
- TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors<selectorType>& selector, const TSourceLoc& loc)
- {
- TIntermAggregate* node = new TIntermAggregate(EOpSequence);
- node->setLoc(loc);
- TIntermSequence &sequenceVector = node->getSequence();
- for (int i = 0; i < selector.size(); i++)
- pushSelector(sequenceVector, selector[i], loc);
- return node;
- }
- //
- // Follow the left branches down to the root of an l-value
- // expression (just "." and []).
- //
- // Return the base of the l-value (where following indexing quits working).
- // Return nullptr if a chain following dereferences cannot be followed.
- //
- // 'swizzleOkay' says whether or not it is okay to consider a swizzle
- // a valid part of the dereference chain.
- //
- const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay)
- {
- do {
- const TIntermBinary* binary = node->getAsBinaryNode();
- if (binary == nullptr)
- return node;
- TOperator op = binary->getOp();
- if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle)
- return nullptr;
- if (! swizzleOkay) {
- if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle)
- return nullptr;
- if ((op == EOpIndexDirect || op == EOpIndexIndirect) &&
- (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) &&
- ! binary->getLeft()->getType().isArray())
- return nullptr;
- }
- node = node->getAsBinaryNode()->getLeft();
- } while (true);
- }
- //
- // Create while and do-while loop nodes.
- //
- TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
- const TSourceLoc& loc)
- {
- TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
- node->setLoc(loc);
- return node;
- }
- //
- // Create a for-loop sequence.
- //
- TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
- TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
- {
- node = new TIntermLoop(body, test, terminal, testFirst);
- node->setLoc(loc);
- // make a sequence of the initializer and statement, but try to reuse the
- // aggregate already created for whatever is in the initializer, if there is one
- TIntermAggregate* loopSequence = (initializer == nullptr ||
- initializer->getAsAggregate() == nullptr) ? makeAggregate(initializer, loc)
- : initializer->getAsAggregate();
- if (loopSequence != nullptr && loopSequence->getOp() == EOpSequence)
- loopSequence->setOp(EOpNull);
- loopSequence = growAggregate(loopSequence, node);
- loopSequence->setOperator(EOpSequence);
- return loopSequence;
- }
- //
- // Add branches.
- //
- TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc)
- {
- return addBranch(branchOp, nullptr, loc);
- }
- TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& loc)
- {
- TIntermBranch* node = new TIntermBranch(branchOp, expression);
- node->setLoc(loc);
- return node;
- }
- // Propagate precision from formal function return type to actual return type,
- // and on to its subtree.
- void TIntermBranch::updatePrecision(TPrecisionQualifier parentPrecision)
- {
- TIntermTyped* exp = getExpression();
- if (exp == nullptr)
- return;
- if (exp->getBasicType() == EbtInt || exp->getBasicType() == EbtUint ||
- exp->getBasicType() == EbtFloat || exp->getBasicType() == EbtFloat16) {
- if (parentPrecision != EpqNone && exp->getQualifier().precision == EpqNone) {
- exp->propagatePrecision(parentPrecision);
- }
- }
- }
- //
- // This is to be executed after the final root is put on top by the parsing
- // process.
- //
- bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
- {
- if (root == nullptr)
- return true;
- // Finish off the top-level sequence
- TIntermAggregate* aggRoot = root->getAsAggregate();
- if (aggRoot && aggRoot->getOp() == EOpNull)
- aggRoot->setOperator(EOpSequence);
- #ifndef GLSLANG_WEB
- // Propagate 'noContraction' label in backward from 'precise' variables.
- glslang::PropagateNoContraction(*this);
- switch (textureSamplerTransformMode) {
- case EShTexSampTransKeep:
- break;
- case EShTexSampTransUpgradeTextureRemoveSampler:
- performTextureUpgradeAndSamplerRemovalTransformation(root);
- break;
- case EShTexSampTransCount:
- assert(0);
- break;
- }
- #endif
- return true;
- }
- void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
- {
- // Add top-level nodes for declarations that must be checked cross
- // compilation unit by a linker, yet might not have been referenced
- // by the AST.
- //
- // Almost entirely, translation of symbols is driven by what's present
- // in the AST traversal, not by translating the symbol table.
- //
- // However, there are some special cases:
- // - From the specification: "Special built-in inputs gl_VertexID and
- // gl_InstanceID are also considered active vertex attributes."
- // - Linker-based type mismatch error reporting needs to see all
- // uniforms/ins/outs variables and blocks.
- // - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active.
- //
- // if (ftransformUsed) {
- // TODO: 1.1 lowering functionality: track ftransform() usage
- // addSymbolLinkageNode(root, symbolTable, "gl_Vertex");
- // addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix");
- //}
- if (language == EShLangVertex) {
- // the names won't be found in the symbol table unless the versions are right,
- // so version logic does not need to be repeated here
- addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID");
- addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID");
- }
- // Add a child to the root node for the linker objects
- linkage->setOperator(EOpLinkerObjects);
- treeRoot = growAggregate(treeRoot, linkage);
- }
- //
- // Add the given name or symbol to the list of nodes at the end of the tree used
- // for link-time checking and external linkage.
- //
- void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
- {
- TSymbol* symbol = symbolTable.find(name);
- if (symbol)
- addSymbolLinkageNode(linkage, *symbol->getAsVariable());
- }
- void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
- {
- const TVariable* variable = symbol.getAsVariable();
- if (! variable) {
- // This must be a member of an anonymous block, and we need to add the whole block
- const TAnonMember* anon = symbol.getAsAnonMember();
- variable = &anon->getAnonContainer();
- }
- TIntermSymbol* node = addSymbol(*variable);
- linkage = growAggregate(linkage, node);
- }
- //
- // Add a caller->callee relationship to the call graph.
- // Assumes the strings are unique per signature.
- //
- void TIntermediate::addToCallGraph(TInfoSink& /*infoSink*/, const TString& caller, const TString& callee)
- {
- // Duplicates are okay, but faster to not keep them, and they come grouped by caller,
- // as long as new ones are push on the same end we check on for duplicates
- for (TGraph::const_iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
- if (call->caller != caller)
- break;
- if (call->callee == callee)
- return;
- }
- callGraph.emplace_front(caller, callee);
- }
- //
- // This deletes the tree.
- //
- void TIntermediate::removeTree()
- {
- if (treeRoot)
- RemoveAllTreeNodes(treeRoot);
- }
- //
- // Implement the part of KHR_vulkan_glsl that lists the set of operations
- // that can result in a specialization constant operation.
- //
- // "5.x Specialization Constant Operations"
- //
- // Only some operations discussed in this section may be applied to a
- // specialization constant and still yield a result that is as
- // specialization constant. The operations allowed are listed below.
- // When a specialization constant is operated on with one of these
- // operators and with another constant or specialization constant, the
- // result is implicitly a specialization constant.
- //
- // - int(), uint(), and bool() constructors for type conversions
- // from any of the following types to any of the following types:
- // * int
- // * uint
- // * bool
- // - vector versions of the above conversion constructors
- // - allowed implicit conversions of the above
- // - swizzles (e.g., foo.yx)
- // - The following when applied to integer or unsigned integer types:
- // * unary negative ( - )
- // * binary operations ( + , - , * , / , % )
- // * shift ( <<, >> )
- // * bitwise operations ( & , | , ^ )
- // - The following when applied to integer or unsigned integer scalar types:
- // * comparison ( == , != , > , >= , < , <= )
- // - The following when applied to the Boolean scalar type:
- // * not ( ! )
- // * logical operations ( && , || , ^^ )
- // * comparison ( == , != )"
- //
- // This function just handles binary and unary nodes. Construction
- // rules are handled in construction paths that are not covered by the unary
- // and binary paths, while required conversions will still show up here
- // as unary converters in the from a construction operator.
- //
- bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
- {
- // The operations resulting in floating point are quite limited
- // (However, some floating-point operations result in bool, like ">",
- // so are handled later.)
- if (node.getType().isFloatingDomain()) {
- switch (node.getOp()) {
- case EOpIndexDirect:
- case EOpIndexIndirect:
- case EOpIndexDirectStruct:
- case EOpVectorSwizzle:
- case EOpConvFloatToDouble:
- case EOpConvDoubleToFloat:
- case EOpConvFloat16ToFloat:
- case EOpConvFloatToFloat16:
- case EOpConvFloat16ToDouble:
- case EOpConvDoubleToFloat16:
- return true;
- default:
- return false;
- }
- }
- // Check for floating-point arguments
- if (const TIntermBinary* bin = node.getAsBinaryNode())
- if (bin->getLeft() ->getType().isFloatingDomain() ||
- bin->getRight()->getType().isFloatingDomain())
- return false;
- // So, for now, we can assume everything left is non-floating-point...
- // Now check for integer/bool-based operations
- switch (node.getOp()) {
- // dereference/swizzle
- case EOpIndexDirect:
- case EOpIndexIndirect:
- case EOpIndexDirectStruct:
- case EOpVectorSwizzle:
- // (u)int* -> bool
- case EOpConvInt8ToBool:
- case EOpConvInt16ToBool:
- case EOpConvIntToBool:
- case EOpConvInt64ToBool:
- case EOpConvUint8ToBool:
- case EOpConvUint16ToBool:
- case EOpConvUintToBool:
- case EOpConvUint64ToBool:
- // bool -> (u)int*
- case EOpConvBoolToInt8:
- case EOpConvBoolToInt16:
- case EOpConvBoolToInt:
- case EOpConvBoolToInt64:
- case EOpConvBoolToUint8:
- case EOpConvBoolToUint16:
- case EOpConvBoolToUint:
- case EOpConvBoolToUint64:
- // int8_t -> (u)int*
- case EOpConvInt8ToInt16:
- case EOpConvInt8ToInt:
- case EOpConvInt8ToInt64:
- case EOpConvInt8ToUint8:
- case EOpConvInt8ToUint16:
- case EOpConvInt8ToUint:
- case EOpConvInt8ToUint64:
- // int16_t -> (u)int*
- case EOpConvInt16ToInt8:
- case EOpConvInt16ToInt:
- case EOpConvInt16ToInt64:
- case EOpConvInt16ToUint8:
- case EOpConvInt16ToUint16:
- case EOpConvInt16ToUint:
- case EOpConvInt16ToUint64:
- // int32_t -> (u)int*
- case EOpConvIntToInt8:
- case EOpConvIntToInt16:
- case EOpConvIntToInt64:
- case EOpConvIntToUint8:
- case EOpConvIntToUint16:
- case EOpConvIntToUint:
- case EOpConvIntToUint64:
- // int64_t -> (u)int*
- case EOpConvInt64ToInt8:
- case EOpConvInt64ToInt16:
- case EOpConvInt64ToInt:
- case EOpConvInt64ToUint8:
- case EOpConvInt64ToUint16:
- case EOpConvInt64ToUint:
- case EOpConvInt64ToUint64:
- // uint8_t -> (u)int*
- case EOpConvUint8ToInt8:
- case EOpConvUint8ToInt16:
- case EOpConvUint8ToInt:
- case EOpConvUint8ToInt64:
- case EOpConvUint8ToUint16:
- case EOpConvUint8ToUint:
- case EOpConvUint8ToUint64:
- // uint16_t -> (u)int*
- case EOpConvUint16ToInt8:
- case EOpConvUint16ToInt16:
- case EOpConvUint16ToInt:
- case EOpConvUint16ToInt64:
- case EOpConvUint16ToUint8:
- case EOpConvUint16ToUint:
- case EOpConvUint16ToUint64:
- // uint32_t -> (u)int*
- case EOpConvUintToInt8:
- case EOpConvUintToInt16:
- case EOpConvUintToInt:
- case EOpConvUintToInt64:
- case EOpConvUintToUint8:
- case EOpConvUintToUint16:
- case EOpConvUintToUint64:
- // uint64_t -> (u)int*
- case EOpConvUint64ToInt8:
- case EOpConvUint64ToInt16:
- case EOpConvUint64ToInt:
- case EOpConvUint64ToInt64:
- case EOpConvUint64ToUint8:
- case EOpConvUint64ToUint16:
- case EOpConvUint64ToUint:
- // unary operations
- case EOpNegative:
- case EOpLogicalNot:
- case EOpBitwiseNot:
- // binary operations
- case EOpAdd:
- case EOpSub:
- case EOpMul:
- case EOpVectorTimesScalar:
- case EOpDiv:
- case EOpMod:
- case EOpRightShift:
- case EOpLeftShift:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpLogicalAnd:
- case EOpEqual:
- case EOpNotEqual:
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- return true;
- default:
- return false;
- }
- }
- // Is the operation one that must propagate nonuniform?
- bool TIntermediate::isNonuniformPropagating(TOperator op) const
- {
- // "* All Operators in Section 5.1 (Operators), except for assignment,
- // arithmetic assignment, and sequence
- // * Component selection in Section 5.5
- // * Matrix components in Section 5.6
- // * Structure and Array Operations in Section 5.7, except for the length
- // method."
- switch (op) {
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- case EOpNegative:
- case EOpLogicalNot:
- case EOpVectorLogicalNot:
- case EOpBitwiseNot:
- case EOpAdd:
- case EOpSub:
- case EOpMul:
- case EOpDiv:
- case EOpMod:
- case EOpRightShift:
- case EOpLeftShift:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpEqual:
- case EOpNotEqual:
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpVectorTimesScalar:
- case EOpVectorTimesMatrix:
- case EOpMatrixTimesVector:
- case EOpMatrixTimesScalar:
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpLogicalAnd:
- case EOpIndexDirect:
- case EOpIndexIndirect:
- case EOpIndexDirectStruct:
- case EOpVectorSwizzle:
- return true;
- default:
- break;
- }
- return false;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Member functions of the nodes used for building the tree.
- //
- ////////////////////////////////////////////////////////////////
- //
- // Say whether or not an operation node changes the value of a variable.
- //
- // Returns true if state is modified.
- //
- bool TIntermOperator::modifiesState() const
- {
- switch (op) {
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- case EOpAssign:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpMulAssign:
- case EOpVectorTimesMatrixAssign:
- case EOpVectorTimesScalarAssign:
- case EOpMatrixTimesScalarAssign:
- case EOpMatrixTimesMatrixAssign:
- case EOpDivAssign:
- case EOpModAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpLeftShiftAssign:
- case EOpRightShiftAssign:
- return true;
- default:
- return false;
- }
- }
- //
- // returns true if the operator is for one of the constructors
- //
- bool TIntermOperator::isConstructor() const
- {
- return op > EOpConstructGuardStart && op < EOpConstructGuardEnd;
- }
- //
- // Make sure the type of an operator is appropriate for its
- // combination of operation and operand type. This will invoke
- // promoteUnary, promoteBinary, etc as needed.
- //
- // Returns false if nothing makes sense.
- //
- bool TIntermediate::promote(TIntermOperator* node)
- {
- if (node == nullptr)
- return false;
- if (node->getAsUnaryNode())
- return promoteUnary(*node->getAsUnaryNode());
- if (node->getAsBinaryNode())
- return promoteBinary(*node->getAsBinaryNode());
- if (node->getAsAggregate())
- return promoteAggregate(*node->getAsAggregate());
- return false;
- }
- //
- // See TIntermediate::promote
- //
- bool TIntermediate::promoteUnary(TIntermUnary& node)
- {
- const TOperator op = node.getOp();
- TIntermTyped* operand = node.getOperand();
- switch (op) {
- case EOpLogicalNot:
- // Convert operand to a boolean type
- if (operand->getBasicType() != EbtBool) {
- // Add constructor to boolean type. If that fails, we can't do it, so return false.
- TIntermTyped* converted = addConversion(op, TType(EbtBool), operand);
- if (converted == nullptr)
- return false;
- // Use the result of converting the node to a bool.
- node.setOperand(operand = converted); // also updates stack variable
- }
- break;
- case EOpBitwiseNot:
- if (!isTypeInt(operand->getBasicType()))
- return false;
- break;
- case EOpNegative:
- case EOpPostIncrement:
- case EOpPostDecrement:
- case EOpPreIncrement:
- case EOpPreDecrement:
- if (!isTypeInt(operand->getBasicType()) &&
- operand->getBasicType() != EbtFloat &&
- operand->getBasicType() != EbtFloat16 &&
- operand->getBasicType() != EbtDouble)
- return false;
- break;
- default:
- // HLSL uses this path for initial function signature finding for built-ins
- // taking a single argument, which generally don't participate in
- // operator-based type promotion (type conversion will occur later).
- // For now, scalar argument cases are relying on the setType() call below.
- if (getSource() == EShSourceHlsl)
- break;
- // GLSL only allows integer arguments for the cases identified above in the
- // case statements.
- if (operand->getBasicType() != EbtFloat)
- return false;
- }
- node.setType(operand->getType());
- node.getWritableType().getQualifier().makeTemporary();
- return true;
- }
- // Propagate precision qualifiers *up* from children to parent.
- void TIntermUnary::updatePrecision()
- {
- if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
- getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
- if (operand->getQualifier().precision > getQualifier().precision)
- getQualifier().precision = operand->getQualifier().precision;
- }
- }
- //
- // See TIntermediate::promote
- //
- bool TIntermediate::promoteBinary(TIntermBinary& node)
- {
- TOperator op = node.getOp();
- TIntermTyped* left = node.getLeft();
- TIntermTyped* right = node.getRight();
- // Arrays and structures have to be exact matches.
- if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct)
- && left->getType() != right->getType())
- return false;
- // Base assumption: just make the type the same as the left
- // operand. Only deviations from this will be coded.
- node.setType(left->getType());
- node.getWritableType().getQualifier().clear();
- // Composite and opaque types don't having pending operator changes, e.g.,
- // array, structure, and samplers. Just establish final type and correctness.
- if (left->isArray() || left->getBasicType() == EbtStruct || left->getBasicType() == EbtSampler) {
- switch (op) {
- case EOpEqual:
- case EOpNotEqual:
- if (left->getBasicType() == EbtSampler) {
- // can't compare samplers
- return false;
- } else {
- // Promote to conditional
- node.setType(TType(EbtBool));
- }
- return true;
- case EOpAssign:
- // Keep type from above
- return true;
- default:
- return false;
- }
- }
- //
- // We now have only scalars, vectors, and matrices to worry about.
- //
- // HLSL implicitly promotes bool -> int for numeric operations.
- // (Implicit conversions to make the operands match each other's types were already done.)
- if (getSource() == EShSourceHlsl &&
- (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)) {
- switch (op) {
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpRightShift:
- case EOpLeftShift:
- case EOpMod:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpMul:
- if (left->getBasicType() == EbtBool)
- left = createConversion(EbtInt, left);
- if (right->getBasicType() == EbtBool)
- right = createConversion(EbtInt, right);
- if (left == nullptr || right == nullptr)
- return false;
- node.setLeft(left);
- node.setRight(right);
- // Update the original base assumption on result type..
- node.setType(left->getType());
- node.getWritableType().getQualifier().clear();
- break;
- default:
- break;
- }
- }
- // Do general type checks against individual operands (comparing left and right is coming up, checking mixed shapes after that)
- switch (op) {
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- // Relational comparisons need numeric types and will promote to scalar Boolean.
- if (left->getBasicType() == EbtBool)
- return false;
- node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
- break;
- case EOpEqual:
- case EOpNotEqual:
- if (getSource() == EShSourceHlsl) {
- const int resultWidth = std::max(left->getVectorSize(), right->getVectorSize());
- // In HLSL, == or != on vectors means component-wise comparison.
- if (resultWidth > 1) {
- op = (op == EOpEqual) ? EOpVectorEqual : EOpVectorNotEqual;
- node.setOp(op);
- }
- node.setType(TType(EbtBool, EvqTemporary, resultWidth));
- } else {
- // All the above comparisons result in a bool (but not the vector compares)
- node.setType(TType(EbtBool));
- }
- break;
- case EOpLogicalAnd:
- case EOpLogicalOr:
- case EOpLogicalXor:
- // logical ops operate only on Booleans or vectors of Booleans.
- if (left->getBasicType() != EbtBool || left->isMatrix())
- return false;
- if (getSource() == EShSourceGlsl) {
- // logical ops operate only on scalar Booleans and will promote to scalar Boolean.
- if (left->isVector())
- return false;
- }
- node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
- break;
- case EOpRightShift:
- case EOpLeftShift:
- case EOpRightShiftAssign:
- case EOpLeftShiftAssign:
- case EOpMod:
- case EOpModAssign:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- if (getSource() == EShSourceHlsl)
- break;
- // Check for integer-only operands.
- if (!isTypeInt(left->getBasicType()) && !isTypeInt(right->getBasicType()))
- return false;
- if (left->isMatrix() || right->isMatrix())
- return false;
- break;
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpMul:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpMulAssign:
- case EOpDivAssign:
- // check for non-Boolean operands
- if (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)
- return false;
- default:
- break;
- }
- // Compare left and right, and finish with the cases where the operand types must match
- switch (op) {
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- case EOpEqual:
- case EOpNotEqual:
- case EOpVectorEqual:
- case EOpVectorNotEqual:
- case EOpLogicalAnd:
- case EOpLogicalOr:
- case EOpLogicalXor:
- return left->getType() == right->getType();
- case EOpMod:
- case EOpModAssign:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpDivAssign:
- // Quick out in case the types do match
- if (left->getType() == right->getType())
- return true;
- // Fall through
- case EOpMul:
- case EOpMulAssign:
- // At least the basic type has to match
- if (left->getBasicType() != right->getBasicType())
- return false;
- default:
- break;
- }
- if (left->getType().isCoopMat() || right->getType().isCoopMat()) {
- if (left->getType().isCoopMat() && right->getType().isCoopMat() &&
- *left->getType().getTypeParameters() != *right->getType().getTypeParameters()) {
- return false;
- }
- switch (op) {
- case EOpMul:
- case EOpMulAssign:
- if (left->getType().isCoopMat() && right->getType().isCoopMat()) {
- return false;
- }
- if (op == EOpMulAssign && right->getType().isCoopMat()) {
- return false;
- }
- node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar);
- if (right->getType().isCoopMat()) {
- node.setType(right->getType());
- }
- return true;
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpAssign:
- // These require both to be cooperative matrices
- if (!left->getType().isCoopMat() || !right->getType().isCoopMat()) {
- return false;
- }
- return true;
- default:
- break;
- }
- return false;
- }
- // Finish handling the case, for all ops, where both operands are scalars.
- if (left->isScalar() && right->isScalar())
- return true;
- // Finish handling the case, for all ops, where there are two vectors of different sizes
- if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize() && right->getVectorSize() > 1)
- return false;
- //
- // We now have a mix of scalars, vectors, or matrices, for non-relational operations.
- //
- // Can these two operands be combined, what is the resulting type?
- TBasicType basicType = left->getBasicType();
- switch (op) {
- case EOpMul:
- if (!left->isMatrix() && right->isMatrix()) {
- if (left->isVector()) {
- if (left->getVectorSize() != right->getMatrixRows())
- return false;
- node.setOp(op = EOpVectorTimesMatrix);
- node.setType(TType(basicType, EvqTemporary, right->getMatrixCols()));
- } else {
- node.setOp(op = EOpMatrixTimesScalar);
- node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows()));
- }
- } else if (left->isMatrix() && !right->isMatrix()) {
- if (right->isVector()) {
- if (left->getMatrixCols() != right->getVectorSize())
- return false;
- node.setOp(op = EOpMatrixTimesVector);
- node.setType(TType(basicType, EvqTemporary, left->getMatrixRows()));
- } else {
- node.setOp(op = EOpMatrixTimesScalar);
- }
- } else if (left->isMatrix() && right->isMatrix()) {
- if (left->getMatrixCols() != right->getMatrixRows())
- return false;
- node.setOp(op = EOpMatrixTimesMatrix);
- node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows()));
- } else if (! left->isMatrix() && ! right->isMatrix()) {
- if (left->isVector() && right->isVector()) {
- ; // leave as component product
- } else if (left->isVector() || right->isVector()) {
- node.setOp(op = EOpVectorTimesScalar);
- if (right->isVector())
- node.setType(TType(basicType, EvqTemporary, right->getVectorSize()));
- }
- } else {
- return false;
- }
- break;
- case EOpMulAssign:
- if (! left->isMatrix() && right->isMatrix()) {
- if (left->isVector()) {
- if (left->getVectorSize() != right->getMatrixRows() || left->getVectorSize() != right->getMatrixCols())
- return false;
- node.setOp(op = EOpVectorTimesMatrixAssign);
- } else {
- return false;
- }
- } else if (left->isMatrix() && !right->isMatrix()) {
- if (right->isVector()) {
- return false;
- } else {
- node.setOp(op = EOpMatrixTimesScalarAssign);
- }
- } else if (left->isMatrix() && right->isMatrix()) {
- if (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows())
- return false;
- node.setOp(op = EOpMatrixTimesMatrixAssign);
- } else if (!left->isMatrix() && !right->isMatrix()) {
- if (left->isVector() && right->isVector()) {
- // leave as component product
- } else if (left->isVector() || right->isVector()) {
- if (! left->isVector())
- return false;
- node.setOp(op = EOpVectorTimesScalarAssign);
- }
- } else {
- return false;
- }
- break;
- case EOpRightShift:
- case EOpLeftShift:
- case EOpRightShiftAssign:
- case EOpLeftShiftAssign:
- if (right->isVector() && (! left->isVector() || right->getVectorSize() != left->getVectorSize()))
- return false;
- break;
- case EOpAssign:
- if (left->getVectorSize() != right->getVectorSize() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows())
- return false;
- // fall through
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpMod:
- case EOpAnd:
- case EOpInclusiveOr:
- case EOpExclusiveOr:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpDivAssign:
- case EOpModAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- if ((left->isMatrix() && right->isVector()) ||
- (left->isVector() && right->isMatrix()) ||
- left->getBasicType() != right->getBasicType())
- return false;
- if (left->isMatrix() && right->isMatrix() && (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows()))
- return false;
- if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
- return false;
- if (right->isVector() || right->isMatrix()) {
- node.getWritableType().shallowCopy(right->getType());
- node.getWritableType().getQualifier().makeTemporary();
- }
- break;
- default:
- return false;
- }
- //
- // One more check for assignment.
- //
- switch (op) {
- // The resulting type has to match the left operand.
- case EOpAssign:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpMulAssign:
- case EOpDivAssign:
- case EOpModAssign:
- case EOpAndAssign:
- case EOpInclusiveOrAssign:
- case EOpExclusiveOrAssign:
- case EOpLeftShiftAssign:
- case EOpRightShiftAssign:
- if (node.getType() != left->getType())
- return false;
- break;
- default:
- break;
- }
- return true;
- }
- //
- // See TIntermediate::promote
- //
- bool TIntermediate::promoteAggregate(TIntermAggregate& node)
- {
- TOperator op = node.getOp();
- TIntermSequence& args = node.getSequence();
- const int numArgs = static_cast<int>(args.size());
- // Presently, only hlsl does intrinsic promotions.
- if (getSource() != EShSourceHlsl)
- return true;
- // set of opcodes that can be promoted in this manner.
- switch (op) {
- case EOpAtan:
- case EOpClamp:
- case EOpCross:
- case EOpDistance:
- case EOpDot:
- case EOpDst:
- case EOpFaceForward:
- // case EOpFindMSB: TODO:
- // case EOpFindLSB: TODO:
- case EOpFma:
- case EOpMod:
- case EOpFrexp:
- case EOpLdexp:
- case EOpMix:
- case EOpLit:
- case EOpMax:
- case EOpMin:
- case EOpModf:
- // case EOpGenMul: TODO:
- case EOpPow:
- case EOpReflect:
- case EOpRefract:
- // case EOpSinCos: TODO:
- case EOpSmoothStep:
- case EOpStep:
- break;
- default:
- return true;
- }
- // TODO: array and struct behavior
- // Try converting all nodes to the given node's type
- TIntermSequence convertedArgs(numArgs, nullptr);
- // Try to convert all types to the nonConvArg type.
- for (int nonConvArg = 0; nonConvArg < numArgs; ++nonConvArg) {
- // Try converting all args to this arg's type
- for (int convArg = 0; convArg < numArgs; ++convArg) {
- convertedArgs[convArg] = addConversion(op, args[nonConvArg]->getAsTyped()->getType(),
- args[convArg]->getAsTyped());
- }
- // If we successfully converted all the args, use the result.
- if (std::all_of(convertedArgs.begin(), convertedArgs.end(),
- [](const TIntermNode* node) { return node != nullptr; })) {
- std::swap(args, convertedArgs);
- return true;
- }
- }
- return false;
- }
- // Propagate precision qualifiers *up* from children to parent, and then
- // back *down* again to the children's subtrees.
- void TIntermBinary::updatePrecision()
- {
- if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
- getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
- getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision);
- if (getQualifier().precision != EpqNone) {
- left->propagatePrecision(getQualifier().precision);
- right->propagatePrecision(getQualifier().precision);
- }
- }
- }
- // Recursively propagate precision qualifiers *down* the subtree of the current node,
- // until reaching a node that already has a precision qualifier or otherwise does
- // not participate in precision propagation.
- void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
- {
- if (getQualifier().precision != EpqNone ||
- (getBasicType() != EbtInt && getBasicType() != EbtUint &&
- getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
- return;
- getQualifier().precision = newPrecision;
- TIntermBinary* binaryNode = getAsBinaryNode();
- if (binaryNode) {
- binaryNode->getLeft()->propagatePrecision(newPrecision);
- binaryNode->getRight()->propagatePrecision(newPrecision);
- return;
- }
- TIntermUnary* unaryNode = getAsUnaryNode();
- if (unaryNode) {
- unaryNode->getOperand()->propagatePrecision(newPrecision);
- return;
- }
- TIntermAggregate* aggregateNode = getAsAggregate();
- if (aggregateNode) {
- TIntermSequence operands = aggregateNode->getSequence();
- for (unsigned int i = 0; i < operands.size(); ++i) {
- TIntermTyped* typedNode = operands[i]->getAsTyped();
- if (! typedNode)
- break;
- typedNode->propagatePrecision(newPrecision);
- }
- return;
- }
- TIntermSelection* selectionNode = getAsSelectionNode();
- if (selectionNode) {
- TIntermTyped* typedNode = selectionNode->getTrueBlock()->getAsTyped();
- if (typedNode) {
- typedNode->propagatePrecision(newPrecision);
- typedNode = selectionNode->getFalseBlock()->getAsTyped();
- if (typedNode)
- typedNode->propagatePrecision(newPrecision);
- }
- return;
- }
- }
- TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
- {
- const TConstUnionArray& rightUnionArray = node->getConstArray();
- int size = node->getType().computeNumComponents();
- TConstUnionArray leftUnionArray(size);
- for (int i=0; i < size; i++) {
- #define PROMOTE(Set, CType, Get) leftUnionArray[i].Set(static_cast<CType>(rightUnionArray[i].Get()))
- #define PROMOTE_TO_BOOL(Get) leftUnionArray[i].setBConst(rightUnionArray[i].Get() != 0)
- #ifdef GLSLANG_WEB
- #define TO_ALL(Get) \
- switch (promoteTo) { \
- case EbtFloat: PROMOTE(setDConst, double, Get); break; \
- case EbtInt: PROMOTE(setIConst, int, Get); break; \
- case EbtUint: PROMOTE(setUConst, unsigned int, Get); break; \
- case EbtBool: PROMOTE_TO_BOOL(Get); break; \
- default: return node; \
- }
- #else
- #define TO_ALL(Get) \
- switch (promoteTo) { \
- case EbtFloat16: PROMOTE(setDConst, double, Get); break; \
- case EbtFloat: PROMOTE(setDConst, double, Get); break; \
- case EbtDouble: PROMOTE(setDConst, double, Get); break; \
- case EbtInt8: PROMOTE(setI8Const, char, Get); break; \
- case EbtInt16: PROMOTE(setI16Const, short, Get); break; \
- case EbtInt: PROMOTE(setIConst, int, Get); break; \
- case EbtInt64: PROMOTE(setI64Const, long long, Get); break; \
- case EbtUint8: PROMOTE(setU8Const, unsigned char, Get); break; \
- case EbtUint16: PROMOTE(setU16Const, unsigned short, Get); break; \
- case EbtUint: PROMOTE(setUConst, unsigned int, Get); break; \
- case EbtUint64: PROMOTE(setU64Const, unsigned long long, Get); break; \
- case EbtBool: PROMOTE_TO_BOOL(Get); break; \
- default: return node; \
- }
- #endif
- switch (node->getType().getBasicType()) {
- case EbtFloat: TO_ALL(getDConst); break;
- case EbtInt: TO_ALL(getIConst); break;
- case EbtUint: TO_ALL(getUConst); break;
- case EbtBool: TO_ALL(getBConst); break;
- #ifndef GLSLANG_WEB
- case EbtFloat16: TO_ALL(getDConst); break;
- case EbtDouble: TO_ALL(getDConst); break;
- case EbtInt8: TO_ALL(getI8Const); break;
- case EbtInt16: TO_ALL(getI16Const); break;
- case EbtInt64: TO_ALL(getI64Const); break;
- case EbtUint8: TO_ALL(getU8Const); break;
- case EbtUint16: TO_ALL(getU16Const); break;
- case EbtUint64: TO_ALL(getU64Const); break;
- #endif
- default: return node;
- }
- }
- const TType& t = node->getType();
- return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier().storage, t.getVectorSize(), t.getMatrixCols(), t.getMatrixRows()),
- node->getLoc());
- }
- void TIntermAggregate::setPragmaTable(const TPragmaTable& pTable)
- {
- assert(pragmaTable == nullptr);
- pragmaTable = new TPragmaTable;
- *pragmaTable = pTable;
- }
- // If either node is a specialization constant, while the other is
- // a constant (or specialization constant), the result is still
- // a specialization constant.
- bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TIntermTyped& node2)
- {
- return (node1.getType().getQualifier().isSpecConstant() && node2.getType().getQualifier().isConstant()) ||
- (node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant());
- }
- struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
- void visitSymbol(TIntermSymbol* symbol) override {
- if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) {
- symbol->getWritableType().getSampler().setCombined(true);
- }
- }
- bool visitAggregate(TVisit, TIntermAggregate* ag) override {
- using namespace std;
- TIntermSequence& seq = ag->getSequence();
- TQualifierList& qual = ag->getQualifierList();
- // qual and seq are indexed using the same indices, so we have to modify both in lock-step
- assert(seq.size() == qual.size() || qual.empty());
- size_t write = 0;
- for (size_t i = 0; i < seq.size(); ++i) {
- TIntermSymbol* symbol = seq[i]->getAsSymbolNode();
- if (symbol && symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()) {
- // remove pure sampler variables
- continue;
- }
- TIntermNode* result = seq[i];
- // replace constructors with sampler/textures
- TIntermAggregate *constructor = seq[i]->getAsAggregate();
- if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
- if (!constructor->getSequence().empty())
- result = constructor->getSequence()[0];
- }
- // write new node & qualifier
- seq[write] = result;
- if (!qual.empty())
- qual[write] = qual[i];
- write++;
- }
- seq.resize(write);
- if (!qual.empty())
- qual.resize(write);
- return true;
- }
- };
- void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root)
- {
- TextureUpgradeAndSamplerRemovalTransform transform;
- root->traverse(&transform);
- }
- const char* TIntermediate::getResourceName(TResourceType res)
- {
- switch (res) {
- case EResSampler: return "shift-sampler-binding";
- case EResTexture: return "shift-texture-binding";
- case EResImage: return "shift-image-binding";
- case EResUbo: return "shift-UBO-binding";
- case EResSsbo: return "shift-ssbo-binding";
- case EResUav: return "shift-uav-binding";
- default:
- assert(0); // internal error: should only be called with valid resource types.
- return nullptr;
- }
- }
- } // end namespace glslang
|