validate_builtins.cpp 208 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775
  1. // Copyright (c) 2018 Google LLC.
  2. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
  3. // reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // Validates correctness of built-in variables.
  17. #include <array>
  18. #include <functional>
  19. #include <list>
  20. #include <map>
  21. #include <set>
  22. #include <sstream>
  23. #include <stack>
  24. #include <string>
  25. #include <vector>
  26. #include "source/opcode.h"
  27. #include "source/spirv_target_env.h"
  28. #include "source/util/bitutils.h"
  29. #include "source/val/instruction.h"
  30. #include "source/val/validate.h"
  31. #include "source/val/validation_state.h"
  32. namespace spvtools {
  33. namespace val {
  34. namespace {
  35. // Returns a short textual description of the id defined by the given
  36. // instruction.
  37. std::string GetIdDesc(const Instruction& inst) {
  38. std::ostringstream ss;
  39. ss << "ID <" << inst.id() << "> (Op" << spvOpcodeString(inst.opcode()) << ")";
  40. return ss.str();
  41. }
  42. // Gets underlying data type which is
  43. // - member type if instruction is OpTypeStruct
  44. // (member index is taken from decoration).
  45. // - data type if id creates a pointer.
  46. // - type of the constant if instruction is OpConst or OpSpecConst.
  47. //
  48. // Fails in any other case. The function is based on built-ins allowed by
  49. // the Vulkan spec.
  50. // TODO: If non-Vulkan validation rules are added then it might need
  51. // to be refactored.
  52. spv_result_t GetUnderlyingType(ValidationState_t& _,
  53. const Decoration& decoration,
  54. const Instruction& inst,
  55. uint32_t* underlying_type) {
  56. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  57. if (inst.opcode() != spv::Op::OpTypeStruct) {
  58. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  59. << GetIdDesc(inst)
  60. << "Attempted to get underlying data type via member index for "
  61. "non-struct type.";
  62. }
  63. *underlying_type = inst.word(decoration.struct_member_index() + 2);
  64. return SPV_SUCCESS;
  65. }
  66. if (inst.opcode() == spv::Op::OpTypeStruct) {
  67. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  68. << GetIdDesc(inst)
  69. << " did not find an member index to get underlying data type for "
  70. "struct type.";
  71. }
  72. if (spvOpcodeIsConstant(inst.opcode())) {
  73. *underlying_type = inst.type_id();
  74. return SPV_SUCCESS;
  75. }
  76. spv::StorageClass storage_class;
  77. if (!_.GetPointerTypeInfo(inst.type_id(), underlying_type, &storage_class)) {
  78. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  79. << GetIdDesc(inst)
  80. << " is decorated with BuiltIn. BuiltIn decoration should only be "
  81. "applied to struct types, variables and constants.";
  82. }
  83. return SPV_SUCCESS;
  84. }
  85. // Returns Storage Class used by the instruction if applicable.
  86. // Returns spv::StorageClass::Max if not.
  87. spv::StorageClass GetStorageClass(const Instruction& inst) {
  88. switch (inst.opcode()) {
  89. case spv::Op::OpTypePointer:
  90. case spv::Op::OpTypeUntypedPointerKHR:
  91. case spv::Op::OpTypeForwardPointer: {
  92. return spv::StorageClass(inst.word(2));
  93. }
  94. case spv::Op::OpVariable: {
  95. return spv::StorageClass(inst.word(3));
  96. }
  97. case spv::Op::OpUntypedVariableKHR: {
  98. return spv::StorageClass(inst.word(4));
  99. }
  100. case spv::Op::OpGenericCastToPtrExplicit: {
  101. return spv::StorageClass(inst.word(4));
  102. }
  103. default: { break; }
  104. }
  105. return spv::StorageClass::Max;
  106. }
  107. typedef enum VUIDError_ {
  108. VUIDErrorExecutionModel = 0,
  109. VUIDErrorStorageClass = 1,
  110. VUIDErrorType = 2,
  111. VUIDErrorMax,
  112. } VUIDError;
  113. const static uint32_t NumVUIDBuiltins = 40;
  114. typedef struct {
  115. spv::BuiltIn builtIn;
  116. uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
  117. } BuiltinVUIDMapping;
  118. // Many built-ins have the same checks (Storage Class, Type, etc)
  119. // This table provides a nice LUT for the VUIDs
  120. std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
  121. // clang-format off
  122. {spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}},
  123. {spv::BuiltIn::SubgroupGeMask, {0, 4372, 4373}},
  124. {spv::BuiltIn::SubgroupGtMask, {0, 4374, 4375}},
  125. {spv::BuiltIn::SubgroupLeMask, {0, 4376, 4377}},
  126. {spv::BuiltIn::SubgroupLtMask, {0, 4378, 4379}},
  127. {spv::BuiltIn::SubgroupLocalInvocationId, {0, 4380, 4381}},
  128. {spv::BuiltIn::SubgroupSize, {0, 4382, 4383}},
  129. {spv::BuiltIn::GlobalInvocationId, {4236, 4237, 4238}},
  130. {spv::BuiltIn::LocalInvocationId, {4281, 4282, 4283}},
  131. {spv::BuiltIn::NumWorkgroups, {4296, 4297, 4298}},
  132. {spv::BuiltIn::NumSubgroups, {4293, 4294, 4295}},
  133. {spv::BuiltIn::SubgroupId, {4367, 4368, 4369}},
  134. {spv::BuiltIn::WorkgroupId, {4422, 4423, 4424}},
  135. {spv::BuiltIn::HitKindKHR, {4242, 4243, 4244}},
  136. {spv::BuiltIn::HitTNV, {4245, 4246, 4247}},
  137. {spv::BuiltIn::InstanceCustomIndexKHR, {4251, 4252, 4253}},
  138. {spv::BuiltIn::InstanceId, {4254, 4255, 4256}},
  139. {spv::BuiltIn::RayGeometryIndexKHR, {4345, 4346, 4347}},
  140. {spv::BuiltIn::ObjectRayDirectionKHR, {4299, 4300, 4301}},
  141. {spv::BuiltIn::ObjectRayOriginKHR, {4302, 4303, 4304}},
  142. {spv::BuiltIn::ObjectToWorldKHR, {4305, 4306, 4307}},
  143. {spv::BuiltIn::WorldToObjectKHR, {4434, 4435, 4436}},
  144. {spv::BuiltIn::IncomingRayFlagsKHR, {4248, 4249, 4250}},
  145. {spv::BuiltIn::RayTminKHR, {4351, 4352, 4353}},
  146. {spv::BuiltIn::RayTmaxKHR, {4348, 4349, 4350}},
  147. {spv::BuiltIn::WorldRayDirectionKHR, {4428, 4429, 4430}},
  148. {spv::BuiltIn::WorldRayOriginKHR, {4431, 4432, 4433}},
  149. {spv::BuiltIn::LaunchIdKHR, {4266, 4267, 4268}},
  150. {spv::BuiltIn::LaunchSizeKHR, {4269, 4270, 4271}},
  151. {spv::BuiltIn::FragInvocationCountEXT, {4217, 4218, 4219}},
  152. {spv::BuiltIn::FragSizeEXT, {4220, 4221, 4222}},
  153. {spv::BuiltIn::FragStencilRefEXT, {4223, 4224, 4225}},
  154. {spv::BuiltIn::FullyCoveredEXT, {4232, 4233, 4234}},
  155. {spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}},
  156. {spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}},
  157. {spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}},
  158. {spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}},
  159. {spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}},
  160. {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
  161. {spv::BuiltIn::CullPrimitiveEXT, {7034, 7035, 7036}},
  162. // clang-format on
  163. }};
  164. uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
  165. uint32_t vuid = 0;
  166. for (const auto& iter: builtinVUIDInfo) {
  167. if (iter.builtIn == builtIn) {
  168. assert(type < VUIDErrorMax);
  169. vuid = iter.vuid[type];
  170. break;
  171. }
  172. }
  173. return vuid;
  174. }
  175. bool IsExecutionModelValidForRtBuiltIn(spv::BuiltIn builtin,
  176. spv::ExecutionModel stage) {
  177. switch (builtin) {
  178. case spv::BuiltIn::HitKindKHR:
  179. case spv::BuiltIn::HitTNV:
  180. if (stage == spv::ExecutionModel::AnyHitKHR ||
  181. stage == spv::ExecutionModel::ClosestHitKHR) {
  182. return true;
  183. }
  184. break;
  185. case spv::BuiltIn::InstanceCustomIndexKHR:
  186. case spv::BuiltIn::InstanceId:
  187. case spv::BuiltIn::RayGeometryIndexKHR:
  188. case spv::BuiltIn::ObjectRayDirectionKHR:
  189. case spv::BuiltIn::ObjectRayOriginKHR:
  190. case spv::BuiltIn::ObjectToWorldKHR:
  191. case spv::BuiltIn::WorldToObjectKHR:
  192. switch (stage) {
  193. case spv::ExecutionModel::IntersectionKHR:
  194. case spv::ExecutionModel::AnyHitKHR:
  195. case spv::ExecutionModel::ClosestHitKHR:
  196. return true;
  197. default:
  198. return false;
  199. }
  200. break;
  201. case spv::BuiltIn::IncomingRayFlagsKHR:
  202. case spv::BuiltIn::RayTminKHR:
  203. case spv::BuiltIn::RayTmaxKHR:
  204. case spv::BuiltIn::WorldRayDirectionKHR:
  205. case spv::BuiltIn::WorldRayOriginKHR:
  206. case spv::BuiltIn::CullMaskKHR:
  207. switch (stage) {
  208. case spv::ExecutionModel::IntersectionKHR:
  209. case spv::ExecutionModel::AnyHitKHR:
  210. case spv::ExecutionModel::ClosestHitKHR:
  211. case spv::ExecutionModel::MissKHR:
  212. return true;
  213. default:
  214. return false;
  215. }
  216. break;
  217. case spv::BuiltIn::LaunchIdKHR:
  218. case spv::BuiltIn::LaunchSizeKHR:
  219. switch (stage) {
  220. case spv::ExecutionModel::RayGenerationKHR:
  221. case spv::ExecutionModel::IntersectionKHR:
  222. case spv::ExecutionModel::AnyHitKHR:
  223. case spv::ExecutionModel::ClosestHitKHR:
  224. case spv::ExecutionModel::MissKHR:
  225. case spv::ExecutionModel::CallableKHR:
  226. return true;
  227. default:
  228. return false;
  229. }
  230. break;
  231. default:
  232. break;
  233. }
  234. return false;
  235. }
  236. // Helper class managing validation of built-ins.
  237. // TODO: Generic functionality of this class can be moved into
  238. // ValidationState_t to be made available to other users.
  239. class BuiltInsValidator {
  240. public:
  241. BuiltInsValidator(ValidationState_t& vstate) : _(vstate) {}
  242. // Run validation.
  243. spv_result_t Run();
  244. private:
  245. // Goes through all decorations in the module, if decoration is BuiltIn
  246. // calls ValidateSingleBuiltInAtDefinition().
  247. spv_result_t ValidateBuiltInsAtDefinition();
  248. // Validates the instruction defining an id with built-in decoration.
  249. // Can be called multiple times for the same id, if multiple built-ins are
  250. // specified. Seeds id_to_at_reference_checks_ with decorated ids if needed.
  251. spv_result_t ValidateSingleBuiltInAtDefinition(const Decoration& decoration,
  252. const Instruction& inst);
  253. spv_result_t ValidateSingleBuiltInAtDefinitionVulkan(
  254. const Decoration& decoration, const Instruction& inst,
  255. const spv::BuiltIn label);
  256. // The following section contains functions which are called when id defined
  257. // by |inst| is decorated with BuiltIn |decoration|.
  258. // Most functions are specific to a single built-in and have naming scheme:
  259. // ValidateXYZAtDefinition. Some functions are common to multiple kinds of
  260. // BuiltIn.
  261. spv_result_t ValidateClipOrCullDistanceAtDefinition(
  262. const Decoration& decoration, const Instruction& inst);
  263. spv_result_t ValidateFragCoordAtDefinition(const Decoration& decoration,
  264. const Instruction& inst);
  265. spv_result_t ValidateFragDepthAtDefinition(const Decoration& decoration,
  266. const Instruction& inst);
  267. spv_result_t ValidateFrontFacingAtDefinition(const Decoration& decoration,
  268. const Instruction& inst);
  269. spv_result_t ValidateHelperInvocationAtDefinition(
  270. const Decoration& decoration, const Instruction& inst);
  271. spv_result_t ValidateInvocationIdAtDefinition(const Decoration& decoration,
  272. const Instruction& inst);
  273. spv_result_t ValidateInstanceIndexAtDefinition(const Decoration& decoration,
  274. const Instruction& inst);
  275. spv_result_t ValidateLayerOrViewportIndexAtDefinition(
  276. const Decoration& decoration, const Instruction& inst);
  277. spv_result_t ValidatePatchVerticesAtDefinition(const Decoration& decoration,
  278. const Instruction& inst);
  279. spv_result_t ValidatePointCoordAtDefinition(const Decoration& decoration,
  280. const Instruction& inst);
  281. spv_result_t ValidatePointSizeAtDefinition(const Decoration& decoration,
  282. const Instruction& inst);
  283. spv_result_t ValidatePositionAtDefinition(const Decoration& decoration,
  284. const Instruction& inst);
  285. spv_result_t ValidatePrimitiveIdAtDefinition(const Decoration& decoration,
  286. const Instruction& inst);
  287. spv_result_t ValidateSampleIdAtDefinition(const Decoration& decoration,
  288. const Instruction& inst);
  289. spv_result_t ValidateSampleMaskAtDefinition(const Decoration& decoration,
  290. const Instruction& inst);
  291. spv_result_t ValidateSamplePositionAtDefinition(const Decoration& decoration,
  292. const Instruction& inst);
  293. spv_result_t ValidateTessCoordAtDefinition(const Decoration& decoration,
  294. const Instruction& inst);
  295. spv_result_t ValidateTessLevelOuterAtDefinition(const Decoration& decoration,
  296. const Instruction& inst);
  297. spv_result_t ValidateTessLevelInnerAtDefinition(const Decoration& decoration,
  298. const Instruction& inst);
  299. spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
  300. const Instruction& inst);
  301. spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
  302. const Instruction& inst);
  303. spv_result_t ValidateLocalInvocationIndexAtDefinition(
  304. const Decoration& decoration, const Instruction& inst);
  305. spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
  306. const Instruction& inst);
  307. spv_result_t ValidateBaseInstanceOrVertexAtDefinition(
  308. const Decoration& decoration, const Instruction& inst);
  309. spv_result_t ValidateDrawIndexAtDefinition(const Decoration& decoration,
  310. const Instruction& inst);
  311. spv_result_t ValidateViewIndexAtDefinition(const Decoration& decoration,
  312. const Instruction& inst);
  313. spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration,
  314. const Instruction& inst);
  315. spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
  316. const Instruction& inst);
  317. spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration,
  318. const Instruction& inst);
  319. spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration,
  320. const Instruction& inst);
  321. spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration,
  322. const Instruction& inst);
  323. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  324. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
  325. const Decoration& decoration, const Instruction& inst);
  326. spv_result_t ValidateNVSMOrARMCoreBuiltinsAtDefinition(const Decoration& decoration,
  327. const Instruction& inst);
  328. // Used for BaryCoord, BaryCoordNoPersp.
  329. spv_result_t ValidateFragmentShaderF32Vec3InputAtDefinition(
  330. const Decoration& decoration, const Instruction& inst);
  331. // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
  332. // SubgroupLeMask.
  333. spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
  334. const Instruction& inst);
  335. // Used for SubgroupLocalInvocationId, SubgroupSize.
  336. spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
  337. const Instruction& inst);
  338. // Used for SubgroupId, NumSubgroups.
  339. spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
  340. const Instruction& inst);
  341. spv_result_t ValidatePrimitiveShadingRateAtDefinition(
  342. const Decoration& decoration, const Instruction& inst);
  343. spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
  344. const Instruction& inst);
  345. spv_result_t ValidateRayTracingBuiltinsAtDefinition(
  346. const Decoration& decoration, const Instruction& inst);
  347. spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
  348. const Decoration& decoration, const Instruction& inst);
  349. // The following section contains functions which are called when id defined
  350. // by |referenced_inst| is
  351. // 1. referenced by |referenced_from_inst|
  352. // 2. dependent on |built_in_inst| which is decorated with BuiltIn
  353. // |decoration|. Most functions are specific to a single built-in and have
  354. // naming scheme: ValidateXYZAtReference. Some functions are common to
  355. // multiple kinds of BuiltIn.
  356. spv_result_t ValidateFragCoordAtReference(
  357. const Decoration& decoration, const Instruction& built_in_inst,
  358. const Instruction& referenced_inst,
  359. const Instruction& referenced_from_inst);
  360. spv_result_t ValidateFragDepthAtReference(
  361. const Decoration& decoration, const Instruction& built_in_inst,
  362. const Instruction& referenced_inst,
  363. const Instruction& referenced_from_inst);
  364. spv_result_t ValidateFrontFacingAtReference(
  365. const Decoration& decoration, const Instruction& built_in_inst,
  366. const Instruction& referenced_inst,
  367. const Instruction& referenced_from_inst);
  368. spv_result_t ValidateHelperInvocationAtReference(
  369. const Decoration& decoration, const Instruction& built_in_inst,
  370. const Instruction& referenced_inst,
  371. const Instruction& referenced_from_inst);
  372. spv_result_t ValidateInvocationIdAtReference(
  373. const Decoration& decoration, const Instruction& built_in_inst,
  374. const Instruction& referenced_inst,
  375. const Instruction& referenced_from_inst);
  376. spv_result_t ValidateInstanceIndexAtReference(
  377. const Decoration& decoration, const Instruction& built_in_inst,
  378. const Instruction& referenced_inst,
  379. const Instruction& referenced_from_inst);
  380. spv_result_t ValidatePatchVerticesAtReference(
  381. const Decoration& decoration, const Instruction& built_in_inst,
  382. const Instruction& referenced_inst,
  383. const Instruction& referenced_from_inst);
  384. spv_result_t ValidatePointCoordAtReference(
  385. const Decoration& decoration, const Instruction& built_in_inst,
  386. const Instruction& referenced_inst,
  387. const Instruction& referenced_from_inst);
  388. spv_result_t ValidatePointSizeAtReference(
  389. const Decoration& decoration, const Instruction& built_in_inst,
  390. const Instruction& referenced_inst,
  391. const Instruction& referenced_from_inst);
  392. spv_result_t ValidatePositionAtReference(
  393. const Decoration& decoration, const Instruction& built_in_inst,
  394. const Instruction& referenced_inst,
  395. const Instruction& referenced_from_inst);
  396. spv_result_t ValidatePrimitiveIdAtReference(
  397. const Decoration& decoration, const Instruction& built_in_inst,
  398. const Instruction& referenced_inst,
  399. const Instruction& referenced_from_inst);
  400. spv_result_t ValidateSampleIdAtReference(
  401. const Decoration& decoration, const Instruction& built_in_inst,
  402. const Instruction& referenced_inst,
  403. const Instruction& referenced_from_inst);
  404. spv_result_t ValidateSampleMaskAtReference(
  405. const Decoration& decoration, const Instruction& built_in_inst,
  406. const Instruction& referenced_inst,
  407. const Instruction& referenced_from_inst);
  408. spv_result_t ValidateSamplePositionAtReference(
  409. const Decoration& decoration, const Instruction& built_in_inst,
  410. const Instruction& referenced_inst,
  411. const Instruction& referenced_from_inst);
  412. spv_result_t ValidateTessCoordAtReference(
  413. const Decoration& decoration, const Instruction& built_in_inst,
  414. const Instruction& referenced_inst,
  415. const Instruction& referenced_from_inst);
  416. spv_result_t ValidateTessLevelAtReference(
  417. const Decoration& decoration, const Instruction& built_in_inst,
  418. const Instruction& referenced_inst,
  419. const Instruction& referenced_from_inst);
  420. spv_result_t ValidateLocalInvocationIndexAtReference(
  421. const Decoration& decoration, const Instruction& built_in_inst,
  422. const Instruction& referenced_inst,
  423. const Instruction& referenced_from_inst);
  424. spv_result_t ValidateVertexIndexAtReference(
  425. const Decoration& decoration, const Instruction& built_in_inst,
  426. const Instruction& referenced_inst,
  427. const Instruction& referenced_from_inst);
  428. spv_result_t ValidateLayerOrViewportIndexAtReference(
  429. const Decoration& decoration, const Instruction& built_in_inst,
  430. const Instruction& referenced_inst,
  431. const Instruction& referenced_from_inst);
  432. spv_result_t ValidateWorkgroupSizeAtReference(
  433. const Decoration& decoration, const Instruction& built_in_inst,
  434. const Instruction& referenced_inst,
  435. const Instruction& referenced_from_inst);
  436. spv_result_t ValidateClipOrCullDistanceAtReference(
  437. const Decoration& decoration, const Instruction& built_in_inst,
  438. const Instruction& referenced_inst,
  439. const Instruction& referenced_from_inst);
  440. spv_result_t ValidateBaseInstanceOrVertexAtReference(
  441. const Decoration& decoration, const Instruction& built_in_inst,
  442. const Instruction& referenced_inst,
  443. const Instruction& referenced_from_inst);
  444. spv_result_t ValidateDrawIndexAtReference(
  445. const Decoration& decoration, const Instruction& built_in_inst,
  446. const Instruction& referenced_inst,
  447. const Instruction& referenced_from_inst);
  448. spv_result_t ValidateViewIndexAtReference(
  449. const Decoration& decoration, const Instruction& built_in_inst,
  450. const Instruction& referenced_inst,
  451. const Instruction& referenced_from_inst);
  452. spv_result_t ValidateDeviceIndexAtReference(
  453. const Decoration& decoration, const Instruction& built_in_inst,
  454. const Instruction& referenced_inst,
  455. const Instruction& referenced_from_inst);
  456. spv_result_t ValidateFragInvocationCountAtReference(
  457. const Decoration& decoration, const Instruction& built_in_inst,
  458. const Instruction& referenced_inst,
  459. const Instruction& referenced_from_inst);
  460. spv_result_t ValidateFragSizeAtReference(
  461. const Decoration& decoration, const Instruction& built_in_inst,
  462. const Instruction& referenced_inst,
  463. const Instruction& referenced_from_inst);
  464. spv_result_t ValidateFragStencilRefAtReference(
  465. const Decoration& decoration, const Instruction& built_in_inst,
  466. const Instruction& referenced_inst,
  467. const Instruction& referenced_from_inst);
  468. spv_result_t ValidateFullyCoveredAtReference(
  469. const Decoration& decoration, const Instruction& built_in_inst,
  470. const Instruction& referenced_inst,
  471. const Instruction& referenced_from_inst);
  472. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  473. spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
  474. const Decoration& decoration, const Instruction& built_in_inst,
  475. const Instruction& referenced_inst,
  476. const Instruction& referenced_from_inst);
  477. // Used for BaryCoord, BaryCoordNoPersp.
  478. spv_result_t ValidateFragmentShaderF32Vec3InputAtReference(
  479. const Decoration& decoration, const Instruction& built_in_inst,
  480. const Instruction& referenced_inst,
  481. const Instruction& referenced_from_inst);
  482. // Used for SubgroupId and NumSubgroups.
  483. spv_result_t ValidateComputeI32InputAtReference(
  484. const Decoration& decoration, const Instruction& built_in_inst,
  485. const Instruction& referenced_inst,
  486. const Instruction& referenced_from_inst);
  487. spv_result_t ValidateNVSMOrARMCoreBuiltinsAtReference(
  488. const Decoration& decoration, const Instruction& built_in_inst,
  489. const Instruction& referenced_inst,
  490. const Instruction& referenced_from_inst);
  491. spv_result_t ValidatePrimitiveShadingRateAtReference(
  492. const Decoration& decoration, const Instruction& built_in_inst,
  493. const Instruction& referenced_inst,
  494. const Instruction& referenced_from_inst);
  495. spv_result_t ValidateShadingRateAtReference(
  496. const Decoration& decoration, const Instruction& built_in_inst,
  497. const Instruction& referenced_inst,
  498. const Instruction& referenced_from_inst);
  499. spv_result_t ValidateRayTracingBuiltinsAtReference(
  500. const Decoration& decoration, const Instruction& built_in_inst,
  501. const Instruction& referenced_inst,
  502. const Instruction& referenced_from_inst);
  503. spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
  504. const Decoration& decoration, const Instruction& built_in_inst,
  505. const Instruction& referenced_inst,
  506. const Instruction& referenced_from_inst);
  507. // Validates that |built_in_inst| is not (even indirectly) referenced from
  508. // within a function which can be called with |execution_model|.
  509. //
  510. // |vuid| - Vulkan ID for the error, or a negative value if none.
  511. // |comment| - text explaining why the restriction was imposed.
  512. // |decoration| - BuiltIn decoration which causes the restriction.
  513. // |referenced_inst| - instruction which is dependent on |built_in_inst| and
  514. // defines the id which was referenced.
  515. // |referenced_from_inst| - instruction which references id defined by
  516. // |referenced_inst| from within a function.
  517. spv_result_t ValidateNotCalledWithExecutionModel(
  518. int vuid, const char* comment, spv::ExecutionModel execution_model,
  519. const Decoration& decoration, const Instruction& built_in_inst,
  520. const Instruction& referenced_inst,
  521. const Instruction& referenced_from_inst);
  522. // The following section contains functions which check that the decorated
  523. // variable has the type specified in the function name. |diag| would be
  524. // called with a corresponding error message, if validation is not successful.
  525. spv_result_t ValidateBool(
  526. const Decoration& decoration, const Instruction& inst,
  527. const std::function<spv_result_t(const std::string& message)>& diag);
  528. spv_result_t ValidateI(
  529. const Decoration& decoration, const Instruction& inst,
  530. const std::function<spv_result_t(const std::string& message)>& diag);
  531. spv_result_t ValidateI32(
  532. const Decoration& decoration, const Instruction& inst,
  533. const std::function<spv_result_t(const std::string& message)>& diag);
  534. spv_result_t ValidateI32Vec(
  535. const Decoration& decoration, const Instruction& inst,
  536. uint32_t num_components,
  537. const std::function<spv_result_t(const std::string& message)>& diag);
  538. spv_result_t ValidateI32Arr(
  539. const Decoration& decoration, const Instruction& inst,
  540. const std::function<spv_result_t(const std::string& message)>& diag);
  541. spv_result_t ValidateArrayedI32Vec(
  542. const Decoration& decoration, const Instruction& inst,
  543. uint32_t num_components,
  544. const std::function<spv_result_t(const std::string& message)>& diag);
  545. spv_result_t ValidateOptionalArrayedI32(
  546. const Decoration& decoration, const Instruction& inst,
  547. const std::function<spv_result_t(const std::string& message)>& diag);
  548. spv_result_t ValidateI32Helper(
  549. const Decoration& decoration, const Instruction& inst,
  550. const std::function<spv_result_t(const std::string& message)>& diag,
  551. uint32_t underlying_type);
  552. spv_result_t ValidateF32(
  553. const Decoration& decoration, const Instruction& inst,
  554. const std::function<spv_result_t(const std::string& message)>& diag);
  555. spv_result_t ValidateOptionalArrayedF32(
  556. const Decoration& decoration, const Instruction& inst,
  557. const std::function<spv_result_t(const std::string& message)>& diag);
  558. spv_result_t ValidateF32Helper(
  559. const Decoration& decoration, const Instruction& inst,
  560. const std::function<spv_result_t(const std::string& message)>& diag,
  561. uint32_t underlying_type);
  562. spv_result_t ValidateF32Vec(
  563. const Decoration& decoration, const Instruction& inst,
  564. uint32_t num_components,
  565. const std::function<spv_result_t(const std::string& message)>& diag);
  566. spv_result_t ValidateOptionalArrayedF32Vec(
  567. const Decoration& decoration, const Instruction& inst,
  568. uint32_t num_components,
  569. const std::function<spv_result_t(const std::string& message)>& diag);
  570. spv_result_t ValidateF32VecHelper(
  571. const Decoration& decoration, const Instruction& inst,
  572. uint32_t num_components,
  573. const std::function<spv_result_t(const std::string& message)>& diag,
  574. uint32_t underlying_type);
  575. // If |num_components| is zero, the number of components is not checked.
  576. spv_result_t ValidateF32Arr(
  577. const Decoration& decoration, const Instruction& inst,
  578. uint32_t num_components,
  579. const std::function<spv_result_t(const std::string& message)>& diag);
  580. spv_result_t ValidateOptionalArrayedF32Arr(
  581. const Decoration& decoration, const Instruction& inst,
  582. uint32_t num_components,
  583. const std::function<spv_result_t(const std::string& message)>& diag);
  584. spv_result_t ValidateF32ArrHelper(
  585. const Decoration& decoration, const Instruction& inst,
  586. uint32_t num_components,
  587. const std::function<spv_result_t(const std::string& message)>& diag,
  588. uint32_t underlying_type);
  589. spv_result_t ValidateF32Mat(
  590. const Decoration& decoration, const Instruction& inst,
  591. uint32_t req_num_rows, uint32_t req_num_columns,
  592. const std::function<spv_result_t(const std::string& message)>& diag);
  593. // Generates strings like "Member #0 of struct ID <2>".
  594. std::string GetDefinitionDesc(const Decoration& decoration,
  595. const Instruction& inst) const;
  596. // Generates strings like "ID <51> (OpTypePointer) is referencing ID <2>
  597. // (OpTypeStruct) which is decorated with BuiltIn Position".
  598. std::string GetReferenceDesc(
  599. const Decoration& decoration, const Instruction& built_in_inst,
  600. const Instruction& referenced_inst,
  601. const Instruction& referenced_from_inst,
  602. spv::ExecutionModel execution_model = spv::ExecutionModel::Max) const;
  603. // Generates strings like "ID <51> (OpTypePointer) uses storage class
  604. // UniformConstant".
  605. std::string GetStorageClassDesc(const Instruction& inst) const;
  606. // Updates inner working of the class. Is called sequentially for every
  607. // instruction.
  608. void Update(const Instruction& inst);
  609. // Check if "inst" is an interface variable
  610. // or type of a interface varibale of any mesh entry point
  611. bool isMeshInterfaceVar(const Instruction& inst) {
  612. auto getUnderlyingTypeId = [&](const Instruction* ifxVar) {
  613. auto pointerTypeInst = _.FindDef(ifxVar->type_id());
  614. auto typeInst = _.FindDef(pointerTypeInst->GetOperandAs<uint32_t>(2));
  615. while (typeInst->opcode() == spv::Op::OpTypeArray) {
  616. typeInst = _.FindDef(typeInst->GetOperandAs<uint32_t>(1));
  617. };
  618. return typeInst->id();
  619. };
  620. for (const uint32_t entry_point : _.entry_points()) {
  621. const auto* models = _.GetExecutionModels(entry_point);
  622. if (models->find(spv::ExecutionModel::MeshEXT) != models->end() ||
  623. models->find(spv::ExecutionModel::MeshNV) != models->end()) {
  624. for (const auto& desc : _.entry_point_descriptions(entry_point)) {
  625. for (auto interface : desc.interfaces) {
  626. if (inst.opcode() == spv::Op::OpTypeStruct) {
  627. auto varInst = _.FindDef(interface);
  628. if (inst.id() == getUnderlyingTypeId(varInst)) return true;
  629. } else if (inst.id() == interface) {
  630. return true;
  631. }
  632. }
  633. }
  634. }
  635. }
  636. return false;
  637. }
  638. ValidationState_t& _;
  639. // Mapping id -> list of rules which validate instruction referencing the
  640. // id. Rules can create new rules and add them to this container.
  641. // Using std::map, and not std::unordered_map to avoid iterator invalidation
  642. // during rehashing.
  643. std::map<uint32_t, std::list<std::function<spv_result_t(const Instruction&)>>>
  644. id_to_at_reference_checks_;
  645. // Id of the function we are currently inside. 0 if not inside a function.
  646. uint32_t function_id_ = 0;
  647. // Entry points which can (indirectly) call the current function.
  648. // The pointer either points to a vector inside to function_to_entry_points_
  649. // or to no_entry_points_. The pointer is guaranteed to never be null.
  650. const std::vector<uint32_t> no_entry_points;
  651. const std::vector<uint32_t>* entry_points_ = &no_entry_points;
  652. // Execution models with which the current function can be called.
  653. std::set<spv::ExecutionModel> execution_models_;
  654. };
  655. void BuiltInsValidator::Update(const Instruction& inst) {
  656. const spv::Op opcode = inst.opcode();
  657. if (opcode == spv::Op::OpFunction) {
  658. // Entering a function.
  659. assert(function_id_ == 0);
  660. function_id_ = inst.id();
  661. execution_models_.clear();
  662. entry_points_ = &_.FunctionEntryPoints(function_id_);
  663. // Collect execution models from all entry points from which the current
  664. // function can be called.
  665. for (const uint32_t entry_point : *entry_points_) {
  666. if (const auto* models = _.GetExecutionModels(entry_point)) {
  667. execution_models_.insert(models->begin(), models->end());
  668. }
  669. }
  670. }
  671. if (opcode == spv::Op::OpFunctionEnd) {
  672. // Exiting a function.
  673. assert(function_id_ != 0);
  674. function_id_ = 0;
  675. entry_points_ = &no_entry_points;
  676. execution_models_.clear();
  677. }
  678. }
  679. std::string BuiltInsValidator::GetDefinitionDesc(
  680. const Decoration& decoration, const Instruction& inst) const {
  681. std::ostringstream ss;
  682. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  683. assert(inst.opcode() == spv::Op::OpTypeStruct);
  684. ss << "Member #" << decoration.struct_member_index();
  685. ss << " of struct ID <" << inst.id() << ">";
  686. } else {
  687. ss << GetIdDesc(inst);
  688. }
  689. return ss.str();
  690. }
  691. std::string BuiltInsValidator::GetReferenceDesc(
  692. const Decoration& decoration, const Instruction& built_in_inst,
  693. const Instruction& referenced_inst, const Instruction& referenced_from_inst,
  694. spv::ExecutionModel execution_model) const {
  695. std::ostringstream ss;
  696. ss << GetIdDesc(referenced_from_inst) << " is referencing "
  697. << GetIdDesc(referenced_inst);
  698. if (built_in_inst.id() != referenced_inst.id()) {
  699. ss << " which is dependent on " << GetIdDesc(built_in_inst);
  700. }
  701. ss << " which is decorated with BuiltIn ";
  702. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  703. (uint32_t)decoration.builtin());
  704. if (function_id_) {
  705. ss << " in function <" << function_id_ << ">";
  706. if (execution_model != spv::ExecutionModel::Max) {
  707. ss << " called with execution model ";
  708. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
  709. uint32_t(execution_model));
  710. }
  711. }
  712. ss << ".";
  713. return ss.str();
  714. }
  715. std::string BuiltInsValidator::GetStorageClassDesc(
  716. const Instruction& inst) const {
  717. std::ostringstream ss;
  718. ss << GetIdDesc(inst) << " uses storage class ";
  719. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_STORAGE_CLASS,
  720. uint32_t(GetStorageClass(inst)));
  721. ss << ".";
  722. return ss.str();
  723. }
  724. spv_result_t BuiltInsValidator::ValidateBool(
  725. const Decoration& decoration, const Instruction& inst,
  726. const std::function<spv_result_t(const std::string& message)>& diag) {
  727. uint32_t underlying_type = 0;
  728. if (spv_result_t error =
  729. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  730. return error;
  731. }
  732. if (!_.IsBoolScalarType(underlying_type)) {
  733. return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
  734. }
  735. return SPV_SUCCESS;
  736. }
  737. spv_result_t BuiltInsValidator::ValidateI(
  738. const Decoration& decoration, const Instruction& inst,
  739. const std::function<spv_result_t(const std::string& message)>& diag) {
  740. uint32_t underlying_type = 0;
  741. if (spv_result_t error =
  742. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  743. return error;
  744. }
  745. if (!_.IsIntScalarType(underlying_type)) {
  746. return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
  747. }
  748. return SPV_SUCCESS;
  749. }
  750. spv_result_t BuiltInsValidator::ValidateI32(
  751. const Decoration& decoration, const Instruction& inst,
  752. const std::function<spv_result_t(const std::string& message)>& diag) {
  753. uint32_t underlying_type = 0;
  754. if (spv_result_t error =
  755. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  756. return error;
  757. }
  758. return ValidateI32Helper(decoration, inst, diag, underlying_type);
  759. }
  760. spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32(
  761. const Decoration& decoration, const Instruction& inst,
  762. const std::function<spv_result_t(const std::string& message)>& diag) {
  763. uint32_t underlying_type = 0;
  764. if (spv_result_t error =
  765. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  766. return error;
  767. }
  768. // Strip the array, if present.
  769. if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
  770. underlying_type = _.FindDef(underlying_type)->word(2u);
  771. }
  772. return ValidateI32Helper(decoration, inst, diag, underlying_type);
  773. }
  774. spv_result_t BuiltInsValidator::ValidateI32Helper(
  775. const Decoration& decoration, const Instruction& inst,
  776. const std::function<spv_result_t(const std::string& message)>& diag,
  777. uint32_t underlying_type) {
  778. if (!_.IsIntScalarType(underlying_type)) {
  779. return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
  780. }
  781. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  782. if (bit_width != 32) {
  783. std::ostringstream ss;
  784. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  785. << ".";
  786. return diag(ss.str());
  787. }
  788. return SPV_SUCCESS;
  789. }
  790. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32(
  791. const Decoration& decoration, const Instruction& inst,
  792. const std::function<spv_result_t(const std::string& message)>& diag) {
  793. uint32_t underlying_type = 0;
  794. if (spv_result_t error =
  795. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  796. return error;
  797. }
  798. // Strip the array, if present.
  799. if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
  800. underlying_type = _.FindDef(underlying_type)->word(2u);
  801. }
  802. return ValidateF32Helper(decoration, inst, diag, underlying_type);
  803. }
  804. spv_result_t BuiltInsValidator::ValidateF32(
  805. const Decoration& decoration, const Instruction& inst,
  806. const std::function<spv_result_t(const std::string& message)>& diag) {
  807. uint32_t underlying_type = 0;
  808. if (spv_result_t error =
  809. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  810. return error;
  811. }
  812. return ValidateF32Helper(decoration, inst, diag, underlying_type);
  813. }
  814. spv_result_t BuiltInsValidator::ValidateF32Helper(
  815. const Decoration& decoration, const Instruction& inst,
  816. const std::function<spv_result_t(const std::string& message)>& diag,
  817. uint32_t underlying_type) {
  818. if (!_.IsFloatScalarType(underlying_type)) {
  819. return diag(GetDefinitionDesc(decoration, inst) +
  820. " is not a float scalar.");
  821. }
  822. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  823. if (bit_width != 32) {
  824. std::ostringstream ss;
  825. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  826. << ".";
  827. return diag(ss.str());
  828. }
  829. return SPV_SUCCESS;
  830. }
  831. spv_result_t BuiltInsValidator::ValidateI32Vec(
  832. const Decoration& decoration, const Instruction& inst,
  833. uint32_t num_components,
  834. const std::function<spv_result_t(const std::string& message)>& diag) {
  835. uint32_t underlying_type = 0;
  836. if (spv_result_t error =
  837. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  838. return error;
  839. }
  840. if (!_.IsIntVectorType(underlying_type)) {
  841. return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
  842. }
  843. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  844. if (_.GetDimension(underlying_type) != num_components) {
  845. std::ostringstream ss;
  846. ss << GetDefinitionDesc(decoration, inst) << " has "
  847. << actual_num_components << " components.";
  848. return diag(ss.str());
  849. }
  850. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  851. if (bit_width != 32) {
  852. std::ostringstream ss;
  853. ss << GetDefinitionDesc(decoration, inst)
  854. << " has components with bit width " << bit_width << ".";
  855. return diag(ss.str());
  856. }
  857. return SPV_SUCCESS;
  858. }
  859. spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
  860. const Decoration& decoration, const Instruction& inst,
  861. uint32_t num_components,
  862. const std::function<spv_result_t(const std::string& message)>& diag) {
  863. uint32_t underlying_type = 0;
  864. if (spv_result_t error =
  865. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  866. return error;
  867. }
  868. const Instruction* const type_inst = _.FindDef(underlying_type);
  869. if (type_inst->opcode() != spv::Op::OpTypeArray) {
  870. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  871. }
  872. const uint32_t component_type = type_inst->word(2);
  873. if (!_.IsIntVectorType(component_type)) {
  874. return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
  875. }
  876. const uint32_t actual_num_components = _.GetDimension(component_type);
  877. if (_.GetDimension(component_type) != num_components) {
  878. std::ostringstream ss;
  879. ss << GetDefinitionDesc(decoration, inst) << " has "
  880. << actual_num_components << " components.";
  881. return diag(ss.str());
  882. }
  883. const uint32_t bit_width = _.GetBitWidth(component_type);
  884. if (bit_width != 32) {
  885. std::ostringstream ss;
  886. ss << GetDefinitionDesc(decoration, inst)
  887. << " has components with bit width " << bit_width << ".";
  888. return diag(ss.str());
  889. }
  890. return SPV_SUCCESS;
  891. }
  892. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
  893. const Decoration& decoration, const Instruction& inst,
  894. uint32_t num_components,
  895. const std::function<spv_result_t(const std::string& message)>& diag) {
  896. uint32_t underlying_type = 0;
  897. if (spv_result_t error =
  898. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  899. return error;
  900. }
  901. // Strip the array, if present.
  902. if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
  903. underlying_type = _.FindDef(underlying_type)->word(2u);
  904. }
  905. return ValidateF32VecHelper(decoration, inst, num_components, diag,
  906. underlying_type);
  907. }
  908. spv_result_t BuiltInsValidator::ValidateF32Vec(
  909. const Decoration& decoration, const Instruction& inst,
  910. uint32_t num_components,
  911. const std::function<spv_result_t(const std::string& message)>& diag) {
  912. uint32_t underlying_type = 0;
  913. if (spv_result_t error =
  914. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  915. return error;
  916. }
  917. return ValidateF32VecHelper(decoration, inst, num_components, diag,
  918. underlying_type);
  919. }
  920. spv_result_t BuiltInsValidator::ValidateF32VecHelper(
  921. const Decoration& decoration, const Instruction& inst,
  922. uint32_t num_components,
  923. const std::function<spv_result_t(const std::string& message)>& diag,
  924. uint32_t underlying_type) {
  925. if (!_.IsFloatVectorType(underlying_type)) {
  926. return diag(GetDefinitionDesc(decoration, inst) +
  927. " is not a float vector.");
  928. }
  929. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  930. if (_.GetDimension(underlying_type) != num_components) {
  931. std::ostringstream ss;
  932. ss << GetDefinitionDesc(decoration, inst) << " has "
  933. << actual_num_components << " components.";
  934. return diag(ss.str());
  935. }
  936. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  937. if (bit_width != 32) {
  938. std::ostringstream ss;
  939. ss << GetDefinitionDesc(decoration, inst)
  940. << " has components with bit width " << bit_width << ".";
  941. return diag(ss.str());
  942. }
  943. return SPV_SUCCESS;
  944. }
  945. spv_result_t BuiltInsValidator::ValidateI32Arr(
  946. const Decoration& decoration, const Instruction& inst,
  947. const std::function<spv_result_t(const std::string& message)>& diag) {
  948. uint32_t underlying_type = 0;
  949. if (spv_result_t error =
  950. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  951. return error;
  952. }
  953. const Instruction* const type_inst = _.FindDef(underlying_type);
  954. if (type_inst->opcode() != spv::Op::OpTypeArray) {
  955. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  956. }
  957. const uint32_t component_type = type_inst->word(2);
  958. if (!_.IsIntScalarType(component_type)) {
  959. return diag(GetDefinitionDesc(decoration, inst) +
  960. " components are not int scalar.");
  961. }
  962. const uint32_t bit_width = _.GetBitWidth(component_type);
  963. if (bit_width != 32) {
  964. std::ostringstream ss;
  965. ss << GetDefinitionDesc(decoration, inst)
  966. << " has components with bit width " << bit_width << ".";
  967. return diag(ss.str());
  968. }
  969. return SPV_SUCCESS;
  970. }
  971. spv_result_t BuiltInsValidator::ValidateF32Arr(
  972. const Decoration& decoration, const Instruction& inst,
  973. uint32_t num_components,
  974. const std::function<spv_result_t(const std::string& message)>& diag) {
  975. uint32_t underlying_type = 0;
  976. if (spv_result_t error =
  977. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  978. return error;
  979. }
  980. return ValidateF32ArrHelper(decoration, inst, num_components, diag,
  981. underlying_type);
  982. }
  983. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Arr(
  984. const Decoration& decoration, const Instruction& inst,
  985. uint32_t num_components,
  986. const std::function<spv_result_t(const std::string& message)>& diag) {
  987. uint32_t underlying_type = 0;
  988. if (spv_result_t error =
  989. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  990. return error;
  991. }
  992. // Strip an extra layer of arraying if present.
  993. if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
  994. uint32_t subtype = _.FindDef(underlying_type)->word(2u);
  995. if (_.GetIdOpcode(subtype) == spv::Op::OpTypeArray) {
  996. underlying_type = subtype;
  997. }
  998. }
  999. return ValidateF32ArrHelper(decoration, inst, num_components, diag,
  1000. underlying_type);
  1001. }
  1002. spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
  1003. const Decoration& decoration, const Instruction& inst,
  1004. uint32_t num_components,
  1005. const std::function<spv_result_t(const std::string& message)>& diag,
  1006. uint32_t underlying_type) {
  1007. const Instruction* const type_inst = _.FindDef(underlying_type);
  1008. if (type_inst->opcode() != spv::Op::OpTypeArray) {
  1009. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  1010. }
  1011. const uint32_t component_type = type_inst->word(2);
  1012. if (!_.IsFloatScalarType(component_type)) {
  1013. return diag(GetDefinitionDesc(decoration, inst) +
  1014. " components are not float scalar.");
  1015. }
  1016. const uint32_t bit_width = _.GetBitWidth(component_type);
  1017. if (bit_width != 32) {
  1018. std::ostringstream ss;
  1019. ss << GetDefinitionDesc(decoration, inst)
  1020. << " has components with bit width " << bit_width << ".";
  1021. return diag(ss.str());
  1022. }
  1023. if (num_components != 0) {
  1024. uint64_t actual_num_components = 0;
  1025. if (!_.EvalConstantValUint64(type_inst->word(3), &actual_num_components)) {
  1026. assert(0 && "Array type definition is corrupt");
  1027. }
  1028. if (actual_num_components != num_components) {
  1029. std::ostringstream ss;
  1030. ss << GetDefinitionDesc(decoration, inst) << " has "
  1031. << actual_num_components << " components.";
  1032. return diag(ss.str());
  1033. }
  1034. }
  1035. return SPV_SUCCESS;
  1036. }
  1037. spv_result_t BuiltInsValidator::ValidateF32Mat(
  1038. const Decoration& decoration, const Instruction& inst,
  1039. uint32_t req_num_rows, uint32_t req_num_columns,
  1040. const std::function<spv_result_t(const std::string& message)>& diag) {
  1041. uint32_t underlying_type = 0;
  1042. uint32_t num_rows = 0;
  1043. uint32_t num_cols = 0;
  1044. uint32_t col_type = 0;
  1045. uint32_t component_type = 0;
  1046. if (spv_result_t error =
  1047. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  1048. return error;
  1049. }
  1050. if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
  1051. &component_type) ||
  1052. num_rows != req_num_rows || num_cols != req_num_columns) {
  1053. std::ostringstream ss;
  1054. ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
  1055. << " and rows " << num_rows << " not equal to expected "
  1056. << req_num_columns << "x" << req_num_rows << ".";
  1057. return diag(ss.str());
  1058. }
  1059. return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
  1060. }
  1061. spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
  1062. int vuid, const char* comment, spv::ExecutionModel execution_model,
  1063. const Decoration& decoration, const Instruction& built_in_inst,
  1064. const Instruction& referenced_inst,
  1065. const Instruction& referenced_from_inst) {
  1066. if (function_id_) {
  1067. if (execution_models_.count(execution_model)) {
  1068. const char* execution_model_str = _.grammar().lookupOperandName(
  1069. SPV_OPERAND_TYPE_EXECUTION_MODEL, uint32_t(execution_model));
  1070. const char* built_in_str = _.grammar().lookupOperandName(
  1071. SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)decoration.builtin());
  1072. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1073. << (vuid < 0 ? std::string("") : _.VkErrorID(vuid)) << comment
  1074. << " " << GetIdDesc(referenced_inst) << " depends on "
  1075. << GetIdDesc(built_in_inst) << " which is decorated with BuiltIn "
  1076. << built_in_str << "."
  1077. << " Id <" << referenced_inst.id() << "> is later referenced by "
  1078. << GetIdDesc(referenced_from_inst) << " in function <"
  1079. << function_id_ << "> which is called with execution model "
  1080. << execution_model_str << ".";
  1081. }
  1082. } else {
  1083. // Propagate this rule to all dependant ids in the global scope.
  1084. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1085. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1086. vuid, comment, execution_model, decoration, built_in_inst,
  1087. referenced_from_inst, std::placeholders::_1));
  1088. }
  1089. return SPV_SUCCESS;
  1090. }
  1091. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtDefinition(
  1092. const Decoration& decoration, const Instruction& inst) {
  1093. // Seed at reference checks with this built-in.
  1094. return ValidateClipOrCullDistanceAtReference(decoration, inst, inst, inst);
  1095. }
  1096. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
  1097. const Decoration& decoration, const Instruction& built_in_inst,
  1098. const Instruction& referenced_inst,
  1099. const Instruction& referenced_from_inst) {
  1100. uint32_t operand = (uint32_t)decoration.builtin();
  1101. if (spvIsVulkanEnv(_.context()->target_env)) {
  1102. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1103. if (storage_class != spv::StorageClass::Max &&
  1104. storage_class != spv::StorageClass::Input &&
  1105. storage_class != spv::StorageClass::Output) {
  1106. uint32_t vuid =
  1107. (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4190 : 4199;
  1108. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1109. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  1110. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1111. operand)
  1112. << " to be only used for variables with Input or Output storage "
  1113. "class. "
  1114. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1115. referenced_from_inst)
  1116. << " " << GetStorageClassDesc(referenced_from_inst);
  1117. }
  1118. if (storage_class == spv::StorageClass::Input) {
  1119. assert(function_id_ == 0);
  1120. uint32_t vuid =
  1121. (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4188 : 4197;
  1122. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1123. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  1124. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  1125. "used for variables with Input storage class if execution model is "
  1126. "Vertex.",
  1127. spv::ExecutionModel::Vertex, decoration, built_in_inst,
  1128. referenced_from_inst, std::placeholders::_1));
  1129. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1130. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  1131. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  1132. "used for variables with Input storage class if execution model is "
  1133. "MeshNV.",
  1134. spv::ExecutionModel::MeshNV, decoration, built_in_inst,
  1135. referenced_from_inst, std::placeholders::_1));
  1136. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1137. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  1138. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  1139. "used for variables with Input storage class if execution model is "
  1140. "MeshEXT.",
  1141. spv::ExecutionModel::MeshEXT, decoration, built_in_inst,
  1142. referenced_from_inst, std::placeholders::_1));
  1143. }
  1144. if (storage_class == spv::StorageClass::Output) {
  1145. assert(function_id_ == 0);
  1146. uint32_t vuid =
  1147. (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4189 : 4198;
  1148. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1149. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  1150. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  1151. "used for variables with Output storage class if execution model is "
  1152. "Fragment.",
  1153. spv::ExecutionModel::Fragment, decoration, built_in_inst,
  1154. referenced_from_inst, std::placeholders::_1));
  1155. }
  1156. for (const spv::ExecutionModel execution_model : execution_models_) {
  1157. switch (execution_model) {
  1158. case spv::ExecutionModel::Fragment:
  1159. case spv::ExecutionModel::Vertex: {
  1160. if (spv_result_t error = ValidateF32Arr(
  1161. decoration, built_in_inst, /* Any number of components */ 0,
  1162. [this, &decoration, &referenced_from_inst](
  1163. const std::string& message) -> spv_result_t {
  1164. uint32_t vuid =
  1165. (decoration.builtin() == spv::BuiltIn::ClipDistance)
  1166. ? 4191
  1167. : 4200;
  1168. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1169. << _.VkErrorID(vuid)
  1170. << "According to the Vulkan spec BuiltIn "
  1171. << _.grammar().lookupOperandName(
  1172. SPV_OPERAND_TYPE_BUILT_IN,
  1173. (uint32_t)decoration.builtin())
  1174. << " variable needs to be a 32-bit float array. "
  1175. << message;
  1176. })) {
  1177. return error;
  1178. }
  1179. break;
  1180. }
  1181. case spv::ExecutionModel::TessellationControl:
  1182. case spv::ExecutionModel::TessellationEvaluation:
  1183. case spv::ExecutionModel::Geometry:
  1184. case spv::ExecutionModel::MeshNV:
  1185. case spv::ExecutionModel::MeshEXT: {
  1186. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1187. // The outer level of array is applied on the variable.
  1188. if (spv_result_t error = ValidateF32Arr(
  1189. decoration, built_in_inst, /* Any number of components */ 0,
  1190. [this, &decoration, &referenced_from_inst](
  1191. const std::string& message) -> spv_result_t {
  1192. uint32_t vuid =
  1193. (decoration.builtin() == spv::BuiltIn::ClipDistance)
  1194. ? 4191
  1195. : 4200;
  1196. return _.diag(SPV_ERROR_INVALID_DATA,
  1197. &referenced_from_inst)
  1198. << _.VkErrorID(vuid)
  1199. << "According to the Vulkan spec BuiltIn "
  1200. << _.grammar().lookupOperandName(
  1201. SPV_OPERAND_TYPE_BUILT_IN,
  1202. (uint32_t)decoration.builtin())
  1203. << " variable needs to be a 32-bit float array. "
  1204. << message;
  1205. })) {
  1206. return error;
  1207. }
  1208. } else {
  1209. if (spv_result_t error = ValidateOptionalArrayedF32Arr(
  1210. decoration, built_in_inst, /* Any number of components */ 0,
  1211. [this, &decoration, &referenced_from_inst](
  1212. const std::string& message) -> spv_result_t {
  1213. uint32_t vuid =
  1214. (decoration.builtin() == spv::BuiltIn::ClipDistance)
  1215. ? 4191
  1216. : 4200;
  1217. return _.diag(SPV_ERROR_INVALID_DATA,
  1218. &referenced_from_inst)
  1219. << _.VkErrorID(vuid)
  1220. << "According to the Vulkan spec BuiltIn "
  1221. << _.grammar().lookupOperandName(
  1222. SPV_OPERAND_TYPE_BUILT_IN,
  1223. (uint32_t)decoration.builtin())
  1224. << " variable needs to be a 32-bit float array. "
  1225. << message;
  1226. })) {
  1227. return error;
  1228. }
  1229. }
  1230. break;
  1231. }
  1232. default: {
  1233. uint32_t vuid = (decoration.builtin() == spv::BuiltIn::ClipDistance)
  1234. ? 4187
  1235. : 4196;
  1236. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1237. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  1238. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1239. operand)
  1240. << " to be used only with Fragment, Vertex, "
  1241. "TessellationControl, TessellationEvaluation or Geometry "
  1242. "execution models. "
  1243. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1244. referenced_from_inst, execution_model);
  1245. }
  1246. }
  1247. }
  1248. }
  1249. if (function_id_ == 0) {
  1250. // Propagate this rule to all dependant ids in the global scope.
  1251. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1252. std::bind(&BuiltInsValidator::ValidateClipOrCullDistanceAtReference,
  1253. this, decoration, built_in_inst, referenced_from_inst,
  1254. std::placeholders::_1));
  1255. }
  1256. return SPV_SUCCESS;
  1257. }
  1258. spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
  1259. const Decoration& decoration, const Instruction& inst) {
  1260. if (spvIsVulkanEnv(_.context()->target_env)) {
  1261. if (spv_result_t error = ValidateF32Vec(
  1262. decoration, inst, 4,
  1263. [this, &inst](const std::string& message) -> spv_result_t {
  1264. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1265. << _.VkErrorID(4212) << "According to the "
  1266. << spvLogStringForEnv(_.context()->target_env)
  1267. << " spec BuiltIn FragCoord "
  1268. "variable needs to be a 4-component 32-bit float "
  1269. "vector. "
  1270. << message;
  1271. })) {
  1272. return error;
  1273. }
  1274. }
  1275. // Seed at reference checks with this built-in.
  1276. return ValidateFragCoordAtReference(decoration, inst, inst, inst);
  1277. }
  1278. spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
  1279. const Decoration& decoration, const Instruction& built_in_inst,
  1280. const Instruction& referenced_inst,
  1281. const Instruction& referenced_from_inst) {
  1282. if (spvIsVulkanEnv(_.context()->target_env)) {
  1283. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1284. if (storage_class != spv::StorageClass::Max &&
  1285. storage_class != spv::StorageClass::Input) {
  1286. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1287. << _.VkErrorID(4211) << spvLogStringForEnv(_.context()->target_env)
  1288. << " spec allows BuiltIn FragCoord to be only used for "
  1289. "variables with Input storage class. "
  1290. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1291. referenced_from_inst)
  1292. << " " << GetStorageClassDesc(referenced_from_inst);
  1293. }
  1294. for (const spv::ExecutionModel execution_model : execution_models_) {
  1295. if (execution_model != spv::ExecutionModel::Fragment) {
  1296. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1297. << _.VkErrorID(4210)
  1298. << spvLogStringForEnv(_.context()->target_env)
  1299. << " spec allows BuiltIn FragCoord to be used only with "
  1300. "Fragment execution model. "
  1301. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1302. referenced_from_inst, execution_model);
  1303. }
  1304. }
  1305. }
  1306. if (function_id_ == 0) {
  1307. // Propagate this rule to all dependant ids in the global scope.
  1308. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1309. &BuiltInsValidator::ValidateFragCoordAtReference, this, decoration,
  1310. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1311. }
  1312. return SPV_SUCCESS;
  1313. }
  1314. spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
  1315. const Decoration& decoration, const Instruction& inst) {
  1316. if (spvIsVulkanEnv(_.context()->target_env)) {
  1317. if (spv_result_t error = ValidateF32(
  1318. decoration, inst,
  1319. [this, &inst](const std::string& message) -> spv_result_t {
  1320. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1321. << _.VkErrorID(4215) << "According to the "
  1322. << spvLogStringForEnv(_.context()->target_env)
  1323. << " spec BuiltIn FragDepth "
  1324. "variable needs to be a 32-bit float scalar. "
  1325. << message;
  1326. })) {
  1327. return error;
  1328. }
  1329. }
  1330. // Seed at reference checks with this built-in.
  1331. return ValidateFragDepthAtReference(decoration, inst, inst, inst);
  1332. }
  1333. spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
  1334. const Decoration& decoration, const Instruction& built_in_inst,
  1335. const Instruction& referenced_inst,
  1336. const Instruction& referenced_from_inst) {
  1337. if (spvIsVulkanEnv(_.context()->target_env)) {
  1338. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1339. if (storage_class != spv::StorageClass::Max &&
  1340. storage_class != spv::StorageClass::Output) {
  1341. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1342. << _.VkErrorID(4214) << spvLogStringForEnv(_.context()->target_env)
  1343. << " spec allows BuiltIn FragDepth to be only used for "
  1344. "variables with Output storage class. "
  1345. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1346. referenced_from_inst)
  1347. << " " << GetStorageClassDesc(referenced_from_inst);
  1348. }
  1349. for (const spv::ExecutionModel execution_model : execution_models_) {
  1350. if (execution_model != spv::ExecutionModel::Fragment) {
  1351. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1352. << _.VkErrorID(4213)
  1353. << spvLogStringForEnv(_.context()->target_env)
  1354. << " spec allows BuiltIn FragDepth to be used only with "
  1355. "Fragment execution model. "
  1356. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1357. referenced_from_inst, execution_model);
  1358. }
  1359. }
  1360. for (const uint32_t entry_point : *entry_points_) {
  1361. // Every entry point from which this function is called needs to have
  1362. // Execution Mode DepthReplacing.
  1363. const auto* modes = _.GetExecutionModes(entry_point);
  1364. if (!modes || !modes->count(spv::ExecutionMode::DepthReplacing)) {
  1365. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1366. << _.VkErrorID(4216)
  1367. << spvLogStringForEnv(_.context()->target_env)
  1368. << " spec requires DepthReplacing execution mode to be "
  1369. "declared when using BuiltIn FragDepth. "
  1370. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1371. referenced_from_inst);
  1372. }
  1373. }
  1374. }
  1375. if (function_id_ == 0) {
  1376. // Propagate this rule to all dependant ids in the global scope.
  1377. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1378. &BuiltInsValidator::ValidateFragDepthAtReference, this, decoration,
  1379. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1380. }
  1381. return SPV_SUCCESS;
  1382. }
  1383. spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
  1384. const Decoration& decoration, const Instruction& inst) {
  1385. if (spvIsVulkanEnv(_.context()->target_env)) {
  1386. if (spv_result_t error = ValidateBool(
  1387. decoration, inst,
  1388. [this, &inst](const std::string& message) -> spv_result_t {
  1389. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1390. << _.VkErrorID(4231) << "According to the "
  1391. << spvLogStringForEnv(_.context()->target_env)
  1392. << " spec BuiltIn FrontFacing "
  1393. "variable needs to be a bool scalar. "
  1394. << message;
  1395. })) {
  1396. return error;
  1397. }
  1398. }
  1399. // Seed at reference checks with this built-in.
  1400. return ValidateFrontFacingAtReference(decoration, inst, inst, inst);
  1401. }
  1402. spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
  1403. const Decoration& decoration, const Instruction& built_in_inst,
  1404. const Instruction& referenced_inst,
  1405. const Instruction& referenced_from_inst) {
  1406. if (spvIsVulkanEnv(_.context()->target_env)) {
  1407. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1408. if (storage_class != spv::StorageClass::Max &&
  1409. storage_class != spv::StorageClass::Input) {
  1410. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1411. << _.VkErrorID(4230) << spvLogStringForEnv(_.context()->target_env)
  1412. << " spec allows BuiltIn FrontFacing to be only used for "
  1413. "variables with Input storage class. "
  1414. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1415. referenced_from_inst)
  1416. << " " << GetStorageClassDesc(referenced_from_inst);
  1417. }
  1418. for (const spv::ExecutionModel execution_model : execution_models_) {
  1419. if (execution_model != spv::ExecutionModel::Fragment) {
  1420. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1421. << _.VkErrorID(4229)
  1422. << spvLogStringForEnv(_.context()->target_env)
  1423. << " spec allows BuiltIn FrontFacing to be used only with "
  1424. "Fragment execution model. "
  1425. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1426. referenced_from_inst, execution_model);
  1427. }
  1428. }
  1429. }
  1430. if (function_id_ == 0) {
  1431. // Propagate this rule to all dependant ids in the global scope.
  1432. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1433. &BuiltInsValidator::ValidateFrontFacingAtReference, this, decoration,
  1434. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1435. }
  1436. return SPV_SUCCESS;
  1437. }
  1438. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition(
  1439. const Decoration& decoration, const Instruction& inst) {
  1440. if (spvIsVulkanEnv(_.context()->target_env)) {
  1441. if (spv_result_t error = ValidateBool(
  1442. decoration, inst,
  1443. [this, &inst](const std::string& message) -> spv_result_t {
  1444. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1445. << _.VkErrorID(4241)
  1446. << "According to the Vulkan spec BuiltIn HelperInvocation "
  1447. "variable needs to be a bool scalar. "
  1448. << message;
  1449. })) {
  1450. return error;
  1451. }
  1452. }
  1453. // Seed at reference checks with this built-in.
  1454. return ValidateHelperInvocationAtReference(decoration, inst, inst, inst);
  1455. }
  1456. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference(
  1457. const Decoration& decoration, const Instruction& built_in_inst,
  1458. const Instruction& referenced_inst,
  1459. const Instruction& referenced_from_inst) {
  1460. if (spvIsVulkanEnv(_.context()->target_env)) {
  1461. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1462. if (storage_class != spv::StorageClass::Max &&
  1463. storage_class != spv::StorageClass::Input) {
  1464. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1465. << _.VkErrorID(4240)
  1466. << "Vulkan spec allows BuiltIn HelperInvocation to be only used "
  1467. "for variables with Input storage class. "
  1468. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1469. referenced_from_inst)
  1470. << " " << GetStorageClassDesc(referenced_from_inst);
  1471. }
  1472. for (const spv::ExecutionModel execution_model : execution_models_) {
  1473. if (execution_model != spv::ExecutionModel::Fragment) {
  1474. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1475. << _.VkErrorID(4239)
  1476. << "Vulkan spec allows BuiltIn HelperInvocation to be used only "
  1477. "with Fragment execution model. "
  1478. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1479. referenced_from_inst, execution_model);
  1480. }
  1481. }
  1482. }
  1483. if (function_id_ == 0) {
  1484. // Propagate this rule to all dependant ids in the global scope.
  1485. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1486. std::bind(&BuiltInsValidator::ValidateHelperInvocationAtReference, this,
  1487. decoration, built_in_inst, referenced_from_inst,
  1488. std::placeholders::_1));
  1489. }
  1490. return SPV_SUCCESS;
  1491. }
  1492. spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition(
  1493. const Decoration& decoration, const Instruction& inst) {
  1494. if (spvIsVulkanEnv(_.context()->target_env)) {
  1495. if (spv_result_t error = ValidateI32(
  1496. decoration, inst,
  1497. [this, &inst](const std::string& message) -> spv_result_t {
  1498. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1499. << _.VkErrorID(4259)
  1500. << "According to the Vulkan spec BuiltIn InvocationId "
  1501. "variable needs to be a 32-bit int scalar. "
  1502. << message;
  1503. })) {
  1504. return error;
  1505. }
  1506. }
  1507. // Seed at reference checks with this built-in.
  1508. return ValidateInvocationIdAtReference(decoration, inst, inst, inst);
  1509. }
  1510. spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
  1511. const Decoration& decoration, const Instruction& built_in_inst,
  1512. const Instruction& referenced_inst,
  1513. const Instruction& referenced_from_inst) {
  1514. if (spvIsVulkanEnv(_.context()->target_env)) {
  1515. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1516. if (storage_class != spv::StorageClass::Max &&
  1517. storage_class != spv::StorageClass::Input) {
  1518. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1519. << _.VkErrorID(4258)
  1520. << "Vulkan spec allows BuiltIn InvocationId to be only used for "
  1521. "variables with Input storage class. "
  1522. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1523. referenced_from_inst)
  1524. << " " << GetStorageClassDesc(referenced_from_inst);
  1525. }
  1526. for (const spv::ExecutionModel execution_model : execution_models_) {
  1527. if (execution_model != spv::ExecutionModel::TessellationControl &&
  1528. execution_model != spv::ExecutionModel::Geometry) {
  1529. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1530. << _.VkErrorID(4257)
  1531. << "Vulkan spec allows BuiltIn InvocationId to be used only "
  1532. "with TessellationControl or Geometry execution models. "
  1533. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1534. referenced_from_inst, execution_model);
  1535. }
  1536. }
  1537. }
  1538. if (function_id_ == 0) {
  1539. // Propagate this rule to all dependant ids in the global scope.
  1540. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1541. &BuiltInsValidator::ValidateInvocationIdAtReference, this, decoration,
  1542. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1543. }
  1544. return SPV_SUCCESS;
  1545. }
  1546. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
  1547. const Decoration& decoration, const Instruction& inst) {
  1548. if (spvIsVulkanEnv(_.context()->target_env)) {
  1549. if (spv_result_t error = ValidateI32(
  1550. decoration, inst,
  1551. [this, &inst](const std::string& message) -> spv_result_t {
  1552. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1553. << _.VkErrorID(4265) << "According to the "
  1554. << spvLogStringForEnv(_.context()->target_env)
  1555. << " spec BuiltIn InstanceIndex "
  1556. "variable needs to be a 32-bit int scalar. "
  1557. << message;
  1558. })) {
  1559. return error;
  1560. }
  1561. }
  1562. // Seed at reference checks with this built-in.
  1563. return ValidateInstanceIndexAtReference(decoration, inst, inst, inst);
  1564. }
  1565. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
  1566. const Decoration& decoration, const Instruction& built_in_inst,
  1567. const Instruction& referenced_inst,
  1568. const Instruction& referenced_from_inst) {
  1569. if (spvIsVulkanEnv(_.context()->target_env)) {
  1570. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1571. if (storage_class != spv::StorageClass::Max &&
  1572. storage_class != spv::StorageClass::Input) {
  1573. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1574. << _.VkErrorID(4264) << spvLogStringForEnv(_.context()->target_env)
  1575. << " spec allows BuiltIn InstanceIndex to be only used for "
  1576. "variables with Input storage class. "
  1577. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1578. referenced_from_inst)
  1579. << " " << GetStorageClassDesc(referenced_from_inst);
  1580. }
  1581. for (const spv::ExecutionModel execution_model : execution_models_) {
  1582. if (execution_model != spv::ExecutionModel::Vertex) {
  1583. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1584. << _.VkErrorID(4263)
  1585. << spvLogStringForEnv(_.context()->target_env)
  1586. << " spec allows BuiltIn InstanceIndex to be used only "
  1587. "with Vertex execution model. "
  1588. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1589. referenced_from_inst, execution_model);
  1590. }
  1591. }
  1592. }
  1593. if (function_id_ == 0) {
  1594. // Propagate this rule to all dependant ids in the global scope.
  1595. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1596. &BuiltInsValidator::ValidateInstanceIndexAtReference, this, decoration,
  1597. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1598. }
  1599. return SPV_SUCCESS;
  1600. }
  1601. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition(
  1602. const Decoration& decoration, const Instruction& inst) {
  1603. if (spvIsVulkanEnv(_.context()->target_env)) {
  1604. if (spv_result_t error = ValidateI32(
  1605. decoration, inst,
  1606. [this, &inst](const std::string& message) -> spv_result_t {
  1607. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1608. << _.VkErrorID(4310)
  1609. << "According to the Vulkan spec BuiltIn PatchVertices "
  1610. "variable needs to be a 32-bit int scalar. "
  1611. << message;
  1612. })) {
  1613. return error;
  1614. }
  1615. }
  1616. // Seed at reference checks with this built-in.
  1617. return ValidatePatchVerticesAtReference(decoration, inst, inst, inst);
  1618. }
  1619. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference(
  1620. const Decoration& decoration, const Instruction& built_in_inst,
  1621. const Instruction& referenced_inst,
  1622. const Instruction& referenced_from_inst) {
  1623. if (spvIsVulkanEnv(_.context()->target_env)) {
  1624. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1625. if (storage_class != spv::StorageClass::Max &&
  1626. storage_class != spv::StorageClass::Input) {
  1627. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1628. << _.VkErrorID(4309)
  1629. << "Vulkan spec allows BuiltIn PatchVertices to be only used for "
  1630. "variables with Input storage class. "
  1631. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1632. referenced_from_inst)
  1633. << " " << GetStorageClassDesc(referenced_from_inst);
  1634. }
  1635. for (const spv::ExecutionModel execution_model : execution_models_) {
  1636. if (execution_model != spv::ExecutionModel::TessellationControl &&
  1637. execution_model != spv::ExecutionModel::TessellationEvaluation) {
  1638. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1639. << _.VkErrorID(4308)
  1640. << "Vulkan spec allows BuiltIn PatchVertices to be used only "
  1641. "with TessellationControl or TessellationEvaluation "
  1642. "execution models. "
  1643. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1644. referenced_from_inst, execution_model);
  1645. }
  1646. }
  1647. }
  1648. if (function_id_ == 0) {
  1649. // Propagate this rule to all dependant ids in the global scope.
  1650. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1651. &BuiltInsValidator::ValidatePatchVerticesAtReference, this, decoration,
  1652. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1653. }
  1654. return SPV_SUCCESS;
  1655. }
  1656. spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition(
  1657. const Decoration& decoration, const Instruction& inst) {
  1658. if (spvIsVulkanEnv(_.context()->target_env)) {
  1659. if (spv_result_t error = ValidateF32Vec(
  1660. decoration, inst, 2,
  1661. [this, &inst](const std::string& message) -> spv_result_t {
  1662. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1663. << _.VkErrorID(4313)
  1664. << "According to the Vulkan spec BuiltIn PointCoord "
  1665. "variable needs to be a 2-component 32-bit float "
  1666. "vector. "
  1667. << message;
  1668. })) {
  1669. return error;
  1670. }
  1671. }
  1672. // Seed at reference checks with this built-in.
  1673. return ValidatePointCoordAtReference(decoration, inst, inst, inst);
  1674. }
  1675. spv_result_t BuiltInsValidator::ValidatePointCoordAtReference(
  1676. const Decoration& decoration, const Instruction& built_in_inst,
  1677. const Instruction& referenced_inst,
  1678. const Instruction& referenced_from_inst) {
  1679. if (spvIsVulkanEnv(_.context()->target_env)) {
  1680. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1681. if (storage_class != spv::StorageClass::Max &&
  1682. storage_class != spv::StorageClass::Input) {
  1683. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1684. << _.VkErrorID(4312)
  1685. << "Vulkan spec allows BuiltIn PointCoord to be only used for "
  1686. "variables with Input storage class. "
  1687. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1688. referenced_from_inst)
  1689. << " " << GetStorageClassDesc(referenced_from_inst);
  1690. }
  1691. for (const spv::ExecutionModel execution_model : execution_models_) {
  1692. if (execution_model != spv::ExecutionModel::Fragment) {
  1693. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1694. << _.VkErrorID(4311)
  1695. << "Vulkan spec allows BuiltIn PointCoord to be used only with "
  1696. "Fragment execution model. "
  1697. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1698. referenced_from_inst, execution_model);
  1699. }
  1700. }
  1701. }
  1702. if (function_id_ == 0) {
  1703. // Propagate this rule to all dependant ids in the global scope.
  1704. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1705. &BuiltInsValidator::ValidatePointCoordAtReference, this, decoration,
  1706. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1707. }
  1708. return SPV_SUCCESS;
  1709. }
  1710. spv_result_t BuiltInsValidator::ValidatePointSizeAtDefinition(
  1711. const Decoration& decoration, const Instruction& inst) {
  1712. // Seed at reference checks with this built-in.
  1713. return ValidatePointSizeAtReference(decoration, inst, inst, inst);
  1714. }
  1715. spv_result_t BuiltInsValidator::ValidatePointSizeAtReference(
  1716. const Decoration& decoration, const Instruction& built_in_inst,
  1717. const Instruction& referenced_inst,
  1718. const Instruction& referenced_from_inst) {
  1719. if (spvIsVulkanEnv(_.context()->target_env)) {
  1720. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1721. if (storage_class != spv::StorageClass::Max &&
  1722. storage_class != spv::StorageClass::Input &&
  1723. storage_class != spv::StorageClass::Output) {
  1724. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1725. << _.VkErrorID(4316)
  1726. << "Vulkan spec allows BuiltIn PointSize to be only used for "
  1727. "variables with Input or Output storage class. "
  1728. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1729. referenced_from_inst)
  1730. << " " << GetStorageClassDesc(referenced_from_inst);
  1731. }
  1732. if (storage_class == spv::StorageClass::Input) {
  1733. assert(function_id_ == 0);
  1734. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1735. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4315,
  1736. "Vulkan spec doesn't allow BuiltIn PointSize to be used for "
  1737. "variables with Input storage class if execution model is "
  1738. "Vertex.",
  1739. spv::ExecutionModel::Vertex, decoration, built_in_inst,
  1740. referenced_from_inst, std::placeholders::_1));
  1741. }
  1742. for (const spv::ExecutionModel execution_model : execution_models_) {
  1743. switch (execution_model) {
  1744. case spv::ExecutionModel::Vertex: {
  1745. if (spv_result_t error = ValidateF32(
  1746. decoration, built_in_inst,
  1747. [this, &referenced_from_inst](
  1748. const std::string& message) -> spv_result_t {
  1749. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1750. << _.VkErrorID(4317)
  1751. << "According to the Vulkan spec BuiltIn PointSize "
  1752. "variable needs to be a 32-bit float scalar. "
  1753. << message;
  1754. })) {
  1755. return error;
  1756. }
  1757. break;
  1758. }
  1759. case spv::ExecutionModel::TessellationControl:
  1760. case spv::ExecutionModel::TessellationEvaluation:
  1761. case spv::ExecutionModel::Geometry:
  1762. case spv::ExecutionModel::MeshNV:
  1763. case spv::ExecutionModel::MeshEXT: {
  1764. // PointSize can be a per-vertex variable for tessellation control,
  1765. // tessellation evaluation and geometry shader stages. In such cases
  1766. // variables will have an array of 32-bit floats.
  1767. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1768. // The array is on the variable, so this must be a 32-bit float.
  1769. if (spv_result_t error = ValidateF32(
  1770. decoration, built_in_inst,
  1771. [this, &referenced_from_inst](
  1772. const std::string& message) -> spv_result_t {
  1773. return _.diag(SPV_ERROR_INVALID_DATA,
  1774. &referenced_from_inst)
  1775. << _.VkErrorID(4317)
  1776. << "According to the Vulkan spec BuiltIn "
  1777. "PointSize variable needs to be a 32-bit "
  1778. "float scalar. "
  1779. << message;
  1780. })) {
  1781. return error;
  1782. }
  1783. } else {
  1784. if (spv_result_t error = ValidateOptionalArrayedF32(
  1785. decoration, built_in_inst,
  1786. [this, &referenced_from_inst](
  1787. const std::string& message) -> spv_result_t {
  1788. return _.diag(SPV_ERROR_INVALID_DATA,
  1789. &referenced_from_inst)
  1790. << _.VkErrorID(4317)
  1791. << "According to the Vulkan spec BuiltIn "
  1792. "PointSize variable needs to be a 32-bit "
  1793. "float scalar. "
  1794. << message;
  1795. })) {
  1796. return error;
  1797. }
  1798. }
  1799. break;
  1800. }
  1801. default: {
  1802. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1803. << _.VkErrorID(4314)
  1804. << "Vulkan spec allows BuiltIn PointSize to be used only with "
  1805. "Vertex, TessellationControl, TessellationEvaluation or "
  1806. "Geometry execution models. "
  1807. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1808. referenced_from_inst, execution_model);
  1809. }
  1810. }
  1811. }
  1812. }
  1813. if (function_id_ == 0) {
  1814. // Propagate this rule to all dependant ids in the global scope.
  1815. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1816. &BuiltInsValidator::ValidatePointSizeAtReference, this, decoration,
  1817. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1818. }
  1819. return SPV_SUCCESS;
  1820. }
  1821. spv_result_t BuiltInsValidator::ValidatePositionAtDefinition(
  1822. const Decoration& decoration, const Instruction& inst) {
  1823. // Seed at reference checks with this built-in.
  1824. return ValidatePositionAtReference(decoration, inst, inst, inst);
  1825. }
  1826. spv_result_t BuiltInsValidator::ValidatePositionAtReference(
  1827. const Decoration& decoration, const Instruction& built_in_inst,
  1828. const Instruction& referenced_inst,
  1829. const Instruction& referenced_from_inst) {
  1830. if (spvIsVulkanEnv(_.context()->target_env)) {
  1831. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1832. if (storage_class != spv::StorageClass::Max &&
  1833. storage_class != spv::StorageClass::Input &&
  1834. storage_class != spv::StorageClass::Output) {
  1835. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1836. << _.VkErrorID(4320) << "Vulkan spec allows BuiltIn Position to be only used for "
  1837. "variables with Input or Output storage class. "
  1838. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1839. referenced_from_inst)
  1840. << " " << GetStorageClassDesc(referenced_from_inst);
  1841. }
  1842. if (storage_class == spv::StorageClass::Input) {
  1843. assert(function_id_ == 0);
  1844. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1845. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
  1846. "Vulkan spec doesn't allow BuiltIn Position to be used "
  1847. "for variables "
  1848. "with Input storage class if execution model is Vertex.",
  1849. spv::ExecutionModel::Vertex, decoration, built_in_inst,
  1850. referenced_from_inst, std::placeholders::_1));
  1851. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1852. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
  1853. "Vulkan spec doesn't allow BuiltIn Position to be used "
  1854. "for variables "
  1855. "with Input storage class if execution model is MeshNV.",
  1856. spv::ExecutionModel::MeshNV, decoration, built_in_inst,
  1857. referenced_from_inst, std::placeholders::_1));
  1858. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1859. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
  1860. "Vulkan spec doesn't allow BuiltIn Position to be used "
  1861. "for variables "
  1862. "with Input storage class if execution model is MeshEXT.",
  1863. spv::ExecutionModel::MeshEXT, decoration, built_in_inst,
  1864. referenced_from_inst, std::placeholders::_1));
  1865. }
  1866. for (const spv::ExecutionModel execution_model : execution_models_) {
  1867. switch (execution_model) {
  1868. case spv::ExecutionModel::Vertex: {
  1869. if (spv_result_t error = ValidateF32Vec(
  1870. decoration, built_in_inst, 4,
  1871. [this, &referenced_from_inst](
  1872. const std::string& message) -> spv_result_t {
  1873. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1874. << _.VkErrorID(4321)
  1875. << "According to the Vulkan spec BuiltIn Position "
  1876. "variable needs to be a 4-component 32-bit float "
  1877. "vector. "
  1878. << message;
  1879. })) {
  1880. return error;
  1881. }
  1882. break;
  1883. }
  1884. case spv::ExecutionModel::Geometry:
  1885. case spv::ExecutionModel::TessellationControl:
  1886. case spv::ExecutionModel::TessellationEvaluation:
  1887. case spv::ExecutionModel::MeshNV:
  1888. case spv::ExecutionModel::MeshEXT: {
  1889. // Position can be a per-vertex variable for tessellation control,
  1890. // tessellation evaluation, geometry and mesh shader stages. In such
  1891. // cases variables will have an array of 4-component 32-bit float
  1892. // vectors.
  1893. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1894. // The array is on the variable, so this must be a 4-component
  1895. // 32-bit float vector.
  1896. if (spv_result_t error = ValidateF32Vec(
  1897. decoration, built_in_inst, 4,
  1898. [this, &referenced_from_inst](
  1899. const std::string& message) -> spv_result_t {
  1900. return _.diag(SPV_ERROR_INVALID_DATA,
  1901. &referenced_from_inst)
  1902. << _.VkErrorID(4321)
  1903. << "According to the Vulkan spec BuiltIn Position "
  1904. "variable needs to be a 4-component 32-bit "
  1905. "float vector. "
  1906. << message;
  1907. })) {
  1908. return error;
  1909. }
  1910. } else {
  1911. if (spv_result_t error = ValidateOptionalArrayedF32Vec(
  1912. decoration, built_in_inst, 4,
  1913. [this, &referenced_from_inst](
  1914. const std::string& message) -> spv_result_t {
  1915. return _.diag(SPV_ERROR_INVALID_DATA,
  1916. &referenced_from_inst)
  1917. << _.VkErrorID(4321)
  1918. << "According to the Vulkan spec BuiltIn Position "
  1919. "variable needs to be a 4-component 32-bit "
  1920. "float vector. "
  1921. << message;
  1922. })) {
  1923. return error;
  1924. }
  1925. }
  1926. break;
  1927. }
  1928. default: {
  1929. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1930. << _.VkErrorID(4318)
  1931. << "Vulkan spec allows BuiltIn Position to be used only "
  1932. "with Vertex, TessellationControl, TessellationEvaluation"
  1933. " or Geometry execution models. "
  1934. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1935. referenced_from_inst, execution_model);
  1936. }
  1937. }
  1938. }
  1939. }
  1940. if (function_id_ == 0) {
  1941. // Propagate this rule to all dependant ids in the global scope.
  1942. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1943. &BuiltInsValidator::ValidatePositionAtReference, this, decoration,
  1944. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1945. }
  1946. return SPV_SUCCESS;
  1947. }
  1948. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
  1949. const Decoration& decoration, const Instruction& inst) {
  1950. if (spvIsVulkanEnv(_.context()->target_env)) {
  1951. // PrimitiveId can be a per-primitive variable for mesh shader stage.
  1952. // In such cases variable will have an array of 32-bit integers.
  1953. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1954. // This must be a 32-bit int scalar.
  1955. if (spv_result_t error = ValidateI32(
  1956. decoration, inst,
  1957. [this, &inst](const std::string& message) -> spv_result_t {
  1958. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1959. << _.VkErrorID(4337)
  1960. << "According to the Vulkan spec BuiltIn PrimitiveId "
  1961. "variable needs to be a 32-bit int scalar. "
  1962. << message;
  1963. })) {
  1964. return error;
  1965. }
  1966. } else {
  1967. if (spv_result_t error = ValidateOptionalArrayedI32(
  1968. decoration, inst,
  1969. [this, &inst](const std::string& message) -> spv_result_t {
  1970. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1971. << _.VkErrorID(4337)
  1972. << "According to the Vulkan spec BuiltIn PrimitiveId "
  1973. "variable needs to be a 32-bit int scalar. "
  1974. << message;
  1975. })) {
  1976. return error;
  1977. }
  1978. }
  1979. if (_.HasCapability(spv::Capability::MeshShadingEXT)) {
  1980. if (isMeshInterfaceVar(inst) &&
  1981. !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
  1982. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1983. << _.VkErrorID(7040)
  1984. << "According to the Vulkan spec the variable decorated with "
  1985. "Builtin PrimitiveId within the MeshEXT Execution Model must "
  1986. "also be decorated with the PerPrimitiveEXT decoration. ";
  1987. }
  1988. }
  1989. }
  1990. // Seed at reference checks with this built-in.
  1991. return ValidatePrimitiveIdAtReference(decoration, inst, inst, inst);
  1992. }
  1993. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
  1994. const Decoration& decoration, const Instruction& built_in_inst,
  1995. const Instruction& referenced_inst,
  1996. const Instruction& referenced_from_inst) {
  1997. if (spvIsVulkanEnv(_.context()->target_env)) {
  1998. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  1999. if (storage_class != spv::StorageClass::Max &&
  2000. storage_class != spv::StorageClass::Input &&
  2001. storage_class != spv::StorageClass::Output) {
  2002. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2003. << "Vulkan spec allows BuiltIn PrimitiveId to be only used for "
  2004. "variables with Input or Output storage class. "
  2005. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2006. referenced_from_inst)
  2007. << " " << GetStorageClassDesc(referenced_from_inst);
  2008. }
  2009. if (storage_class == spv::StorageClass::Output) {
  2010. assert(function_id_ == 0);
  2011. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2012. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2013. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2014. "variables with Output storage class if execution model is "
  2015. "TessellationControl.",
  2016. spv::ExecutionModel::TessellationControl, decoration, built_in_inst,
  2017. referenced_from_inst, std::placeholders::_1));
  2018. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2019. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2020. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2021. "variables with Output storage class if execution model is "
  2022. "TessellationEvaluation.",
  2023. spv::ExecutionModel::TessellationEvaluation, decoration, built_in_inst,
  2024. referenced_from_inst, std::placeholders::_1));
  2025. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2026. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2027. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2028. "variables with Output storage class if execution model is "
  2029. "Fragment.",
  2030. spv::ExecutionModel::Fragment, decoration, built_in_inst,
  2031. referenced_from_inst, std::placeholders::_1));
  2032. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2033. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2034. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2035. "variables with Output storage class if execution model is "
  2036. "IntersectionKHR.",
  2037. spv::ExecutionModel::IntersectionKHR, decoration, built_in_inst,
  2038. referenced_from_inst, std::placeholders::_1));
  2039. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2040. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2041. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2042. "variables with Output storage class if execution model is "
  2043. "AnyHitKHR.",
  2044. spv::ExecutionModel::AnyHitKHR, decoration, built_in_inst,
  2045. referenced_from_inst, std::placeholders::_1));
  2046. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2047. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  2048. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  2049. "variables with Output storage class if execution model is "
  2050. "ClosestHitKHR.",
  2051. spv::ExecutionModel::ClosestHitKHR, decoration, built_in_inst,
  2052. referenced_from_inst, std::placeholders::_1));
  2053. }
  2054. for (const spv::ExecutionModel execution_model : execution_models_) {
  2055. switch (execution_model) {
  2056. case spv::ExecutionModel::Fragment:
  2057. case spv::ExecutionModel::TessellationControl:
  2058. case spv::ExecutionModel::TessellationEvaluation:
  2059. case spv::ExecutionModel::Geometry:
  2060. case spv::ExecutionModel::MeshNV:
  2061. case spv::ExecutionModel::MeshEXT:
  2062. case spv::ExecutionModel::IntersectionKHR:
  2063. case spv::ExecutionModel::AnyHitKHR:
  2064. case spv::ExecutionModel::ClosestHitKHR: {
  2065. // Ok.
  2066. break;
  2067. }
  2068. default: {
  2069. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2070. << _.VkErrorID(4330)
  2071. << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
  2072. "with Fragment, TessellationControl, "
  2073. "TessellationEvaluation, Geometry, MeshNV, MeshEXT, "
  2074. "IntersectionKHR, AnyHitKHR, and ClosestHitKHR execution models. "
  2075. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2076. referenced_from_inst, execution_model);
  2077. }
  2078. }
  2079. }
  2080. }
  2081. if (function_id_ == 0) {
  2082. // Propagate this rule to all dependant ids in the global scope.
  2083. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2084. &BuiltInsValidator::ValidatePrimitiveIdAtReference, this, decoration,
  2085. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2086. }
  2087. return SPV_SUCCESS;
  2088. }
  2089. spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition(
  2090. const Decoration& decoration, const Instruction& inst) {
  2091. if (spvIsVulkanEnv(_.context()->target_env)) {
  2092. if (spv_result_t error = ValidateI32(
  2093. decoration, inst,
  2094. [this, &inst](const std::string& message) -> spv_result_t {
  2095. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2096. << _.VkErrorID(4356)
  2097. << "According to the Vulkan spec BuiltIn SampleId "
  2098. "variable needs to be a 32-bit int scalar. "
  2099. << message;
  2100. })) {
  2101. return error;
  2102. }
  2103. }
  2104. // Seed at reference checks with this built-in.
  2105. return ValidateSampleIdAtReference(decoration, inst, inst, inst);
  2106. }
  2107. spv_result_t BuiltInsValidator::ValidateSampleIdAtReference(
  2108. const Decoration& decoration, const Instruction& built_in_inst,
  2109. const Instruction& referenced_inst,
  2110. const Instruction& referenced_from_inst) {
  2111. if (spvIsVulkanEnv(_.context()->target_env)) {
  2112. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2113. if (storage_class != spv::StorageClass::Max &&
  2114. storage_class != spv::StorageClass::Input) {
  2115. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2116. << _.VkErrorID(4355)
  2117. << "Vulkan spec allows BuiltIn SampleId to be only used for "
  2118. "variables with Input storage class. "
  2119. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2120. referenced_from_inst)
  2121. << " " << GetStorageClassDesc(referenced_from_inst);
  2122. }
  2123. for (const spv::ExecutionModel execution_model : execution_models_) {
  2124. if (execution_model != spv::ExecutionModel::Fragment) {
  2125. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2126. << _.VkErrorID(4354)
  2127. << "Vulkan spec allows BuiltIn SampleId to be used only with "
  2128. "Fragment execution model. "
  2129. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2130. referenced_from_inst, execution_model);
  2131. }
  2132. }
  2133. }
  2134. if (function_id_ == 0) {
  2135. // Propagate this rule to all dependant ids in the global scope.
  2136. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2137. &BuiltInsValidator::ValidateSampleIdAtReference, this, decoration,
  2138. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2139. }
  2140. return SPV_SUCCESS;
  2141. }
  2142. spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition(
  2143. const Decoration& decoration, const Instruction& inst) {
  2144. if (spvIsVulkanEnv(_.context()->target_env)) {
  2145. if (spv_result_t error = ValidateI32Arr(
  2146. decoration, inst,
  2147. [this, &inst](const std::string& message) -> spv_result_t {
  2148. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2149. << _.VkErrorID(4359)
  2150. << "According to the Vulkan spec BuiltIn SampleMask "
  2151. "variable needs to be a 32-bit int array. "
  2152. << message;
  2153. })) {
  2154. return error;
  2155. }
  2156. }
  2157. // Seed at reference checks with this built-in.
  2158. return ValidateSampleMaskAtReference(decoration, inst, inst, inst);
  2159. }
  2160. spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference(
  2161. const Decoration& decoration, const Instruction& built_in_inst,
  2162. const Instruction& referenced_inst,
  2163. const Instruction& referenced_from_inst) {
  2164. if (spvIsVulkanEnv(_.context()->target_env)) {
  2165. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2166. if (storage_class != spv::StorageClass::Max &&
  2167. storage_class != spv::StorageClass::Input &&
  2168. storage_class != spv::StorageClass::Output) {
  2169. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2170. << _.VkErrorID(4358)
  2171. << "Vulkan spec allows BuiltIn SampleMask to be only used for "
  2172. "variables with Input or Output storage class. "
  2173. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2174. referenced_from_inst)
  2175. << " " << GetStorageClassDesc(referenced_from_inst);
  2176. }
  2177. for (const spv::ExecutionModel execution_model : execution_models_) {
  2178. if (execution_model != spv::ExecutionModel::Fragment) {
  2179. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2180. << _.VkErrorID(4357)
  2181. << "Vulkan spec allows BuiltIn SampleMask to be used only "
  2182. "with "
  2183. "Fragment execution model. "
  2184. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2185. referenced_from_inst, execution_model);
  2186. }
  2187. }
  2188. }
  2189. if (function_id_ == 0) {
  2190. // Propagate this rule to all dependant ids in the global scope.
  2191. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2192. &BuiltInsValidator::ValidateSampleMaskAtReference, this, decoration,
  2193. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2194. }
  2195. return SPV_SUCCESS;
  2196. }
  2197. spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition(
  2198. const Decoration& decoration, const Instruction& inst) {
  2199. if (spvIsVulkanEnv(_.context()->target_env)) {
  2200. if (spv_result_t error = ValidateF32Vec(
  2201. decoration, inst, 2,
  2202. [this, &inst](const std::string& message) -> spv_result_t {
  2203. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2204. << _.VkErrorID(4362)
  2205. << "According to the Vulkan spec BuiltIn SamplePosition "
  2206. "variable needs to be a 2-component 32-bit float "
  2207. "vector. "
  2208. << message;
  2209. })) {
  2210. return error;
  2211. }
  2212. }
  2213. // Seed at reference checks with this built-in.
  2214. return ValidateSamplePositionAtReference(decoration, inst, inst, inst);
  2215. }
  2216. spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference(
  2217. const Decoration& decoration, const Instruction& built_in_inst,
  2218. const Instruction& referenced_inst,
  2219. const Instruction& referenced_from_inst) {
  2220. if (spvIsVulkanEnv(_.context()->target_env)) {
  2221. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2222. if (storage_class != spv::StorageClass::Max &&
  2223. storage_class != spv::StorageClass::Input) {
  2224. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2225. << _.VkErrorID(4361)
  2226. << "Vulkan spec allows BuiltIn SamplePosition to be only used "
  2227. "for "
  2228. "variables with Input storage class. "
  2229. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2230. referenced_from_inst)
  2231. << " " << GetStorageClassDesc(referenced_from_inst);
  2232. }
  2233. for (const spv::ExecutionModel execution_model : execution_models_) {
  2234. if (execution_model != spv::ExecutionModel::Fragment) {
  2235. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2236. << _.VkErrorID(4360)
  2237. << "Vulkan spec allows BuiltIn SamplePosition to be used only "
  2238. "with "
  2239. "Fragment execution model. "
  2240. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2241. referenced_from_inst, execution_model);
  2242. }
  2243. }
  2244. }
  2245. if (function_id_ == 0) {
  2246. // Propagate this rule to all dependant ids in the global scope.
  2247. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2248. &BuiltInsValidator::ValidateSamplePositionAtReference, this, decoration,
  2249. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2250. }
  2251. return SPV_SUCCESS;
  2252. }
  2253. spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition(
  2254. const Decoration& decoration, const Instruction& inst) {
  2255. if (spvIsVulkanEnv(_.context()->target_env)) {
  2256. if (spv_result_t error = ValidateF32Vec(
  2257. decoration, inst, 3,
  2258. [this, &inst](const std::string& message) -> spv_result_t {
  2259. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2260. << _.VkErrorID(4389)
  2261. << "According to the Vulkan spec BuiltIn TessCoord "
  2262. "variable needs to be a 3-component 32-bit float "
  2263. "vector. "
  2264. << message;
  2265. })) {
  2266. return error;
  2267. }
  2268. }
  2269. // Seed at reference checks with this built-in.
  2270. return ValidateTessCoordAtReference(decoration, inst, inst, inst);
  2271. }
  2272. spv_result_t BuiltInsValidator::ValidateTessCoordAtReference(
  2273. const Decoration& decoration, const Instruction& built_in_inst,
  2274. const Instruction& referenced_inst,
  2275. const Instruction& referenced_from_inst) {
  2276. if (spvIsVulkanEnv(_.context()->target_env)) {
  2277. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2278. if (storage_class != spv::StorageClass::Max &&
  2279. storage_class != spv::StorageClass::Input) {
  2280. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2281. << _.VkErrorID(4388)
  2282. << "Vulkan spec allows BuiltIn TessCoord to be only used for "
  2283. "variables with Input storage class. "
  2284. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2285. referenced_from_inst)
  2286. << " " << GetStorageClassDesc(referenced_from_inst);
  2287. }
  2288. for (const spv::ExecutionModel execution_model : execution_models_) {
  2289. if (execution_model != spv::ExecutionModel::TessellationEvaluation) {
  2290. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2291. << _.VkErrorID(4387)
  2292. << "Vulkan spec allows BuiltIn TessCoord to be used only with "
  2293. "TessellationEvaluation execution model. "
  2294. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2295. referenced_from_inst, execution_model);
  2296. }
  2297. }
  2298. }
  2299. if (function_id_ == 0) {
  2300. // Propagate this rule to all dependant ids in the global scope.
  2301. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2302. &BuiltInsValidator::ValidateTessCoordAtReference, this, decoration,
  2303. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2304. }
  2305. return SPV_SUCCESS;
  2306. }
  2307. spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
  2308. const Decoration& decoration, const Instruction& inst) {
  2309. if (spvIsVulkanEnv(_.context()->target_env)) {
  2310. if (spv_result_t error = ValidateF32Arr(
  2311. decoration, inst, 4,
  2312. [this, &inst](const std::string& message) -> spv_result_t {
  2313. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2314. << _.VkErrorID(4393)
  2315. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  2316. "variable needs to be a 4-component 32-bit float "
  2317. "array. "
  2318. << message;
  2319. })) {
  2320. return error;
  2321. }
  2322. }
  2323. // Seed at reference checks with this built-in.
  2324. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  2325. }
  2326. spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
  2327. const Decoration& decoration, const Instruction& inst) {
  2328. if (spvIsVulkanEnv(_.context()->target_env)) {
  2329. if (spv_result_t error = ValidateF32Arr(
  2330. decoration, inst, 2,
  2331. [this, &inst](const std::string& message) -> spv_result_t {
  2332. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2333. << _.VkErrorID(4397)
  2334. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  2335. "variable needs to be a 2-component 32-bit float "
  2336. "array. "
  2337. << message;
  2338. })) {
  2339. return error;
  2340. }
  2341. }
  2342. // Seed at reference checks with this built-in.
  2343. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  2344. }
  2345. spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
  2346. const Decoration& decoration, const Instruction& built_in_inst,
  2347. const Instruction& referenced_inst,
  2348. const Instruction& referenced_from_inst) {
  2349. uint32_t operand = (uint32_t)decoration.builtin();
  2350. if (spvIsVulkanEnv(_.context()->target_env)) {
  2351. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2352. if (storage_class != spv::StorageClass::Max &&
  2353. storage_class != spv::StorageClass::Input &&
  2354. storage_class != spv::StorageClass::Output) {
  2355. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2356. << "Vulkan spec allows BuiltIn "
  2357. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2358. operand)
  2359. << " to be only used for variables with Input or Output storage "
  2360. "class. "
  2361. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2362. referenced_from_inst)
  2363. << " " << GetStorageClassDesc(referenced_from_inst);
  2364. }
  2365. if (storage_class == spv::StorageClass::Input) {
  2366. assert(function_id_ == 0);
  2367. uint32_t vuid =
  2368. (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4391 : 4395;
  2369. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2370. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  2371. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
  2372. "used "
  2373. "for variables with Input storage class if execution model is "
  2374. "TessellationControl.",
  2375. spv::ExecutionModel::TessellationControl, decoration, built_in_inst,
  2376. referenced_from_inst, std::placeholders::_1));
  2377. }
  2378. if (storage_class == spv::StorageClass::Output) {
  2379. assert(function_id_ == 0);
  2380. uint32_t vuid =
  2381. (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4392 : 4396;
  2382. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2383. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  2384. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
  2385. "used "
  2386. "for variables with Output storage class if execution model is "
  2387. "TessellationEvaluation.",
  2388. spv::ExecutionModel::TessellationEvaluation, decoration, built_in_inst,
  2389. referenced_from_inst, std::placeholders::_1));
  2390. }
  2391. for (const spv::ExecutionModel execution_model : execution_models_) {
  2392. switch (execution_model) {
  2393. case spv::ExecutionModel::TessellationControl:
  2394. case spv::ExecutionModel::TessellationEvaluation: {
  2395. // Ok.
  2396. break;
  2397. }
  2398. default: {
  2399. uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::TessLevelOuter) ? 4390 : 4394;
  2400. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2401. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2402. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2403. operand)
  2404. << " to be used only with TessellationControl or "
  2405. "TessellationEvaluation execution models. "
  2406. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2407. referenced_from_inst, execution_model);
  2408. }
  2409. }
  2410. }
  2411. }
  2412. if (function_id_ == 0) {
  2413. // Propagate this rule to all dependant ids in the global scope.
  2414. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2415. &BuiltInsValidator::ValidateTessLevelAtReference, this, decoration,
  2416. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2417. }
  2418. return SPV_SUCCESS;
  2419. }
  2420. spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
  2421. const Decoration& decoration, const Instruction& inst) {
  2422. if (spvIsVulkanEnv(_.context()->target_env)) {
  2423. if (spv_result_t error = ValidateI32(
  2424. decoration, inst,
  2425. [this, &inst](const std::string& message) -> spv_result_t {
  2426. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2427. << _.VkErrorID(4400) << "According to the "
  2428. << spvLogStringForEnv(_.context()->target_env)
  2429. << " spec BuiltIn VertexIndex variable needs to be a "
  2430. "32-bit int scalar. "
  2431. << message;
  2432. })) {
  2433. return error;
  2434. }
  2435. }
  2436. // Seed at reference checks with this built-in.
  2437. return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
  2438. }
  2439. spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
  2440. const Decoration& decoration, const Instruction& inst) {
  2441. (void)decoration;
  2442. if (spvIsVulkanEnv(_.context()->target_env)) {
  2443. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2444. << "Vulkan spec doesn't allow BuiltIn VertexId "
  2445. "to be used.";
  2446. }
  2447. return SPV_SUCCESS;
  2448. }
  2449. spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
  2450. const Decoration& decoration, const Instruction& inst) {
  2451. // Seed at reference checks with this built-in.
  2452. return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst);
  2453. }
  2454. spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
  2455. const Decoration& decoration, const Instruction& built_in_inst,
  2456. const Instruction&,
  2457. const Instruction& referenced_from_inst) {
  2458. if (function_id_ == 0) {
  2459. // Propagate this rule to all dependant ids in the global scope.
  2460. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2461. std::bind(&BuiltInsValidator::ValidateLocalInvocationIndexAtReference,
  2462. this, decoration, built_in_inst, referenced_from_inst,
  2463. std::placeholders::_1));
  2464. }
  2465. return SPV_SUCCESS;
  2466. }
  2467. spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
  2468. const Decoration& decoration, const Instruction& built_in_inst,
  2469. const Instruction& referenced_inst,
  2470. const Instruction& referenced_from_inst) {
  2471. if (spvIsVulkanEnv(_.context()->target_env)) {
  2472. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2473. if (storage_class != spv::StorageClass::Max &&
  2474. storage_class != spv::StorageClass::Input) {
  2475. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2476. << _.VkErrorID(4399) << spvLogStringForEnv(_.context()->target_env)
  2477. << " spec allows BuiltIn VertexIndex to be only used for "
  2478. "variables with Input storage class. "
  2479. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2480. referenced_from_inst)
  2481. << " " << GetStorageClassDesc(referenced_from_inst);
  2482. }
  2483. for (const spv::ExecutionModel execution_model : execution_models_) {
  2484. if (execution_model != spv::ExecutionModel::Vertex) {
  2485. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2486. << _.VkErrorID(4398)
  2487. << spvLogStringForEnv(_.context()->target_env)
  2488. << " spec allows BuiltIn VertexIndex to be used only with "
  2489. "Vertex execution model. "
  2490. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2491. referenced_from_inst, execution_model);
  2492. }
  2493. }
  2494. }
  2495. if (function_id_ == 0) {
  2496. // Propagate this rule to all dependant ids in the global scope.
  2497. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2498. &BuiltInsValidator::ValidateVertexIndexAtReference, this, decoration,
  2499. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2500. }
  2501. return SPV_SUCCESS;
  2502. }
  2503. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
  2504. const Decoration& decoration, const Instruction& inst) {
  2505. if (spvIsVulkanEnv(_.context()->target_env)) {
  2506. // This can be a per-primitive variable for mesh shader stage.
  2507. // In such cases variable will have an array of 32-bit integers.
  2508. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2509. // This must be a 32-bit int scalar.
  2510. if (spv_result_t error = ValidateI32(
  2511. decoration, inst,
  2512. [this, &decoration,
  2513. &inst](const std::string& message) -> spv_result_t {
  2514. uint32_t vuid =
  2515. (decoration.builtin() == spv::BuiltIn::Layer) ? 4276 : 4408;
  2516. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2517. << _.VkErrorID(vuid)
  2518. << "According to the Vulkan spec BuiltIn "
  2519. << _.grammar().lookupOperandName(
  2520. SPV_OPERAND_TYPE_BUILT_IN,
  2521. (uint32_t)decoration.builtin())
  2522. << "variable needs to be a 32-bit int scalar. "
  2523. << message;
  2524. })) {
  2525. return error;
  2526. }
  2527. } else {
  2528. if (spv_result_t error = ValidateOptionalArrayedI32(
  2529. decoration, inst,
  2530. [this, &decoration,
  2531. &inst](const std::string& message) -> spv_result_t {
  2532. uint32_t vuid =
  2533. (decoration.builtin() == spv::BuiltIn::Layer) ? 4276 : 4408;
  2534. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2535. << _.VkErrorID(vuid)
  2536. << "According to the Vulkan spec BuiltIn "
  2537. << _.grammar().lookupOperandName(
  2538. SPV_OPERAND_TYPE_BUILT_IN,
  2539. (uint32_t)decoration.builtin())
  2540. << "variable needs to be a 32-bit int scalar. "
  2541. << message;
  2542. })) {
  2543. return error;
  2544. }
  2545. }
  2546. if (isMeshInterfaceVar(inst) &&
  2547. _.HasCapability(spv::Capability::MeshShadingEXT) &&
  2548. !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
  2549. const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
  2550. uint32_t vkerrid = (label == spv::BuiltIn::Layer) ? 7039 : 7060;
  2551. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2552. << _.VkErrorID(vkerrid)
  2553. << "According to the Vulkan spec the variable decorated with "
  2554. "Builtin "
  2555. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2556. decoration.params()[0])
  2557. << " within the MeshEXT Execution Model must also be decorated "
  2558. "with the PerPrimitiveEXT decoration. ";
  2559. }
  2560. }
  2561. // Seed at reference checks with this built-in.
  2562. return ValidateLayerOrViewportIndexAtReference(decoration, inst, inst, inst);
  2563. }
  2564. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
  2565. const Decoration& decoration, const Instruction& built_in_inst,
  2566. const Instruction& referenced_inst,
  2567. const Instruction& referenced_from_inst) {
  2568. uint32_t operand = (uint32_t)decoration.builtin();
  2569. if (spvIsVulkanEnv(_.context()->target_env)) {
  2570. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2571. if (storage_class != spv::StorageClass::Max &&
  2572. storage_class != spv::StorageClass::Input &&
  2573. storage_class != spv::StorageClass::Output) {
  2574. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2575. << "Vulkan spec allows BuiltIn "
  2576. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2577. operand)
  2578. << " to be only used for variables with Input or Output storage "
  2579. "class. "
  2580. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2581. referenced_from_inst)
  2582. << " " << GetStorageClassDesc(referenced_from_inst);
  2583. }
  2584. if (storage_class == spv::StorageClass::Input) {
  2585. assert(function_id_ == 0);
  2586. for (const auto em :
  2587. {spv::ExecutionModel::Vertex, spv::ExecutionModel::TessellationEvaluation,
  2588. spv::ExecutionModel::Geometry, spv::ExecutionModel::MeshNV,
  2589. spv::ExecutionModel::MeshEXT}) {
  2590. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2591. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
  2592. this, ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4274 : 4406),
  2593. "Vulkan spec doesn't allow BuiltIn Layer and "
  2594. "ViewportIndex to be "
  2595. "used for variables with Input storage class if "
  2596. "execution model is Vertex, TessellationEvaluation, "
  2597. "Geometry, MeshNV or MeshEXT.",
  2598. em, decoration, built_in_inst, referenced_from_inst,
  2599. std::placeholders::_1));
  2600. }
  2601. }
  2602. if (storage_class == spv::StorageClass::Output) {
  2603. assert(function_id_ == 0);
  2604. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2605. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
  2606. this, ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4275 : 4407),
  2607. "Vulkan spec doesn't allow BuiltIn Layer and "
  2608. "ViewportIndex to be "
  2609. "used for variables with Output storage class if "
  2610. "execution model is "
  2611. "Fragment.",
  2612. spv::ExecutionModel::Fragment, decoration, built_in_inst,
  2613. referenced_from_inst, std::placeholders::_1));
  2614. }
  2615. for (const spv::ExecutionModel execution_model : execution_models_) {
  2616. switch (execution_model) {
  2617. case spv::ExecutionModel::Geometry:
  2618. case spv::ExecutionModel::Fragment:
  2619. case spv::ExecutionModel::MeshNV:
  2620. case spv::ExecutionModel::MeshEXT:
  2621. // Ok.
  2622. break;
  2623. case spv::ExecutionModel::Vertex:
  2624. case spv::ExecutionModel::TessellationEvaluation: {
  2625. if (!_.HasCapability(spv::Capability::ShaderViewportIndexLayerEXT)) {
  2626. if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex &&
  2627. _.HasCapability(spv::Capability::ShaderViewportIndex))
  2628. break; // Ok
  2629. if (spv::BuiltIn(operand) == spv::BuiltIn::Layer &&
  2630. _.HasCapability(spv::Capability::ShaderLayer))
  2631. break; // Ok
  2632. const char* capability = "ShaderViewportIndexLayerEXT";
  2633. if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex)
  2634. capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex";
  2635. if (spv::BuiltIn(operand) == spv::BuiltIn::Layer)
  2636. capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
  2637. uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4273 : 4405;
  2638. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2639. << _.VkErrorID(vuid) << "Using BuiltIn "
  2640. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2641. operand)
  2642. << " in Vertex or Tessellation execution model requires the "
  2643. << capability << " capability.";
  2644. }
  2645. break;
  2646. }
  2647. default: {
  2648. uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4272 : 4404;
  2649. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2650. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2651. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2652. operand)
  2653. << " to be used only with Vertex, TessellationEvaluation, "
  2654. "Geometry, or Fragment execution models. "
  2655. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2656. referenced_from_inst, execution_model);
  2657. }
  2658. }
  2659. }
  2660. }
  2661. if (function_id_ == 0) {
  2662. // Propagate this rule to all dependant ids in the global scope.
  2663. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2664. std::bind(&BuiltInsValidator::ValidateLayerOrViewportIndexAtReference,
  2665. this, decoration, built_in_inst, referenced_from_inst,
  2666. std::placeholders::_1));
  2667. }
  2668. return SPV_SUCCESS;
  2669. }
  2670. spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtDefinition(
  2671. const Decoration& decoration, const Instruction& inst) {
  2672. if (spvIsVulkanEnv(_.context()->target_env)) {
  2673. const spv::BuiltIn builtin = decoration.builtin();
  2674. if (spv_result_t error = ValidateF32Vec(
  2675. decoration, inst, 3,
  2676. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2677. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2678. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2679. << _.VkErrorID(vuid) << "According to the "
  2680. << spvLogStringForEnv(_.context()->target_env)
  2681. << " spec BuiltIn "
  2682. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2683. uint32_t(builtin))
  2684. << " variable needs to be a 3-component 32-bit float "
  2685. "vector. "
  2686. << message;
  2687. })) {
  2688. return error;
  2689. }
  2690. }
  2691. // Seed at reference checks with this built-in.
  2692. return ValidateFragmentShaderF32Vec3InputAtReference(decoration, inst, inst,
  2693. inst);
  2694. }
  2695. spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference(
  2696. const Decoration& decoration, const Instruction& built_in_inst,
  2697. const Instruction& referenced_inst,
  2698. const Instruction& referenced_from_inst) {
  2699. if (spvIsVulkanEnv(_.context()->target_env)) {
  2700. const spv::BuiltIn builtin = decoration.builtin();
  2701. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2702. if (storage_class != spv::StorageClass::Max &&
  2703. storage_class != spv::StorageClass::Input) {
  2704. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2705. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2706. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  2707. << " spec allows BuiltIn "
  2708. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2709. << " to be only used for variables with Input storage class. "
  2710. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2711. referenced_from_inst)
  2712. << " " << GetStorageClassDesc(referenced_from_inst);
  2713. }
  2714. for (const spv::ExecutionModel execution_model : execution_models_) {
  2715. if (execution_model != spv::ExecutionModel::Fragment) {
  2716. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  2717. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2718. << _.VkErrorID(vuid)
  2719. << spvLogStringForEnv(_.context()->target_env)
  2720. << " spec allows BuiltIn "
  2721. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2722. << " to be used only with Fragment execution model. "
  2723. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2724. referenced_from_inst, execution_model);
  2725. }
  2726. }
  2727. }
  2728. if (function_id_ == 0) {
  2729. // Propagate this rule to all dependant ids in the global scope.
  2730. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2731. &BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference, this,
  2732. decoration, built_in_inst, referenced_from_inst,
  2733. std::placeholders::_1));
  2734. }
  2735. return SPV_SUCCESS;
  2736. }
  2737. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
  2738. const Decoration& decoration, const Instruction& inst) {
  2739. if (spvIsVulkanEnv(_.context()->target_env)) {
  2740. const spv::BuiltIn builtin = decoration.builtin();
  2741. if (spv_result_t error = ValidateI32Vec(
  2742. decoration, inst, 3,
  2743. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2744. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2745. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2746. << _.VkErrorID(vuid) << "According to the "
  2747. << spvLogStringForEnv(_.context()->target_env)
  2748. << " spec BuiltIn "
  2749. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2750. uint32_t(builtin))
  2751. << " variable needs to be a 3-component 32-bit int "
  2752. "vector. "
  2753. << message;
  2754. })) {
  2755. return error;
  2756. }
  2757. }
  2758. // Seed at reference checks with this built-in.
  2759. return ValidateComputeShaderI32Vec3InputAtReference(decoration, inst, inst,
  2760. inst);
  2761. }
  2762. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
  2763. const Decoration& decoration, const Instruction& built_in_inst,
  2764. const Instruction& referenced_inst,
  2765. const Instruction& referenced_from_inst) {
  2766. if (spvIsVulkanEnv(_.context()->target_env)) {
  2767. const spv::BuiltIn builtin = decoration.builtin();
  2768. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2769. if (storage_class != spv::StorageClass::Max &&
  2770. storage_class != spv::StorageClass::Input) {
  2771. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2772. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2773. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  2774. << " spec allows BuiltIn "
  2775. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2776. << " to be only used for variables with Input storage class. "
  2777. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2778. referenced_from_inst)
  2779. << " " << GetStorageClassDesc(referenced_from_inst);
  2780. }
  2781. for (const spv::ExecutionModel execution_model : execution_models_) {
  2782. bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
  2783. execution_model == spv::ExecutionModel::TaskNV ||
  2784. execution_model == spv::ExecutionModel::MeshNV ||
  2785. execution_model == spv::ExecutionModel::TaskEXT ||
  2786. execution_model == spv::ExecutionModel::MeshEXT;
  2787. if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
  2788. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  2789. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2790. << _.VkErrorID(vuid)
  2791. << spvLogStringForEnv(_.context()->target_env)
  2792. << " spec allows BuiltIn "
  2793. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2794. << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or"
  2795. << " TaskEXT execution model. "
  2796. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2797. referenced_from_inst, execution_model);
  2798. }
  2799. }
  2800. }
  2801. if (function_id_ == 0) {
  2802. // Propagate this rule to all dependant ids in the global scope.
  2803. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2804. &BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference, this,
  2805. decoration, built_in_inst, referenced_from_inst,
  2806. std::placeholders::_1));
  2807. }
  2808. return SPV_SUCCESS;
  2809. }
  2810. spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
  2811. const Decoration& decoration, const Instruction& inst) {
  2812. if (spvIsVulkanEnv(_.context()->target_env)) {
  2813. const spv::BuiltIn builtin = decoration.builtin();
  2814. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2815. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2816. << "BuiltIn "
  2817. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2818. << " cannot be used as a member decoration ";
  2819. }
  2820. if (spv_result_t error = ValidateI32(
  2821. decoration, inst,
  2822. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2823. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2824. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2825. << _.VkErrorID(vuid)
  2826. << "According to the "
  2827. << spvLogStringForEnv(_.context()->target_env)
  2828. << " spec BuiltIn "
  2829. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2830. << " variable needs to be a 32-bit int "
  2831. "vector. "
  2832. << message;
  2833. })) {
  2834. return error;
  2835. }
  2836. }
  2837. // Seed at reference checks with this built-in.
  2838. return ValidateComputeI32InputAtReference(decoration, inst, inst, inst);
  2839. }
  2840. spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
  2841. const Decoration& decoration, const Instruction& built_in_inst,
  2842. const Instruction& referenced_inst,
  2843. const Instruction& referenced_from_inst) {
  2844. if (spvIsVulkanEnv(_.context()->target_env)) {
  2845. const spv::BuiltIn builtin = decoration.builtin();
  2846. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  2847. if (storage_class != spv::StorageClass::Max &&
  2848. storage_class != spv::StorageClass::Input) {
  2849. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2850. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2851. << _.VkErrorID(vuid)
  2852. << spvLogStringForEnv(_.context()->target_env)
  2853. << " spec allows BuiltIn "
  2854. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2855. << " to be only used for variables with Input storage class. "
  2856. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2857. referenced_from_inst)
  2858. << " " << GetStorageClassDesc(referenced_from_inst);
  2859. }
  2860. for (const spv::ExecutionModel execution_model : execution_models_) {
  2861. bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
  2862. execution_model == spv::ExecutionModel::TaskNV ||
  2863. execution_model == spv::ExecutionModel::MeshNV ||
  2864. execution_model == spv::ExecutionModel::TaskEXT ||
  2865. execution_model == spv::ExecutionModel::MeshEXT;
  2866. if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
  2867. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  2868. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2869. << _.VkErrorID(vuid)
  2870. << spvLogStringForEnv(_.context()->target_env)
  2871. << " spec allows BuiltIn "
  2872. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2873. << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
  2874. << "TaskEXT execution model. "
  2875. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2876. referenced_from_inst, execution_model);
  2877. }
  2878. }
  2879. }
  2880. if (function_id_ == 0) {
  2881. // Propagate this rule to all dependant ids in the global scope.
  2882. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2883. std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this,
  2884. decoration, built_in_inst, referenced_from_inst,
  2885. std::placeholders::_1));
  2886. }
  2887. return SPV_SUCCESS;
  2888. }
  2889. spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
  2890. const Decoration& decoration, const Instruction& inst) {
  2891. if (spvIsVulkanEnv(_.context()->target_env)) {
  2892. const spv::BuiltIn builtin = decoration.builtin();
  2893. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2894. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2895. << "BuiltIn "
  2896. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2897. << " cannot be used as a member decoration ";
  2898. }
  2899. if (spv_result_t error = ValidateI32(
  2900. decoration, inst,
  2901. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2902. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2903. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2904. << _.VkErrorID(vuid)
  2905. << "According to the "
  2906. << spvLogStringForEnv(_.context()->target_env)
  2907. << " spec BuiltIn "
  2908. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2909. << " variable needs to be a 32-bit int. " << message;
  2910. })) {
  2911. return error;
  2912. }
  2913. const spv::StorageClass storage_class = GetStorageClass(inst);
  2914. if (storage_class != spv::StorageClass::Max &&
  2915. storage_class != spv::StorageClass::Input) {
  2916. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2917. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2918. << _.VkErrorID(vuid)
  2919. << spvLogStringForEnv(_.context()->target_env)
  2920. << " spec allows BuiltIn "
  2921. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2922. << " to be only used for variables with Input storage class. "
  2923. << GetReferenceDesc(decoration, inst, inst, inst) << " "
  2924. << GetStorageClassDesc(inst);
  2925. }
  2926. }
  2927. return SPV_SUCCESS;
  2928. }
  2929. spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
  2930. const Decoration& decoration, const Instruction& inst) {
  2931. if (spvIsVulkanEnv(_.context()->target_env)) {
  2932. const spv::BuiltIn builtin = decoration.builtin();
  2933. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2934. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2935. << "BuiltIn "
  2936. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2937. << " cannot be used as a member decoration ";
  2938. }
  2939. if (spv_result_t error = ValidateI32Vec(
  2940. decoration, inst, 4,
  2941. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2942. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2943. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2944. << _.VkErrorID(vuid)
  2945. << "According to the "
  2946. << spvLogStringForEnv(_.context()->target_env)
  2947. << " spec BuiltIn "
  2948. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2949. << " variable needs to be a 4-component 32-bit int "
  2950. "vector. "
  2951. << message;
  2952. })) {
  2953. return error;
  2954. }
  2955. const spv::StorageClass storage_class = GetStorageClass(inst);
  2956. if (storage_class != spv::StorageClass::Max &&
  2957. storage_class != spv::StorageClass::Input) {
  2958. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2959. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2960. << _.VkErrorID(vuid)
  2961. << spvLogStringForEnv(_.context()->target_env)
  2962. << " spec allows BuiltIn "
  2963. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  2964. << " to be only used for variables with Input storage class. "
  2965. << GetReferenceDesc(decoration, inst, inst, inst) << " "
  2966. << GetStorageClassDesc(inst);
  2967. }
  2968. }
  2969. return SPV_SUCCESS;
  2970. }
  2971. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
  2972. const Decoration& decoration, const Instruction& inst) {
  2973. // Vulkan requires 32-bit int, but Universal has no restrictions
  2974. if (spvIsVulkanEnv(_.context()->target_env)) {
  2975. if (spv_result_t error = ValidateI32Vec(
  2976. decoration, inst, 3,
  2977. [this, &inst](const std::string& message) -> spv_result_t {
  2978. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2979. << _.VkErrorID(4427) << "According to the "
  2980. << spvLogStringForEnv(_.context()->target_env)
  2981. << " spec BuiltIn WorkgroupSize variable needs to be a "
  2982. "3-component 32-bit int vector. "
  2983. << message;
  2984. })) {
  2985. return error;
  2986. }
  2987. }
  2988. if (!spvOpcodeIsConstant(inst.opcode())) {
  2989. if (spvIsVulkanEnv(_.context()->target_env)) {
  2990. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2991. << _.VkErrorID(4426)
  2992. << "Vulkan spec requires BuiltIn WorkgroupSize to be a "
  2993. "constant. "
  2994. << GetIdDesc(inst) << " is not a constant.";
  2995. }
  2996. } else if (inst.opcode() == spv::Op::OpConstantComposite) {
  2997. // can only validate product if static and not spec constant
  2998. if (_.FindDef(inst.word(3))->opcode() == spv::Op::OpConstant &&
  2999. _.FindDef(inst.word(4))->opcode() == spv::Op::OpConstant &&
  3000. _.FindDef(inst.word(5))->opcode() == spv::Op::OpConstant) {
  3001. uint64_t x_size, y_size, z_size;
  3002. // ValidateI32Vec above confirms there will be 3 words to read
  3003. bool static_x = _.EvalConstantValUint64(inst.word(3), &x_size);
  3004. bool static_y = _.EvalConstantValUint64(inst.word(4), &y_size);
  3005. bool static_z = _.EvalConstantValUint64(inst.word(5), &z_size);
  3006. if (static_x && static_y && static_z &&
  3007. ((x_size * y_size * z_size) == 0)) {
  3008. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3009. << "WorkgroupSize decorations must not have a static "
  3010. "product of zero (X = "
  3011. << x_size << ", Y = " << y_size << ", Z = " << z_size << ").";
  3012. }
  3013. }
  3014. }
  3015. // Seed at reference checks with this built-in.
  3016. return ValidateWorkgroupSizeAtReference(decoration, inst, inst, inst);
  3017. }
  3018. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
  3019. const Decoration& decoration, const Instruction& built_in_inst,
  3020. const Instruction& referenced_inst,
  3021. const Instruction& referenced_from_inst) {
  3022. if (spvIsVulkanEnv(_.context()->target_env)) {
  3023. for (const spv::ExecutionModel execution_model : execution_models_) {
  3024. if (execution_model != spv::ExecutionModel::GLCompute &&
  3025. execution_model != spv::ExecutionModel::TaskNV &&
  3026. execution_model != spv::ExecutionModel::MeshNV &&
  3027. execution_model != spv::ExecutionModel::TaskEXT &&
  3028. execution_model != spv::ExecutionModel::MeshEXT) {
  3029. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3030. << _.VkErrorID(4425)
  3031. << spvLogStringForEnv(_.context()->target_env)
  3032. << " spec allows BuiltIn "
  3033. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3034. (uint32_t)decoration.builtin())
  3035. << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
  3036. << "TaskEXT execution model. "
  3037. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3038. referenced_from_inst, execution_model);
  3039. }
  3040. }
  3041. }
  3042. if (function_id_ == 0) {
  3043. // Propagate this rule to all dependant ids in the global scope.
  3044. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3045. &BuiltInsValidator::ValidateWorkgroupSizeAtReference, this, decoration,
  3046. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3047. }
  3048. return SPV_SUCCESS;
  3049. }
  3050. spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtDefinition(
  3051. const Decoration& decoration, const Instruction& inst) {
  3052. if (spvIsVulkanEnv(_.context()->target_env)) {
  3053. if (spv_result_t error = ValidateI32(
  3054. decoration, inst,
  3055. [this, &inst,
  3056. &decoration](const std::string& message) -> spv_result_t {
  3057. uint32_t vuid =
  3058. (decoration.builtin() == spv::BuiltIn::BaseInstance) ? 4183
  3059. : 4186;
  3060. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3061. << _.VkErrorID(vuid)
  3062. << "According to the Vulkan spec BuiltIn "
  3063. << _.grammar().lookupOperandName(
  3064. SPV_OPERAND_TYPE_BUILT_IN,
  3065. (uint32_t)decoration.builtin())
  3066. << " variable needs to be a 32-bit int scalar. "
  3067. << message;
  3068. })) {
  3069. return error;
  3070. }
  3071. }
  3072. return ValidateBaseInstanceOrVertexAtReference(decoration, inst, inst, inst);
  3073. }
  3074. spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference(
  3075. const Decoration& decoration, const Instruction& built_in_inst,
  3076. const Instruction& referenced_inst,
  3077. const Instruction& referenced_from_inst) {
  3078. uint32_t operand = (uint32_t)decoration.builtin();
  3079. if (spvIsVulkanEnv(_.context()->target_env)) {
  3080. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3081. if (storage_class != spv::StorageClass::Max &&
  3082. storage_class != spv::StorageClass::Input) {
  3083. uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4182 : 4185;
  3084. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3085. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  3086. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3087. operand)
  3088. << " to be only used for variables with Input storage class. "
  3089. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3090. referenced_from_inst)
  3091. << " " << GetStorageClassDesc(referenced_from_inst);
  3092. }
  3093. for (const spv::ExecutionModel execution_model : execution_models_) {
  3094. if (execution_model != spv::ExecutionModel::Vertex) {
  3095. uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4181 : 4184;
  3096. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3097. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  3098. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3099. operand)
  3100. << " to be used only with Vertex execution model. "
  3101. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3102. referenced_from_inst, execution_model);
  3103. }
  3104. }
  3105. }
  3106. if (function_id_ == 0) {
  3107. // Propagate this rule to all dependant ids in the global scope.
  3108. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  3109. std::bind(&BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference,
  3110. this, decoration, built_in_inst, referenced_from_inst,
  3111. std::placeholders::_1));
  3112. }
  3113. return SPV_SUCCESS;
  3114. }
  3115. spv_result_t BuiltInsValidator::ValidateDrawIndexAtDefinition(
  3116. const Decoration& decoration, const Instruction& inst) {
  3117. if (spvIsVulkanEnv(_.context()->target_env)) {
  3118. if (spv_result_t error = ValidateI32(
  3119. decoration, inst,
  3120. [this, &inst,
  3121. &decoration](const std::string& message) -> spv_result_t {
  3122. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3123. << _.VkErrorID(4209)
  3124. << "According to the Vulkan spec BuiltIn "
  3125. << _.grammar().lookupOperandName(
  3126. SPV_OPERAND_TYPE_BUILT_IN,
  3127. (uint32_t)decoration.builtin())
  3128. << " variable needs to be a 32-bit int scalar. "
  3129. << message;
  3130. })) {
  3131. return error;
  3132. }
  3133. }
  3134. return ValidateDrawIndexAtReference(decoration, inst, inst, inst);
  3135. }
  3136. spv_result_t BuiltInsValidator::ValidateDrawIndexAtReference(
  3137. const Decoration& decoration, const Instruction& built_in_inst,
  3138. const Instruction& referenced_inst,
  3139. const Instruction& referenced_from_inst) {
  3140. uint32_t operand = (uint32_t)decoration.builtin();
  3141. if (spvIsVulkanEnv(_.context()->target_env)) {
  3142. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3143. if (storage_class != spv::StorageClass::Max &&
  3144. storage_class != spv::StorageClass::Input) {
  3145. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3146. << _.VkErrorID(4208) << "Vulkan spec allows BuiltIn "
  3147. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3148. operand)
  3149. << " to be only used for variables with Input storage class. "
  3150. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3151. referenced_from_inst)
  3152. << " " << GetStorageClassDesc(referenced_from_inst);
  3153. }
  3154. for (const spv::ExecutionModel execution_model : execution_models_) {
  3155. if (execution_model != spv::ExecutionModel::Vertex &&
  3156. execution_model != spv::ExecutionModel::MeshNV &&
  3157. execution_model != spv::ExecutionModel::TaskNV &&
  3158. execution_model != spv::ExecutionModel::MeshEXT &&
  3159. execution_model != spv::ExecutionModel::TaskEXT) {
  3160. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3161. << _.VkErrorID(4207) << "Vulkan spec allows BuiltIn "
  3162. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3163. operand)
  3164. << " to be used only with Vertex, MeshNV, TaskNV , MeshEXT or"
  3165. << " TaskEXT execution "
  3166. "model. "
  3167. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3168. referenced_from_inst, execution_model);
  3169. }
  3170. }
  3171. }
  3172. if (function_id_ == 0) {
  3173. // Propagate this rule to all dependant ids in the global scope.
  3174. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3175. &BuiltInsValidator::ValidateDrawIndexAtReference, this, decoration,
  3176. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3177. }
  3178. return SPV_SUCCESS;
  3179. }
  3180. spv_result_t BuiltInsValidator::ValidateViewIndexAtDefinition(
  3181. const Decoration& decoration, const Instruction& inst) {
  3182. if (spvIsVulkanEnv(_.context()->target_env)) {
  3183. if (spv_result_t error = ValidateI32(
  3184. decoration, inst,
  3185. [this, &inst,
  3186. &decoration](const std::string& message) -> spv_result_t {
  3187. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3188. << _.VkErrorID(4403)
  3189. << "According to the Vulkan spec BuiltIn "
  3190. << _.grammar().lookupOperandName(
  3191. SPV_OPERAND_TYPE_BUILT_IN,
  3192. (uint32_t)decoration.builtin())
  3193. << " variable needs to be a 32-bit int scalar. "
  3194. << message;
  3195. })) {
  3196. return error;
  3197. }
  3198. }
  3199. return ValidateViewIndexAtReference(decoration, inst, inst, inst);
  3200. }
  3201. spv_result_t BuiltInsValidator::ValidateViewIndexAtReference(
  3202. const Decoration& decoration, const Instruction& built_in_inst,
  3203. const Instruction& referenced_inst,
  3204. const Instruction& referenced_from_inst) {
  3205. uint32_t operand = (uint32_t)decoration.builtin();
  3206. if (spvIsVulkanEnv(_.context()->target_env)) {
  3207. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3208. if (storage_class != spv::StorageClass::Max &&
  3209. storage_class != spv::StorageClass::Input) {
  3210. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3211. << _.VkErrorID(4402) << "Vulkan spec allows BuiltIn "
  3212. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3213. operand)
  3214. << " to be only used for variables with Input storage class. "
  3215. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3216. referenced_from_inst)
  3217. << " " << GetStorageClassDesc(referenced_from_inst);
  3218. }
  3219. for (const spv::ExecutionModel execution_model : execution_models_) {
  3220. if (execution_model == spv::ExecutionModel::GLCompute) {
  3221. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3222. << _.VkErrorID(4401) << "Vulkan spec allows BuiltIn "
  3223. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3224. operand)
  3225. << " to be not be used with GLCompute execution model. "
  3226. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3227. referenced_from_inst, execution_model);
  3228. }
  3229. }
  3230. }
  3231. if (function_id_ == 0) {
  3232. // Propagate this rule to all dependant ids in the global scope.
  3233. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3234. &BuiltInsValidator::ValidateViewIndexAtReference, this, decoration,
  3235. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3236. }
  3237. return SPV_SUCCESS;
  3238. }
  3239. spv_result_t BuiltInsValidator::ValidateDeviceIndexAtDefinition(
  3240. const Decoration& decoration, const Instruction& inst) {
  3241. if (spvIsVulkanEnv(_.context()->target_env)) {
  3242. if (spv_result_t error = ValidateI32(
  3243. decoration, inst,
  3244. [this, &inst,
  3245. &decoration](const std::string& message) -> spv_result_t {
  3246. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3247. << _.VkErrorID(4206)
  3248. << "According to the Vulkan spec BuiltIn "
  3249. << _.grammar().lookupOperandName(
  3250. SPV_OPERAND_TYPE_BUILT_IN,
  3251. (uint32_t)decoration.builtin())
  3252. << " variable needs to be a 32-bit int scalar. "
  3253. << message;
  3254. })) {
  3255. return error;
  3256. }
  3257. }
  3258. return ValidateDeviceIndexAtReference(decoration, inst, inst, inst);
  3259. }
  3260. spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference(
  3261. const Decoration& decoration, const Instruction& built_in_inst,
  3262. const Instruction& referenced_inst,
  3263. const Instruction& referenced_from_inst) {
  3264. uint32_t operand = (uint32_t)decoration.builtin();
  3265. if (spvIsVulkanEnv(_.context()->target_env)) {
  3266. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3267. if (storage_class != spv::StorageClass::Max &&
  3268. storage_class != spv::StorageClass::Input) {
  3269. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3270. << _.VkErrorID(4205) << "Vulkan spec allows BuiltIn "
  3271. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3272. operand)
  3273. << " to be only used for variables with Input storage class. "
  3274. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3275. referenced_from_inst)
  3276. << " " << GetStorageClassDesc(referenced_from_inst);
  3277. }
  3278. }
  3279. if (function_id_ == 0) {
  3280. // Propagate this rule to all dependant ids in the global scope.
  3281. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3282. &BuiltInsValidator::ValidateDeviceIndexAtReference, this, decoration,
  3283. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3284. }
  3285. return SPV_SUCCESS;
  3286. }
  3287. spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
  3288. const Instruction& inst) {
  3289. if (spvIsVulkanEnv(_.context()->target_env)) {
  3290. const spv::BuiltIn builtin = decoration.builtin();
  3291. if (spv_result_t error = ValidateI32(
  3292. decoration, inst,
  3293. [this, &inst, &builtin](const std::string& message) -> spv_result_t {
  3294. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3295. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3296. << _.VkErrorID(vuid) << "According to the "
  3297. << spvLogStringForEnv(_.context()->target_env)
  3298. << " spec BuiltIn "
  3299. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3300. uint32_t(builtin))
  3301. << " variable needs to be a 32-bit int scalar. "
  3302. << message;
  3303. })) {
  3304. return error;
  3305. }
  3306. }
  3307. return ValidateFragInvocationCountAtReference(decoration, inst, inst, inst);
  3308. }
  3309. spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference(
  3310. const Decoration& decoration, const Instruction& built_in_inst,
  3311. const Instruction& referenced_inst,
  3312. const Instruction& referenced_from_inst) {
  3313. if (spvIsVulkanEnv(_.context()->target_env)) {
  3314. const spv::BuiltIn builtin = decoration.builtin();
  3315. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3316. if (storage_class != spv::StorageClass::Max &&
  3317. storage_class != spv::StorageClass::Input) {
  3318. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3319. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3320. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  3321. << " spec allows BuiltIn "
  3322. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3323. << " to be only used for variables with Input storage class. "
  3324. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3325. referenced_from_inst)
  3326. << " " << GetStorageClassDesc(referenced_from_inst);
  3327. }
  3328. for (const spv::ExecutionModel execution_model : execution_models_) {
  3329. if (execution_model != spv::ExecutionModel::Fragment) {
  3330. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3331. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3332. << _.VkErrorID(vuid)
  3333. << spvLogStringForEnv(_.context()->target_env)
  3334. << " spec allows BuiltIn "
  3335. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3336. << " to be used only with Fragment execution model. "
  3337. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3338. referenced_from_inst, execution_model);
  3339. }
  3340. }
  3341. }
  3342. if (function_id_ == 0) {
  3343. // Propagate this rule to all dependant ids in the global scope.
  3344. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3345. &BuiltInsValidator::ValidateFragInvocationCountAtReference, this, decoration,
  3346. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3347. }
  3348. return SPV_SUCCESS;
  3349. }
  3350. spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration,
  3351. const Instruction& inst) {
  3352. if (spvIsVulkanEnv(_.context()->target_env)) {
  3353. const spv::BuiltIn builtin = decoration.builtin();
  3354. if (spv_result_t error = ValidateI32Vec(
  3355. decoration, inst, 2,
  3356. [this, &inst, &builtin](const std::string& message) -> spv_result_t {
  3357. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3358. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3359. << _.VkErrorID(vuid) << "According to the "
  3360. << spvLogStringForEnv(_.context()->target_env)
  3361. << " spec BuiltIn "
  3362. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3363. uint32_t(builtin))
  3364. << " variable needs to be a 2-component 32-bit int vector. "
  3365. << message;
  3366. })) {
  3367. return error;
  3368. }
  3369. }
  3370. return ValidateFragSizeAtReference(decoration, inst, inst, inst);
  3371. }
  3372. spv_result_t BuiltInsValidator::ValidateFragSizeAtReference(
  3373. const Decoration& decoration, const Instruction& built_in_inst,
  3374. const Instruction& referenced_inst,
  3375. const Instruction& referenced_from_inst) {
  3376. if (spvIsVulkanEnv(_.context()->target_env)) {
  3377. const spv::BuiltIn builtin = decoration.builtin();
  3378. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3379. if (storage_class != spv::StorageClass::Max &&
  3380. storage_class != spv::StorageClass::Input) {
  3381. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3382. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3383. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  3384. << " spec allows BuiltIn "
  3385. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3386. << " to be only used for variables with Input storage class. "
  3387. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3388. referenced_from_inst)
  3389. << " " << GetStorageClassDesc(referenced_from_inst);
  3390. }
  3391. for (const spv::ExecutionModel execution_model : execution_models_) {
  3392. if (execution_model != spv::ExecutionModel::Fragment) {
  3393. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3394. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3395. << _.VkErrorID(vuid)
  3396. << spvLogStringForEnv(_.context()->target_env)
  3397. << " spec allows BuiltIn "
  3398. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3399. << " to be used only with Fragment execution model. "
  3400. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3401. referenced_from_inst, execution_model);
  3402. }
  3403. }
  3404. }
  3405. if (function_id_ == 0) {
  3406. // Propagate this rule to all dependant ids in the global scope.
  3407. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3408. &BuiltInsValidator::ValidateFragSizeAtReference, this, decoration,
  3409. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3410. }
  3411. return SPV_SUCCESS;
  3412. }
  3413. spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration,
  3414. const Instruction& inst) {
  3415. if (spvIsVulkanEnv(_.context()->target_env)) {
  3416. const spv::BuiltIn builtin = decoration.builtin();
  3417. if (spv_result_t error = ValidateI(
  3418. decoration, inst,
  3419. [this, &inst, &builtin](const std::string& message) -> spv_result_t {
  3420. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3421. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3422. << _.VkErrorID(vuid) << "According to the "
  3423. << spvLogStringForEnv(_.context()->target_env)
  3424. << " spec BuiltIn "
  3425. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3426. uint32_t(builtin))
  3427. << " variable needs to be a int scalar. "
  3428. << message;
  3429. })) {
  3430. return error;
  3431. }
  3432. }
  3433. return ValidateFragStencilRefAtReference(decoration, inst, inst, inst);
  3434. }
  3435. spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference(
  3436. const Decoration& decoration, const Instruction& built_in_inst,
  3437. const Instruction& referenced_inst,
  3438. const Instruction& referenced_from_inst) {
  3439. if (spvIsVulkanEnv(_.context()->target_env)) {
  3440. const spv::BuiltIn builtin = decoration.builtin();
  3441. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3442. if (storage_class != spv::StorageClass::Max &&
  3443. storage_class != spv::StorageClass::Output) {
  3444. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3445. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3446. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  3447. << " spec allows BuiltIn "
  3448. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3449. << " to be only used for variables with Output storage class. "
  3450. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3451. referenced_from_inst)
  3452. << " " << GetStorageClassDesc(referenced_from_inst);
  3453. }
  3454. for (const spv::ExecutionModel execution_model : execution_models_) {
  3455. if (execution_model != spv::ExecutionModel::Fragment) {
  3456. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3457. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3458. << _.VkErrorID(vuid)
  3459. << spvLogStringForEnv(_.context()->target_env)
  3460. << " spec allows BuiltIn "
  3461. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3462. << " to be used only with Fragment execution model. "
  3463. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3464. referenced_from_inst, execution_model);
  3465. }
  3466. }
  3467. }
  3468. if (function_id_ == 0) {
  3469. // Propagate this rule to all dependant ids in the global scope.
  3470. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3471. &BuiltInsValidator::ValidateFragStencilRefAtReference, this, decoration,
  3472. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3473. }
  3474. return SPV_SUCCESS;
  3475. }
  3476. spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration,
  3477. const Instruction& inst) {
  3478. if (spvIsVulkanEnv(_.context()->target_env)) {
  3479. const spv::BuiltIn builtin = decoration.builtin();
  3480. if (spv_result_t error = ValidateBool(
  3481. decoration, inst,
  3482. [this, &inst, &builtin](const std::string& message) -> spv_result_t {
  3483. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3484. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3485. << _.VkErrorID(vuid) << "According to the "
  3486. << spvLogStringForEnv(_.context()->target_env)
  3487. << " spec BuiltIn "
  3488. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3489. uint32_t(builtin))
  3490. << " variable needs to be a bool scalar. "
  3491. << message;
  3492. })) {
  3493. return error;
  3494. }
  3495. }
  3496. return ValidateFullyCoveredAtReference(decoration, inst, inst, inst);
  3497. }
  3498. spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference(
  3499. const Decoration& decoration, const Instruction& built_in_inst,
  3500. const Instruction& referenced_inst,
  3501. const Instruction& referenced_from_inst) {
  3502. if (spvIsVulkanEnv(_.context()->target_env)) {
  3503. const spv::BuiltIn builtin = decoration.builtin();
  3504. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3505. if (storage_class != spv::StorageClass::Max &&
  3506. storage_class != spv::StorageClass::Input) {
  3507. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3508. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3509. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  3510. << " spec allows BuiltIn "
  3511. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3512. << " to be only used for variables with Input storage class. "
  3513. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3514. referenced_from_inst)
  3515. << " " << GetStorageClassDesc(referenced_from_inst);
  3516. }
  3517. for (const spv::ExecutionModel execution_model : execution_models_) {
  3518. if (execution_model != spv::ExecutionModel::Fragment) {
  3519. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3520. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3521. << _.VkErrorID(vuid)
  3522. << spvLogStringForEnv(_.context()->target_env)
  3523. << " spec allows BuiltIn "
  3524. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3525. << " to be used only with Fragment execution model. "
  3526. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3527. referenced_from_inst, execution_model);
  3528. }
  3529. }
  3530. }
  3531. if (function_id_ == 0) {
  3532. // Propagate this rule to all dependant ids in the global scope.
  3533. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3534. &BuiltInsValidator::ValidateFullyCoveredAtReference, this, decoration,
  3535. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3536. }
  3537. return SPV_SUCCESS;
  3538. }
  3539. spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtDefinition(
  3540. const Decoration& decoration, const Instruction& inst) {
  3541. if (spvIsVulkanEnv(_.context()->target_env)) {
  3542. if (spv_result_t error = ValidateI32(
  3543. decoration, inst,
  3544. [this, &inst,
  3545. &decoration](const std::string& message) -> spv_result_t {
  3546. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3547. << "According to the "
  3548. << spvLogStringForEnv(_.context()->target_env)
  3549. << " spec BuiltIn "
  3550. << _.grammar().lookupOperandName(
  3551. SPV_OPERAND_TYPE_BUILT_IN,
  3552. (uint32_t)decoration.builtin())
  3553. << " variable needs to be a 32-bit int scalar. "
  3554. << message;
  3555. })) {
  3556. return error;
  3557. }
  3558. }
  3559. // Seed at reference checks with this built-in.
  3560. return ValidateNVSMOrARMCoreBuiltinsAtReference(decoration, inst, inst, inst);
  3561. }
  3562. spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference(
  3563. const Decoration& decoration, const Instruction& built_in_inst,
  3564. const Instruction& referenced_inst,
  3565. const Instruction& referenced_from_inst) {
  3566. if (spvIsVulkanEnv(_.context()->target_env)) {
  3567. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3568. if (storage_class != spv::StorageClass::Max &&
  3569. storage_class != spv::StorageClass::Input) {
  3570. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3571. << spvLogStringForEnv(_.context()->target_env)
  3572. << " spec allows BuiltIn "
  3573. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3574. (uint32_t)decoration.builtin())
  3575. << " to be only used for "
  3576. "variables with Input storage class. "
  3577. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3578. referenced_from_inst)
  3579. << " " << GetStorageClassDesc(referenced_from_inst);
  3580. }
  3581. }
  3582. if (function_id_ == 0) {
  3583. // Propagate this rule to all dependant ids in the global scope.
  3584. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3585. &BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference, this, decoration,
  3586. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3587. }
  3588. return SPV_SUCCESS;
  3589. }
  3590. spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition(
  3591. const Decoration& decoration, const Instruction& inst) {
  3592. if (spvIsVulkanEnv(_.context()->target_env)) {
  3593. if (spv_result_t error = ValidateI32(
  3594. decoration, inst,
  3595. [this, &inst,
  3596. &decoration](const std::string& message) -> spv_result_t {
  3597. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3598. << _.VkErrorID(4486)
  3599. << "According to the Vulkan spec BuiltIn "
  3600. << _.grammar().lookupOperandName(
  3601. SPV_OPERAND_TYPE_BUILT_IN,
  3602. (uint32_t)decoration.builtin())
  3603. << " variable needs to be a 32-bit int scalar. "
  3604. << message;
  3605. })) {
  3606. return error;
  3607. }
  3608. if (isMeshInterfaceVar(inst) &&
  3609. _.HasCapability(spv::Capability::MeshShadingEXT) &&
  3610. !_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
  3611. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3612. << _.VkErrorID(7059)
  3613. << "The variable decorated with PrimitiveShadingRateKHR "
  3614. "within the MeshEXT Execution Model must also be "
  3615. "decorated with the PerPrimitiveEXT decoration";
  3616. }
  3617. }
  3618. // Seed at reference checks with this built-in.
  3619. return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst);
  3620. }
  3621. spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference(
  3622. const Decoration& decoration, const Instruction& built_in_inst,
  3623. const Instruction& referenced_inst,
  3624. const Instruction& referenced_from_inst) {
  3625. if (spvIsVulkanEnv(_.context()->target_env)) {
  3626. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3627. if (storage_class != spv::StorageClass::Max &&
  3628. storage_class != spv::StorageClass::Output) {
  3629. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3630. << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn "
  3631. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3632. (uint32_t)decoration.builtin())
  3633. << " to be only used for variables with Output storage class. "
  3634. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3635. referenced_from_inst)
  3636. << " " << GetStorageClassDesc(referenced_from_inst);
  3637. }
  3638. for (const spv::ExecutionModel execution_model : execution_models_) {
  3639. switch (execution_model) {
  3640. case spv::ExecutionModel::Vertex:
  3641. case spv::ExecutionModel::Geometry:
  3642. case spv::ExecutionModel::MeshNV:
  3643. case spv::ExecutionModel::MeshEXT:
  3644. break;
  3645. default: {
  3646. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3647. << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn "
  3648. << _.grammar().lookupOperandName(
  3649. SPV_OPERAND_TYPE_BUILT_IN,
  3650. (uint32_t)decoration.builtin())
  3651. << " to be used only with Vertex, Geometry, MeshNV or MeshEXT "
  3652. "execution models. "
  3653. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3654. referenced_from_inst, execution_model);
  3655. }
  3656. }
  3657. }
  3658. }
  3659. if (function_id_ == 0) {
  3660. // Propagate this rule to all dependant ids in the global scope.
  3661. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  3662. std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference,
  3663. this, decoration, built_in_inst, referenced_from_inst,
  3664. std::placeholders::_1));
  3665. }
  3666. return SPV_SUCCESS;
  3667. }
  3668. spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition(
  3669. const Decoration& decoration, const Instruction& inst) {
  3670. if (spvIsVulkanEnv(_.context()->target_env)) {
  3671. if (spv_result_t error = ValidateI32(
  3672. decoration, inst,
  3673. [this, &inst,
  3674. &decoration](const std::string& message) -> spv_result_t {
  3675. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3676. << _.VkErrorID(4492)
  3677. << "According to the Vulkan spec BuiltIn "
  3678. << _.grammar().lookupOperandName(
  3679. SPV_OPERAND_TYPE_BUILT_IN,
  3680. (uint32_t)decoration.builtin())
  3681. << " variable needs to be a 32-bit int scalar. "
  3682. << message;
  3683. })) {
  3684. return error;
  3685. }
  3686. }
  3687. // Seed at reference checks with this built-in.
  3688. return ValidateShadingRateAtReference(decoration, inst, inst, inst);
  3689. }
  3690. spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
  3691. const Decoration& decoration, const Instruction& built_in_inst,
  3692. const Instruction& referenced_inst,
  3693. const Instruction& referenced_from_inst) {
  3694. if (spvIsVulkanEnv(_.context()->target_env)) {
  3695. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3696. if (storage_class != spv::StorageClass::Max &&
  3697. storage_class != spv::StorageClass::Input) {
  3698. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3699. << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn "
  3700. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3701. (uint32_t)decoration.builtin())
  3702. << " to be only used for variables with Input storage class. "
  3703. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3704. referenced_from_inst)
  3705. << " " << GetStorageClassDesc(referenced_from_inst);
  3706. }
  3707. for (const spv::ExecutionModel execution_model : execution_models_) {
  3708. if (execution_model != spv::ExecutionModel::Fragment) {
  3709. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3710. << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn "
  3711. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3712. (uint32_t)decoration.builtin())
  3713. << " to be used only with the Fragment execution model. "
  3714. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3715. referenced_from_inst, execution_model);
  3716. }
  3717. }
  3718. }
  3719. if (function_id_ == 0) {
  3720. // Propagate this rule to all dependant ids in the global scope.
  3721. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3722. &BuiltInsValidator::ValidateShadingRateAtReference, this, decoration,
  3723. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3724. }
  3725. return SPV_SUCCESS;
  3726. }
  3727. spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
  3728. const Decoration& decoration, const Instruction& inst) {
  3729. if (spvIsVulkanEnv(_.context()->target_env)) {
  3730. const spv::BuiltIn builtin = decoration.builtin();
  3731. switch (builtin) {
  3732. case spv::BuiltIn::HitTNV:
  3733. case spv::BuiltIn::RayTminKHR:
  3734. case spv::BuiltIn::RayTmaxKHR:
  3735. // f32 scalar
  3736. if (spv_result_t error = ValidateF32(
  3737. decoration, inst,
  3738. [this, &inst,
  3739. builtin](const std::string& message) -> spv_result_t {
  3740. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3741. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3742. << _.VkErrorID(vuid)
  3743. << "According to the Vulkan spec BuiltIn "
  3744. << _.grammar().lookupOperandName(
  3745. SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3746. << " variable needs to be a 32-bit float scalar. "
  3747. << message;
  3748. })) {
  3749. return error;
  3750. }
  3751. break;
  3752. case spv::BuiltIn::HitKindKHR:
  3753. case spv::BuiltIn::InstanceCustomIndexKHR:
  3754. case spv::BuiltIn::InstanceId:
  3755. case spv::BuiltIn::RayGeometryIndexKHR:
  3756. case spv::BuiltIn::IncomingRayFlagsKHR:
  3757. case spv::BuiltIn::CullMaskKHR:
  3758. // i32 scalar
  3759. if (spv_result_t error = ValidateI32(
  3760. decoration, inst,
  3761. [this, &inst,
  3762. builtin](const std::string& message) -> spv_result_t {
  3763. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3764. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3765. << _.VkErrorID(vuid)
  3766. << "According to the Vulkan spec BuiltIn "
  3767. << _.grammar().lookupOperandName(
  3768. SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3769. << " variable needs to be a 32-bit int scalar. "
  3770. << message;
  3771. })) {
  3772. return error;
  3773. }
  3774. break;
  3775. case spv::BuiltIn::ObjectRayDirectionKHR:
  3776. case spv::BuiltIn::ObjectRayOriginKHR:
  3777. case spv::BuiltIn::WorldRayDirectionKHR:
  3778. case spv::BuiltIn::WorldRayOriginKHR:
  3779. // f32 vec3
  3780. if (spv_result_t error = ValidateF32Vec(
  3781. decoration, inst, 3,
  3782. [this, &inst,
  3783. builtin](const std::string& message) -> spv_result_t {
  3784. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3785. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3786. << _.VkErrorID(vuid)
  3787. << "According to the Vulkan spec BuiltIn "
  3788. << _.grammar().lookupOperandName(
  3789. SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3790. << " variable needs to be a 3-component 32-bit float "
  3791. "vector. "
  3792. << message;
  3793. })) {
  3794. return error;
  3795. }
  3796. break;
  3797. case spv::BuiltIn::LaunchIdKHR:
  3798. case spv::BuiltIn::LaunchSizeKHR:
  3799. // i32 vec3
  3800. if (spv_result_t error = ValidateI32Vec(
  3801. decoration, inst, 3,
  3802. [this, &inst,
  3803. builtin](const std::string& message) -> spv_result_t {
  3804. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3805. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3806. << _.VkErrorID(vuid)
  3807. << "According to the Vulkan spec BuiltIn "
  3808. << _.grammar().lookupOperandName(
  3809. SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3810. << " variable needs to be a 3-component 32-bit int "
  3811. "vector. "
  3812. << message;
  3813. })) {
  3814. return error;
  3815. }
  3816. break;
  3817. case spv::BuiltIn::ObjectToWorldKHR:
  3818. case spv::BuiltIn::WorldToObjectKHR:
  3819. // f32 mat4x3
  3820. if (spv_result_t error = ValidateF32Mat(
  3821. decoration, inst, 3, 4,
  3822. [this, &inst,
  3823. builtin](const std::string& message) -> spv_result_t {
  3824. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3825. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3826. << _.VkErrorID(vuid)
  3827. << "According to the Vulkan spec BuiltIn "
  3828. << _.grammar().lookupOperandName(
  3829. SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
  3830. << " variable needs to be a matrix with"
  3831. << " 4 columns of 3-component vectors of 32-bit "
  3832. "floats. "
  3833. << message;
  3834. })) {
  3835. return error;
  3836. }
  3837. break;
  3838. default:
  3839. assert(0 && "Unexpected ray tracing builtin");
  3840. break;
  3841. }
  3842. }
  3843. // Seed at reference checks with this built-in.
  3844. return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
  3845. }
  3846. spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
  3847. const Decoration& decoration, const Instruction& built_in_inst,
  3848. const Instruction& referenced_inst,
  3849. const Instruction& referenced_from_inst) {
  3850. if (spvIsVulkanEnv(_.context()->target_env)) {
  3851. const spv::BuiltIn builtin = decoration.builtin();
  3852. const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
  3853. if (storage_class != spv::StorageClass::Max &&
  3854. storage_class != spv::StorageClass::Input) {
  3855. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3856. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3857. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  3858. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3859. (uint32_t)decoration.builtin())
  3860. << " to be only used for variables with Input storage class. "
  3861. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3862. referenced_from_inst)
  3863. << " " << GetStorageClassDesc(referenced_from_inst);
  3864. }
  3865. for (const spv::ExecutionModel execution_model : execution_models_) {
  3866. if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
  3867. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3868. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3869. << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
  3870. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3871. (uint32_t)decoration.builtin())
  3872. << " to be used with the execution model "
  3873. << _.grammar().lookupOperandName(
  3874. SPV_OPERAND_TYPE_EXECUTION_MODEL,
  3875. uint32_t(execution_model))
  3876. << ".\n"
  3877. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3878. referenced_from_inst, execution_model);
  3879. }
  3880. }
  3881. }
  3882. if (function_id_ == 0) {
  3883. // Propagate this rule to all dependant ids in the global scope.
  3884. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  3885. std::bind(&BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
  3886. this, decoration, built_in_inst, referenced_from_inst,
  3887. std::placeholders::_1));
  3888. }
  3889. return SPV_SUCCESS;
  3890. }
  3891. spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
  3892. const Decoration& decoration, const Instruction& inst) {
  3893. if (spvIsVulkanEnv(_.context()->target_env)) {
  3894. const spv::BuiltIn builtin = decoration.builtin();
  3895. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3896. switch (builtin) {
  3897. case spv::BuiltIn::PrimitivePointIndicesEXT:
  3898. if (spv_result_t error = ValidateI32Arr(
  3899. decoration, inst,
  3900. [this, &inst, &decoration,
  3901. &vuid](const std::string& message) -> spv_result_t {
  3902. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3903. << _.VkErrorID(vuid) << "According to the "
  3904. << spvLogStringForEnv(_.context()->target_env)
  3905. << " spec BuiltIn "
  3906. << _.grammar().lookupOperandName(
  3907. SPV_OPERAND_TYPE_BUILT_IN,
  3908. (uint32_t)decoration.builtin())
  3909. << " variable needs to be a 32-bit int array."
  3910. << message;
  3911. })) {
  3912. return error;
  3913. }
  3914. break;
  3915. case spv::BuiltIn::PrimitiveLineIndicesEXT:
  3916. if (spv_result_t error = ValidateArrayedI32Vec(
  3917. decoration, inst, 2,
  3918. [this, &inst, &decoration,
  3919. &vuid](const std::string& message) -> spv_result_t {
  3920. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3921. << _.VkErrorID(vuid) << "According to the "
  3922. << spvLogStringForEnv(_.context()->target_env)
  3923. << " spec BuiltIn "
  3924. << _.grammar().lookupOperandName(
  3925. SPV_OPERAND_TYPE_BUILT_IN,
  3926. (uint32_t)decoration.builtin())
  3927. << " variable needs to be a 2-component 32-bit int "
  3928. "array."
  3929. << message;
  3930. })) {
  3931. return error;
  3932. }
  3933. break;
  3934. case spv::BuiltIn::PrimitiveTriangleIndicesEXT:
  3935. if (spv_result_t error = ValidateArrayedI32Vec(
  3936. decoration, inst, 3,
  3937. [this, &inst, &decoration,
  3938. &vuid](const std::string& message) -> spv_result_t {
  3939. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3940. << _.VkErrorID(vuid) << "According to the "
  3941. << spvLogStringForEnv(_.context()->target_env)
  3942. << " spec BuiltIn "
  3943. << _.grammar().lookupOperandName(
  3944. SPV_OPERAND_TYPE_BUILT_IN,
  3945. (uint32_t)decoration.builtin())
  3946. << " variable needs to be a 3-component 32-bit int "
  3947. "array."
  3948. << message;
  3949. })) {
  3950. return error;
  3951. }
  3952. break;
  3953. case spv::BuiltIn::CullPrimitiveEXT:
  3954. if (spv_result_t error = ValidateBool(
  3955. decoration, inst,
  3956. [this, &inst, &decoration,
  3957. &vuid](const std::string& message) -> spv_result_t {
  3958. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3959. << _.VkErrorID(vuid) << "According to the "
  3960. << spvLogStringForEnv(_.context()->target_env)
  3961. << " spec BuiltIn "
  3962. << _.grammar().lookupOperandName(
  3963. SPV_OPERAND_TYPE_BUILT_IN,
  3964. (uint32_t)decoration.builtin())
  3965. << " variable needs to be a boolean value "
  3966. "array."
  3967. << message;
  3968. })) {
  3969. return error;
  3970. }
  3971. if (!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
  3972. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3973. << _.VkErrorID(7038)
  3974. << "The variable decorated with CullPrimitiveEXT within the "
  3975. "MeshEXT Execution Model must also be decorated with the "
  3976. "PerPrimitiveEXT decoration ";
  3977. }
  3978. break;
  3979. default:
  3980. assert(0 && "Unexpected mesh EXT builtin");
  3981. }
  3982. for (const uint32_t entry_point : _.entry_points()) {
  3983. const auto* modes = _.GetExecutionModes(entry_point);
  3984. uint64_t maxOutputPrimitives = _.GetOutputPrimitivesEXT(entry_point);
  3985. uint32_t underlying_type = 0;
  3986. if (spv_result_t error =
  3987. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  3988. return error;
  3989. }
  3990. uint64_t primitiveArrayDim = 0;
  3991. if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
  3992. underlying_type = _.FindDef(underlying_type)->word(3u);
  3993. if (!_.EvalConstantValUint64(underlying_type, &primitiveArrayDim)) {
  3994. assert(0 && "Array type definition is corrupt");
  3995. }
  3996. }
  3997. switch (builtin) {
  3998. case spv::BuiltIn::PrimitivePointIndicesEXT:
  3999. if (!modes || !modes->count(spv::ExecutionMode::OutputPoints)) {
  4000. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4001. << _.VkErrorID(7042)
  4002. << "The PrimitivePointIndicesEXT decoration must be used "
  4003. "with "
  4004. "the OutputPoints Execution Mode. ";
  4005. }
  4006. if (primitiveArrayDim && primitiveArrayDim != maxOutputPrimitives) {
  4007. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4008. << _.VkErrorID(7046)
  4009. << "The size of the array decorated with "
  4010. "PrimitivePointIndicesEXT must match the value specified "
  4011. "by OutputPrimitivesEXT. ";
  4012. }
  4013. break;
  4014. case spv::BuiltIn::PrimitiveLineIndicesEXT:
  4015. if (!modes || !modes->count(spv::ExecutionMode::OutputLinesEXT)) {
  4016. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4017. << _.VkErrorID(7048)
  4018. << "The PrimitiveLineIndicesEXT decoration must be used "
  4019. "with "
  4020. "the OutputLinesEXT Execution Mode. ";
  4021. }
  4022. if (primitiveArrayDim && primitiveArrayDim != maxOutputPrimitives) {
  4023. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4024. << _.VkErrorID(7052)
  4025. << "The size of the array decorated with "
  4026. "PrimitiveLineIndicesEXT must match the value specified "
  4027. "by OutputPrimitivesEXT. ";
  4028. }
  4029. break;
  4030. case spv::BuiltIn::PrimitiveTriangleIndicesEXT:
  4031. if (!modes || !modes->count(spv::ExecutionMode::OutputTrianglesEXT)) {
  4032. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4033. << _.VkErrorID(7054)
  4034. << "The PrimitiveTriangleIndicesEXT decoration must be used "
  4035. "with "
  4036. "the OutputTrianglesEXT Execution Mode. ";
  4037. }
  4038. if (primitiveArrayDim && primitiveArrayDim != maxOutputPrimitives) {
  4039. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  4040. << _.VkErrorID(7058)
  4041. << "The size of the array decorated with "
  4042. "PrimitiveTriangleIndicesEXT must match the value "
  4043. "specified "
  4044. "by OutputPrimitivesEXT. ";
  4045. }
  4046. break;
  4047. default:
  4048. break; // no validation rules
  4049. }
  4050. }
  4051. }
  4052. // Seed at reference checks with this built-in.
  4053. return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
  4054. inst);
  4055. }
  4056. spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
  4057. const Decoration& decoration, const Instruction& built_in_inst,
  4058. const Instruction& referenced_inst,
  4059. const Instruction& referenced_from_inst) {
  4060. if (spvIsVulkanEnv(_.context()->target_env)) {
  4061. const spv::BuiltIn builtin = decoration.builtin();
  4062. const spv::StorageClass storage_class =
  4063. GetStorageClass(referenced_from_inst);
  4064. if (storage_class != spv::StorageClass::Max &&
  4065. storage_class != spv::StorageClass::Output) {
  4066. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  4067. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  4068. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  4069. << " spec allows BuiltIn "
  4070. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  4071. uint32_t(builtin))
  4072. << " to be only used for variables with Output storage class. "
  4073. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  4074. referenced_from_inst)
  4075. << " " << GetStorageClassDesc(referenced_from_inst);
  4076. }
  4077. for (const spv::ExecutionModel execution_model : execution_models_) {
  4078. if (execution_model != spv::ExecutionModel::MeshEXT) {
  4079. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  4080. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  4081. << _.VkErrorID(vuid)
  4082. << spvLogStringForEnv(_.context()->target_env)
  4083. << " spec allows BuiltIn "
  4084. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  4085. uint32_t(builtin))
  4086. << " to be used only with MeshEXT execution model. "
  4087. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  4088. referenced_from_inst, execution_model);
  4089. }
  4090. }
  4091. }
  4092. if (function_id_ == 0) {
  4093. // Propagate this rule to all dependant ids in the global scope.
  4094. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  4095. std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference,
  4096. this, decoration, built_in_inst, referenced_from_inst,
  4097. std::placeholders::_1));
  4098. }
  4099. return SPV_SUCCESS;
  4100. }
  4101. spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
  4102. const Decoration& decoration, const Instruction& inst) {
  4103. const spv::BuiltIn label = decoration.builtin();
  4104. // Universial checks
  4105. if (label == spv::BuiltIn::WorkgroupSize) {
  4106. return ValidateWorkgroupSizeAtDefinition(decoration, inst);
  4107. }
  4108. if (spvIsVulkanEnv(_.context()->target_env)) {
  4109. return ValidateSingleBuiltInAtDefinitionVulkan(decoration, inst, label);
  4110. }
  4111. return SPV_SUCCESS;
  4112. }
  4113. spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinitionVulkan(
  4114. const Decoration& decoration, const Instruction& inst,
  4115. const spv::BuiltIn label) {
  4116. // If you are adding a new BuiltIn enum, please register it here.
  4117. // If the newly added enum has validation rules associated with it
  4118. // consider leaving a TODO and/or creating an issue.
  4119. switch (label) {
  4120. case spv::BuiltIn::ClipDistance:
  4121. case spv::BuiltIn::CullDistance: {
  4122. return ValidateClipOrCullDistanceAtDefinition(decoration, inst);
  4123. }
  4124. case spv::BuiltIn::FragCoord: {
  4125. return ValidateFragCoordAtDefinition(decoration, inst);
  4126. }
  4127. case spv::BuiltIn::FragDepth: {
  4128. return ValidateFragDepthAtDefinition(decoration, inst);
  4129. }
  4130. case spv::BuiltIn::FrontFacing: {
  4131. return ValidateFrontFacingAtDefinition(decoration, inst);
  4132. }
  4133. case spv::BuiltIn::GlobalInvocationId:
  4134. case spv::BuiltIn::LocalInvocationId:
  4135. case spv::BuiltIn::NumWorkgroups:
  4136. case spv::BuiltIn::WorkgroupId: {
  4137. return ValidateComputeShaderI32Vec3InputAtDefinition(decoration, inst);
  4138. }
  4139. case spv::BuiltIn::BaryCoordKHR:
  4140. case spv::BuiltIn::BaryCoordNoPerspKHR: {
  4141. return ValidateFragmentShaderF32Vec3InputAtDefinition(decoration, inst);
  4142. }
  4143. case spv::BuiltIn::HelperInvocation: {
  4144. return ValidateHelperInvocationAtDefinition(decoration, inst);
  4145. }
  4146. case spv::BuiltIn::InvocationId: {
  4147. return ValidateInvocationIdAtDefinition(decoration, inst);
  4148. }
  4149. case spv::BuiltIn::InstanceIndex: {
  4150. return ValidateInstanceIndexAtDefinition(decoration, inst);
  4151. }
  4152. case spv::BuiltIn::Layer:
  4153. case spv::BuiltIn::ViewportIndex: {
  4154. return ValidateLayerOrViewportIndexAtDefinition(decoration, inst);
  4155. }
  4156. case spv::BuiltIn::PatchVertices: {
  4157. return ValidatePatchVerticesAtDefinition(decoration, inst);
  4158. }
  4159. case spv::BuiltIn::PointCoord: {
  4160. return ValidatePointCoordAtDefinition(decoration, inst);
  4161. }
  4162. case spv::BuiltIn::PointSize: {
  4163. return ValidatePointSizeAtDefinition(decoration, inst);
  4164. }
  4165. case spv::BuiltIn::Position: {
  4166. return ValidatePositionAtDefinition(decoration, inst);
  4167. }
  4168. case spv::BuiltIn::PrimitiveId: {
  4169. return ValidatePrimitiveIdAtDefinition(decoration, inst);
  4170. }
  4171. case spv::BuiltIn::SampleId: {
  4172. return ValidateSampleIdAtDefinition(decoration, inst);
  4173. }
  4174. case spv::BuiltIn::SampleMask: {
  4175. return ValidateSampleMaskAtDefinition(decoration, inst);
  4176. }
  4177. case spv::BuiltIn::SamplePosition: {
  4178. return ValidateSamplePositionAtDefinition(decoration, inst);
  4179. }
  4180. case spv::BuiltIn::SubgroupId:
  4181. case spv::BuiltIn::NumSubgroups: {
  4182. return ValidateComputeI32InputAtDefinition(decoration, inst);
  4183. }
  4184. case spv::BuiltIn::SubgroupLocalInvocationId:
  4185. case spv::BuiltIn::SubgroupSize: {
  4186. return ValidateI32InputAtDefinition(decoration, inst);
  4187. }
  4188. case spv::BuiltIn::SubgroupEqMask:
  4189. case spv::BuiltIn::SubgroupGeMask:
  4190. case spv::BuiltIn::SubgroupGtMask:
  4191. case spv::BuiltIn::SubgroupLeMask:
  4192. case spv::BuiltIn::SubgroupLtMask: {
  4193. return ValidateI32Vec4InputAtDefinition(decoration, inst);
  4194. }
  4195. case spv::BuiltIn::TessCoord: {
  4196. return ValidateTessCoordAtDefinition(decoration, inst);
  4197. }
  4198. case spv::BuiltIn::TessLevelOuter: {
  4199. return ValidateTessLevelOuterAtDefinition(decoration, inst);
  4200. }
  4201. case spv::BuiltIn::TessLevelInner: {
  4202. return ValidateTessLevelInnerAtDefinition(decoration, inst);
  4203. }
  4204. case spv::BuiltIn::VertexIndex: {
  4205. return ValidateVertexIndexAtDefinition(decoration, inst);
  4206. }
  4207. case spv::BuiltIn::VertexId: {
  4208. return ValidateVertexIdAtDefinition(decoration, inst);
  4209. }
  4210. case spv::BuiltIn::LocalInvocationIndex: {
  4211. return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
  4212. }
  4213. case spv::BuiltIn::CoreIDARM:
  4214. case spv::BuiltIn::CoreCountARM:
  4215. case spv::BuiltIn::CoreMaxIDARM:
  4216. case spv::BuiltIn::WarpIDARM:
  4217. case spv::BuiltIn::WarpMaxIDARM:
  4218. case spv::BuiltIn::WarpsPerSMNV:
  4219. case spv::BuiltIn::SMCountNV:
  4220. case spv::BuiltIn::WarpIDNV:
  4221. case spv::BuiltIn::SMIDNV: {
  4222. return ValidateNVSMOrARMCoreBuiltinsAtDefinition(decoration, inst);
  4223. }
  4224. case spv::BuiltIn::BaseInstance:
  4225. case spv::BuiltIn::BaseVertex: {
  4226. return ValidateBaseInstanceOrVertexAtDefinition(decoration, inst);
  4227. }
  4228. case spv::BuiltIn::DrawIndex: {
  4229. return ValidateDrawIndexAtDefinition(decoration, inst);
  4230. }
  4231. case spv::BuiltIn::ViewIndex: {
  4232. return ValidateViewIndexAtDefinition(decoration, inst);
  4233. }
  4234. case spv::BuiltIn::DeviceIndex: {
  4235. return ValidateDeviceIndexAtDefinition(decoration, inst);
  4236. }
  4237. case spv::BuiltIn::FragInvocationCountEXT: {
  4238. // alias spv::BuiltIn::InvocationsPerPixelNV
  4239. return ValidateFragInvocationCountAtDefinition(decoration, inst);
  4240. }
  4241. case spv::BuiltIn::FragSizeEXT: {
  4242. // alias spv::BuiltIn::FragmentSizeNV
  4243. return ValidateFragSizeAtDefinition(decoration, inst);
  4244. }
  4245. case spv::BuiltIn::FragStencilRefEXT: {
  4246. return ValidateFragStencilRefAtDefinition(decoration, inst);
  4247. }
  4248. case spv::BuiltIn::FullyCoveredEXT:{
  4249. return ValidateFullyCoveredAtDefinition(decoration, inst);
  4250. }
  4251. // Ray tracing builtins
  4252. case spv::BuiltIn::HitKindKHR: // alias spv::BuiltIn::HitKindNV
  4253. case spv::BuiltIn::HitTNV: // NOT present in KHR
  4254. case spv::BuiltIn::InstanceId:
  4255. case spv::BuiltIn::LaunchIdKHR: // alias spv::BuiltIn::LaunchIdNV
  4256. case spv::BuiltIn::LaunchSizeKHR: // alias spv::BuiltIn::LaunchSizeNV
  4257. case spv::BuiltIn::WorldRayOriginKHR: // alias spv::BuiltIn::WorldRayOriginNV
  4258. case spv::BuiltIn::WorldRayDirectionKHR: // alias spv::BuiltIn::WorldRayDirectionNV
  4259. case spv::BuiltIn::ObjectRayOriginKHR: // alias spv::BuiltIn::ObjectRayOriginNV
  4260. case spv::BuiltIn::ObjectRayDirectionKHR: // alias
  4261. // spv::BuiltIn::ObjectRayDirectionNV
  4262. case spv::BuiltIn::RayTminKHR: // alias spv::BuiltIn::RayTminNV
  4263. case spv::BuiltIn::RayTmaxKHR: // alias spv::BuiltIn::RayTmaxNV
  4264. case spv::BuiltIn::InstanceCustomIndexKHR: // alias
  4265. // spv::BuiltIn::InstanceCustomIndexNV
  4266. case spv::BuiltIn::ObjectToWorldKHR: // alias spv::BuiltIn::ObjectToWorldNV
  4267. case spv::BuiltIn::WorldToObjectKHR: // alias spv::BuiltIn::WorldToObjectNV
  4268. case spv::BuiltIn::IncomingRayFlagsKHR: // alias spv::BuiltIn::IncomingRayFlagsNV
  4269. case spv::BuiltIn::RayGeometryIndexKHR: // NOT present in NV
  4270. case spv::BuiltIn::CullMaskKHR: {
  4271. return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
  4272. }
  4273. case spv::BuiltIn::CullPrimitiveEXT:
  4274. case spv::BuiltIn::PrimitivePointIndicesEXT:
  4275. case spv::BuiltIn::PrimitiveLineIndicesEXT:
  4276. case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
  4277. return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
  4278. }
  4279. case spv::BuiltIn::PrimitiveShadingRateKHR: {
  4280. return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
  4281. }
  4282. case spv::BuiltIn::ShadingRateKHR: {
  4283. return ValidateShadingRateAtDefinition(decoration, inst);
  4284. }
  4285. default:
  4286. // No validation rules (for the moment).
  4287. break;
  4288. }
  4289. return SPV_SUCCESS;
  4290. }
  4291. spv_result_t BuiltInsValidator::ValidateBuiltInsAtDefinition() {
  4292. for (const auto& kv : _.id_decorations()) {
  4293. const uint32_t id = kv.first;
  4294. const auto& decorations = kv.second;
  4295. if (decorations.empty()) {
  4296. continue;
  4297. }
  4298. const Instruction* inst = _.FindDef(id);
  4299. assert(inst);
  4300. for (const auto& decoration : kv.second) {
  4301. if (decoration.dec_type() != spv::Decoration::BuiltIn) {
  4302. continue;
  4303. }
  4304. if (spv_result_t error =
  4305. ValidateSingleBuiltInAtDefinition(decoration, *inst)) {
  4306. return error;
  4307. }
  4308. }
  4309. }
  4310. return SPV_SUCCESS;
  4311. }
  4312. spv_result_t BuiltInsValidator::Run() {
  4313. // First pass: validate all built-ins at definition and seed
  4314. // id_to_at_reference_checks_ with built-ins.
  4315. if (auto error = ValidateBuiltInsAtDefinition()) {
  4316. return error;
  4317. }
  4318. if (id_to_at_reference_checks_.empty()) {
  4319. // No validation tasks were seeded. Nothing else to do.
  4320. return SPV_SUCCESS;
  4321. }
  4322. // Second pass: validate every id reference in the module using
  4323. // rules in id_to_at_reference_checks_.
  4324. for (const Instruction& inst : _.ordered_instructions()) {
  4325. Update(inst);
  4326. std::set<uint32_t> already_checked;
  4327. for (const auto& operand : inst.operands()) {
  4328. if (!spvIsIdType(operand.type)) {
  4329. // Not id.
  4330. continue;
  4331. }
  4332. const uint32_t id = inst.word(operand.offset);
  4333. if (id == inst.id()) {
  4334. // No need to check result id.
  4335. continue;
  4336. }
  4337. if (!already_checked.insert(id).second) {
  4338. // The instruction has already referenced this id.
  4339. continue;
  4340. }
  4341. // Instruction references the id. Run all checks associated with the id
  4342. // on the instruction. id_to_at_reference_checks_ can be modified in the
  4343. // process, iterators are safe because it's a tree-based map.
  4344. const auto it = id_to_at_reference_checks_.find(id);
  4345. if (it != id_to_at_reference_checks_.end()) {
  4346. for (const auto& check : it->second) {
  4347. if (spv_result_t error = check(inst)) {
  4348. return error;
  4349. }
  4350. }
  4351. }
  4352. }
  4353. }
  4354. return SPV_SUCCESS;
  4355. }
  4356. } // namespace
  4357. // Validates correctness of built-in variables.
  4358. spv_result_t ValidateBuiltIns(ValidationState_t& _) {
  4359. BuiltInsValidator validator(_);
  4360. return validator.Run();
  4361. }
  4362. } // namespace val
  4363. } // namespace spvtools