val_cfg_test.cpp 143 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Validation tests for Control Flow Graph
  15. #include <array>
  16. #include <functional>
  17. #include <sstream>
  18. #include <string>
  19. #include <utility>
  20. #include <vector>
  21. #include "gmock/gmock.h"
  22. #include "source/spirv_target_env.h"
  23. #include "source/val/validate.h"
  24. #include "test/test_fixture.h"
  25. #include "test/unit_spirv.h"
  26. #include "test/val/val_fixtures.h"
  27. namespace spvtools {
  28. namespace val {
  29. namespace {
  30. using ::testing::HasSubstr;
  31. using ::testing::MatchesRegex;
  32. using ValidateCFG = spvtest::ValidateBase<spv::Capability>;
  33. using spvtest::ScopedContext;
  34. std::string nameOps() { return ""; }
  35. template <typename... Args>
  36. std::string nameOps(std::pair<std::string, std::string> head, Args... names) {
  37. return "OpName %" + head.first + " \"" + head.second + "\"\n" +
  38. nameOps(names...);
  39. }
  40. template <typename... Args>
  41. std::string nameOps(std::string head, Args... names) {
  42. return "OpName %" + head + " \"" + head + "\"\n" + nameOps(names...);
  43. }
  44. /// This class allows the easy creation of complex control flow without writing
  45. /// SPIR-V. This class is used in the test cases below.
  46. class Block {
  47. std::string label_;
  48. std::string body_;
  49. spv::Op type_;
  50. std::vector<Block> successors_;
  51. public:
  52. /// Creates a Block with a given label
  53. ///
  54. /// @param[in]: label the label id of the block
  55. /// @param[in]: type the branch instruction that ends the block
  56. explicit Block(std::string label, spv::Op type = spv::Op::OpBranch)
  57. : label_(label), body_(), type_(type), successors_() {}
  58. /// Sets the instructions which will appear in the body of the block
  59. Block& SetBody(std::string body) {
  60. body_ = body;
  61. return *this;
  62. }
  63. Block& AppendBody(std::string body) {
  64. body_ += body;
  65. return *this;
  66. }
  67. /// Converts the block into a SPIR-V string
  68. operator std::string() {
  69. std::stringstream out;
  70. out << std::setw(8) << "%" + label_ + " = OpLabel \n";
  71. if (!body_.empty()) {
  72. out << body_;
  73. }
  74. switch (type_) {
  75. case spv::Op::OpBranchConditional:
  76. out << "OpBranchConditional %cond ";
  77. for (Block& b : successors_) {
  78. out << "%" + b.label_ + " ";
  79. }
  80. break;
  81. case spv::Op::OpSwitch: {
  82. out << "OpSwitch %one %" + successors_.front().label_;
  83. std::stringstream ss;
  84. for (size_t i = 1; i < successors_.size(); i++) {
  85. ss << " " << i << " %" << successors_[i].label_;
  86. }
  87. out << ss.str();
  88. } break;
  89. case spv::Op::OpLoopMerge: {
  90. assert(successors_.size() == 2);
  91. out << "OpLoopMerge %" + successors_[0].label_ + " %" +
  92. successors_[0].label_ + "None";
  93. } break;
  94. case spv::Op::OpReturn:
  95. assert(successors_.size() == 0);
  96. out << "OpReturn\n";
  97. break;
  98. case spv::Op::OpUnreachable:
  99. assert(successors_.size() == 0);
  100. out << "OpUnreachable\n";
  101. break;
  102. case spv::Op::OpBranch:
  103. assert(successors_.size() == 1);
  104. out << "OpBranch %" + successors_.front().label_;
  105. break;
  106. case spv::Op::OpKill:
  107. assert(successors_.size() == 0);
  108. out << "OpKill\n";
  109. break;
  110. default:
  111. assert(1 == 0 && "Unhandled");
  112. }
  113. out << "\n";
  114. return out.str();
  115. }
  116. friend Block& operator>>(Block& curr, std::vector<Block> successors);
  117. friend Block& operator>>(Block& lhs, Block& successor);
  118. };
  119. /// Assigns the successors for the Block on the lhs
  120. Block& operator>>(Block& lhs, std::vector<Block> successors) {
  121. if (lhs.type_ == spv::Op::OpBranchConditional) {
  122. assert(successors.size() == 2);
  123. } else if (lhs.type_ == spv::Op::OpSwitch) {
  124. assert(successors.size() > 1);
  125. }
  126. lhs.successors_ = successors;
  127. return lhs;
  128. }
  129. /// Assigns the successor for the Block on the lhs
  130. Block& operator>>(Block& lhs, Block& successor) {
  131. assert(lhs.type_ == spv::Op::OpBranch);
  132. lhs.successors_.push_back(successor);
  133. return lhs;
  134. }
  135. const std::string& GetDefaultHeader(spv::Capability cap) {
  136. static const std::string shader_header =
  137. "OpCapability Shader\n"
  138. "OpCapability Linkage\n"
  139. "OpMemoryModel Logical GLSL450\n";
  140. static const std::string kernel_header =
  141. "OpCapability Kernel\n"
  142. "OpCapability Linkage\n"
  143. "OpMemoryModel Logical OpenCL\n";
  144. return (cap == spv::Capability::Shader) ? shader_header : kernel_header;
  145. }
  146. const std::string& types_consts() {
  147. static const std::string types =
  148. "%voidt = OpTypeVoid\n"
  149. "%boolt = OpTypeBool\n"
  150. "%intt = OpTypeInt 32 0\n"
  151. "%one = OpConstant %intt 1\n"
  152. "%two = OpConstant %intt 2\n"
  153. "%ptrt = OpTypePointer Function %intt\n"
  154. "%funct = OpTypeFunction %voidt\n";
  155. return types;
  156. }
  157. INSTANTIATE_TEST_SUITE_P(StructuredControlFlow, ValidateCFG,
  158. ::testing::Values(spv::Capability::Shader,
  159. spv::Capability::Kernel));
  160. TEST_P(ValidateCFG, LoopReachableFromEntryButNeverLeadingToReturn) {
  161. // In this case, the loop is reachable from a node without a predecessor,
  162. // but never reaches a node with a return.
  163. //
  164. // This motivates the need for the pseudo-exit node to have a node
  165. // from a cycle in its predecessors list. Otherwise the validator's
  166. // post-dominance calculation will go into an infinite loop.
  167. //
  168. // For more motivation, see
  169. // https://github.com/KhronosGroup/SPIRV-Tools/issues/279
  170. std::string str = R"(
  171. OpCapability Shader
  172. OpCapability Linkage
  173. OpMemoryModel Logical GLSL450
  174. OpName %entry "entry"
  175. OpName %loop "loop"
  176. OpName %exit "exit"
  177. %voidt = OpTypeVoid
  178. %funct = OpTypeFunction %voidt
  179. %main = OpFunction %voidt None %funct
  180. %entry = OpLabel
  181. OpBranch %loop
  182. %loop = OpLabel
  183. OpLoopMerge %exit %loop None
  184. OpBranch %loop
  185. %exit = OpLabel
  186. OpReturn
  187. OpFunctionEnd
  188. )";
  189. CompileSuccessfully(str);
  190. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str;
  191. }
  192. TEST_P(ValidateCFG, LoopUnreachableFromEntryButLeadingToReturn) {
  193. // In this case, the loop is not reachable from a node without a
  194. // predecessor, but eventually reaches a node with a return.
  195. //
  196. // This motivates the need for the pseudo-entry node to have a node
  197. // from a cycle in its successors list. Otherwise the validator's
  198. // dominance calculation will go into an infinite loop.
  199. //
  200. // For more motivation, see
  201. // https://github.com/KhronosGroup/SPIRV-Tools/issues/279
  202. // Before that fix, we'd have an infinite loop when calculating
  203. // post-dominators.
  204. std::string str = R"(
  205. OpCapability Shader
  206. OpCapability Linkage
  207. OpMemoryModel Logical GLSL450
  208. OpName %entry "entry"
  209. OpName %loop "loop"
  210. OpName %cont "cont"
  211. OpName %exit "exit"
  212. %voidt = OpTypeVoid
  213. %funct = OpTypeFunction %voidt
  214. %boolt = OpTypeBool
  215. %false = OpConstantFalse %boolt
  216. %main = OpFunction %voidt None %funct
  217. %entry = OpLabel
  218. OpReturn
  219. %loop = OpLabel
  220. OpLoopMerge %exit %cont None
  221. OpBranch %cont
  222. %cont = OpLabel
  223. OpBranchConditional %false %loop %exit
  224. %exit = OpLabel
  225. OpReturn
  226. OpFunctionEnd
  227. )";
  228. CompileSuccessfully(str);
  229. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions())
  230. << str << getDiagnosticString();
  231. }
  232. TEST_P(ValidateCFG, Simple) {
  233. bool is_shader = GetParam() == spv::Capability::Shader;
  234. Block entry("entry");
  235. Block loop("loop", spv::Op::OpBranchConditional);
  236. Block cont("cont");
  237. Block merge("merge", spv::Op::OpReturn);
  238. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  239. if (is_shader) {
  240. loop.SetBody("OpLoopMerge %merge %cont None\n");
  241. }
  242. std::string str = GetDefaultHeader(GetParam()) +
  243. nameOps("loop", "entry", "cont", "merge",
  244. std::make_pair("func", "Main")) +
  245. types_consts() +
  246. "%func = OpFunction %voidt None %funct\n";
  247. str += entry >> loop;
  248. str += loop >> std::vector<Block>({cont, merge});
  249. str += cont >> loop;
  250. str += merge;
  251. str += "OpFunctionEnd\n";
  252. CompileSuccessfully(str);
  253. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  254. }
  255. TEST_P(ValidateCFG, Variable) {
  256. Block entry("entry");
  257. Block cont("cont");
  258. Block exit("exit", spv::Op::OpReturn);
  259. entry.SetBody("%var = OpVariable %ptrt Function\n");
  260. std::string str = GetDefaultHeader(GetParam()) +
  261. nameOps(std::make_pair("func", "Main")) + types_consts() +
  262. " %func = OpFunction %voidt None %funct\n";
  263. str += entry >> cont;
  264. str += cont >> exit;
  265. str += exit;
  266. str += "OpFunctionEnd\n";
  267. CompileSuccessfully(str);
  268. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  269. }
  270. TEST_P(ValidateCFG, VariableNotInFirstBlockBad) {
  271. Block entry("entry");
  272. Block cont("cont");
  273. Block exit("exit", spv::Op::OpReturn);
  274. // This operation should only be performed in the entry block
  275. cont.SetBody("%var = OpVariable %ptrt Function\n");
  276. std::string str = GetDefaultHeader(GetParam()) +
  277. nameOps(std::make_pair("func", "Main")) + types_consts() +
  278. " %func = OpFunction %voidt None %funct\n";
  279. str += entry >> cont;
  280. str += cont >> exit;
  281. str += exit;
  282. str += "OpFunctionEnd\n";
  283. CompileSuccessfully(str);
  284. ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  285. EXPECT_THAT(getDiagnosticString(),
  286. HasSubstr("All OpVariable instructions in a function must be the "
  287. "first instructions in the first block"));
  288. }
  289. TEST_P(ValidateCFG, BlockSelfLoopIsOk) {
  290. bool is_shader = GetParam() == spv::Capability::Shader;
  291. Block entry("entry");
  292. Block loop("loop", spv::Op::OpBranchConditional);
  293. Block merge("merge", spv::Op::OpReturn);
  294. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  295. if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
  296. std::string str = GetDefaultHeader(GetParam()) +
  297. nameOps("loop", "merge", std::make_pair("func", "Main")) +
  298. types_consts() +
  299. "%func = OpFunction %voidt None %funct\n";
  300. str += entry >> loop;
  301. // loop branches to itself, but does not trigger an error.
  302. str += loop >> std::vector<Block>({merge, loop});
  303. str += merge;
  304. str += "OpFunctionEnd\n";
  305. CompileSuccessfully(str);
  306. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  307. }
  308. TEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) {
  309. bool is_shader = GetParam() == spv::Capability::Shader;
  310. Block entry("entry");
  311. Block cont("cont");
  312. Block branch("branch", spv::Op::OpBranchConditional);
  313. Block merge("merge", spv::Op::OpReturn);
  314. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  315. if (is_shader) branch.SetBody("OpSelectionMerge %merge None\n");
  316. std::string str = GetDefaultHeader(GetParam()) +
  317. nameOps("cont", "branch", std::make_pair("func", "Main")) +
  318. types_consts() +
  319. "%func = OpFunction %voidt None %funct\n";
  320. str += entry >> branch;
  321. str += cont >> merge; // cont appears before its dominator
  322. str += branch >> std::vector<Block>({cont, merge});
  323. str += merge;
  324. str += "OpFunctionEnd\n";
  325. CompileSuccessfully(str);
  326. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  327. EXPECT_THAT(getDiagnosticString(),
  328. MatchesRegex("Block '.\\[%cont\\]' appears in the binary "
  329. "before its dominator '.\\[%branch\\]'\n"
  330. " %branch = OpLabel\n"));
  331. }
  332. TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) {
  333. bool is_shader = GetParam() == spv::Capability::Shader;
  334. Block entry("entry");
  335. Block loop("loop");
  336. Block selection("selection", spv::Op::OpBranchConditional);
  337. Block merge("merge", spv::Op::OpReturn);
  338. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  339. if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n");
  340. // cannot share the same merge
  341. if (is_shader) selection.SetBody("OpSelectionMerge %merge None\n");
  342. std::string str = GetDefaultHeader(GetParam()) +
  343. nameOps("merge", std::make_pair("func", "Main")) +
  344. types_consts() +
  345. "%func = OpFunction %voidt None %funct\n";
  346. str += entry >> loop;
  347. str += loop >> selection;
  348. str += selection >> std::vector<Block>({loop, merge});
  349. str += merge;
  350. str += "OpFunctionEnd\n";
  351. CompileSuccessfully(str);
  352. if (is_shader) {
  353. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  354. EXPECT_THAT(getDiagnosticString(),
  355. MatchesRegex("Block '.\\[%merge\\]' is already a merge block "
  356. "for another header\n"
  357. " %Main = OpFunction %void None %9\n"));
  358. } else {
  359. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  360. }
  361. }
  362. TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) {
  363. bool is_shader = GetParam() == spv::Capability::Shader;
  364. Block entry("entry");
  365. Block loop("loop", spv::Op::OpBranchConditional);
  366. Block selection("selection", spv::Op::OpBranchConditional);
  367. Block merge("merge", spv::Op::OpReturn);
  368. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  369. if (is_shader) selection.SetBody(" OpSelectionMerge %merge None\n");
  370. // cannot share the same merge
  371. if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n");
  372. std::string str = GetDefaultHeader(GetParam()) +
  373. nameOps("merge", std::make_pair("func", "Main")) +
  374. types_consts() +
  375. "%func = OpFunction %voidt None %funct\n";
  376. str += entry >> selection;
  377. str += selection >> std::vector<Block>({merge, loop});
  378. str += loop >> std::vector<Block>({loop, merge});
  379. str += merge;
  380. str += "OpFunctionEnd\n";
  381. CompileSuccessfully(str);
  382. if (is_shader) {
  383. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  384. EXPECT_THAT(getDiagnosticString(),
  385. MatchesRegex("Block '.\\[%merge\\]' is already a merge block "
  386. "for another header\n"
  387. " %Main = OpFunction %void None %9\n"));
  388. } else {
  389. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  390. }
  391. }
  392. TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceEntryBlock) {
  393. Block entry("entry");
  394. Block bad("bad");
  395. Block end("end", spv::Op::OpReturn);
  396. std::string str = GetDefaultHeader(GetParam()) +
  397. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  398. types_consts() +
  399. "%func = OpFunction %voidt None %funct\n";
  400. str += entry >> bad;
  401. str += bad >> entry; // Cannot target entry block
  402. str += end;
  403. str += "OpFunctionEnd\n";
  404. CompileSuccessfully(str);
  405. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  406. EXPECT_THAT(getDiagnosticString(),
  407. MatchesRegex("First block '.\\[%entry\\]' of function "
  408. "'.\\[%Main\\]' is targeted by block '.\\[%bad\\]'\n"
  409. " %Main = OpFunction %void None %10\n"));
  410. }
  411. TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) {
  412. Block entry("entry");
  413. entry.SetBody("%undef = OpUndef %boolt\n");
  414. Block bad("bad");
  415. Block end("end", spv::Op::OpReturn);
  416. Block badvalue("undef"); // This references the OpUndef.
  417. std::string str = GetDefaultHeader(GetParam()) +
  418. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  419. types_consts() +
  420. "%func = OpFunction %voidt None %funct\n";
  421. str += entry >> bad;
  422. str +=
  423. bad >> badvalue; // Check branch to a function value (it's not a block!)
  424. str += end;
  425. str += "OpFunctionEnd\n";
  426. CompileSuccessfully(str);
  427. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  428. EXPECT_THAT(getDiagnosticString(),
  429. HasSubstr("'Target Label' operands for OpBranch must "
  430. "be the ID of an OpLabel instruction"));
  431. }
  432. TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) {
  433. Block entry("entry");
  434. Block bad("bad", spv::Op::OpBranchConditional);
  435. Block exit("exit", spv::Op::OpReturn);
  436. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  437. bad.SetBody(" OpLoopMerge %entry %exit None\n");
  438. std::string str = GetDefaultHeader(GetParam()) +
  439. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  440. types_consts() +
  441. "%func = OpFunction %voidt None %funct\n";
  442. str += entry >> bad;
  443. str += bad >> std::vector<Block>({entry, exit}); // cannot target entry block
  444. str += exit;
  445. str += "OpFunctionEnd\n";
  446. CompileSuccessfully(str);
  447. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  448. EXPECT_THAT(
  449. getDiagnosticString(),
  450. MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' "
  451. "is targeted by block '.\\[%bad\\]'\n"
  452. " %Main = OpFunction %void None %10\n"));
  453. }
  454. TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) {
  455. Block entry("entry");
  456. Block bad("bad", spv::Op::OpBranchConditional);
  457. Block t("t");
  458. Block merge("merge");
  459. Block end("end", spv::Op::OpReturn);
  460. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  461. bad.SetBody("OpLoopMerge %merge %cont None\n");
  462. std::string str = GetDefaultHeader(GetParam()) +
  463. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  464. types_consts() +
  465. "%func = OpFunction %voidt None %funct\n";
  466. str += entry >> bad;
  467. str += bad >> std::vector<Block>({t, entry});
  468. str += merge >> end;
  469. str += end;
  470. str += "OpFunctionEnd\n";
  471. CompileSuccessfully(str);
  472. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  473. EXPECT_THAT(
  474. getDiagnosticString(),
  475. MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' "
  476. "is targeted by block '.\\[%bad\\]'\n"
  477. " %Main = OpFunction %void None %10\n"));
  478. }
  479. TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) {
  480. Block entry("entry");
  481. Block bad("bad", spv::Op::OpSwitch);
  482. Block block1("block1");
  483. Block block2("block2");
  484. Block block3("block3");
  485. Block def("def"); // default block
  486. Block merge("merge");
  487. Block end("end", spv::Op::OpReturn);
  488. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  489. bad.SetBody("OpSelectionMerge %merge None\n");
  490. std::string str = GetDefaultHeader(GetParam()) +
  491. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  492. types_consts() +
  493. "%func = OpFunction %voidt None %funct\n";
  494. str += entry >> bad;
  495. str += bad >> std::vector<Block>({def, block1, block2, block3, entry});
  496. str += def >> merge;
  497. str += block1 >> merge;
  498. str += block2 >> merge;
  499. str += block3 >> merge;
  500. str += merge >> end;
  501. str += end;
  502. str += "OpFunctionEnd\n";
  503. CompileSuccessfully(str);
  504. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  505. EXPECT_THAT(
  506. getDiagnosticString(),
  507. MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' "
  508. "is targeted by block '.\\[%bad\\]'\n"
  509. " %Main = OpFunction %void None %10\n"));
  510. }
  511. TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) {
  512. Block entry("entry");
  513. Block middle("middle", spv::Op::OpBranchConditional);
  514. Block end("end", spv::Op::OpReturn);
  515. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  516. middle.SetBody("OpSelectionMerge %end None\n");
  517. Block entry2("entry2");
  518. Block middle2("middle2");
  519. Block end2("end2", spv::Op::OpReturn);
  520. std::string str = GetDefaultHeader(GetParam()) +
  521. nameOps("middle2", std::make_pair("func", "Main")) +
  522. types_consts() +
  523. "%func = OpFunction %voidt None %funct\n";
  524. str += entry >> middle;
  525. str += middle >> std::vector<Block>({end, middle2});
  526. str += end;
  527. str += "OpFunctionEnd\n";
  528. str += "%func2 = OpFunction %voidt None %funct\n";
  529. str += entry2 >> middle2;
  530. str += middle2 >> end2;
  531. str += end2;
  532. str += "OpFunctionEnd\n";
  533. CompileSuccessfully(str);
  534. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  535. EXPECT_THAT(getDiagnosticString(),
  536. MatchesRegex(
  537. "Block\\(s\\) \\{'.\\[%middle2\\]'\\} are referenced but not "
  538. "defined in function '.\\[%Main\\]'\n"
  539. " %Main = OpFunction %void None %9\n"));
  540. }
  541. TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) {
  542. // If a merge block is reachable, then it must be strictly dominated by
  543. // its header block.
  544. bool is_shader = GetParam() == spv::Capability::Shader;
  545. Block head("head", spv::Op::OpBranchConditional);
  546. Block exit("exit", spv::Op::OpReturn);
  547. head.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  548. if (is_shader) head.AppendBody("OpSelectionMerge %head None\n");
  549. std::string str = GetDefaultHeader(GetParam()) +
  550. nameOps("head", "exit", std::make_pair("func", "Main")) +
  551. types_consts() +
  552. "%func = OpFunction %voidt None %funct\n";
  553. str += head >> std::vector<Block>({exit, exit});
  554. str += exit;
  555. str += "OpFunctionEnd\n";
  556. CompileSuccessfully(str);
  557. if (is_shader) {
  558. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  559. EXPECT_THAT(
  560. getDiagnosticString(),
  561. MatchesRegex(
  562. "The selection construct with the selection header "
  563. "'.\\[%head\\]' does not strictly structurally dominate the "
  564. "merge block "
  565. "'.\\[%head\\]'\n %head = OpLabel\n"));
  566. } else {
  567. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str;
  568. }
  569. }
  570. std::string GetUnreachableMergeNoMergeInst(spv::Capability cap) {
  571. std::string header = GetDefaultHeader(cap);
  572. Block entry("entry");
  573. Block branch("branch", spv::Op::OpBranchConditional);
  574. Block t("t", spv::Op::OpReturn);
  575. Block f("f", spv::Op::OpReturn);
  576. Block merge("merge", spv::Op::OpReturn);
  577. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  578. if (cap == spv::Capability::Shader)
  579. branch.AppendBody("OpSelectionMerge %merge None\n");
  580. std::string str = header;
  581. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  582. str += types_consts() + "%func = OpFunction %voidt None %funct\n";
  583. str += entry >> branch;
  584. str += branch >> std::vector<Block>({t, f});
  585. str += t;
  586. str += f;
  587. str += merge;
  588. str += "OpFunctionEnd\n";
  589. return str;
  590. }
  591. TEST_P(ValidateCFG, UnreachableMergeNoMergeInst) {
  592. CompileSuccessfully(GetUnreachableMergeNoMergeInst(GetParam()));
  593. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  594. }
  595. std::string GetUnreachableMergeTerminatedBy(spv::Capability cap, spv::Op op) {
  596. std::string header = GetDefaultHeader(cap);
  597. Block entry("entry");
  598. Block branch("branch", spv::Op::OpBranchConditional);
  599. Block t("t", spv::Op::OpReturn);
  600. Block f("f", spv::Op::OpReturn);
  601. Block merge("merge", op);
  602. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  603. std::string str = header;
  604. if (cap == spv::Capability::Shader)
  605. branch.AppendBody("OpSelectionMerge %merge None\n");
  606. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  607. str += types_consts();
  608. str += "%func = OpFunction %voidt None %funct\n";
  609. str += entry >> branch;
  610. str += branch >> std::vector<Block>({t, f});
  611. str += t;
  612. str += f;
  613. str += merge;
  614. str += "OpFunctionEnd\n";
  615. return str;
  616. }
  617. TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) {
  618. CompileSuccessfully(
  619. GetUnreachableMergeTerminatedBy(GetParam(), spv::Op::OpUnreachable));
  620. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  621. }
  622. TEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) {
  623. CompileSuccessfully(GetUnreachableMergeTerminatedBy(spv::Capability::Shader,
  624. spv::Op::OpKill));
  625. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  626. }
  627. TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) {
  628. CompileSuccessfully(
  629. GetUnreachableMergeTerminatedBy(GetParam(), spv::Op::OpReturn));
  630. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  631. }
  632. std::string GetUnreachableContinueTerminatedBy(spv::Capability cap,
  633. spv::Op op) {
  634. std::string header = GetDefaultHeader(cap);
  635. Block entry("entry");
  636. Block branch("branch", spv::Op::OpBranch);
  637. Block merge("merge", spv::Op::OpReturn);
  638. Block target("target", op);
  639. if (op == spv::Op::OpBranch) target >> branch;
  640. std::string str = header;
  641. if (cap == spv::Capability::Shader)
  642. branch.AppendBody("OpLoopMerge %merge %target None\n");
  643. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  644. str += types_consts();
  645. str += "%func = OpFunction %voidt None %funct\n";
  646. str += entry >> branch;
  647. str += branch >> std::vector<Block>({merge});
  648. str += merge;
  649. str += target;
  650. str += "OpFunctionEnd\n";
  651. return str;
  652. }
  653. TEST_P(ValidateCFG, UnreachableContinueTerminatedByOpUnreachable) {
  654. CompileSuccessfully(
  655. GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpUnreachable));
  656. if (GetParam() == spv::Capability::Shader) {
  657. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  658. EXPECT_THAT(getDiagnosticString(),
  659. HasSubstr("targeted by 0 back-edge blocks"));
  660. } else {
  661. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  662. }
  663. }
  664. TEST_F(ValidateCFG, UnreachableContinueTerminatedByOpKill) {
  665. CompileSuccessfully(GetUnreachableContinueTerminatedBy(
  666. spv::Capability::Shader, spv::Op::OpKill));
  667. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  668. EXPECT_THAT(getDiagnosticString(),
  669. HasSubstr("targeted by 0 back-edge blocks"));
  670. }
  671. TEST_P(ValidateCFG, UnreachableContinueTerminatedByOpReturn) {
  672. CompileSuccessfully(
  673. GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpReturn));
  674. if (GetParam() == spv::Capability::Shader) {
  675. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  676. EXPECT_THAT(getDiagnosticString(),
  677. HasSubstr("targeted by 0 back-edge blocks"));
  678. } else {
  679. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  680. }
  681. }
  682. TEST_P(ValidateCFG, UnreachableContinueTerminatedByOpBranch) {
  683. CompileSuccessfully(
  684. GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpBranch));
  685. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  686. }
  687. std::string GetUnreachableMergeUnreachableMergeInst(spv::Capability cap) {
  688. std::string header = GetDefaultHeader(cap);
  689. Block body("body", spv::Op::OpReturn);
  690. Block entry("entry");
  691. Block branch("branch", spv::Op::OpBranchConditional);
  692. Block t("t", spv::Op::OpReturn);
  693. Block f("f", spv::Op::OpReturn);
  694. Block merge("merge", spv::Op::OpUnreachable);
  695. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  696. std::string str = header;
  697. if (cap == spv::Capability::Shader)
  698. branch.AppendBody("OpSelectionMerge %merge None\n");
  699. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  700. str += types_consts();
  701. str += "%func = OpFunction %voidt None %funct\n";
  702. str += body;
  703. str += merge;
  704. str += entry >> branch;
  705. str += branch >> std::vector<Block>({t, f});
  706. str += t;
  707. str += f;
  708. str += "OpFunctionEnd\n";
  709. return str;
  710. }
  711. TEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) {
  712. CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(GetParam()));
  713. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  714. }
  715. std::string GetUnreachableContinueUnreachableLoopInst(spv::Capability cap) {
  716. std::string header = GetDefaultHeader(cap);
  717. Block body("body", spv::Op::OpReturn);
  718. Block entry("entry");
  719. Block branch("branch", spv::Op::OpBranch);
  720. Block merge("merge", spv::Op::OpReturn);
  721. Block target("target", spv::Op::OpBranch);
  722. target >> branch;
  723. std::string str = header;
  724. if (cap == spv::Capability::Shader)
  725. branch.AppendBody("OpLoopMerge %merge %target None\n");
  726. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  727. str += types_consts();
  728. str += "%func = OpFunction %voidt None %funct\n";
  729. str += body;
  730. str += target;
  731. str += merge;
  732. str += entry >> branch;
  733. str += branch >> std::vector<Block>({merge});
  734. str += "OpFunctionEnd\n";
  735. return str;
  736. }
  737. TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) {
  738. CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(GetParam()));
  739. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  740. }
  741. std::string GetUnreachableMergeWithComplexBody(spv::Capability cap) {
  742. std::string header = GetDefaultHeader(cap);
  743. Block entry("entry");
  744. Block branch("branch", spv::Op::OpBranchConditional);
  745. Block t("t", spv::Op::OpReturn);
  746. Block f("f", spv::Op::OpReturn);
  747. Block merge("merge", spv::Op::OpUnreachable);
  748. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  749. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  750. merge.AppendBody("OpStore %placeholder %one\n");
  751. std::string str = header;
  752. if (cap == spv::Capability::Shader)
  753. branch.AppendBody("OpSelectionMerge %merge None\n");
  754. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  755. str += types_consts();
  756. str += "%intptrt = OpTypePointer Function %intt\n";
  757. str += "%func = OpFunction %voidt None %funct\n";
  758. str += entry >> branch;
  759. str += branch >> std::vector<Block>({t, f});
  760. str += t;
  761. str += f;
  762. str += merge;
  763. str += "OpFunctionEnd\n";
  764. return str;
  765. }
  766. TEST_P(ValidateCFG, UnreachableMergeWithComplexBody) {
  767. CompileSuccessfully(GetUnreachableMergeWithComplexBody(GetParam()));
  768. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  769. }
  770. std::string GetUnreachableContinueWithComplexBody(spv::Capability cap) {
  771. std::string header = GetDefaultHeader(cap);
  772. Block entry("entry");
  773. Block branch("branch", spv::Op::OpBranch);
  774. Block merge("merge", spv::Op::OpReturn);
  775. Block target("target", spv::Op::OpBranch);
  776. target >> branch;
  777. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  778. target.AppendBody("OpStore %placeholder %one\n");
  779. std::string str = header;
  780. if (cap == spv::Capability::Shader)
  781. branch.AppendBody("OpLoopMerge %merge %target None\n");
  782. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  783. str += types_consts();
  784. str += "%intptrt = OpTypePointer Function %intt\n";
  785. str += "%func = OpFunction %voidt None %funct\n";
  786. str += entry >> branch;
  787. str += branch >> std::vector<Block>({merge});
  788. str += merge;
  789. str += target;
  790. str += "OpFunctionEnd\n";
  791. return str;
  792. }
  793. TEST_P(ValidateCFG, UnreachableContinueWithComplexBody) {
  794. CompileSuccessfully(GetUnreachableContinueWithComplexBody(GetParam()));
  795. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  796. }
  797. std::string GetUnreachableMergeWithBranchUse(spv::Capability cap) {
  798. std::string header = GetDefaultHeader(cap);
  799. Block entry("entry");
  800. Block branch("branch", spv::Op::OpBranchConditional);
  801. Block t("t", spv::Op::OpBranch);
  802. Block f("f", spv::Op::OpReturn);
  803. Block merge("merge", spv::Op::OpUnreachable);
  804. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  805. std::string str = header;
  806. if (cap == spv::Capability::Shader)
  807. branch.AppendBody("OpSelectionMerge %merge None\n");
  808. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  809. str += types_consts();
  810. str += "%func = OpFunction %voidt None %funct\n";
  811. str += entry >> branch;
  812. str += branch >> std::vector<Block>({t, f});
  813. str += t >> merge;
  814. str += f;
  815. str += merge;
  816. str += "OpFunctionEnd\n";
  817. return str;
  818. }
  819. TEST_P(ValidateCFG, UnreachableMergeWithBranchUse) {
  820. CompileSuccessfully(GetUnreachableMergeWithBranchUse(GetParam()));
  821. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  822. }
  823. std::string GetUnreachableMergeWithMultipleUses(spv::Capability cap) {
  824. std::string header = GetDefaultHeader(cap);
  825. Block entry("entry");
  826. Block branch("branch", spv::Op::OpBranchConditional);
  827. Block t("t", spv::Op::OpReturn);
  828. Block f("f", spv::Op::OpReturn);
  829. Block merge("merge", spv::Op::OpUnreachable);
  830. Block duplicate("duplicate", spv::Op::OpBranchConditional);
  831. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  832. std::string str = header;
  833. if (cap == spv::Capability::Shader) {
  834. branch.AppendBody("OpSelectionMerge %merge None\n");
  835. duplicate.AppendBody("OpSelectionMerge %merge None\n");
  836. }
  837. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  838. str += types_consts();
  839. str += "%func = OpFunction %voidt None %funct\n";
  840. str += entry >> branch;
  841. str += branch >> std::vector<Block>({t, f});
  842. str += duplicate >> std::vector<Block>({t, f});
  843. str += t;
  844. str += f;
  845. str += merge;
  846. str += "OpFunctionEnd\n";
  847. return str;
  848. }
  849. TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) {
  850. CompileSuccessfully(GetUnreachableMergeWithMultipleUses(GetParam()));
  851. if (GetParam() == spv::Capability::Shader) {
  852. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  853. EXPECT_THAT(getDiagnosticString(),
  854. HasSubstr("is already a merge block for another header"));
  855. } else {
  856. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  857. }
  858. }
  859. std::string GetUnreachableContinueWithBranchUse(spv::Capability cap) {
  860. std::string header = GetDefaultHeader(cap);
  861. Block entry("entry");
  862. Block branch("branch", spv::Op::OpBranch);
  863. Block merge("merge", spv::Op::OpReturn);
  864. Block target("target", spv::Op::OpBranch);
  865. target >> branch;
  866. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  867. std::string str = header;
  868. if (cap == spv::Capability::Shader)
  869. branch.AppendBody("OpLoopMerge %merge %target None\n");
  870. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  871. str += types_consts();
  872. str += "%intptrt = OpTypePointer Function %intt\n";
  873. str += "%func = OpFunction %voidt None %funct\n";
  874. str += entry >> branch;
  875. str += branch >> std::vector<Block>({merge});
  876. str += merge;
  877. str += target;
  878. str += "OpFunctionEnd\n";
  879. return str;
  880. }
  881. TEST_P(ValidateCFG, UnreachableContinueWithBranchUse) {
  882. CompileSuccessfully(GetUnreachableContinueWithBranchUse(GetParam()));
  883. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  884. }
  885. std::string GetReachableMergeAndContinue(spv::Capability cap) {
  886. std::string header = GetDefaultHeader(cap);
  887. Block entry("entry");
  888. Block branch("branch", spv::Op::OpBranch);
  889. Block merge("merge", spv::Op::OpReturn);
  890. Block target("target", spv::Op::OpBranch);
  891. Block body("body", spv::Op::OpBranchConditional);
  892. Block t("t", spv::Op::OpBranch);
  893. Block f("f", spv::Op::OpBranch);
  894. target >> branch;
  895. body.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  896. t >> merge;
  897. f >> target;
  898. std::string str = header;
  899. if (cap == spv::Capability::Shader) {
  900. branch.AppendBody("OpLoopMerge %merge %target None\n");
  901. body.AppendBody("OpSelectionMerge %f None\n");
  902. }
  903. str += nameOps("branch", "merge", "target", "body", "t", "f",
  904. std::make_pair("func", "Main"));
  905. str += types_consts();
  906. str += "%func = OpFunction %voidt None %funct\n";
  907. str += entry >> branch;
  908. str += branch >> std::vector<Block>({body});
  909. str += body >> std::vector<Block>({t, f});
  910. str += t;
  911. str += f;
  912. str += merge;
  913. str += target;
  914. str += "OpFunctionEnd\n";
  915. return str;
  916. }
  917. TEST_P(ValidateCFG, ReachableMergeAndContinue) {
  918. CompileSuccessfully(GetReachableMergeAndContinue(GetParam()));
  919. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  920. }
  921. std::string GetUnreachableMergeAndContinue(spv::Capability cap) {
  922. std::string header = GetDefaultHeader(cap);
  923. Block entry("entry");
  924. Block branch("branch", spv::Op::OpBranch);
  925. Block merge("merge", spv::Op::OpReturn);
  926. Block target("target", spv::Op::OpBranch);
  927. Block body("body", spv::Op::OpBranchConditional);
  928. Block t("t", spv::Op::OpReturn);
  929. Block f("f", spv::Op::OpReturn);
  930. Block pre_target("pre_target", spv::Op::OpBranch);
  931. target >> branch;
  932. body.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  933. std::string str = header;
  934. if (cap == spv::Capability::Shader) {
  935. branch.AppendBody("OpLoopMerge %merge %target None\n");
  936. body.AppendBody("OpSelectionMerge %pre_target None\n");
  937. }
  938. str += nameOps("branch", "merge", "pre_target", "target", "body", "t", "f",
  939. std::make_pair("func", "Main"));
  940. str += types_consts();
  941. str += "%func = OpFunction %voidt None %funct\n";
  942. str += entry >> branch;
  943. str += branch >> std::vector<Block>({body});
  944. str += body >> std::vector<Block>({t, f});
  945. str += t;
  946. str += f;
  947. str += merge;
  948. str += pre_target >> target;
  949. str += target;
  950. str += "OpFunctionEnd\n";
  951. return str;
  952. }
  953. TEST_P(ValidateCFG, UnreachableMergeAndContinue) {
  954. CompileSuccessfully(GetUnreachableMergeAndContinue(GetParam()));
  955. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  956. }
  957. std::string GetUnreachableBlock(spv::Capability cap) {
  958. std::string header = GetDefaultHeader(cap);
  959. Block entry("entry");
  960. Block unreachable("unreachable");
  961. Block exit("exit", spv::Op::OpReturn);
  962. std::string str = header;
  963. str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
  964. str += types_consts();
  965. str += "%func = OpFunction %voidt None %funct\n";
  966. str += entry >> exit;
  967. str += unreachable >> exit;
  968. str += exit;
  969. str += "OpFunctionEnd\n";
  970. return str;
  971. }
  972. TEST_P(ValidateCFG, UnreachableBlock) {
  973. CompileSuccessfully(GetUnreachableBlock(GetParam()));
  974. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  975. }
  976. std::string GetUnreachableBranch(spv::Capability cap) {
  977. std::string header = GetDefaultHeader(cap);
  978. Block entry("entry");
  979. Block unreachable("unreachable", spv::Op::OpBranchConditional);
  980. Block unreachablechildt("unreachablechildt");
  981. Block unreachablechildf("unreachablechildf");
  982. Block merge("merge");
  983. Block exit("exit", spv::Op::OpReturn);
  984. unreachable.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  985. if (cap == spv::Capability::Shader)
  986. unreachable.AppendBody("OpSelectionMerge %merge None\n");
  987. std::string str = header;
  988. str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
  989. str += types_consts();
  990. str += "%func = OpFunction %voidt None %funct\n";
  991. str += entry >> exit;
  992. str +=
  993. unreachable >> std::vector<Block>({unreachablechildt, unreachablechildf});
  994. str += unreachablechildt >> merge;
  995. str += unreachablechildf >> merge;
  996. str += merge >> exit;
  997. str += exit;
  998. str += "OpFunctionEnd\n";
  999. return str;
  1000. }
  1001. TEST_P(ValidateCFG, UnreachableBranch) {
  1002. CompileSuccessfully(GetUnreachableBranch(GetParam()));
  1003. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1004. }
  1005. TEST_P(ValidateCFG, EmptyFunction) {
  1006. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1007. R"(%func = OpFunction %voidt None %funct
  1008. %l = OpLabel
  1009. OpReturn
  1010. OpFunctionEnd)";
  1011. CompileSuccessfully(str);
  1012. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1013. }
  1014. TEST_P(ValidateCFG, SingleBlockLoop) {
  1015. bool is_shader = GetParam() == spv::Capability::Shader;
  1016. Block entry("entry");
  1017. Block loop("loop", spv::Op::OpBranchConditional);
  1018. Block exit("exit", spv::Op::OpReturn);
  1019. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1020. if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n");
  1021. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1022. "%func = OpFunction %voidt None %funct\n";
  1023. str += entry >> loop;
  1024. str += loop >> std::vector<Block>({loop, exit});
  1025. str += exit;
  1026. str += "OpFunctionEnd";
  1027. CompileSuccessfully(str);
  1028. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1029. }
  1030. TEST_P(ValidateCFG, NestedLoops) {
  1031. bool is_shader = GetParam() == spv::Capability::Shader;
  1032. Block entry("entry");
  1033. Block loop1("loop1");
  1034. Block loop1_cont_break_block("loop1_cont_break_block",
  1035. spv::Op::OpBranchConditional);
  1036. Block loop2("loop2", spv::Op::OpBranchConditional);
  1037. Block loop2_merge("loop2_merge");
  1038. Block loop1_merge("loop1_merge");
  1039. Block exit("exit", spv::Op::OpReturn);
  1040. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1041. if (is_shader) {
  1042. loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n");
  1043. loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
  1044. }
  1045. std::string str =
  1046. GetDefaultHeader(GetParam()) +
  1047. nameOps("loop1", "loop1_cont_break_block", "loop2", "loop2_merge") +
  1048. types_consts() + "%func = OpFunction %voidt None %funct\n";
  1049. str += entry >> loop1;
  1050. str += loop1 >> loop1_cont_break_block;
  1051. str += loop1_cont_break_block >> std::vector<Block>({loop1_merge, loop2});
  1052. str += loop2 >> std::vector<Block>({loop2, loop2_merge});
  1053. str += loop2_merge >> loop1;
  1054. str += loop1_merge >> exit;
  1055. str += exit;
  1056. str += "OpFunctionEnd";
  1057. CompileSuccessfully(str);
  1058. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1059. }
  1060. TEST_P(ValidateCFG, NestedSelection) {
  1061. bool is_shader = GetParam() == spv::Capability::Shader;
  1062. Block entry("entry");
  1063. const int N = 256;
  1064. std::vector<Block> if_blocks;
  1065. std::vector<Block> merge_blocks;
  1066. Block inner("inner");
  1067. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1068. if_blocks.emplace_back("if0", spv::Op::OpBranchConditional);
  1069. if (is_shader) if_blocks[0].SetBody("OpSelectionMerge %if_merge0 None\n");
  1070. merge_blocks.emplace_back("if_merge0", spv::Op::OpReturn);
  1071. for (int i = 1; i < N; i++) {
  1072. std::stringstream ss;
  1073. ss << i;
  1074. if_blocks.emplace_back("if" + ss.str(), spv::Op::OpBranchConditional);
  1075. if (is_shader)
  1076. if_blocks[i].SetBody("OpSelectionMerge %if_merge" + ss.str() + " None\n");
  1077. merge_blocks.emplace_back("if_merge" + ss.str(), spv::Op::OpBranch);
  1078. }
  1079. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1080. "%func = OpFunction %voidt None %funct\n";
  1081. str += entry >> if_blocks[0];
  1082. for (int i = 0; i < N - 1; i++) {
  1083. str +=
  1084. if_blocks[i] >> std::vector<Block>({if_blocks[i + 1], merge_blocks[i]});
  1085. }
  1086. str += if_blocks.back() >> std::vector<Block>({inner, merge_blocks.back()});
  1087. str += inner >> merge_blocks.back();
  1088. for (int i = N - 1; i > 0; i--) {
  1089. str += merge_blocks[i] >> merge_blocks[i - 1];
  1090. }
  1091. str += merge_blocks[0];
  1092. str += "OpFunctionEnd";
  1093. CompileSuccessfully(str);
  1094. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1095. }
  1096. TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) {
  1097. bool is_shader = GetParam() == spv::Capability::Shader;
  1098. Block entry("entry");
  1099. Block loop1("loop1", spv::Op::OpBranchConditional);
  1100. Block loop2("loop2", spv::Op::OpBranchConditional);
  1101. Block loop2_merge("loop2_merge");
  1102. Block loop1_cont("loop1_cont", spv::Op::OpBranchConditional);
  1103. Block be_block("be_block");
  1104. Block exit("exit", spv::Op::OpReturn);
  1105. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1106. if (is_shader) {
  1107. loop1.SetBody("OpLoopMerge %exit %loop1_cont None\n");
  1108. loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
  1109. }
  1110. std::string str =
  1111. GetDefaultHeader(GetParam()) +
  1112. nameOps("loop1", "loop2", "be_block", "loop1_cont", "loop2_merge") +
  1113. types_consts() + "%func = OpFunction %voidt None %funct\n";
  1114. str += entry >> loop1;
  1115. str += loop1 >> std::vector<Block>({loop2, exit});
  1116. str += loop2 >> std::vector<Block>({loop2, loop2_merge});
  1117. str += loop2_merge >> loop1_cont;
  1118. str += loop1_cont >> std::vector<Block>({be_block, exit});
  1119. str += be_block >> loop1;
  1120. str += exit;
  1121. str += "OpFunctionEnd";
  1122. CompileSuccessfully(str);
  1123. if (GetParam() == spv::Capability::Shader) {
  1124. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1125. EXPECT_THAT(
  1126. getDiagnosticString(),
  1127. MatchesRegex(
  1128. "The continue construct with the continue target "
  1129. "'.\\[%loop1_cont\\]' is not structurally post dominated by the "
  1130. "back-edge block '.\\[%be_block\\]'\n"
  1131. " %be_block = OpLabel\n"));
  1132. } else {
  1133. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1134. }
  1135. }
  1136. TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) {
  1137. bool is_shader = GetParam() == spv::Capability::Shader;
  1138. Block entry("entry");
  1139. Block split("split", spv::Op::OpBranchConditional);
  1140. Block t("t");
  1141. Block f("f");
  1142. Block exit("exit", spv::Op::OpReturn);
  1143. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1144. if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
  1145. std::string str = GetDefaultHeader(GetParam()) + nameOps("split", "f") +
  1146. types_consts() +
  1147. "%func = OpFunction %voidt None %funct\n";
  1148. str += entry >> split;
  1149. str += split >> std::vector<Block>({t, f});
  1150. str += t >> exit;
  1151. str += f >> split;
  1152. str += exit;
  1153. str += "OpFunctionEnd";
  1154. CompileSuccessfully(str);
  1155. if (is_shader) {
  1156. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1157. EXPECT_THAT(
  1158. getDiagnosticString(),
  1159. MatchesRegex("Back-edges \\('.\\[%f\\]' -> '.\\[%split\\]'\\) can only "
  1160. "be formed between a block and a loop header.\n"
  1161. " %f = OpLabel\n"));
  1162. } else {
  1163. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1164. }
  1165. }
  1166. TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) {
  1167. bool is_shader = GetParam() == spv::Capability::Shader;
  1168. Block entry("entry");
  1169. Block split("split", spv::Op::OpBranchConditional);
  1170. Block exit("exit", spv::Op::OpReturn);
  1171. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1172. if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
  1173. std::string str = GetDefaultHeader(GetParam()) + nameOps("split") +
  1174. types_consts() +
  1175. "%func = OpFunction %voidt None %funct\n";
  1176. str += entry >> split;
  1177. str += split >> std::vector<Block>({split, exit});
  1178. str += exit;
  1179. str += "OpFunctionEnd";
  1180. CompileSuccessfully(str);
  1181. if (is_shader) {
  1182. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1183. EXPECT_THAT(
  1184. getDiagnosticString(),
  1185. MatchesRegex(
  1186. "Back-edges \\('.\\[%split\\]' -> '.\\[%split\\]'\\) can only be "
  1187. "formed between a block and a loop header.\n %split = OpLabel\n"));
  1188. } else {
  1189. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1190. }
  1191. }
  1192. TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) {
  1193. bool is_shader = GetParam() == spv::Capability::Shader;
  1194. Block entry("entry");
  1195. Block loop("loop", spv::Op::OpBranchConditional);
  1196. Block back0("back0");
  1197. Block back1("back1");
  1198. Block merge("merge", spv::Op::OpReturn);
  1199. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1200. if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n");
  1201. std::string str = GetDefaultHeader(GetParam()) +
  1202. nameOps("loop", "back0", "back1") + types_consts() +
  1203. "%func = OpFunction %voidt None %funct\n";
  1204. str += entry >> loop;
  1205. str += loop >> std::vector<Block>({back0, back1});
  1206. str += back0 >> loop;
  1207. str += back1 >> loop;
  1208. str += merge;
  1209. str += "OpFunctionEnd";
  1210. CompileSuccessfully(str);
  1211. if (is_shader) {
  1212. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1213. EXPECT_THAT(
  1214. getDiagnosticString(),
  1215. MatchesRegex(
  1216. "Loop header '.\\[%loop\\]' is targeted by 2 back-edge blocks but "
  1217. "the standard requires exactly one\n %loop = OpLabel\n"))
  1218. << str;
  1219. } else {
  1220. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1221. }
  1222. }
  1223. TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) {
  1224. bool is_shader = GetParam() == spv::Capability::Shader;
  1225. Block entry("entry");
  1226. Block loop("loop", spv::Op::OpBranchConditional);
  1227. Block cheader("cheader", spv::Op::OpBranchConditional);
  1228. Block be_block("be_block");
  1229. Block merge("merge", spv::Op::OpReturn);
  1230. Block exit("exit", spv::Op::OpReturn);
  1231. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1232. if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n");
  1233. std::string str = GetDefaultHeader(GetParam()) +
  1234. nameOps("cheader", "be_block") + types_consts() +
  1235. "%func = OpFunction %voidt None %funct\n";
  1236. str += entry >> loop;
  1237. str += loop >> std::vector<Block>({cheader, merge});
  1238. str += cheader >> std::vector<Block>({exit, be_block});
  1239. str += exit; // Branches out of a continue construct
  1240. str += be_block >> loop;
  1241. str += merge;
  1242. str += "OpFunctionEnd";
  1243. CompileSuccessfully(str);
  1244. if (is_shader) {
  1245. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1246. EXPECT_THAT(
  1247. getDiagnosticString(),
  1248. MatchesRegex(
  1249. "The continue construct with the continue target "
  1250. "'.\\[%cheader\\]' is not structurally post dominated by the "
  1251. "back-edge block '.\\[%be_block\\]'\n"
  1252. " %be_block = OpLabel\n"));
  1253. } else {
  1254. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1255. }
  1256. }
  1257. TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) {
  1258. bool is_shader = GetParam() == spv::Capability::Shader;
  1259. Block entry("entry");
  1260. Block loop("loop", spv::Op::OpBranchConditional);
  1261. Block cont("cont", spv::Op::OpBranchConditional);
  1262. Block merge("merge", spv::Op::OpReturn);
  1263. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1264. if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
  1265. std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") +
  1266. types_consts() +
  1267. "%func = OpFunction %voidt None %funct\n";
  1268. str += entry >> loop;
  1269. str += loop >> std::vector<Block>({cont, merge});
  1270. str += cont >> std::vector<Block>({loop, merge});
  1271. str += merge;
  1272. str += "OpFunctionEnd";
  1273. CompileSuccessfully(str);
  1274. if (is_shader) {
  1275. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1276. EXPECT_THAT(
  1277. getDiagnosticString(),
  1278. MatchesRegex("The continue construct with the continue target "
  1279. "'.\\[%loop\\]' is not structurally post dominated by the "
  1280. "back-edge block '.\\[%cont\\]'\n"
  1281. " %cont = OpLabel\n"))
  1282. << str;
  1283. } else {
  1284. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1285. }
  1286. }
  1287. TEST_P(ValidateCFG, BranchOutOfConstructBad) {
  1288. bool is_shader = GetParam() == spv::Capability::Shader;
  1289. Block entry("entry");
  1290. Block loop("loop", spv::Op::OpBranchConditional);
  1291. Block cont("cont", spv::Op::OpBranchConditional);
  1292. Block merge("merge");
  1293. Block exit("exit", spv::Op::OpReturn);
  1294. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1295. if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
  1296. std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") +
  1297. types_consts() +
  1298. "%func = OpFunction %voidt None %funct\n";
  1299. str += entry >> loop;
  1300. str += loop >> std::vector<Block>({cont, merge});
  1301. str += cont >> std::vector<Block>({loop, exit});
  1302. str += merge >> exit;
  1303. str += exit;
  1304. str += "OpFunctionEnd";
  1305. CompileSuccessfully(str);
  1306. if (is_shader) {
  1307. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1308. EXPECT_THAT(
  1309. getDiagnosticString(),
  1310. MatchesRegex("The continue construct with the continue target "
  1311. "'.\\[%loop\\]' is not structurally post dominated by the "
  1312. "back-edge block '.\\[%cont\\]'\n"
  1313. " %cont = OpLabel\n"));
  1314. } else {
  1315. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1316. }
  1317. }
  1318. TEST_F(ValidateCFG, OpSwitchToUnreachableBlock) {
  1319. Block entry("entry", spv::Op::OpSwitch);
  1320. Block case0("case0");
  1321. Block case1("case1");
  1322. Block case2("case2");
  1323. Block def("default", spv::Op::OpUnreachable);
  1324. Block phi("phi", spv::Op::OpReturn);
  1325. std::string str = R"(
  1326. OpCapability Shader
  1327. OpMemoryModel Logical GLSL450
  1328. OpEntryPoint GLCompute %main "main" %id
  1329. OpExecutionMode %main LocalSize 1 1 1
  1330. OpSource GLSL 430
  1331. OpName %main "main"
  1332. OpDecorate %id BuiltIn GlobalInvocationId
  1333. %void = OpTypeVoid
  1334. %voidf = OpTypeFunction %void
  1335. %u32 = OpTypeInt 32 0
  1336. %f32 = OpTypeFloat 32
  1337. %uvec3 = OpTypeVector %u32 3
  1338. %fvec3 = OpTypeVector %f32 3
  1339. %uvec3ptr = OpTypePointer Input %uvec3
  1340. %id = OpVariable %uvec3ptr Input
  1341. %one = OpConstant %u32 1
  1342. %three = OpConstant %u32 3
  1343. %main = OpFunction %void None %voidf
  1344. )";
  1345. entry.SetBody(
  1346. "%idval = OpLoad %uvec3 %id\n"
  1347. "%x = OpCompositeExtract %u32 %idval 0\n"
  1348. "%selector = OpUMod %u32 %x %three\n"
  1349. "OpSelectionMerge %phi None\n");
  1350. str += entry >> std::vector<Block>({def, case0, case1, case2});
  1351. str += case1 >> phi;
  1352. str += def;
  1353. str += phi;
  1354. str += case0 >> phi;
  1355. str += case2 >> phi;
  1356. str += "OpFunctionEnd";
  1357. CompileSuccessfully(str);
  1358. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  1359. }
  1360. TEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) {
  1361. std::string str = R"(
  1362. OpCapability Shader
  1363. OpMemoryModel Logical GLSL450
  1364. OpEntryPoint Fragment %main "main"
  1365. OpExecutionMode %main OriginUpperLeft
  1366. OpName %loop "loop"
  1367. %voidt = OpTypeVoid
  1368. %funct = OpTypeFunction %voidt
  1369. %main = OpFunction %voidt None %funct
  1370. %loop = OpLabel
  1371. OpLoopMerge %exit %loop None
  1372. OpBranch %exit
  1373. %exit = OpLabel
  1374. OpReturn
  1375. OpFunctionEnd
  1376. )";
  1377. CompileSuccessfully(str);
  1378. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1379. EXPECT_THAT(
  1380. getDiagnosticString(),
  1381. MatchesRegex("Loop header '.\\[%loop\\]' is targeted by "
  1382. "0 back-edge blocks but the standard requires exactly "
  1383. "one\n %loop = OpLabel\n"));
  1384. }
  1385. TEST_F(ValidateCFG, LoopWithBackEdgeFromUnreachableContinueConstructGood) {
  1386. std::string str = R"(
  1387. OpCapability Shader
  1388. OpMemoryModel Logical GLSL450
  1389. OpEntryPoint Fragment %main "main"
  1390. OpExecutionMode %main OriginUpperLeft
  1391. OpName %loop "loop"
  1392. %voidt = OpTypeVoid
  1393. %funct = OpTypeFunction %voidt
  1394. %floatt = OpTypeFloat 32
  1395. %boolt = OpTypeBool
  1396. %one = OpConstant %floatt 1
  1397. %two = OpConstant %floatt 2
  1398. %main = OpFunction %voidt None %funct
  1399. %entry = OpLabel
  1400. OpBranch %loop
  1401. %loop = OpLabel
  1402. OpLoopMerge %exit %cont None
  1403. OpBranch %16
  1404. %16 = OpLabel
  1405. %cond = OpFOrdLessThan %boolt %one %two
  1406. OpBranchConditional %cond %body %exit
  1407. %body = OpLabel
  1408. OpReturn
  1409. %cont = OpLabel ; Reachable only from OpLoopMerge ContinueTarget parameter
  1410. OpBranch %loop ; Should be considered a back-edge
  1411. %exit = OpLabel
  1412. OpReturn
  1413. OpFunctionEnd
  1414. )";
  1415. CompileSuccessfully(str);
  1416. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  1417. }
  1418. TEST_P(ValidateCFG,
  1419. NestedConstructWithUnreachableMergeBlockBranchingToOuterMergeBlock) {
  1420. // Test for https://github.com/KhronosGroup/SPIRV-Tools/issues/297
  1421. // The nested construct has an unreachable merge block. In the
  1422. // augmented CFG that merge block
  1423. // we still determine that the
  1424. bool is_shader = GetParam() == spv::Capability::Shader;
  1425. Block entry("entry", spv::Op::OpBranchConditional);
  1426. Block inner_head("inner_head", spv::Op::OpBranchConditional);
  1427. Block inner_true("inner_true", spv::Op::OpReturn);
  1428. Block inner_false("inner_false", spv::Op::OpReturn);
  1429. Block inner_merge("inner_merge");
  1430. Block exit("exit", spv::Op::OpReturn);
  1431. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1432. if (is_shader) {
  1433. entry.AppendBody("OpSelectionMerge %exit None\n");
  1434. inner_head.SetBody("OpSelectionMerge %inner_merge None\n");
  1435. }
  1436. std::string str = GetDefaultHeader(GetParam()) +
  1437. nameOps("entry", "inner_merge", "exit") + types_consts() +
  1438. "%func = OpFunction %voidt None %funct\n";
  1439. str += entry >> std::vector<Block>({inner_head, exit});
  1440. str += inner_head >> std::vector<Block>({inner_true, inner_false});
  1441. str += inner_true;
  1442. str += inner_false;
  1443. str += inner_merge >> exit;
  1444. str += exit;
  1445. str += "OpFunctionEnd";
  1446. CompileSuccessfully(str);
  1447. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  1448. }
  1449. TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructure) {
  1450. // The continue construct cannot be the merge target of a nested selection
  1451. // because the loop construct must contain "if_merge" because it contains
  1452. // "if_head".
  1453. bool is_shader = GetParam() == spv::Capability::Shader;
  1454. Block entry("entry");
  1455. Block loop("loop");
  1456. Block if_head("if_head", spv::Op::OpBranchConditional);
  1457. Block if_true("if_true");
  1458. Block if_merge("if_merge", spv::Op::OpBranchConditional);
  1459. Block merge("merge", spv::Op::OpReturn);
  1460. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1461. if (is_shader) {
  1462. loop.SetBody("OpLoopMerge %merge %if_merge None\n");
  1463. if_head.SetBody("OpSelectionMerge %if_merge None\n");
  1464. }
  1465. std::string str =
  1466. GetDefaultHeader(GetParam()) +
  1467. nameOps("entry", "loop", "if_head", "if_true", "if_merge", "merge") +
  1468. types_consts() + "%func = OpFunction %voidt None %funct\n";
  1469. str += entry >> loop;
  1470. str += loop >> if_head;
  1471. str += if_head >> std::vector<Block>({if_true, if_merge});
  1472. str += if_true >> if_merge;
  1473. str += if_merge >> std::vector<Block>({loop, merge});
  1474. str += merge;
  1475. str += "OpFunctionEnd";
  1476. CompileSuccessfully(str);
  1477. if (is_shader) {
  1478. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1479. EXPECT_THAT(
  1480. getDiagnosticString(),
  1481. HasSubstr(
  1482. "Header block '3[%if_head]' is contained in the loop construct "
  1483. "headed "
  1484. "by '2[%loop]', but its merge block '5[%if_merge]' is not"));
  1485. } else {
  1486. EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
  1487. }
  1488. }
  1489. TEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) {
  1490. // This test case ensures we allow both branches of a loop latch block
  1491. // to go back to the loop header. It still counts as a single back edge.
  1492. bool is_shader = GetParam() == spv::Capability::Shader;
  1493. Block entry("entry");
  1494. Block loop("loop", spv::Op::OpBranchConditional);
  1495. Block latch("latch", spv::Op::OpBranchConditional);
  1496. Block merge("merge", spv::Op::OpReturn);
  1497. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1498. if (is_shader) {
  1499. loop.SetBody("OpLoopMerge %merge %latch None\n");
  1500. }
  1501. std::string str = GetDefaultHeader(GetParam()) +
  1502. nameOps("entry", "loop", "latch", "merge") +
  1503. types_consts() +
  1504. "%func = OpFunction %voidt None %funct\n";
  1505. str += entry >> loop;
  1506. str += loop >> std::vector<Block>({latch, merge});
  1507. str += latch >> std::vector<Block>({loop, loop}); // This is the key
  1508. str += merge;
  1509. str += "OpFunctionEnd";
  1510. CompileSuccessfully(str);
  1511. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions())
  1512. << str << getDiagnosticString();
  1513. }
  1514. // Unit test to check the case where a basic block is the entry block of 2
  1515. // different constructs. In this case, the basic block is the entry block of a
  1516. // continue construct as well as a selection construct. See issue# 517 for more
  1517. // details.
  1518. TEST_F(ValidateCFG, BasicBlockIsEntryBlockOfTwoConstructsGood) {
  1519. std::string spirv = R"(
  1520. OpCapability Shader
  1521. OpCapability Linkage
  1522. OpMemoryModel Logical GLSL450
  1523. %void = OpTypeVoid
  1524. %bool = OpTypeBool
  1525. %int = OpTypeInt 32 1
  1526. %void_func = OpTypeFunction %void
  1527. %int_0 = OpConstant %int 0
  1528. %testfun = OpFunction %void None %void_func
  1529. %label_1 = OpLabel
  1530. OpBranch %start
  1531. %start = OpLabel
  1532. %cond = OpSLessThan %bool %int_0 %int_0
  1533. ;
  1534. ; Note: In this case, the "target" block is both the entry block of
  1535. ; the continue construct of the loop as well as the entry block of
  1536. ; the selection construct.
  1537. ;
  1538. OpLoopMerge %loop_merge %target None
  1539. OpBranchConditional %cond %target %loop_merge
  1540. %loop_merge = OpLabel
  1541. OpReturn
  1542. %target = OpLabel
  1543. OpSelectionMerge %selection_merge None
  1544. OpBranchConditional %cond %do_stuff %do_other_stuff
  1545. %do_other_stuff = OpLabel
  1546. OpBranch %selection_merge
  1547. %selection_merge = OpLabel
  1548. OpBranch %start
  1549. %do_stuff = OpLabel
  1550. OpBranch %selection_merge
  1551. OpFunctionEnd
  1552. )";
  1553. CompileSuccessfully(spirv);
  1554. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  1555. }
  1556. TEST_F(ValidateCFG, OpReturnInNonVoidFunc) {
  1557. std::string spirv = R"(
  1558. OpCapability Shader
  1559. OpCapability Linkage
  1560. OpMemoryModel Logical GLSL450
  1561. %int = OpTypeInt 32 1
  1562. %int_func = OpTypeFunction %int
  1563. %testfun = OpFunction %int None %int_func
  1564. %label_1 = OpLabel
  1565. OpReturn
  1566. OpFunctionEnd
  1567. )";
  1568. CompileSuccessfully(spirv);
  1569. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1570. EXPECT_THAT(
  1571. getDiagnosticString(),
  1572. HasSubstr(
  1573. "OpReturn can only be called from a function with void return type.\n"
  1574. " OpReturn"));
  1575. }
  1576. TEST_F(ValidateCFG, StructuredCFGBranchIntoSelectionBody) {
  1577. std::string spirv = R"(
  1578. OpCapability Shader
  1579. OpMemoryModel Logical GLSL450
  1580. OpEntryPoint Fragment %func "func"
  1581. OpExecutionMode %func OriginUpperLeft
  1582. %void = OpTypeVoid
  1583. %bool = OpTypeBool
  1584. %true = OpConstantTrue %bool
  1585. %functy = OpTypeFunction %void
  1586. %func = OpFunction %void None %functy
  1587. %entry = OpLabel
  1588. OpSelectionMerge %merge None
  1589. OpBranchConditional %true %then %merge
  1590. %merge = OpLabel
  1591. OpBranch %then
  1592. %then = OpLabel
  1593. OpReturn
  1594. OpFunctionEnd
  1595. )";
  1596. CompileSuccessfully(spirv);
  1597. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1598. EXPECT_THAT(getDiagnosticString(),
  1599. HasSubstr("branches to the selection construct, but not to the "
  1600. "selection header <ID> 6\n %7 = OpLabel"));
  1601. }
  1602. TEST_F(ValidateCFG, SwitchDefaultOnly) {
  1603. std::string text = R"(
  1604. OpCapability Shader
  1605. OpCapability Linkage
  1606. OpMemoryModel Logical GLSL450
  1607. %1 = OpTypeVoid
  1608. %2 = OpTypeInt 32 0
  1609. %3 = OpConstant %2 0
  1610. %4 = OpTypeFunction %1
  1611. %5 = OpFunction %1 None %4
  1612. %6 = OpLabel
  1613. OpSelectionMerge %7 None
  1614. OpSwitch %3 %7
  1615. %7 = OpLabel
  1616. OpReturn
  1617. OpFunctionEnd
  1618. )";
  1619. CompileSuccessfully(text);
  1620. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1621. }
  1622. TEST_F(ValidateCFG, SwitchSingleCase) {
  1623. std::string text = R"(
  1624. OpCapability Shader
  1625. OpCapability Linkage
  1626. OpMemoryModel Logical GLSL450
  1627. %1 = OpTypeVoid
  1628. %2 = OpTypeInt 32 0
  1629. %3 = OpConstant %2 0
  1630. %4 = OpTypeFunction %1
  1631. %5 = OpFunction %1 None %4
  1632. %6 = OpLabel
  1633. OpSelectionMerge %7 None
  1634. OpSwitch %3 %7 0 %8
  1635. %8 = OpLabel
  1636. OpBranch %7
  1637. %7 = OpLabel
  1638. OpReturn
  1639. OpFunctionEnd
  1640. )";
  1641. CompileSuccessfully(text);
  1642. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1643. }
  1644. TEST_F(ValidateCFG, MultipleFallThroughBlocks) {
  1645. std::string text = R"(
  1646. OpCapability Shader
  1647. OpCapability Linkage
  1648. OpMemoryModel Logical GLSL450
  1649. %1 = OpTypeVoid
  1650. %2 = OpTypeInt 32 0
  1651. %3 = OpConstant %2 0
  1652. %4 = OpTypeFunction %1
  1653. %5 = OpTypeBool
  1654. %6 = OpConstantTrue %5
  1655. %7 = OpFunction %1 None %4
  1656. %8 = OpLabel
  1657. OpSelectionMerge %9 None
  1658. OpSwitch %3 %10 0 %11 1 %12
  1659. %10 = OpLabel
  1660. OpBranchConditional %6 %11 %12
  1661. %11 = OpLabel
  1662. OpBranch %9
  1663. %12 = OpLabel
  1664. OpBranch %9
  1665. %9 = OpLabel
  1666. OpReturn
  1667. OpFunctionEnd
  1668. )";
  1669. CompileSuccessfully(text);
  1670. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1671. EXPECT_THAT(
  1672. getDiagnosticString(),
  1673. HasSubstr(
  1674. "Case construct that targets '10[%10]' has branches to multiple "
  1675. "other "
  1676. "case construct targets '12[%12]' and '11[%11]'\n %10 = OpLabel"));
  1677. }
  1678. TEST_F(ValidateCFG, MultipleFallThroughToDefault) {
  1679. std::string text = R"(
  1680. OpCapability Shader
  1681. OpCapability Linkage
  1682. OpMemoryModel Logical GLSL450
  1683. %1 = OpTypeVoid
  1684. %2 = OpTypeInt 32 0
  1685. %3 = OpConstant %2 0
  1686. %4 = OpTypeFunction %1
  1687. %5 = OpTypeBool
  1688. %6 = OpConstantTrue %5
  1689. %7 = OpFunction %1 None %4
  1690. %8 = OpLabel
  1691. OpSelectionMerge %9 None
  1692. OpSwitch %3 %10 0 %11 1 %12
  1693. %10 = OpLabel
  1694. OpBranch %9
  1695. %11 = OpLabel
  1696. OpBranch %10
  1697. %12 = OpLabel
  1698. OpBranch %10
  1699. %9 = OpLabel
  1700. OpReturn
  1701. OpFunctionEnd
  1702. )";
  1703. CompileSuccessfully(text);
  1704. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1705. EXPECT_THAT(
  1706. getDiagnosticString(),
  1707. HasSubstr("Multiple case constructs have branches to the case construct "
  1708. "that targets '10[%10]'\n %10 = OpLabel"));
  1709. }
  1710. TEST_F(ValidateCFG, MultipleFallThroughToNonDefault) {
  1711. std::string text = R"(
  1712. OpCapability Shader
  1713. OpCapability Linkage
  1714. OpMemoryModel Logical GLSL450
  1715. %1 = OpTypeVoid
  1716. %2 = OpTypeInt 32 0
  1717. %3 = OpConstant %2 0
  1718. %4 = OpTypeFunction %1
  1719. %5 = OpTypeBool
  1720. %6 = OpConstantTrue %5
  1721. %7 = OpFunction %1 None %4
  1722. %8 = OpLabel
  1723. OpSelectionMerge %9 None
  1724. OpSwitch %3 %10 0 %11 1 %12
  1725. %10 = OpLabel
  1726. OpBranch %12
  1727. %11 = OpLabel
  1728. OpBranch %12
  1729. %12 = OpLabel
  1730. OpBranch %9
  1731. %9 = OpLabel
  1732. OpReturn
  1733. OpFunctionEnd
  1734. )";
  1735. CompileSuccessfully(text);
  1736. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1737. EXPECT_THAT(
  1738. getDiagnosticString(),
  1739. HasSubstr("Multiple case constructs have branches to the case construct "
  1740. "that targets '12[%12]'\n %12 = OpLabel"));
  1741. }
  1742. TEST_F(ValidateCFG, DuplicateTargetWithFallThrough) {
  1743. std::string text = R"(
  1744. OpCapability Shader
  1745. OpCapability Linkage
  1746. OpMemoryModel Logical GLSL450
  1747. %1 = OpTypeVoid
  1748. %2 = OpTypeInt 32 0
  1749. %3 = OpConstant %2 0
  1750. %4 = OpTypeFunction %1
  1751. %5 = OpTypeBool
  1752. %6 = OpConstantTrue %5
  1753. %7 = OpFunction %1 None %4
  1754. %8 = OpLabel
  1755. OpSelectionMerge %9 None
  1756. OpSwitch %3 %10 0 %10 1 %11
  1757. %10 = OpLabel
  1758. OpBranch %11
  1759. %11 = OpLabel
  1760. OpBranch %9
  1761. %9 = OpLabel
  1762. OpReturn
  1763. OpFunctionEnd
  1764. )";
  1765. CompileSuccessfully(text);
  1766. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1767. }
  1768. TEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopMergeBlock) {
  1769. std::string text = R"(
  1770. OpCapability Shader
  1771. OpCapability Linkage
  1772. OpMemoryModel Logical GLSL450
  1773. %1 = OpTypeVoid
  1774. %2 = OpTypeFunction %1
  1775. %3 = OpTypeBool
  1776. %4 = OpUndef %3
  1777. %5 = OpTypeInt 32 0
  1778. %6 = OpConstant %5 0
  1779. %7 = OpFunction %1 None %2
  1780. %8 = OpLabel
  1781. OpBranch %9
  1782. %9 = OpLabel
  1783. OpLoopMerge %10 %11 None
  1784. OpBranch %12
  1785. %12 = OpLabel
  1786. OpSelectionMerge %13 None
  1787. OpSwitch %6 %13 0 %10 1 %14
  1788. %14 = OpLabel
  1789. OpBranch %13
  1790. %13 = OpLabel
  1791. OpBranch %11
  1792. %11 = OpLabel
  1793. OpBranch %9
  1794. %10 = OpLabel
  1795. OpReturn
  1796. OpFunctionEnd
  1797. )";
  1798. CompileSuccessfully(text);
  1799. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1800. EXPECT_THAT(
  1801. getDiagnosticString(),
  1802. HasSubstr(
  1803. "Switch header '12[%12]' does not structurally dominate its case construct '10[%10]'\n"
  1804. " %12 = OpLabel"));
  1805. }
  1806. TEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopContinueBlock) {
  1807. std::string text = R"(
  1808. OpCapability Shader
  1809. OpCapability Linkage
  1810. OpMemoryModel Logical GLSL450
  1811. %1 = OpTypeVoid
  1812. %2 = OpTypeFunction %1
  1813. %3 = OpTypeBool
  1814. %4 = OpUndef %3
  1815. %5 = OpTypeInt 32 0
  1816. %6 = OpConstant %5 0
  1817. %7 = OpFunction %1 None %2
  1818. %8 = OpLabel
  1819. OpBranch %9
  1820. %9 = OpLabel
  1821. OpLoopMerge %10 %11 None
  1822. OpBranch %12
  1823. %12 = OpLabel
  1824. OpSelectionMerge %13 None
  1825. OpSwitch %6 %13 0 %11 1 %14
  1826. %14 = OpLabel
  1827. OpBranch %13
  1828. %13 = OpLabel
  1829. OpBranch %11
  1830. %11 = OpLabel
  1831. OpBranch %9
  1832. %10 = OpLabel
  1833. OpReturn
  1834. OpFunctionEnd
  1835. )";
  1836. CompileSuccessfully(text);
  1837. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1838. EXPECT_THAT(
  1839. getDiagnosticString(),
  1840. HasSubstr(
  1841. "Switch header '12[%12]' does not structurally dominate its case construct '11[%11]'\n"
  1842. " %12 = OpLabel"));
  1843. }
  1844. TEST_F(ValidateCFG, WrongOperandList) {
  1845. std::string text = R"(
  1846. OpCapability Shader
  1847. OpCapability Linkage
  1848. OpMemoryModel Logical GLSL450
  1849. %1 = OpTypeVoid
  1850. %2 = OpTypeInt 32 0
  1851. %3 = OpConstant %2 0
  1852. %4 = OpTypeFunction %1
  1853. %5 = OpTypeBool
  1854. %6 = OpConstantTrue %5
  1855. %7 = OpFunction %1 None %4
  1856. %8 = OpLabel
  1857. OpSelectionMerge %9 None
  1858. OpSwitch %3 %10 0 %11 1 %12
  1859. %10 = OpLabel
  1860. OpBranch %9
  1861. %12 = OpLabel
  1862. OpBranch %11
  1863. %11 = OpLabel
  1864. OpBranch %9
  1865. %9 = OpLabel
  1866. OpReturn
  1867. OpFunctionEnd
  1868. )";
  1869. CompileSuccessfully(text);
  1870. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1871. EXPECT_THAT(
  1872. getDiagnosticString(),
  1873. HasSubstr(
  1874. "Case construct that targets '12[%12]' has branches to the case "
  1875. "construct that targets '11[%11]', but does not immediately "
  1876. "precede it in the OpSwitch's target list\n"
  1877. " OpSwitch %uint_0 %10 0 %11 1 %12"));
  1878. }
  1879. TEST_F(ValidateCFG, WrongOperandListThroughDefault) {
  1880. std::string text = R"(
  1881. OpCapability Shader
  1882. OpCapability Linkage
  1883. OpMemoryModel Logical GLSL450
  1884. %1 = OpTypeVoid
  1885. %2 = OpTypeInt 32 0
  1886. %3 = OpConstant %2 0
  1887. %4 = OpTypeFunction %1
  1888. %5 = OpTypeBool
  1889. %6 = OpConstantTrue %5
  1890. %7 = OpFunction %1 None %4
  1891. %8 = OpLabel
  1892. OpSelectionMerge %9 None
  1893. OpSwitch %3 %10 0 %11 1 %12
  1894. %10 = OpLabel
  1895. OpBranch %11
  1896. %12 = OpLabel
  1897. OpBranch %10
  1898. %11 = OpLabel
  1899. OpBranch %9
  1900. %9 = OpLabel
  1901. OpReturn
  1902. OpFunctionEnd
  1903. )";
  1904. CompileSuccessfully(text);
  1905. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1906. EXPECT_THAT(
  1907. getDiagnosticString(),
  1908. HasSubstr(
  1909. "Case construct that targets '12[%12]' has branches to the case "
  1910. "construct that targets '11[%11]', but does not immediately "
  1911. "precede it in the OpSwitch's target list\n"
  1912. " OpSwitch %uint_0 %10 0 %11 1 %12"));
  1913. }
  1914. TEST_F(ValidateCFG, WrongOperandListNotLast) {
  1915. std::string text = R"(
  1916. OpCapability Shader
  1917. OpCapability Linkage
  1918. OpMemoryModel Logical GLSL450
  1919. %1 = OpTypeVoid
  1920. %2 = OpTypeInt 32 0
  1921. %3 = OpConstant %2 0
  1922. %4 = OpTypeFunction %1
  1923. %5 = OpTypeBool
  1924. %6 = OpConstantTrue %5
  1925. %7 = OpFunction %1 None %4
  1926. %8 = OpLabel
  1927. OpSelectionMerge %9 None
  1928. OpSwitch %3 %10 0 %11 1 %12 2 %13
  1929. %10 = OpLabel
  1930. OpBranch %9
  1931. %12 = OpLabel
  1932. OpBranch %11
  1933. %11 = OpLabel
  1934. OpBranch %9
  1935. %13 = OpLabel
  1936. OpBranch %9
  1937. %9 = OpLabel
  1938. OpReturn
  1939. OpFunctionEnd
  1940. )";
  1941. CompileSuccessfully(text);
  1942. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1943. EXPECT_THAT(
  1944. getDiagnosticString(),
  1945. HasSubstr(
  1946. "Case construct that targets '12[%12]' has branches to the case "
  1947. "construct that targets '11[%11]', but does not immediately "
  1948. "precede it in the OpSwitch's target list\n"
  1949. " OpSwitch %uint_0 %10 0 %11 1 %12 2 %13"));
  1950. }
  1951. TEST_F(ValidateCFG, GoodUnreachableSwitch) {
  1952. const std::string text = R"(
  1953. OpCapability Shader
  1954. OpMemoryModel Logical GLSL450
  1955. OpEntryPoint Fragment %2 "main"
  1956. OpExecutionMode %2 OriginUpperLeft
  1957. %3 = OpTypeVoid
  1958. %4 = OpTypeFunction %3
  1959. %5 = OpTypeBool
  1960. %6 = OpConstantTrue %5
  1961. %7 = OpTypeInt 32 1
  1962. %9 = OpConstant %7 0
  1963. %2 = OpFunction %3 None %4
  1964. %10 = OpLabel
  1965. OpSelectionMerge %11 None
  1966. OpBranchConditional %6 %12 %13
  1967. %12 = OpLabel
  1968. OpReturn
  1969. %13 = OpLabel
  1970. OpReturn
  1971. %11 = OpLabel
  1972. OpSelectionMerge %14 None
  1973. OpSwitch %9 %14 0 %15
  1974. %15 = OpLabel
  1975. OpBranch %14
  1976. %14 = OpLabel
  1977. OpReturn
  1978. OpFunctionEnd
  1979. )";
  1980. CompileSuccessfully(text);
  1981. EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
  1982. }
  1983. TEST_F(ValidateCFG, InvalidCaseExit) {
  1984. const std::string text = R"(
  1985. OpCapability Shader
  1986. OpMemoryModel Logical GLSL450
  1987. OpEntryPoint Fragment %1 "func"
  1988. OpExecutionMode %1 OriginUpperLeft
  1989. %2 = OpTypeVoid
  1990. %3 = OpTypeInt 32 0
  1991. %4 = OpTypeFunction %2
  1992. %5 = OpConstant %3 0
  1993. %1 = OpFunction %2 None %4
  1994. %6 = OpLabel
  1995. OpSelectionMerge %7 None
  1996. OpSwitch %5 %7 0 %8 1 %9
  1997. %8 = OpLabel
  1998. OpBranch %10
  1999. %9 = OpLabel
  2000. OpBranch %10
  2001. %10 = OpLabel
  2002. OpReturn
  2003. %7 = OpLabel
  2004. OpReturn
  2005. OpFunctionEnd
  2006. )";
  2007. CompileSuccessfully(text);
  2008. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2009. EXPECT_THAT(
  2010. getDiagnosticString(),
  2011. HasSubstr("Case construct that targets '8[%8]' has invalid branch "
  2012. "to block '10[%10]' (not another case construct, "
  2013. "corresponding merge, outer loop merge or outer loop "
  2014. "continue)"));
  2015. }
  2016. TEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) {
  2017. const std::string text = R"(
  2018. OpCapability Shader
  2019. OpMemoryModel Logical GLSL450
  2020. OpEntryPoint Fragment %func "func"
  2021. OpExecutionMode %func OriginUpperLeft
  2022. %void = OpTypeVoid
  2023. %bool = OpTypeBool
  2024. %true = OpConstantTrue %bool
  2025. %int = OpTypeInt 32 0
  2026. %int0 = OpConstant %int 0
  2027. %func_ty = OpTypeFunction %void
  2028. %func = OpFunction %void None %func_ty
  2029. %1 = OpLabel
  2030. OpBranch %2
  2031. %2 = OpLabel
  2032. OpLoopMerge %7 %6 None
  2033. OpBranch %3
  2034. %3 = OpLabel
  2035. OpSelectionMerge %5 None
  2036. OpSwitch %int0 %5 0 %4
  2037. %4 = OpLabel
  2038. OpBranchConditional %true %6 %7
  2039. %5 = OpLabel
  2040. OpBranchConditional %true %6 %7
  2041. %6 = OpLabel
  2042. OpBranch %2
  2043. %7 = OpLabel
  2044. OpReturn
  2045. OpFunctionEnd
  2046. )";
  2047. CompileSuccessfully(text);
  2048. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  2049. }
  2050. TEST_F(ValidateCFG, SwitchCaseOrderingBad1) {
  2051. const std::string text = R"(
  2052. OpCapability Shader
  2053. OpCapability Linkage
  2054. OpMemoryModel Logical GLSL450
  2055. OpName %default "default"
  2056. OpName %other "other"
  2057. %void = OpTypeVoid
  2058. %int = OpTypeInt 32 0
  2059. %undef = OpUndef %int
  2060. %void_fn = OpTypeFunction %void
  2061. %func = OpFunction %void None %void_fn
  2062. %entry = OpLabel
  2063. OpSelectionMerge %merge None
  2064. OpSwitch %undef %default 0 %other 1 %default
  2065. %default = OpLabel
  2066. OpBranch %other
  2067. %other = OpLabel
  2068. OpBranch %merge
  2069. %merge = OpLabel
  2070. OpReturn
  2071. OpFunctionEnd
  2072. )";
  2073. CompileSuccessfully(text);
  2074. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2075. EXPECT_THAT(
  2076. getDiagnosticString(),
  2077. HasSubstr("Case construct that targets '1[%default]' has branches to the "
  2078. "case construct that targets '2[%other]', but does not "
  2079. "immediately precede it in the OpSwitch's target list"));
  2080. }
  2081. TEST_F(ValidateCFG, SwitchCaseOrderingBad2) {
  2082. const std::string text = R"(
  2083. OpCapability Shader
  2084. OpCapability Linkage
  2085. OpMemoryModel Logical GLSL450
  2086. OpName %default "default"
  2087. OpName %other "other"
  2088. %void = OpTypeVoid
  2089. %int = OpTypeInt 32 0
  2090. %undef = OpUndef %int
  2091. %void_fn = OpTypeFunction %void
  2092. %func = OpFunction %void None %void_fn
  2093. %entry = OpLabel
  2094. OpSelectionMerge %merge None
  2095. OpSwitch %undef %default 0 %default 1 %other
  2096. %other = OpLabel
  2097. OpBranch %default
  2098. %default = OpLabel
  2099. OpBranch %merge
  2100. %merge = OpLabel
  2101. OpReturn
  2102. OpFunctionEnd
  2103. )";
  2104. CompileSuccessfully(text);
  2105. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2106. EXPECT_THAT(
  2107. getDiagnosticString(),
  2108. HasSubstr("Case construct that targets '2[%other]' has branches to the "
  2109. "case construct that targets '1[%default]', but does not "
  2110. "immediately precede it in the OpSwitch's target list"));
  2111. }
  2112. TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughGood) {
  2113. const std::string text = R"(
  2114. OpCapability Shader
  2115. OpCapability Linkage
  2116. OpMemoryModel Logical GLSL450
  2117. OpName %first "first"
  2118. OpName %second "second"
  2119. OpName %third "third"
  2120. %void = OpTypeVoid
  2121. %int = OpTypeInt 32 0
  2122. %undef = OpUndef %int
  2123. %void_fn = OpTypeFunction %void
  2124. %func = OpFunction %void None %void_fn
  2125. %entry = OpLabel
  2126. OpSelectionMerge %merge None
  2127. OpSwitch %undef %second 0 %first 1 %second 2 %third
  2128. %first = OpLabel
  2129. OpBranch %second
  2130. %second = OpLabel
  2131. OpBranch %third
  2132. %third = OpLabel
  2133. OpBranch %merge
  2134. %merge = OpLabel
  2135. OpReturn
  2136. OpFunctionEnd
  2137. )";
  2138. CompileSuccessfully(text);
  2139. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2140. }
  2141. TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughBad) {
  2142. const std::string text = R"(
  2143. OpCapability Shader
  2144. OpCapability Linkage
  2145. OpMemoryModel Logical GLSL450
  2146. OpName %first "first"
  2147. OpName %second "second"
  2148. OpName %third "third"
  2149. %void = OpTypeVoid
  2150. %int = OpTypeInt 32 0
  2151. %undef = OpUndef %int
  2152. %void_fn = OpTypeFunction %void
  2153. %func = OpFunction %void None %void_fn
  2154. %entry = OpLabel
  2155. OpSelectionMerge %merge None
  2156. OpSwitch %undef %second 0 %second 1 %first 2 %third
  2157. %first = OpLabel
  2158. OpBranch %second
  2159. %second = OpLabel
  2160. OpBranch %third
  2161. %third = OpLabel
  2162. OpBranch %merge
  2163. %merge = OpLabel
  2164. OpReturn
  2165. OpFunctionEnd
  2166. )";
  2167. CompileSuccessfully(text);
  2168. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2169. }
  2170. TEST_F(ValidateCFG, GoodUnreachableSelection) {
  2171. const std::string text = R"(
  2172. OpCapability Shader
  2173. %1 = OpExtInstImport "GLSL.std.450"
  2174. OpMemoryModel Logical GLSL450
  2175. OpEntryPoint Fragment %main "main"
  2176. OpExecutionMode %main OriginUpperLeft
  2177. %void = OpTypeVoid
  2178. %8 = OpTypeFunction %void
  2179. %bool = OpTypeBool
  2180. %false = OpConstantFalse %bool
  2181. %main = OpFunction %void None %8
  2182. %15 = OpLabel
  2183. OpBranch %16
  2184. %16 = OpLabel
  2185. OpLoopMerge %17 %18 None
  2186. OpBranch %19
  2187. %19 = OpLabel
  2188. OpBranchConditional %false %21 %17
  2189. %21 = OpLabel
  2190. OpSelectionMerge %22 None
  2191. OpBranchConditional %false %23 %22
  2192. %23 = OpLabel
  2193. OpBranch %24
  2194. %24 = OpLabel
  2195. OpLoopMerge %25 %26 None
  2196. OpBranch %27
  2197. %27 = OpLabel
  2198. OpReturn
  2199. %26 = OpLabel
  2200. OpBranchConditional %false %24 %25
  2201. %25 = OpLabel
  2202. OpSelectionMerge %28 None
  2203. OpBranchConditional %false %18 %28
  2204. %28 = OpLabel
  2205. OpBranch %22
  2206. %22 = OpLabel
  2207. OpBranch %18
  2208. %18 = OpLabel
  2209. OpBranch %16
  2210. %17 = OpLabel
  2211. OpReturn
  2212. OpFunctionEnd
  2213. )";
  2214. CompileSuccessfully(text);
  2215. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  2216. }
  2217. TEST_F(ValidateCFG, ShaderWithPhiPtr) {
  2218. const std::string text = R"(
  2219. OpCapability Shader
  2220. OpMemoryModel Logical GLSL450
  2221. OpEntryPoint GLCompute %1 "main"
  2222. OpExecutionMode %1 LocalSize 1 1 1
  2223. OpSource HLSL 600
  2224. %bool = OpTypeBool
  2225. %_ptr_Function_bool = OpTypePointer Function %bool
  2226. %void = OpTypeVoid
  2227. %5 = OpTypeFunction %void
  2228. %1 = OpFunction %void None %5
  2229. %6 = OpLabel
  2230. %7 = OpVariable %_ptr_Function_bool Function
  2231. %8 = OpVariable %_ptr_Function_bool Function
  2232. %9 = OpUndef %bool
  2233. OpSelectionMerge %10 None
  2234. OpBranchConditional %9 %11 %10
  2235. %11 = OpLabel
  2236. OpBranch %10
  2237. %10 = OpLabel
  2238. %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11
  2239. OpReturn
  2240. OpFunctionEnd
  2241. )";
  2242. CompileSuccessfully(text);
  2243. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  2244. EXPECT_THAT(getDiagnosticString(),
  2245. HasSubstr("Using pointers with OpPhi requires capability "
  2246. "VariablePointers or VariablePointersStorageBuffer"));
  2247. }
  2248. TEST_F(ValidateCFG, VarPtrShaderWithPhiPtr) {
  2249. const std::string text = R"(
  2250. OpCapability Shader
  2251. OpCapability VariablePointers
  2252. OpExtension "SPV_KHR_variable_pointers"
  2253. OpMemoryModel Logical GLSL450
  2254. OpEntryPoint GLCompute %1 "main"
  2255. OpExecutionMode %1 LocalSize 1 1 1
  2256. OpSource HLSL 600
  2257. %bool = OpTypeBool
  2258. %_ptr_Function_bool = OpTypePointer Function %bool
  2259. %void = OpTypeVoid
  2260. %5 = OpTypeFunction %void
  2261. %1 = OpFunction %void None %5
  2262. %6 = OpLabel
  2263. %7 = OpVariable %_ptr_Function_bool Function
  2264. %8 = OpVariable %_ptr_Function_bool Function
  2265. %9 = OpUndef %bool
  2266. OpSelectionMerge %10 None
  2267. OpBranchConditional %9 %11 %10
  2268. %11 = OpLabel
  2269. OpBranch %10
  2270. %10 = OpLabel
  2271. %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11
  2272. OpReturn
  2273. OpFunctionEnd
  2274. )";
  2275. CompileSuccessfully(text);
  2276. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2277. }
  2278. TEST_F(ValidateCFG, VarPtrStgBufShaderWithPhiStgBufPtr) {
  2279. const std::string text = R"(
  2280. OpCapability Shader
  2281. OpCapability VariablePointersStorageBuffer
  2282. OpExtension "SPV_KHR_variable_pointers"
  2283. OpMemoryModel Logical GLSL450
  2284. OpEntryPoint GLCompute %1 "main"
  2285. OpExecutionMode %1 LocalSize 1 1 1
  2286. OpSource HLSL 600
  2287. %bool = OpTypeBool
  2288. %float = OpTypeFloat 32
  2289. %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
  2290. %7 = OpVariable %_ptr_StorageBuffer_float StorageBuffer
  2291. %8 = OpVariable %_ptr_StorageBuffer_float StorageBuffer
  2292. %void = OpTypeVoid
  2293. %5 = OpTypeFunction %void
  2294. %1 = OpFunction %void None %5
  2295. %6 = OpLabel
  2296. %9 = OpUndef %bool
  2297. OpSelectionMerge %10 None
  2298. OpBranchConditional %9 %11 %10
  2299. %11 = OpLabel
  2300. OpBranch %10
  2301. %10 = OpLabel
  2302. %12 = OpPhi %_ptr_StorageBuffer_float %7 %6 %8 %11
  2303. OpReturn
  2304. OpFunctionEnd
  2305. )";
  2306. CompileSuccessfully(text);
  2307. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2308. }
  2309. TEST_F(ValidateCFG, KernelWithPhiPtr) {
  2310. const std::string text = R"(
  2311. OpCapability Kernel
  2312. OpCapability Addresses
  2313. OpMemoryModel Physical32 OpenCL
  2314. OpEntryPoint Kernel %1 "main"
  2315. OpExecutionMode %1 LocalSize 1 1 1
  2316. OpSource HLSL 600
  2317. %bool = OpTypeBool
  2318. %_ptr_Function_bool = OpTypePointer Function %bool
  2319. %void = OpTypeVoid
  2320. %5 = OpTypeFunction %void
  2321. %1 = OpFunction %void None %5
  2322. %6 = OpLabel
  2323. %7 = OpVariable %_ptr_Function_bool Function
  2324. %8 = OpVariable %_ptr_Function_bool Function
  2325. %9 = OpUndef %bool
  2326. OpSelectionMerge %10 None
  2327. OpBranchConditional %9 %11 %10
  2328. %11 = OpLabel
  2329. OpBranch %10
  2330. %10 = OpLabel
  2331. %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11
  2332. OpReturn
  2333. OpFunctionEnd
  2334. )";
  2335. CompileSuccessfully(text);
  2336. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2337. }
  2338. TEST_F(ValidateCFG, SwitchTargetMustBeLabel) {
  2339. const std::string text = R"(
  2340. OpCapability Shader
  2341. OpMemoryModel Logical GLSL450
  2342. OpEntryPoint GLCompute %1 "foo"
  2343. %uint = OpTypeInt 32 0
  2344. %uint_0 = OpConstant %uint 0
  2345. %void = OpTypeVoid
  2346. %5 = OpTypeFunction %void
  2347. %1 = OpFunction %void None %5
  2348. %6 = OpLabel
  2349. %7 = OpCopyObject %uint %uint_0
  2350. OpSelectionMerge %8 None
  2351. OpSwitch %uint_0 %8 0 %7
  2352. %8 = OpLabel
  2353. OpReturn
  2354. OpFunctionEnd
  2355. )";
  2356. CompileSuccessfully(text);
  2357. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2358. EXPECT_THAT(getDiagnosticString(),
  2359. HasSubstr("'Target Label' operands for OpSwitch must "
  2360. "be IDs of an OpLabel instruction"));
  2361. }
  2362. TEST_F(ValidateCFG, BranchTargetMustBeLabel) {
  2363. const std::string text = R"(
  2364. OpCapability Shader
  2365. OpMemoryModel Logical GLSL450
  2366. OpEntryPoint GLCompute %1 "foo"
  2367. %uint = OpTypeInt 32 0
  2368. %uint_0 = OpConstant %uint 0
  2369. %void = OpTypeVoid
  2370. %5 = OpTypeFunction %void
  2371. %1 = OpFunction %void None %5
  2372. %2 = OpLabel
  2373. %7 = OpCopyObject %uint %uint_0
  2374. OpBranch %7
  2375. %8 = OpLabel
  2376. OpReturn
  2377. OpFunctionEnd
  2378. )";
  2379. CompileSuccessfully(text);
  2380. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2381. EXPECT_THAT(getDiagnosticString(),
  2382. HasSubstr("'Target Label' operands for OpBranch must "
  2383. "be the ID of an OpLabel instruction"));
  2384. }
  2385. TEST_F(ValidateCFG, ReachableOpUnreachableOneBlock) {
  2386. const std::string text = R"(
  2387. OpCapability Shader
  2388. OpCapability Linkage
  2389. OpMemoryModel Logical GLSL450
  2390. %void = OpTypeVoid
  2391. %void_fn = OpTypeFunction %void
  2392. %func = OpFunction %void None %void_fn
  2393. %entry = OpLabel
  2394. OpUnreachable
  2395. OpFunctionEnd
  2396. )";
  2397. CompileSuccessfully(text);
  2398. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2399. }
  2400. TEST_F(ValidateCFG, ReachableOpUnreachableOpBranch) {
  2401. const std::string text = R"(
  2402. OpCapability Shader
  2403. OpCapability Linkage
  2404. OpMemoryModel Logical GLSL450
  2405. %void = OpTypeVoid
  2406. %void_fn = OpTypeFunction %void
  2407. %func = OpFunction %void None %void_fn
  2408. %entry = OpLabel
  2409. OpBranch %block
  2410. %block = OpLabel
  2411. OpUnreachable
  2412. OpFunctionEnd
  2413. )";
  2414. CompileSuccessfully(text);
  2415. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2416. }
  2417. TEST_F(ValidateCFG, ReachableOpUnreachableOpBranchConditional) {
  2418. const std::string text = R"(
  2419. OpCapability Shader
  2420. OpCapability Linkage
  2421. OpMemoryModel Logical GLSL450
  2422. %void = OpTypeVoid
  2423. %void_fn = OpTypeFunction %void
  2424. %bool = OpTypeBool
  2425. %undef = OpUndef %bool
  2426. %func = OpFunction %void None %void_fn
  2427. %entry = OpLabel
  2428. OpSelectionMerge %block None
  2429. OpBranchConditional %undef %block %unreachable
  2430. %block = OpLabel
  2431. OpReturn
  2432. %unreachable = OpLabel
  2433. OpUnreachable
  2434. OpFunctionEnd
  2435. )";
  2436. CompileSuccessfully(text);
  2437. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2438. }
  2439. TEST_F(ValidateCFG, ReachableOpUnreachableOpSwitch) {
  2440. const std::string text = R"(
  2441. OpCapability Shader
  2442. OpCapability Linkage
  2443. OpMemoryModel Logical GLSL450
  2444. %void = OpTypeVoid
  2445. %void_fn = OpTypeFunction %void
  2446. %int = OpTypeInt 32 0
  2447. %undef = OpUndef %int
  2448. %func = OpFunction %void None %void_fn
  2449. %entry = OpLabel
  2450. OpSelectionMerge %block1 None
  2451. OpSwitch %undef %block1 0 %unreachable 1 %block2
  2452. %block1 = OpLabel
  2453. OpReturn
  2454. %unreachable = OpLabel
  2455. OpUnreachable
  2456. %block2 = OpLabel
  2457. OpReturn
  2458. OpFunctionEnd
  2459. )";
  2460. CompileSuccessfully(text);
  2461. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2462. }
  2463. TEST_F(ValidateCFG, ReachableOpUnreachableLoop) {
  2464. const std::string text = R"(
  2465. OpCapability Shader
  2466. OpCapability Linkage
  2467. OpMemoryModel Logical GLSL450
  2468. %void = OpTypeVoid
  2469. %void_fn = OpTypeFunction %void
  2470. %bool = OpTypeBool
  2471. %undef = OpUndef %bool
  2472. %func = OpFunction %void None %void_fn
  2473. %entry = OpLabel
  2474. OpBranch %loop
  2475. %loop = OpLabel
  2476. OpLoopMerge %unreachable %loop None
  2477. OpBranchConditional %undef %loop %unreachable
  2478. %unreachable = OpLabel
  2479. OpUnreachable
  2480. OpFunctionEnd
  2481. )";
  2482. CompileSuccessfully(text);
  2483. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2484. }
  2485. TEST_F(ValidateCFG, UnreachableLoopBadBackedge) {
  2486. const std::string text = R"(
  2487. OpCapability Shader
  2488. OpMemoryModel Logical GLSL450
  2489. OpEntryPoint Fragment %2 "main"
  2490. OpExecutionMode %2 OriginUpperLeft
  2491. %4 = OpTypeVoid
  2492. %5 = OpTypeFunction %4
  2493. %8 = OpTypeBool
  2494. %13 = OpConstantTrue %8
  2495. %2 = OpFunction %4 None %5
  2496. %14 = OpLabel
  2497. OpSelectionMerge %15 None
  2498. OpBranchConditional %13 %15 %15
  2499. %16 = OpLabel
  2500. OpLoopMerge %17 %18 None
  2501. OpBranch %17
  2502. %18 = OpLabel
  2503. OpBranch %17
  2504. %17 = OpLabel
  2505. OpBranch %15
  2506. %15 = OpLabel
  2507. OpReturn
  2508. OpFunctionEnd
  2509. )";
  2510. // The back-edge in this test is bad, but the validator fails to identify it
  2511. // because it is in an entirely unreachable section of code. Prior to #2488
  2512. // this code failed an assert in Construct::blocks().
  2513. CompileSuccessfully(text);
  2514. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2515. }
  2516. TEST_F(ValidateCFG, OneContinueTwoBackedges) {
  2517. const std::string text = R"(
  2518. OpCapability Shader
  2519. OpMemoryModel Logical GLSL450
  2520. OpEntryPoint GLCompute %1 "main"
  2521. OpExecutionMode %1 LocalSize 1 1 1
  2522. %void = OpTypeVoid
  2523. %bool = OpTypeBool
  2524. %true = OpConstantTrue %bool
  2525. %5 = OpTypeFunction %void
  2526. %1 = OpFunction %void None %5
  2527. %6 = OpLabel
  2528. OpBranch %7
  2529. %7 = OpLabel
  2530. OpLoopMerge %8 %9 None
  2531. OpBranch %10
  2532. %10 = OpLabel
  2533. OpLoopMerge %11 %9 None
  2534. OpBranchConditional %true %11 %9
  2535. %9 = OpLabel
  2536. OpBranchConditional %true %10 %7
  2537. %11 = OpLabel
  2538. OpBranch %8
  2539. %8 = OpLabel
  2540. OpReturn
  2541. OpFunctionEnd
  2542. )";
  2543. CompileSuccessfully(text);
  2544. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2545. EXPECT_THAT(getDiagnosticString(),
  2546. HasSubstr("Back-edges ('10[%10]' -> '9[%9]') can only be formed "
  2547. "between a block and a loop header"));
  2548. }
  2549. TEST_F(ValidateCFG, LoopMergeMergeBlockNotLabel) {
  2550. const std::string text = R"(
  2551. OpCapability Shader
  2552. OpCapability Linkage
  2553. OpMemoryModel Logical GLSL450
  2554. OpName %undef "undef"
  2555. %void = OpTypeVoid
  2556. %bool = OpTypeBool
  2557. %undef = OpUndef %bool
  2558. %void_fn = OpTypeFunction %void
  2559. %func = OpFunction %void None %void_fn
  2560. %1 = OpLabel
  2561. OpLoopMerge %undef %2 None
  2562. OpBranchConditional %undef %2 %2
  2563. %2 = OpLabel
  2564. OpReturn
  2565. OpFunctionEnd
  2566. )";
  2567. CompileSuccessfully(text);
  2568. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2569. EXPECT_THAT(getDiagnosticString(),
  2570. HasSubstr("Merge Block '1[%undef]' must be an OpLabel"));
  2571. }
  2572. TEST_F(ValidateCFG, LoopMergeContinueTargetNotLabel) {
  2573. const std::string text = R"(
  2574. OpCapability Shader
  2575. OpCapability Linkage
  2576. OpMemoryModel Logical GLSL450
  2577. OpName %undef "undef"
  2578. %void = OpTypeVoid
  2579. %bool = OpTypeBool
  2580. %undef = OpUndef %bool
  2581. %void_fn = OpTypeFunction %void
  2582. %func = OpFunction %void None %void_fn
  2583. %1 = OpLabel
  2584. OpLoopMerge %2 %undef None
  2585. OpBranchConditional %undef %2 %2
  2586. %2 = OpLabel
  2587. OpReturn
  2588. OpFunctionEnd
  2589. )";
  2590. CompileSuccessfully(text);
  2591. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2592. EXPECT_THAT(getDiagnosticString(),
  2593. HasSubstr("Continue Target '1[%undef]' must be an OpLabel"));
  2594. }
  2595. TEST_F(ValidateCFG, LoopMergeMergeBlockContinueTargetSameLabel) {
  2596. const std::string text = R"(
  2597. OpCapability Shader
  2598. OpCapability Linkage
  2599. OpMemoryModel Logical GLSL450
  2600. OpName %undef "undef"
  2601. %void = OpTypeVoid
  2602. %bool = OpTypeBool
  2603. %undef = OpUndef %bool
  2604. %void_fn = OpTypeFunction %void
  2605. %func = OpFunction %void None %void_fn
  2606. %1 = OpLabel
  2607. OpLoopMerge %2 %2 None
  2608. OpBranchConditional %undef %2 %2
  2609. %2 = OpLabel
  2610. OpReturn
  2611. OpFunctionEnd
  2612. )";
  2613. CompileSuccessfully(text);
  2614. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2615. EXPECT_THAT(
  2616. getDiagnosticString(),
  2617. HasSubstr("Merge Block and Continue Target must be different ids"));
  2618. }
  2619. TEST_F(ValidateCFG, LoopMergeUnrollAndDontUnroll) {
  2620. const std::string text = R"(
  2621. OpCapability Shader
  2622. OpCapability Linkage
  2623. OpMemoryModel Logical GLSL450
  2624. OpName %undef "undef"
  2625. %void = OpTypeVoid
  2626. %bool = OpTypeBool
  2627. %undef = OpUndef %bool
  2628. %void_fn = OpTypeFunction %void
  2629. %func = OpFunction %void None %void_fn
  2630. %5 = OpLabel
  2631. OpBranch %1
  2632. %1 = OpLabel
  2633. OpLoopMerge %2 %3 Unroll|DontUnroll
  2634. OpBranchConditional %undef %2 %3
  2635. %3 = OpLabel
  2636. OpBranch %1
  2637. %2 = OpLabel
  2638. OpReturn
  2639. OpFunctionEnd
  2640. )";
  2641. CompileSuccessfully(text);
  2642. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  2643. EXPECT_THAT(
  2644. getDiagnosticString(),
  2645. HasSubstr(
  2646. "Unroll and DontUnroll loop controls must not both be specified"));
  2647. }
  2648. TEST_F(ValidateCFG, LoopMergePeelCountAndDontUnroll) {
  2649. const std::string text = R"(
  2650. OpCapability Shader
  2651. OpCapability Linkage
  2652. OpMemoryModel Logical GLSL450
  2653. OpName %undef "undef"
  2654. %void = OpTypeVoid
  2655. %bool = OpTypeBool
  2656. %undef = OpUndef %bool
  2657. %void_fn = OpTypeFunction %void
  2658. %func = OpFunction %void None %void_fn
  2659. %5 = OpLabel
  2660. OpBranch %1
  2661. %1 = OpLabel
  2662. OpLoopMerge %2 %3 DontUnroll|PeelCount 1
  2663. OpBranchConditional %undef %2 %3
  2664. %3 = OpLabel
  2665. OpBranch %1
  2666. %2 = OpLabel
  2667. OpReturn
  2668. OpFunctionEnd
  2669. )";
  2670. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2671. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2672. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2673. EXPECT_THAT(
  2674. getDiagnosticString(),
  2675. HasSubstr(
  2676. "PeelCount and DontUnroll loop controls must not both be specified"));
  2677. }
  2678. TEST_F(ValidateCFG, LoopMergePartialCountAndDontUnroll) {
  2679. const std::string text = R"(
  2680. OpCapability Shader
  2681. OpCapability Linkage
  2682. OpMemoryModel Logical GLSL450
  2683. OpName %undef "undef"
  2684. %void = OpTypeVoid
  2685. %bool = OpTypeBool
  2686. %undef = OpUndef %bool
  2687. %void_fn = OpTypeFunction %void
  2688. %func = OpFunction %void None %void_fn
  2689. %5 = OpLabel
  2690. OpBranch %1
  2691. %1 = OpLabel
  2692. OpLoopMerge %2 %3 DontUnroll|PartialCount 1
  2693. OpBranchConditional %undef %2 %3
  2694. %3 = OpLabel
  2695. OpBranch %1
  2696. %2 = OpLabel
  2697. OpReturn
  2698. OpFunctionEnd
  2699. )";
  2700. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2701. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2702. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2703. EXPECT_THAT(getDiagnosticString(),
  2704. HasSubstr("PartialCount and DontUnroll loop controls must not "
  2705. "both be specified"));
  2706. }
  2707. TEST_F(ValidateCFG, LoopMergeIterationMultipleZero) {
  2708. const std::string text = R"(
  2709. OpCapability Shader
  2710. OpCapability Linkage
  2711. OpMemoryModel Logical GLSL450
  2712. OpName %undef "undef"
  2713. %void = OpTypeVoid
  2714. %bool = OpTypeBool
  2715. %undef = OpUndef %bool
  2716. %void_fn = OpTypeFunction %void
  2717. %func = OpFunction %void None %void_fn
  2718. %5 = OpLabel
  2719. OpBranch %1
  2720. %1 = OpLabel
  2721. OpLoopMerge %2 %3 IterationMultiple 0
  2722. OpBranchConditional %undef %2 %3
  2723. %3 = OpLabel
  2724. OpBranch %1
  2725. %2 = OpLabel
  2726. OpReturn
  2727. OpFunctionEnd
  2728. )";
  2729. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2730. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2731. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2732. EXPECT_THAT(
  2733. getDiagnosticString(),
  2734. HasSubstr(
  2735. "IterationMultiple loop control operand must be greater than zero"));
  2736. }
  2737. TEST_F(ValidateCFG, LoopMergeIterationMultipleZeroMoreOperands) {
  2738. const std::string text = R"(
  2739. OpCapability Shader
  2740. OpCapability Linkage
  2741. OpMemoryModel Logical GLSL450
  2742. OpName %undef "undef"
  2743. %void = OpTypeVoid
  2744. %bool = OpTypeBool
  2745. %undef = OpUndef %bool
  2746. %void_fn = OpTypeFunction %void
  2747. %func = OpFunction %void None %void_fn
  2748. %5 = OpLabel
  2749. OpBranch %1
  2750. %1 = OpLabel
  2751. OpLoopMerge %2 %3 MaxIterations|IterationMultiple 4 0
  2752. OpBranchConditional %undef %2 %3
  2753. %3 = OpLabel
  2754. OpBranch %1
  2755. %2 = OpLabel
  2756. OpReturn
  2757. OpFunctionEnd
  2758. )";
  2759. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2760. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2761. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2762. EXPECT_THAT(
  2763. getDiagnosticString(),
  2764. HasSubstr(
  2765. "IterationMultiple loop control operand must be greater than zero"));
  2766. }
  2767. TEST_F(ValidateCFG, LoopMergeTargetsHeader) {
  2768. const std::string text = R"(
  2769. OpCapability Shader
  2770. OpCapability Linkage
  2771. OpMemoryModel Logical GLSL450
  2772. %void = OpTypeVoid
  2773. %bool = OpTypeBool
  2774. %undef = OpUndef %bool
  2775. %void_fn = OpTypeFunction %void
  2776. %fn = OpFunction %void None %void_fn
  2777. %entry = OpLabel
  2778. OpBranch %loop
  2779. %loop = OpLabel
  2780. OpLoopMerge %loop %continue None
  2781. OpBranch %body
  2782. %continue = OpLabel
  2783. OpBranch %loop
  2784. %body = OpLabel
  2785. OpReturn
  2786. OpFunctionEnd
  2787. )";
  2788. CompileSuccessfully(text);
  2789. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2790. EXPECT_THAT(
  2791. getDiagnosticString(),
  2792. HasSubstr("Merge Block may not be the block containing the OpLoopMerge"));
  2793. }
  2794. TEST_F(ValidateCFG, InvalidSelectionExit) {
  2795. const std::string text = R"(
  2796. OpCapability Shader
  2797. OpMemoryModel Logical GLSL450
  2798. OpEntryPoint Fragment %1 "main"
  2799. OpExecutionMode %1 OriginUpperLeft
  2800. %2 = OpTypeVoid
  2801. %3 = OpTypeBool
  2802. %4 = OpConstantTrue %3
  2803. %5 = OpTypeFunction %2
  2804. %1 = OpFunction %2 None %5
  2805. %6 = OpLabel
  2806. OpSelectionMerge %7 None
  2807. OpBranchConditional %4 %7 %8
  2808. %8 = OpLabel
  2809. OpSelectionMerge %9 None
  2810. OpBranchConditional %4 %10 %9
  2811. %10 = OpLabel
  2812. OpBranch %7
  2813. %9 = OpLabel
  2814. OpBranch %7
  2815. %7 = OpLabel
  2816. OpReturn
  2817. OpFunctionEnd
  2818. )";
  2819. CompileSuccessfully(text);
  2820. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2821. EXPECT_THAT(
  2822. getDiagnosticString(),
  2823. HasSubstr("block <ID> '10[%10]' exits the selection headed by <ID> "
  2824. "'8[%8]', but not via a structured exit"));
  2825. }
  2826. TEST_F(ValidateCFG, InvalidLoopExit) {
  2827. const std::string text = R"(
  2828. OpCapability Shader
  2829. OpMemoryModel Logical GLSL450
  2830. OpEntryPoint Fragment %1 "main"
  2831. OpExecutionMode %1 OriginUpperLeft
  2832. %2 = OpTypeVoid
  2833. %3 = OpTypeBool
  2834. %4 = OpConstantTrue %3
  2835. %5 = OpTypeFunction %2
  2836. %1 = OpFunction %2 None %5
  2837. %6 = OpLabel
  2838. OpSelectionMerge %7 None
  2839. OpBranchConditional %4 %7 %8
  2840. %8 = OpLabel
  2841. OpLoopMerge %9 %10 None
  2842. OpBranchConditional %4 %9 %11
  2843. %11 = OpLabel
  2844. OpBranchConditional %4 %7 %10
  2845. %10 = OpLabel
  2846. OpBranch %8
  2847. %9 = OpLabel
  2848. OpBranch %7
  2849. %7 = OpLabel
  2850. OpReturn
  2851. OpFunctionEnd
  2852. )";
  2853. CompileSuccessfully(text);
  2854. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2855. EXPECT_THAT(getDiagnosticString(),
  2856. HasSubstr("block <ID> '11[%11]' exits the loop headed by <ID> "
  2857. "'8[%8]', but not via a structured exit"));
  2858. }
  2859. TEST_F(ValidateCFG, InvalidContinueExit) {
  2860. const std::string text = R"(
  2861. OpCapability Shader
  2862. OpMemoryModel Logical GLSL450
  2863. OpEntryPoint Fragment %1 "main"
  2864. OpExecutionMode %1 OriginUpperLeft
  2865. %2 = OpTypeVoid
  2866. %3 = OpTypeBool
  2867. %4 = OpConstantTrue %3
  2868. %5 = OpTypeFunction %2
  2869. %1 = OpFunction %2 None %5
  2870. %6 = OpLabel
  2871. OpSelectionMerge %7 None
  2872. OpBranchConditional %4 %7 %8
  2873. %8 = OpLabel
  2874. OpLoopMerge %9 %10 None
  2875. OpBranchConditional %4 %9 %10
  2876. %10 = OpLabel
  2877. OpBranch %11
  2878. %11 = OpLabel
  2879. OpBranchConditional %4 %8 %7
  2880. %9 = OpLabel
  2881. OpBranch %7
  2882. %7 = OpLabel
  2883. OpReturn
  2884. OpFunctionEnd
  2885. )";
  2886. CompileSuccessfully(text);
  2887. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2888. EXPECT_THAT(
  2889. getDiagnosticString(),
  2890. HasSubstr("block <ID> '11[%11]' exits the continue headed by <ID> "
  2891. "'10[%10]', but not via a structured exit"));
  2892. }
  2893. TEST_F(ValidateCFG, InvalidSelectionExitBackedge) {
  2894. const std::string text = R"(
  2895. OpCapability Shader
  2896. OpCapability Linkage
  2897. OpMemoryModel Logical GLSL450
  2898. %1 = OpTypeVoid
  2899. %2 = OpTypeBool
  2900. %3 = OpUndef %2
  2901. %4 = OpTypeFunction %1
  2902. %5 = OpFunction %1 None %4
  2903. %6 = OpLabel
  2904. OpBranch %7
  2905. %7 = OpLabel
  2906. OpLoopMerge %8 %9 None
  2907. OpBranchConditional %3 %8 %9
  2908. %9 = OpLabel
  2909. OpSelectionMerge %10 None
  2910. OpBranchConditional %3 %11 %12
  2911. %11 = OpLabel
  2912. OpBranch %13
  2913. %12 = OpLabel
  2914. OpBranch %13
  2915. %13 = OpLabel
  2916. OpBranch %7
  2917. %10 = OpLabel
  2918. OpUnreachable
  2919. %8 = OpLabel
  2920. OpReturn
  2921. OpFunctionEnd
  2922. )";
  2923. CompileSuccessfully(text);
  2924. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2925. EXPECT_THAT(
  2926. getDiagnosticString(),
  2927. HasSubstr(
  2928. "The continue construct with the continue target '9[%9]' is not "
  2929. "structurally post dominated by the back-edge block '13[%13]'"));
  2930. }
  2931. TEST_F(ValidateCFG, BreakFromSwitch) {
  2932. const std::string text = R"(
  2933. OpCapability Shader
  2934. OpCapability Linkage
  2935. OpMemoryModel Logical GLSL450
  2936. %1 = OpTypeVoid
  2937. %2 = OpTypeBool
  2938. %3 = OpTypeInt 32 0
  2939. %4 = OpUndef %2
  2940. %5 = OpUndef %3
  2941. %6 = OpTypeFunction %1
  2942. %7 = OpFunction %1 None %6
  2943. %8 = OpLabel
  2944. OpSelectionMerge %9 None
  2945. OpSwitch %5 %9 0 %10
  2946. %10 = OpLabel
  2947. OpSelectionMerge %11 None
  2948. OpBranchConditional %4 %11 %12
  2949. %12 = OpLabel
  2950. OpBranch %9
  2951. %11 = OpLabel
  2952. OpBranch %9
  2953. %9 = OpLabel
  2954. OpReturn
  2955. OpFunctionEnd
  2956. )";
  2957. CompileSuccessfully(text);
  2958. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2959. }
  2960. TEST_F(ValidateCFG, InvalidBreakFromSwitch) {
  2961. const std::string text = R"(
  2962. OpCapability Shader
  2963. OpCapability Linkage
  2964. OpMemoryModel Logical GLSL450
  2965. %1 = OpTypeVoid
  2966. %2 = OpTypeBool
  2967. %3 = OpTypeInt 32 0
  2968. %4 = OpUndef %2
  2969. %5 = OpUndef %3
  2970. %6 = OpTypeFunction %1
  2971. %7 = OpFunction %1 None %6
  2972. %8 = OpLabel
  2973. OpSelectionMerge %9 None
  2974. OpSwitch %5 %9 0 %10
  2975. %10 = OpLabel
  2976. OpSelectionMerge %11 None
  2977. OpSwitch %5 %11 0 %12
  2978. %12 = OpLabel
  2979. OpBranch %9
  2980. %11 = OpLabel
  2981. OpBranch %9
  2982. %9 = OpLabel
  2983. OpReturn
  2984. OpFunctionEnd
  2985. )";
  2986. CompileSuccessfully(text);
  2987. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2988. EXPECT_THAT(
  2989. getDiagnosticString(),
  2990. HasSubstr("block <ID> '12[%12]' exits the selection headed by <ID> "
  2991. "'10[%10]', but not via a structured exit"));
  2992. }
  2993. TEST_F(ValidateCFG, BreakToOuterSwitch) {
  2994. const std::string text = R"(
  2995. OpCapability Shader
  2996. OpCapability Linkage
  2997. OpMemoryModel Logical GLSL450
  2998. %1 = OpTypeVoid
  2999. %2 = OpTypeBool
  3000. %3 = OpTypeInt 32 0
  3001. %4 = OpUndef %2
  3002. %5 = OpUndef %3
  3003. %6 = OpTypeFunction %1
  3004. %7 = OpFunction %1 None %6
  3005. %8 = OpLabel
  3006. OpSelectionMerge %9 None
  3007. OpSwitch %5 %9 0 %10
  3008. %10 = OpLabel
  3009. OpSelectionMerge %11 None
  3010. OpSwitch %5 %11 0 %12
  3011. %12 = OpLabel
  3012. OpSelectionMerge %13 None
  3013. OpBranchConditional %4 %13 %14
  3014. %14 = OpLabel
  3015. OpBranch %9
  3016. %13 = OpLabel
  3017. OpBranch %11
  3018. %11 = OpLabel
  3019. OpBranch %9
  3020. %9 = OpLabel
  3021. OpReturn
  3022. OpFunctionEnd
  3023. )";
  3024. CompileSuccessfully(text);
  3025. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3026. EXPECT_THAT(
  3027. getDiagnosticString(),
  3028. HasSubstr("block <ID> '14[%14]' exits the selection headed by <ID> "
  3029. "'10[%10]', but not via a structured exit"));
  3030. }
  3031. TEST_F(ValidateCFG, BreakToOuterLoop) {
  3032. const std::string text = R"(
  3033. OpCapability Shader
  3034. OpCapability Linkage
  3035. OpMemoryModel Logical GLSL450
  3036. %1 = OpTypeVoid
  3037. %2 = OpTypeBool
  3038. %3 = OpUndef %2
  3039. %4 = OpTypeFunction %1
  3040. %5 = OpFunction %1 None %4
  3041. %6 = OpLabel
  3042. OpBranch %7
  3043. %7 = OpLabel
  3044. OpLoopMerge %8 %9 None
  3045. OpBranch %10
  3046. %10 = OpLabel
  3047. OpLoopMerge %11 %12 None
  3048. OpBranch %13
  3049. %13 = OpLabel
  3050. OpSelectionMerge %14 None
  3051. OpBranchConditional %3 %14 %15
  3052. %15 = OpLabel
  3053. OpBranch %8
  3054. %14 = OpLabel
  3055. OpBranch %12
  3056. %12 = OpLabel
  3057. OpBranchConditional %3 %10 %11
  3058. %11 = OpLabel
  3059. OpBranch %9
  3060. %9 = OpLabel
  3061. OpBranchConditional %3 %7 %8
  3062. %8 = OpLabel
  3063. OpReturn
  3064. OpFunctionEnd
  3065. )";
  3066. CompileSuccessfully(text);
  3067. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3068. EXPECT_THAT(getDiagnosticString(),
  3069. HasSubstr("block <ID> '15[%15]' exits the loop headed by <ID> "
  3070. "'10[%10]', but not via a structured exit"));
  3071. }
  3072. TEST_F(ValidateCFG, ContinueFromNestedSelection) {
  3073. const std::string text = R"(
  3074. OpCapability Shader
  3075. OpCapability Linkage
  3076. OpMemoryModel Logical GLSL450
  3077. %void = OpTypeVoid
  3078. %void_fn = OpTypeFunction %void
  3079. %bool = OpTypeBool
  3080. %undef = OpUndef %bool
  3081. %4 = OpFunction %void None %void_fn
  3082. %5 = OpLabel
  3083. OpBranch %48
  3084. %48 = OpLabel
  3085. OpLoopMerge %47 %50 None
  3086. OpBranch %10
  3087. %10 = OpLabel
  3088. OpLoopMerge %12 %37 None
  3089. OpBranchConditional %undef %11 %12
  3090. %11 = OpLabel
  3091. OpSelectionMerge %31 None
  3092. OpBranchConditional %undef %30 %31
  3093. %30 = OpLabel
  3094. OpSelectionMerge %38 None
  3095. OpBranchConditional %undef %36 %38
  3096. %36 = OpLabel
  3097. OpBranch %38
  3098. %38 = OpLabel
  3099. OpBranch %37
  3100. %37 = OpLabel
  3101. OpBranch %10
  3102. %31 = OpLabel
  3103. OpBranch %12
  3104. %12 = OpLabel
  3105. OpSelectionMerge %55 None
  3106. OpBranchConditional %undef %47 %55
  3107. %55 = OpLabel
  3108. OpBranch %47
  3109. %50 = OpLabel
  3110. OpBranch %48
  3111. %47 = OpLabel
  3112. OpReturn
  3113. OpFunctionEnd
  3114. )";
  3115. CompileSuccessfully(text);
  3116. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3117. }
  3118. TEST_F(ValidateCFG, MissingMergeConditionalBranchBad) {
  3119. const std::string text = R"(
  3120. OpCapability Shader
  3121. OpCapability Linkage
  3122. OpMemoryModel Logical GLSL450
  3123. %void = OpTypeVoid
  3124. %void_fn = OpTypeFunction %void
  3125. %bool = OpTypeBool
  3126. %undef = OpUndef %bool
  3127. %func = OpFunction %void None %void_fn
  3128. %entry = OpLabel
  3129. OpBranchConditional %undef %then %else
  3130. %then = OpLabel
  3131. OpReturn
  3132. %else = OpLabel
  3133. OpReturn
  3134. OpFunctionEnd
  3135. )";
  3136. CompileSuccessfully(text);
  3137. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3138. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3139. }
  3140. TEST_F(ValidateCFG, LoopConditionalBranchWithoutExitBad) {
  3141. const std::string text = R"(
  3142. OpCapability Shader
  3143. OpCapability Linkage
  3144. OpMemoryModel Logical GLSL450
  3145. %void = OpTypeVoid
  3146. %void_fn = OpTypeFunction %void
  3147. %bool = OpTypeBool
  3148. %undef = OpUndef %bool
  3149. %func = OpFunction %void None %void_fn
  3150. %entry = OpLabel
  3151. OpBranch %loop
  3152. %loop = OpLabel
  3153. OpLoopMerge %exit %continue None
  3154. OpBranchConditional %undef %then %else
  3155. %then = OpLabel
  3156. OpBranch %continue
  3157. %else = OpLabel
  3158. OpBranch %exit
  3159. %continue = OpLabel
  3160. OpBranch %loop
  3161. %exit = OpLabel
  3162. OpReturn
  3163. OpFunctionEnd
  3164. )";
  3165. CompileSuccessfully(text);
  3166. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3167. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3168. }
  3169. TEST_F(ValidateCFG, MissingMergeSwitchBad) {
  3170. const std::string text = R"(
  3171. OpCapability Shader
  3172. OpCapability Linkage
  3173. OpMemoryModel Logical GLSL450
  3174. %void = OpTypeVoid
  3175. %void_fn = OpTypeFunction %void
  3176. %int = OpTypeInt 32 0
  3177. %undef = OpUndef %int
  3178. %func = OpFunction %void None %void_fn
  3179. %entry = OpLabel
  3180. OpSwitch %undef %then 0 %else
  3181. %then = OpLabel
  3182. OpReturn
  3183. %else = OpLabel
  3184. OpReturn
  3185. OpFunctionEnd
  3186. )";
  3187. CompileSuccessfully(text);
  3188. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3189. EXPECT_THAT(
  3190. getDiagnosticString(),
  3191. HasSubstr(
  3192. "OpSwitch must be preceded by an OpSelectionMerge instruction"));
  3193. }
  3194. TEST_F(ValidateCFG, MissingMergeSwitchBad2) {
  3195. const std::string text = R"(
  3196. OpCapability Shader
  3197. OpCapability Linkage
  3198. OpMemoryModel Logical GLSL450
  3199. %void = OpTypeVoid
  3200. %void_fn = OpTypeFunction %void
  3201. %int = OpTypeInt 32 0
  3202. %undef = OpUndef %int
  3203. %func = OpFunction %void None %void_fn
  3204. %entry = OpLabel
  3205. OpSwitch %undef %then 0 %then 1 %then 2 %else
  3206. %then = OpLabel
  3207. OpReturn
  3208. %else = OpLabel
  3209. OpReturn
  3210. OpFunctionEnd
  3211. )";
  3212. CompileSuccessfully(text);
  3213. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3214. EXPECT_THAT(
  3215. getDiagnosticString(),
  3216. HasSubstr(
  3217. "OpSwitch must be preceded by an OpSelectionMerge instruction"));
  3218. }
  3219. TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) {
  3220. const std::string text = R"(
  3221. OpCapability Shader
  3222. OpCapability Linkage
  3223. OpMemoryModel Logical GLSL450
  3224. %void = OpTypeVoid
  3225. %void_fn = OpTypeFunction %void
  3226. %bool = OpTypeBool
  3227. %undef = OpUndef %bool
  3228. %func = OpFunction %void None %void_fn
  3229. %entry = OpLabel
  3230. OpSelectionMerge %b3 None
  3231. OpBranchConditional %undef %b1 %b2
  3232. %b1 = OpLabel
  3233. OpBranchConditional %undef %b2 %b3
  3234. %b2 = OpLabel
  3235. OpBranch %b3
  3236. %b3 = OpLabel
  3237. OpReturn
  3238. OpFunctionEnd
  3239. )";
  3240. CompileSuccessfully(text);
  3241. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3242. }
  3243. TEST_F(ValidateCFG, MissingMergeSameTargetConditionalBranchGood) {
  3244. const std::string text = R"(
  3245. OpCapability Shader
  3246. OpCapability Linkage
  3247. OpMemoryModel Logical GLSL450
  3248. %void = OpTypeVoid
  3249. %void_fn = OpTypeFunction %void
  3250. %bool = OpTypeBool
  3251. %undef = OpUndef %bool
  3252. %func = OpFunction %void None %void_fn
  3253. %entry = OpLabel
  3254. OpBranchConditional %undef %then %then
  3255. %then = OpLabel
  3256. OpReturn
  3257. OpFunctionEnd
  3258. )";
  3259. CompileSuccessfully(text);
  3260. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3261. }
  3262. TEST_F(ValidateCFG, MissingMergeOneTargetSwitchBad) {
  3263. const std::string text = R"(
  3264. OpCapability Shader
  3265. OpCapability Linkage
  3266. OpMemoryModel Logical GLSL450
  3267. %void = OpTypeVoid
  3268. %void_fn = OpTypeFunction %void
  3269. %int = OpTypeInt 32 0
  3270. %undef = OpUndef %int
  3271. %func = OpFunction %void None %void_fn
  3272. %entry = OpLabel
  3273. OpSwitch %undef %then 0 %then 1 %then
  3274. %then = OpLabel
  3275. OpReturn
  3276. OpFunctionEnd
  3277. )";
  3278. CompileSuccessfully(text);
  3279. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3280. EXPECT_THAT(
  3281. getDiagnosticString(),
  3282. HasSubstr(
  3283. "OpSwitch must be preceded by an OpSelectionMerge instruction"));
  3284. }
  3285. TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchBad) {
  3286. const std::string text = R"(
  3287. OpCapability Shader
  3288. OpCapability Linkage
  3289. OpMemoryModel Logical GLSL450
  3290. %void = OpTypeVoid
  3291. %void_fn = OpTypeFunction %void
  3292. %int = OpTypeInt 32 0
  3293. %undef_int = OpUndef %int
  3294. %bool = OpTypeBool
  3295. %undef_bool = OpUndef %bool
  3296. %func = OpFunction %void None %void_fn
  3297. %entry = OpLabel
  3298. OpSelectionMerge %merge None
  3299. OpBranchConditional %undef_bool %merge %b1
  3300. %b1 = OpLabel
  3301. OpSwitch %undef_int %b2 0 %b2 1 %merge 2 %b2
  3302. %b2 = OpLabel
  3303. OpBranch %merge
  3304. %merge = OpLabel
  3305. OpReturn
  3306. OpFunctionEnd
  3307. )";
  3308. CompileSuccessfully(text);
  3309. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3310. EXPECT_THAT(
  3311. getDiagnosticString(),
  3312. HasSubstr(
  3313. "OpSwitch must be preceded by an OpSelectionMerge instruction"));
  3314. }
  3315. TEST_F(ValidateCFG, MissingMergeLoopBreakGood) {
  3316. const std::string text = R"(
  3317. OpCapability Shader
  3318. OpCapability Linkage
  3319. OpMemoryModel Logical GLSL450
  3320. %void = OpTypeVoid
  3321. %void_fn = OpTypeFunction %void
  3322. %bool = OpTypeBool
  3323. %undef = OpUndef %bool
  3324. %func = OpFunction %void None %void_fn
  3325. %entry = OpLabel
  3326. OpBranch %loop
  3327. %loop = OpLabel
  3328. OpLoopMerge %exit %continue None
  3329. OpBranch %body
  3330. %body = OpLabel
  3331. OpBranchConditional %undef %body2 %exit
  3332. %body2 = OpLabel
  3333. OpBranch %continue
  3334. %continue = OpLabel
  3335. OpBranch %loop
  3336. %exit = OpLabel
  3337. OpReturn
  3338. OpFunctionEnd
  3339. )";
  3340. CompileSuccessfully(text);
  3341. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3342. }
  3343. TEST_F(ValidateCFG, MissingMergeLoopContinueGood) {
  3344. const std::string text = R"(
  3345. OpCapability Shader
  3346. OpCapability Linkage
  3347. OpMemoryModel Logical GLSL450
  3348. %void = OpTypeVoid
  3349. %void_fn = OpTypeFunction %void
  3350. %bool = OpTypeBool
  3351. %undef = OpUndef %bool
  3352. %func = OpFunction %void None %void_fn
  3353. %entry = OpLabel
  3354. OpBranch %loop
  3355. %loop = OpLabel
  3356. OpLoopMerge %exit %continue None
  3357. OpBranch %body
  3358. %body = OpLabel
  3359. OpBranchConditional %undef %body2 %continue
  3360. %body2 = OpLabel
  3361. OpBranch %continue
  3362. %continue = OpLabel
  3363. OpBranch %loop
  3364. %exit = OpLabel
  3365. OpReturn
  3366. OpFunctionEnd
  3367. )";
  3368. CompileSuccessfully(text);
  3369. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3370. }
  3371. TEST_F(ValidateCFG, MissingMergeSwitchBreakGood) {
  3372. const std::string text = R"(
  3373. OpCapability Shader
  3374. OpCapability Linkage
  3375. OpMemoryModel Logical GLSL450
  3376. %void = OpTypeVoid
  3377. %void_fn = OpTypeFunction %void
  3378. %bool = OpTypeBool
  3379. %undef = OpUndef %bool
  3380. %int = OpTypeInt 32 0
  3381. %int_0 = OpConstant %int 0
  3382. %func = OpFunction %void None %void_fn
  3383. %entry = OpLabel
  3384. OpSelectionMerge %merge None
  3385. OpSwitch %int_0 %merge 1 %b1
  3386. %b1 = OpLabel
  3387. OpBranchConditional %undef %merge %b2
  3388. %b2 = OpLabel
  3389. OpBranch %merge
  3390. %merge = OpLabel
  3391. OpReturn
  3392. OpFunctionEnd
  3393. )";
  3394. CompileSuccessfully(text);
  3395. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3396. }
  3397. TEST_F(ValidateCFG, MissingMergeSwitchFallThroughGood) {
  3398. const std::string text = R"(
  3399. OpCapability Shader
  3400. OpCapability Linkage
  3401. OpMemoryModel Logical GLSL450
  3402. %void = OpTypeVoid
  3403. %void_fn = OpTypeFunction %void
  3404. %bool = OpTypeBool
  3405. %undef = OpUndef %bool
  3406. %int = OpTypeInt 32 0
  3407. %int_0 = OpConstant %int 0
  3408. %func = OpFunction %void None %void_fn
  3409. %entry = OpLabel
  3410. OpSelectionMerge %merge None
  3411. OpSwitch %int_0 %b1 1 %b2
  3412. %b1 = OpLabel
  3413. OpBranchConditional %undef %b3 %b2
  3414. %b2 = OpLabel
  3415. OpBranch %merge
  3416. %b3 = OpLabel
  3417. OpBranch %merge
  3418. %merge = OpLabel
  3419. OpReturn
  3420. OpFunctionEnd
  3421. )";
  3422. CompileSuccessfully(text);
  3423. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3424. }
  3425. TEST_F(ValidateCFG, MissingMergeInALoopBad) {
  3426. const std::string text = R"(
  3427. OpCapability Shader
  3428. OpCapability Linkage
  3429. OpMemoryModel Logical GLSL450
  3430. %void = OpTypeVoid
  3431. %void_fn = OpTypeFunction %void
  3432. %bool = OpTypeBool
  3433. %undef = OpUndef %bool
  3434. %func = OpFunction %void None %void_fn
  3435. %entry = OpLabel
  3436. OpBranch %loop
  3437. %loop = OpLabel
  3438. OpLoopMerge %exit %continue None
  3439. OpBranch %body
  3440. %body = OpLabel
  3441. OpBranchConditional %undef %b1 %b2
  3442. %b1 = OpLabel
  3443. OpBranch %exit
  3444. %b2 = OpLabel
  3445. OpBranch %continue
  3446. %continue = OpLabel
  3447. OpBranch %loop
  3448. %exit = OpLabel
  3449. OpReturn
  3450. OpFunctionEnd
  3451. )";
  3452. CompileSuccessfully(text);
  3453. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3454. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3455. }
  3456. TEST_F(ValidateCFG, MissingMergeCrissCrossBad) {
  3457. const std::string text = R"(
  3458. OpCapability Shader
  3459. OpCapability Linkage
  3460. OpMemoryModel Logical GLSL450
  3461. %void = OpTypeVoid
  3462. %void_fn = OpTypeFunction %void
  3463. %bool = OpTypeBool
  3464. %undef = OpUndef %bool
  3465. %func = OpFunction %void None %void_fn
  3466. %entry = OpLabel
  3467. OpSelectionMerge %merge None
  3468. OpBranchConditional %undef %b1 %b2
  3469. %b1 = OpLabel
  3470. OpBranchConditional %undef %b3 %b4
  3471. %b2 = OpLabel
  3472. OpBranchConditional %undef %b3 %b4
  3473. %b3 = OpLabel
  3474. OpBranch %merge
  3475. %b4 = OpLabel
  3476. OpBranch %merge
  3477. %merge = OpLabel
  3478. OpReturn
  3479. OpFunctionEnd
  3480. )";
  3481. CompileSuccessfully(text);
  3482. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3483. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3484. }
  3485. TEST_F(ValidateCFG, ContinueCannotBeSelectionMergeTarget) {
  3486. const std::string text = R"(
  3487. OpCapability Shader
  3488. OpCapability Linkage
  3489. OpMemoryModel Logical GLSL450
  3490. OpName %loop "loop"
  3491. OpName %continue "continue"
  3492. OpName %body "body"
  3493. %void = OpTypeVoid
  3494. %void_fn = OpTypeFunction %void
  3495. %bool = OpTypeBool
  3496. %undef = OpUndef %bool
  3497. %func = OpFunction %void None %void_fn
  3498. %entry = OpLabel
  3499. OpBranch %loop
  3500. %loop = OpLabel
  3501. OpLoopMerge %exit %continue None
  3502. OpBranch %body
  3503. %body = OpLabel
  3504. OpSelectionMerge %continue None
  3505. OpBranchConditional %undef %exit %continue
  3506. %continue = OpLabel
  3507. OpBranch %loop
  3508. %exit = OpLabel
  3509. OpReturn
  3510. OpFunctionEnd
  3511. )";
  3512. CompileSuccessfully(text);
  3513. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3514. EXPECT_THAT(
  3515. getDiagnosticString(),
  3516. HasSubstr("Header block '3[%body]' is contained in the loop construct "
  3517. "headed by "
  3518. "'1[%loop]', but its merge block '2[%continue]' is not"));
  3519. }
  3520. TEST_F(ValidateCFG, ContinueCannotBeLoopMergeTarget) {
  3521. const std::string text = R"(
  3522. OpCapability Shader
  3523. OpCapability Linkage
  3524. OpMemoryModel Logical GLSL450
  3525. OpName %loop "loop"
  3526. OpName %continue "continue"
  3527. OpName %inner "inner"
  3528. %void = OpTypeVoid
  3529. %void_fn = OpTypeFunction %void
  3530. %bool = OpTypeBool
  3531. %undef = OpUndef %bool
  3532. %func = OpFunction %void None %void_fn
  3533. %entry = OpLabel
  3534. OpBranch %loop
  3535. %loop = OpLabel
  3536. OpLoopMerge %exit %continue None
  3537. OpBranchConditional %undef %exit %inner
  3538. %inner = OpLabel
  3539. OpLoopMerge %continue %inner None
  3540. OpBranchConditional %undef %inner %continue
  3541. %continue = OpLabel
  3542. OpBranch %loop
  3543. %exit = OpLabel
  3544. OpReturn
  3545. OpFunctionEnd
  3546. )";
  3547. CompileSuccessfully(text);
  3548. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3549. EXPECT_THAT(
  3550. getDiagnosticString(),
  3551. HasSubstr("Header block '3[%inner]' is contained in the loop construct "
  3552. "headed by "
  3553. "'1[%loop]', but its merge block '2[%continue]' is not"));
  3554. }
  3555. TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge) {
  3556. const std::string text = R"(
  3557. OpCapability Shader
  3558. OpCapability Linkage
  3559. OpMemoryModel Logical GLSL450
  3560. %void = OpTypeVoid
  3561. %2 = OpTypeFunction %void
  3562. %int = OpTypeInt 32 1
  3563. %4 = OpUndef %int
  3564. %bool = OpTypeBool
  3565. %6 = OpUndef %bool
  3566. %7 = OpFunction %void None %2
  3567. %8 = OpLabel
  3568. OpSelectionMerge %9 None
  3569. OpSwitch %4 %10 0 %11
  3570. %10 = OpLabel
  3571. OpBranch %9
  3572. %11 = OpLabel
  3573. OpBranch %12
  3574. %12 = OpLabel
  3575. OpLoopMerge %13 %14 None
  3576. OpBranch %15
  3577. %15 = OpLabel
  3578. OpSelectionMerge %16 None
  3579. OpSwitch %4 %17 1 %18 2 %19
  3580. %17 = OpLabel
  3581. OpBranch %16
  3582. %18 = OpLabel
  3583. OpBranch %14
  3584. %19 = OpLabel
  3585. OpBranch %16
  3586. %16 = OpLabel
  3587. OpBranch %14
  3588. %14 = OpLabel
  3589. OpBranchConditional %6 %12 %13
  3590. %13 = OpLabel
  3591. OpSelectionMerge %20 None
  3592. OpBranchConditional %6 %21 %20
  3593. %21 = OpLabel
  3594. OpBranch %9
  3595. %20 = OpLabel
  3596. OpBranch %10
  3597. %9 = OpLabel
  3598. OpReturn
  3599. OpFunctionEnd
  3600. )";
  3601. CompileSuccessfully(text);
  3602. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3603. }
  3604. TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge2) {
  3605. const std::string text = R"(
  3606. OpCapability Shader
  3607. %1 = OpExtInstImport "GLSL.std.450"
  3608. OpMemoryModel Logical GLSL450
  3609. OpEntryPoint Fragment %2 "main"
  3610. OpExecutionMode %2 OriginUpperLeft
  3611. %void = OpTypeVoid
  3612. %4 = OpTypeFunction %void
  3613. %int = OpTypeInt 32 1
  3614. %6 = OpUndef %int
  3615. %bool = OpTypeBool
  3616. %8 = OpUndef %bool
  3617. %2 = OpFunction %void None %4
  3618. %9 = OpLabel
  3619. OpSelectionMerge %10 None
  3620. OpSwitch %6 %11 0 %12
  3621. %11 = OpLabel
  3622. OpBranch %10
  3623. %12 = OpLabel
  3624. OpBranch %13
  3625. %13 = OpLabel
  3626. OpLoopMerge %14 %15 None
  3627. OpBranch %16
  3628. %16 = OpLabel
  3629. OpSelectionMerge %17 None
  3630. OpSwitch %6 %18 1 %19 2 %20
  3631. %18 = OpLabel
  3632. OpBranch %17
  3633. %19 = OpLabel
  3634. OpBranch %15
  3635. %20 = OpLabel
  3636. OpBranch %17
  3637. %17 = OpLabel
  3638. OpBranch %15
  3639. %15 = OpLabel
  3640. OpBranchConditional %8 %13 %14
  3641. %14 = OpLabel
  3642. OpSelectionMerge %21 None
  3643. OpBranchConditional %8 %22 %21
  3644. %22 = OpLabel
  3645. OpSelectionMerge %23 None
  3646. OpBranchConditional %8 %24 %23
  3647. %24 = OpLabel
  3648. OpBranch %10
  3649. %23 = OpLabel
  3650. OpBranch %21
  3651. %21 = OpLabel
  3652. OpBranch %11
  3653. %10 = OpLabel
  3654. OpReturn
  3655. OpFunctionEnd
  3656. )";
  3657. CompileSuccessfully(text);
  3658. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3659. }
  3660. TEST_F(ValidateCFG, PhiResultInvalidSampler) {
  3661. const std::string text = R"(
  3662. OpCapability Shader
  3663. OpCapability Linkage
  3664. OpMemoryModel Logical GLSL450
  3665. %void = OpTypeVoid
  3666. %bool = OpTypeBool
  3667. %f32 = OpTypeFloat 32
  3668. %sampler = OpTypeSampler
  3669. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3670. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3671. %undef_bool = OpUndef %bool
  3672. %undef_sampler = OpUndef %sampler
  3673. %void_fn = OpTypeFunction %void
  3674. %fn = OpFunction %void None %void_fn
  3675. %entry = OpLabel
  3676. %ld_sampler = OpLoad %sampler %sampler_var
  3677. OpBranch %loop
  3678. %loop = OpLabel
  3679. %phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop
  3680. OpLoopMerge %exit %loop None
  3681. OpBranchConditional %undef_bool %exit %loop
  3682. %exit = OpLabel
  3683. OpReturn
  3684. OpFunctionEnd
  3685. )";
  3686. CompileSuccessfully(text);
  3687. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3688. EXPECT_THAT(getDiagnosticString(),
  3689. HasSubstr("Result type cannot be OpTypeSampler"));
  3690. }
  3691. TEST_F(ValidateCFG, PhiResultInvalidImage) {
  3692. const std::string text = R"(
  3693. OpCapability Shader
  3694. OpCapability Linkage
  3695. OpMemoryModel Logical GLSL450
  3696. %void = OpTypeVoid
  3697. %bool = OpTypeBool
  3698. %f32 = OpTypeFloat 32
  3699. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3700. %ptr_uc_image = OpTypePointer UniformConstant %image
  3701. %image_var = OpVariable %ptr_uc_image UniformConstant
  3702. %undef_bool = OpUndef %bool
  3703. %undef_image = OpUndef %image
  3704. %void_fn = OpTypeFunction %void
  3705. %fn = OpFunction %void None %void_fn
  3706. %entry = OpLabel
  3707. %ld_image = OpLoad %image %image_var
  3708. OpBranch %loop
  3709. %loop = OpLabel
  3710. %phi = OpPhi %image %undef_image %entry %ld_image %loop
  3711. OpLoopMerge %exit %loop None
  3712. OpBranchConditional %undef_bool %exit %loop
  3713. %exit = OpLabel
  3714. OpReturn
  3715. OpFunctionEnd
  3716. )";
  3717. CompileSuccessfully(text);
  3718. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3719. EXPECT_THAT(getDiagnosticString(),
  3720. HasSubstr("Result type cannot be OpTypeImage"));
  3721. }
  3722. TEST_F(ValidateCFG, PhiResultInvalidSampledImage) {
  3723. const std::string text = R"(
  3724. OpCapability Shader
  3725. OpCapability Linkage
  3726. OpMemoryModel Logical GLSL450
  3727. %void = OpTypeVoid
  3728. %bool = OpTypeBool
  3729. %f32 = OpTypeFloat 32
  3730. %sampler = OpTypeSampler
  3731. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3732. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3733. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3734. %ptr_uc_image = OpTypePointer UniformConstant %image
  3735. %image_var = OpVariable %ptr_uc_image UniformConstant
  3736. %sampled_image = OpTypeSampledImage %image
  3737. %undef_bool = OpUndef %bool
  3738. %undef_sampled_image = OpUndef %sampled_image
  3739. %void_fn = OpTypeFunction %void
  3740. %fn = OpFunction %void None %void_fn
  3741. %entry = OpLabel
  3742. %ld_image = OpLoad %image %image_var
  3743. %ld_sampler = OpLoad %sampler %sampler_var
  3744. OpBranch %loop
  3745. %loop = OpLabel
  3746. %phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop
  3747. %sample = OpSampledImage %sampled_image %ld_image %ld_sampler
  3748. OpLoopMerge %exit %loop None
  3749. OpBranchConditional %undef_bool %exit %loop
  3750. %exit = OpLabel
  3751. OpReturn
  3752. OpFunctionEnd
  3753. )";
  3754. CompileSuccessfully(text);
  3755. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3756. EXPECT_THAT(getDiagnosticString(),
  3757. HasSubstr("Result type cannot be OpTypeSampledImage"));
  3758. }
  3759. TEST_F(ValidateCFG, PhiResultValidPreLegalizationSampler) {
  3760. const std::string text = R"(
  3761. OpCapability Shader
  3762. OpCapability Linkage
  3763. OpMemoryModel Logical GLSL450
  3764. %void = OpTypeVoid
  3765. %bool = OpTypeBool
  3766. %f32 = OpTypeFloat 32
  3767. %sampler = OpTypeSampler
  3768. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3769. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3770. %undef_bool = OpUndef %bool
  3771. %undef_sampler = OpUndef %sampler
  3772. %void_fn = OpTypeFunction %void
  3773. %fn = OpFunction %void None %void_fn
  3774. %entry = OpLabel
  3775. %ld_sampler = OpLoad %sampler %sampler_var
  3776. OpBranch %loop
  3777. %loop = OpLabel
  3778. %phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop
  3779. OpLoopMerge %exit %loop None
  3780. OpBranchConditional %undef_bool %exit %loop
  3781. %exit = OpLabel
  3782. OpReturn
  3783. OpFunctionEnd
  3784. )";
  3785. options_->before_hlsl_legalization = true;
  3786. CompileSuccessfully(text);
  3787. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3788. }
  3789. TEST_F(ValidateCFG, PhiResultValidPreLegalizationImage) {
  3790. const std::string text = R"(
  3791. OpCapability Shader
  3792. OpCapability Linkage
  3793. OpMemoryModel Logical GLSL450
  3794. %void = OpTypeVoid
  3795. %bool = OpTypeBool
  3796. %f32 = OpTypeFloat 32
  3797. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3798. %ptr_uc_image = OpTypePointer UniformConstant %image
  3799. %image_var = OpVariable %ptr_uc_image UniformConstant
  3800. %undef_bool = OpUndef %bool
  3801. %undef_image = OpUndef %image
  3802. %void_fn = OpTypeFunction %void
  3803. %fn = OpFunction %void None %void_fn
  3804. %entry = OpLabel
  3805. %ld_image = OpLoad %image %image_var
  3806. OpBranch %loop
  3807. %loop = OpLabel
  3808. %phi = OpPhi %image %undef_image %entry %ld_image %loop
  3809. OpLoopMerge %exit %loop None
  3810. OpBranchConditional %undef_bool %exit %loop
  3811. %exit = OpLabel
  3812. OpReturn
  3813. OpFunctionEnd
  3814. )";
  3815. options_->before_hlsl_legalization = true;
  3816. CompileSuccessfully(text);
  3817. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3818. }
  3819. TEST_F(ValidateCFG, PhiResultValidPreLegalizationSampledImage) {
  3820. const std::string text = R"(
  3821. OpCapability Shader
  3822. OpCapability Linkage
  3823. OpMemoryModel Logical GLSL450
  3824. %void = OpTypeVoid
  3825. %bool = OpTypeBool
  3826. %f32 = OpTypeFloat 32
  3827. %sampler = OpTypeSampler
  3828. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3829. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3830. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3831. %ptr_uc_image = OpTypePointer UniformConstant %image
  3832. %image_var = OpVariable %ptr_uc_image UniformConstant
  3833. %sampled_image = OpTypeSampledImage %image
  3834. %undef_bool = OpUndef %bool
  3835. %undef_sampled_image = OpUndef %sampled_image
  3836. %void_fn = OpTypeFunction %void
  3837. %fn = OpFunction %void None %void_fn
  3838. %entry = OpLabel
  3839. %ld_image = OpLoad %image %image_var
  3840. %ld_sampler = OpLoad %sampler %sampler_var
  3841. OpBranch %loop
  3842. %loop = OpLabel
  3843. %phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop
  3844. %sample = OpSampledImage %sampled_image %ld_image %ld_sampler
  3845. OpLoopMerge %exit %loop None
  3846. OpBranchConditional %undef_bool %exit %loop
  3847. %exit = OpLabel
  3848. OpReturn
  3849. OpFunctionEnd
  3850. )";
  3851. options_->before_hlsl_legalization = true;
  3852. CompileSuccessfully(text);
  3853. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3854. }
  3855. TEST_F(ValidateCFG, StructuredSelections_RegisterBothTrueAndFalse) {
  3856. // In this test, we try to make a case where the false branches
  3857. // to %20 and %60 from blocks %10 and %50 must be registered
  3858. // during the validity check for sturctured selections.
  3859. // However, an error is caught earlier in the flow, that the
  3860. // branches from %100 to %20 and %60 violate dominance.
  3861. const std::string text = R"(
  3862. OpCapability Shader
  3863. OpMemoryModel Logical Simple
  3864. OpEntryPoint Fragment %main "main"
  3865. OpExecutionMode %main OriginUpperLeft
  3866. %void = OpTypeVoid
  3867. %void_fn = OpTypeFunction %void
  3868. %bool = OpTypeBool
  3869. %cond = OpUndef %bool
  3870. %main = OpFunction %void None %void_fn
  3871. %1 = OpLabel
  3872. OpSelectionMerge %999 None
  3873. OpBranchConditional %cond %10 %100
  3874. %10 = OpLabel
  3875. OpSelectionMerge %30 None ; force registration of %30
  3876. OpBranchConditional %cond %30 %20 ; %20 should be registered too
  3877. %20 = OpLabel
  3878. OpBranch %30
  3879. %30 = OpLabel ; merge for first if
  3880. OpBranch %50
  3881. %50 = OpLabel
  3882. OpSelectionMerge %70 None ; force registration of %70
  3883. OpBranchConditional %cond %70 %60 ; %60 should be registered
  3884. %60 = OpLabel
  3885. OpBranch %70
  3886. %70 = OpLabel ; merge for second if
  3887. OpBranch %999
  3888. %100 = OpLabel
  3889. OpBranchConditional %cond %20 %60 ; should require a merge
  3890. %999 = OpLabel
  3891. OpReturn
  3892. OpFunctionEnd
  3893. )";
  3894. CompileSuccessfully(text);
  3895. EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
  3896. EXPECT_THAT(getDiagnosticString(),
  3897. HasSubstr("The selection construct with the selection header "
  3898. "'8[%8]' does not structurally dominate the merge "
  3899. "block '10[%10]'\n"));
  3900. }
  3901. TEST_F(ValidateCFG, UnreachableIsStaticallyReachable) {
  3902. const std::string text = R"(
  3903. OpCapability Shader
  3904. OpCapability Linkage
  3905. OpMemoryModel Logical GLSL450
  3906. %1 = OpTypeVoid
  3907. %2 = OpTypeFunction %1
  3908. %3 = OpFunction %1 None %2
  3909. %4 = OpLabel
  3910. OpBranch %5
  3911. %5 = OpLabel
  3912. OpUnreachable
  3913. OpFunctionEnd
  3914. )";
  3915. CompileSuccessfully(text);
  3916. EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
  3917. auto f = vstate_->function(3);
  3918. auto entry = f->GetBlock(4).first;
  3919. ASSERT_TRUE(entry->reachable());
  3920. auto end = f->GetBlock(5).first;
  3921. ASSERT_TRUE(end->reachable());
  3922. }
  3923. TEST_F(ValidateCFG, BlockOrderDoesNotAffectReachability) {
  3924. const std::string text = R"(
  3925. OpCapability Shader
  3926. OpCapability Linkage
  3927. OpMemoryModel Logical GLSL450
  3928. %1 = OpTypeVoid
  3929. %2 = OpTypeFunction %1
  3930. %3 = OpTypeBool
  3931. %4 = OpUndef %3
  3932. %5 = OpFunction %1 None %2
  3933. %6 = OpLabel
  3934. OpBranch %7
  3935. %7 = OpLabel
  3936. OpSelectionMerge %8 None
  3937. OpBranchConditional %4 %9 %10
  3938. %8 = OpLabel
  3939. OpReturn
  3940. %9 = OpLabel
  3941. OpBranch %8
  3942. %10 = OpLabel
  3943. OpBranch %8
  3944. %11 = OpLabel
  3945. OpUnreachable
  3946. OpFunctionEnd
  3947. )";
  3948. CompileSuccessfully(text);
  3949. EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
  3950. auto f = vstate_->function(5);
  3951. auto b6 = f->GetBlock(6).first;
  3952. auto b7 = f->GetBlock(7).first;
  3953. auto b8 = f->GetBlock(8).first;
  3954. auto b9 = f->GetBlock(9).first;
  3955. auto b10 = f->GetBlock(10).first;
  3956. auto b11 = f->GetBlock(11).first;
  3957. ASSERT_TRUE(b6->reachable());
  3958. ASSERT_TRUE(b7->reachable());
  3959. ASSERT_TRUE(b8->reachable());
  3960. ASSERT_TRUE(b9->reachable());
  3961. ASSERT_TRUE(b10->reachable());
  3962. ASSERT_FALSE(b11->reachable());
  3963. }
  3964. TEST_F(ValidateCFG, PhiInstructionWithDuplicateIncomingEdges) {
  3965. const std::string text = R"(
  3966. OpCapability Shader
  3967. %1 = OpExtInstImport "GLSL.std.450"
  3968. OpMemoryModel Logical GLSL450
  3969. OpEntryPoint Fragment %4 "main"
  3970. OpExecutionMode %4 OriginUpperLeft
  3971. OpSource ESSL 320
  3972. %2 = OpTypeVoid
  3973. %3 = OpTypeFunction %2
  3974. %6 = OpTypeBool
  3975. %7 = OpConstantTrue %6
  3976. %4 = OpFunction %2 None %3
  3977. %5 = OpLabel
  3978. OpSelectionMerge %10 None
  3979. OpBranchConditional %7 %8 %9
  3980. %8 = OpLabel
  3981. OpBranch %10
  3982. %9 = OpLabel
  3983. OpBranch %10
  3984. %10 = OpLabel
  3985. %11 = OpPhi %6 %7 %8 %7 %8
  3986. OpReturn
  3987. OpFunctionEnd
  3988. )";
  3989. CompileSuccessfully(text);
  3990. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3991. EXPECT_THAT(getDiagnosticString(),
  3992. HasSubstr("OpPhi references incoming basic block <id> "));
  3993. EXPECT_THAT(getDiagnosticString(), HasSubstr("multiple times."));
  3994. }
  3995. TEST_F(ValidateCFG, PhiOnVoid) {
  3996. const std::string text = R"(
  3997. OpCapability Shader
  3998. %1 = OpExtInstImport "GLSL.std.450"
  3999. OpMemoryModel Logical GLSL450
  4000. OpEntryPoint Fragment %4 "main"
  4001. OpExecutionMode %4 OriginUpperLeft
  4002. OpSource ESSL 320
  4003. OpName %4 "main"
  4004. OpName %6 "foo("
  4005. %2 = OpTypeVoid
  4006. %3 = OpTypeFunction %2
  4007. %4 = OpFunction %2 None %3
  4008. %5 = OpLabel
  4009. %8 = OpFunctionCall %2 %6
  4010. OpBranch %20
  4011. %20 = OpLabel
  4012. %21 = OpPhi %2 %8 %20
  4013. OpReturn
  4014. OpFunctionEnd
  4015. %6 = OpFunction %2 None %3
  4016. %7 = OpLabel
  4017. OpReturn
  4018. OpFunctionEnd
  4019. )";
  4020. CompileSuccessfully(text);
  4021. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  4022. EXPECT_THAT(getDiagnosticString(),
  4023. HasSubstr("OpPhi must not have void result type"));
  4024. }
  4025. TEST_F(ValidateCFG, InvalidExitSingleBlockLoop) {
  4026. const std::string text = R"(
  4027. OpCapability Shader
  4028. OpCapability Linkage
  4029. OpMemoryModel Logical GLSL450
  4030. OpName %5 "BAD"
  4031. %void = OpTypeVoid
  4032. %bool = OpTypeBool
  4033. %undef = OpUndef %bool
  4034. %void_fn = OpTypeFunction %void
  4035. %fn = OpFunction %void None %void_fn
  4036. %1 = OpLabel
  4037. OpBranch %2
  4038. %2 = OpLabel
  4039. OpLoopMerge %3 %4 None
  4040. OpBranchConditional %undef %3 %5
  4041. %5 = OpLabel
  4042. OpLoopMerge %6 %5 None
  4043. OpBranchConditional %undef %5 %4
  4044. %6 = OpLabel
  4045. OpReturn
  4046. %4 = OpLabel
  4047. OpBranch %2
  4048. %3 = OpLabel
  4049. OpReturn
  4050. OpFunctionEnd
  4051. )";
  4052. CompileSuccessfully(text);
  4053. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4054. EXPECT_THAT(
  4055. getDiagnosticString(),
  4056. HasSubstr("block <ID> '1[%BAD]' exits the continue headed by <ID> "
  4057. "'1[%BAD]', but not via a structured exit"));
  4058. }
  4059. TEST_F(ValidateCFG, SwitchSelectorNotAnInt) {
  4060. const std::string spirv = R"(
  4061. OpCapability Shader
  4062. OpMemoryModel Logical GLSL450
  4063. OpEntryPoint GLCompute %main "main"
  4064. OpExecutionMode %main LocalSize 1 1 1
  4065. %void = OpTypeVoid
  4066. %float = OpTypeFloat 32
  4067. %float_1 = OpConstant %float 1
  4068. %void_fn = OpTypeFunction %void
  4069. %main = OpFunction %void None %void_fn
  4070. %entry = OpLabel
  4071. OpSelectionMerge %default None
  4072. OpSwitch %float_1 %default
  4073. %default = OpLabel
  4074. OpReturn
  4075. OpFunctionEnd
  4076. )";
  4077. CompileSuccessfully(spirv);
  4078. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  4079. EXPECT_THAT(getDiagnosticString(),
  4080. HasSubstr("Selector type must be OpTypeInt"));
  4081. }
  4082. TEST_F(ValidateCFG, SwitchDefaultNotALabel) {
  4083. const std::string spirv = R"(
  4084. OpCapability Shader
  4085. OpMemoryModel Logical GLSL450
  4086. OpEntryPoint GLCompute %main "main"
  4087. OpExecutionMode %main LocalSize 1 1 1
  4088. %void = OpTypeVoid
  4089. %int = OpTypeInt 32 0
  4090. %int_1 = OpConstant %int 1
  4091. %void_fn = OpTypeFunction %void
  4092. %main = OpFunction %void None %void_fn
  4093. %entry = OpLabel
  4094. OpSelectionMerge %default None
  4095. OpSwitch %int_1 %int_1
  4096. %default = OpLabel
  4097. OpReturn
  4098. OpFunctionEnd
  4099. )";
  4100. CompileSuccessfully(spirv);
  4101. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  4102. EXPECT_THAT(getDiagnosticString(),
  4103. HasSubstr("Default must be an OpLabel instruction"));
  4104. }
  4105. TEST_F(ValidateCFG, BlockDepthRecursion) {
  4106. const std::string text = R"(
  4107. OpCapability Shader
  4108. OpMemoryModel Logical GLSL450
  4109. OpEntryPoint GLCompute %main "main"
  4110. %void = OpTypeVoid
  4111. %bool = OpTypeBool
  4112. %undef = OpUndef %bool
  4113. %void_fn = OpTypeFunction %void
  4114. %main = OpFunction %void None %void_fn
  4115. %1 = OpLabel
  4116. OpBranch %2
  4117. %2 = OpLabel
  4118. OpLoopMerge %3 %4 None
  4119. OpBranchConditional %undef %3 %4
  4120. %4 = OpLabel
  4121. OpBranch %2
  4122. %3 = OpLabel
  4123. OpBranch %5
  4124. %5 = OpLabel
  4125. OpSelectionMerge %2 None
  4126. OpBranchConditional %undef %6 %7
  4127. %6 = OpLabel
  4128. OpReturn
  4129. %7 = OpLabel
  4130. OpReturn
  4131. OpFunctionEnd
  4132. )";
  4133. CompileSuccessfully(text);
  4134. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4135. }
  4136. TEST_F(ValidateCFG, BadStructuredExitBackwardsMerge) {
  4137. const std::string spirv = R"(
  4138. OpCapability Shader
  4139. OpMemoryModel Logical GLSL450
  4140. OpEntryPoint GLCompute %main "main"
  4141. %void = OpTypeVoid
  4142. %bool = OpTypeBool
  4143. %undef = OpUndef %bool
  4144. %void_fn = OpTypeFunction %void
  4145. %main = OpFunction %void None %void_fn
  4146. %1 = OpLabel
  4147. OpBranch %2
  4148. %2 = OpLabel
  4149. OpLoopMerge %4 %5 None
  4150. OpBranchConditional %undef %4 %6
  4151. %6 = OpLabel
  4152. OpSelectionMerge %7 None
  4153. OpBranchConditional %undef %8 %9
  4154. %7 = OpLabel
  4155. OpReturn
  4156. %8 = OpLabel
  4157. OpBranch %5
  4158. %9 = OpLabel
  4159. OpSelectionMerge %6 None
  4160. OpBranchConditional %undef %5 %5
  4161. %5 = OpLabel
  4162. OpBranch %2
  4163. %4 = OpLabel
  4164. OpReturn
  4165. OpFunctionEnd
  4166. )";
  4167. CompileSuccessfully(spirv);
  4168. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4169. }
  4170. TEST_F(ValidateCFG, BranchConditionalDifferentTargetsPre1p6) {
  4171. const std::string text = R"(
  4172. OpCapability Shader
  4173. OpCapability Linkage
  4174. OpMemoryModel Logical GLSL450
  4175. %void = OpTypeVoid
  4176. %bool = OpTypeBool
  4177. %undef = OpUndef %bool
  4178. %void_fn = OpTypeFunction %void
  4179. %func = OpFunction %void None %void_fn
  4180. %entry = OpLabel
  4181. OpBranchConditional %undef %target %target
  4182. %target = OpLabel
  4183. OpReturn
  4184. OpFunctionEnd
  4185. )";
  4186. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5);
  4187. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
  4188. }
  4189. TEST_F(ValidateCFG, BranchConditionalDifferentTargetsPost1p6) {
  4190. const std::string text = R"(
  4191. OpCapability Shader
  4192. OpCapability Linkage
  4193. OpMemoryModel Logical GLSL450
  4194. %void = OpTypeVoid
  4195. %bool = OpTypeBool
  4196. %undef = OpUndef %bool
  4197. %void_fn = OpTypeFunction %void
  4198. %func = OpFunction %void None %void_fn
  4199. %entry = OpLabel
  4200. OpBranchConditional %undef %target %target
  4201. %target = OpLabel
  4202. OpReturn
  4203. OpFunctionEnd
  4204. )";
  4205. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6);
  4206. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
  4207. EXPECT_THAT(getDiagnosticString(),
  4208. HasSubstr("In SPIR-V 1.6 or later, True Label and False Label "
  4209. "must be different labels"));
  4210. }
  4211. TEST_F(ValidateCFG, BadBackEdgeUnreachableContinue) {
  4212. const std::string text = R"(
  4213. OpCapability Shader
  4214. OpCapability Linkage
  4215. OpMemoryModel Logical GLSL450
  4216. %1 = OpTypeVoid
  4217. %2 = OpTypeFunction %1
  4218. %3 = OpFunction %1 None %2
  4219. %4 = OpLabel
  4220. OpBranch %5
  4221. %5 = OpLabel
  4222. OpLoopMerge %6 %7 None
  4223. OpBranch %8
  4224. %8 = OpLabel
  4225. OpBranch %5
  4226. %7 = OpLabel
  4227. OpUnreachable
  4228. %6 = OpLabel
  4229. OpUnreachable
  4230. OpFunctionEnd
  4231. )";
  4232. CompileSuccessfully(text);
  4233. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4234. EXPECT_THAT(
  4235. getDiagnosticString(),
  4236. HasSubstr("The continue construct with the continue target '7[%7]' "
  4237. "does not structurally dominate the back-edge block '8[%8]'"));
  4238. }
  4239. TEST_F(ValidateCFG, BadLoop) {
  4240. const std::string text = R"(
  4241. OpCapability Shader
  4242. OpMemoryModel Logical Simple
  4243. OpEntryPoint Fragment %2 " "
  4244. OpExecutionMode %2 OriginUpperLeft
  4245. OpName %49 "loop"
  4246. %void = OpTypeVoid
  4247. %12 = OpTypeFunction %void
  4248. %2 = OpFunction %void None %12
  4249. %33 = OpLabel
  4250. OpBranch %49
  4251. %50 = OpLabel
  4252. OpBranch %49
  4253. %49 = OpLabel
  4254. OpLoopMerge %33 %50 Unroll
  4255. OpBranch %49
  4256. OpFunctionEnd
  4257. )";
  4258. CompileSuccessfully(text);
  4259. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4260. EXPECT_THAT(getDiagnosticString(),
  4261. HasSubstr("Loop header '2[%loop]' is targeted by 2 back-edge "
  4262. "blocks but the standard requires exactly one"));
  4263. }
  4264. TEST_F(ValidateCFG, BadSwitch) {
  4265. const std::string text = R"(
  4266. OpCapability StorageImageExtendedFormats
  4267. OpMemoryModel Logical GLSL450
  4268. OpEntryPoint Fragment %2 "blah" %58
  4269. OpExecutionMode %2 OriginUpperLeft
  4270. OpName %BAD "BAD"
  4271. %11 = OpTypeVoid
  4272. %12 = OpTypeFunction %11
  4273. %19 = OpTypeInt 32 1
  4274. %21 = OpConstant %19 555758549
  4275. %2 = OpFunction %11 None %12
  4276. %4 = OpLabel
  4277. OpBranch %33
  4278. %33 = OpLabel
  4279. OpLoopMerge %34 %35 None
  4280. OpBranch %55
  4281. %BAD = OpLabel
  4282. OpSelectionMerge %53 None
  4283. OpSwitch %21 %34 196153896 %53 20856160 %34 33570306 %34 593494531 %52
  4284. %55 = OpLabel
  4285. OpLoopMerge %52 %58 DontUnroll
  4286. OpBranch %35
  4287. %58 = OpLabel
  4288. OpSelectionMerge %58 None
  4289. OpSwitch %21 %52 178168 %55 608223677 %34 604111047 %34 -553516825 %34 -106432813 %BAD 6946864 %55 1257373689 %55 973090296 %35 -113180668 %55 537002232 %BAD 13762553 %BAD 1030172152 %35 -553516825 %55 -262137 %35 -1091822332 %BAD 131320 %52 131321 %35 131320 %52 131321 %35 -1091822332 %BAD
  4290. %53 = OpLabel
  4291. OpBranch %35
  4292. %52 = OpLabel
  4293. OpBranch %34
  4294. %35 = OpLabel
  4295. OpBranch %33
  4296. %34 = OpLabel
  4297. OpKill
  4298. OpFunctionEnd
  4299. )";
  4300. CompileSuccessfully(text);
  4301. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4302. EXPECT_THAT(getDiagnosticString(),
  4303. HasSubstr("exits the selection headed by <ID> '3[%BAD]', but not "
  4304. "via a structured exit"));
  4305. }
  4306. TEST_F(ValidateCFG,
  4307. MaximalReconvergenceBranchConditionalSameTargetNotInCallTree) {
  4308. const std::string text = R"(
  4309. OpCapability Shader
  4310. OpExtension "SPV_KHR_maximal_reconvergence"
  4311. OpMemoryModel Logical GLSL450
  4312. OpEntryPoint GLCompute %main "main"
  4313. OpExecutionMode %main LocalSize 1 1 1
  4314. OpExecutionMode %main MaximallyReconvergesKHR
  4315. %void = OpTypeVoid
  4316. %bool = OpTypeBool
  4317. %cond = OpUndef %bool
  4318. %void_fn = OpTypeFunction %void
  4319. %func = OpFunction %void None %void_fn
  4320. %func_entry = OpLabel
  4321. OpBranchConditional %cond %func_exit %func_exit
  4322. %func_exit = OpLabel
  4323. OpReturn
  4324. OpFunctionEnd
  4325. %main = OpFunction %void None %void_fn
  4326. %main_entry = OpLabel
  4327. OpReturn
  4328. OpFunctionEnd
  4329. )";
  4330. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
  4331. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
  4332. }
  4333. TEST_F(ValidateCFG, MaximalReconvergenceBranchConditionalSameTargetInCallTree) {
  4334. const std::string text = R"(
  4335. OpCapability Shader
  4336. OpExtension "SPV_KHR_maximal_reconvergence"
  4337. OpMemoryModel Logical GLSL450
  4338. OpEntryPoint GLCompute %main "main"
  4339. OpExecutionMode %main LocalSize 1 1 1
  4340. OpExecutionMode %main MaximallyReconvergesKHR
  4341. %void = OpTypeVoid
  4342. %bool = OpTypeBool
  4343. %cond = OpUndef %bool
  4344. %void_fn = OpTypeFunction %void
  4345. %func = OpFunction %void None %void_fn
  4346. %func_entry = OpLabel
  4347. OpBranchConditional %cond %func_exit %func_exit
  4348. %func_exit = OpLabel
  4349. OpReturn
  4350. OpFunctionEnd
  4351. %main = OpFunction %void None %void_fn
  4352. %main_entry = OpLabel
  4353. %call = OpFunctionCall %void %func
  4354. OpReturn
  4355. OpFunctionEnd
  4356. )";
  4357. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
  4358. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
  4359. EXPECT_THAT(getDiagnosticString(),
  4360. HasSubstr("In entry points using the MaximallyReconvergesKHR "
  4361. "execution mode, True "
  4362. "Label and False Label must be different labels"));
  4363. }
  4364. TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceNotInCallTree) {
  4365. const std::string text = R"(
  4366. OpCapability Shader
  4367. OpExtension "SPV_KHR_maximal_reconvergence"
  4368. OpMemoryModel Logical GLSL450
  4369. OpEntryPoint GLCompute %main "main"
  4370. OpExecutionMode %main LocalSize 1 1 1
  4371. OpExecutionMode %main MaximallyReconvergesKHR
  4372. %void = OpTypeVoid
  4373. %bool = OpTypeBool
  4374. %cond = OpUndef %bool
  4375. %void_fn = OpTypeFunction %void
  4376. %func = OpFunction %void None %void_fn
  4377. %func_entry = OpLabel
  4378. OpSelectionMerge %func_exit None
  4379. OpBranchConditional %cond %then %else
  4380. %then = OpLabel
  4381. OpBranch %merge
  4382. %else = OpLabel
  4383. OpBranch %merge
  4384. %merge = OpLabel
  4385. OpBranch %func_exit
  4386. %func_exit = OpLabel
  4387. OpReturn
  4388. OpFunctionEnd
  4389. %main = OpFunction %void None %void_fn
  4390. %main_entry = OpLabel
  4391. OpReturn
  4392. OpFunctionEnd
  4393. )";
  4394. CompileSuccessfully(text);
  4395. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4396. }
  4397. TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceInCallTree) {
  4398. const std::string text = R"(
  4399. OpCapability Shader
  4400. OpExtension "SPV_KHR_maximal_reconvergence"
  4401. OpMemoryModel Logical GLSL450
  4402. OpEntryPoint GLCompute %main "main"
  4403. OpExecutionMode %main LocalSize 1 1 1
  4404. OpExecutionMode %main MaximallyReconvergesKHR
  4405. %void = OpTypeVoid
  4406. %bool = OpTypeBool
  4407. %cond = OpUndef %bool
  4408. %void_fn = OpTypeFunction %void
  4409. %func = OpFunction %void None %void_fn
  4410. %func_entry = OpLabel
  4411. OpSelectionMerge %func_exit None
  4412. OpBranchConditional %cond %then %else
  4413. %then = OpLabel
  4414. OpBranch %merge
  4415. %else = OpLabel
  4416. OpBranch %merge
  4417. %merge = OpLabel
  4418. OpBranch %func_exit
  4419. %func_exit = OpLabel
  4420. OpReturn
  4421. OpFunctionEnd
  4422. %main = OpFunction %void None %void_fn
  4423. %main_entry = OpLabel
  4424. %call = OpFunctionCall %void %func
  4425. OpReturn
  4426. OpFunctionEnd
  4427. )";
  4428. CompileSuccessfully(text);
  4429. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  4430. EXPECT_THAT(
  4431. getDiagnosticString(),
  4432. HasSubstr(
  4433. "In entry points using the MaximallyReconvergesKHR execution mode, "
  4434. "this basic block must not have multiple unique predecessors"));
  4435. }
  4436. TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk) {
  4437. const std::string text = R"(
  4438. OpCapability Shader
  4439. OpExtension "SPV_KHR_maximal_reconvergence"
  4440. OpMemoryModel Logical GLSL450
  4441. OpEntryPoint GLCompute %main "main"
  4442. OpExecutionMode %main LocalSize 1 1 1
  4443. OpExecutionMode %main MaximallyReconvergesKHR
  4444. %void = OpTypeVoid
  4445. %bool = OpTypeBool
  4446. %cond = OpUndef %bool
  4447. %void_fn = OpTypeFunction %void
  4448. %main = OpFunction %void None %void_fn
  4449. %main_entry = OpLabel
  4450. OpBranch %loop
  4451. %loop = OpLabel
  4452. OpLoopMerge %merge %loop None
  4453. OpBranchConditional %cond %loop %merge
  4454. %merge = OpLabel
  4455. OpReturn
  4456. OpFunctionEnd
  4457. )";
  4458. CompileSuccessfully(text);
  4459. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4460. }
  4461. TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk2) {
  4462. const std::string text = R"(
  4463. OpCapability Shader
  4464. OpExtension "SPV_KHR_maximal_reconvergence"
  4465. OpMemoryModel Logical GLSL450
  4466. OpEntryPoint GLCompute %main "main"
  4467. OpExecutionMode %main LocalSize 1 1 1
  4468. OpExecutionMode %main MaximallyReconvergesKHR
  4469. %void = OpTypeVoid
  4470. %bool = OpTypeBool
  4471. %cond = OpUndef %bool
  4472. %void_fn = OpTypeFunction %void
  4473. %main = OpFunction %void None %void_fn
  4474. %main_entry = OpLabel
  4475. OpBranch %loop
  4476. %loop = OpLabel
  4477. OpLoopMerge %merge %cont None
  4478. OpBranch %body
  4479. %body = OpLabel
  4480. OpBranch %cont
  4481. %cont = OpLabel
  4482. OpBranchConditional %cond %loop %merge
  4483. %merge = OpLabel
  4484. OpReturn
  4485. OpFunctionEnd
  4486. )";
  4487. CompileSuccessfully(text);
  4488. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4489. }
  4490. TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk) {
  4491. const std::string text = R"(
  4492. OpCapability Shader
  4493. OpExtension "SPV_KHR_maximal_reconvergence"
  4494. OpMemoryModel Logical GLSL450
  4495. OpEntryPoint GLCompute %main "main"
  4496. OpExecutionMode %main LocalSize 1 1 1
  4497. OpExecutionMode %main MaximallyReconvergesKHR
  4498. %void = OpTypeVoid
  4499. %bool = OpTypeBool
  4500. %cond = OpUndef %bool
  4501. %void_fn = OpTypeFunction %void
  4502. %main = OpFunction %void None %void_fn
  4503. %main_entry = OpLabel
  4504. OpSelectionMerge %merge None
  4505. OpBranchConditional %cond %then %else
  4506. %then = OpLabel
  4507. OpBranch %merge
  4508. %else = OpLabel
  4509. OpBranch %merge
  4510. %merge = OpLabel
  4511. OpReturn
  4512. OpFunctionEnd
  4513. )";
  4514. CompileSuccessfully(text);
  4515. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4516. }
  4517. TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk2) {
  4518. const std::string text = R"(
  4519. OpCapability Shader
  4520. OpExtension "SPV_KHR_maximal_reconvergence"
  4521. OpMemoryModel Logical GLSL450
  4522. OpEntryPoint GLCompute %main "main"
  4523. OpExecutionMode %main LocalSize 1 1 1
  4524. OpExecutionMode %main MaximallyReconvergesKHR
  4525. OpName %merge "merge"
  4526. %void = OpTypeVoid
  4527. %bool = OpTypeBool
  4528. %cond = OpUndef %bool
  4529. %void_fn = OpTypeFunction %void
  4530. %main = OpFunction %void None %void_fn
  4531. %main_entry = OpLabel
  4532. OpSelectionMerge %merge None
  4533. OpBranchConditional %cond %then %else
  4534. %then = OpLabel
  4535. OpBranch %merge
  4536. %else = OpLabel
  4537. OpBranch %merge
  4538. %merge = OpLabel
  4539. OpReturn
  4540. OpFunctionEnd
  4541. )";
  4542. CompileSuccessfully(text);
  4543. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4544. }
  4545. TEST_F(ValidateCFG, MaximalReconvergenceLoopMergeMultiplePredsOk) {
  4546. const std::string text = R"(
  4547. OpCapability Shader
  4548. OpExtension "SPV_KHR_maximal_reconvergence"
  4549. OpMemoryModel Logical GLSL450
  4550. OpEntryPoint GLCompute %main "main"
  4551. OpExecutionMode %main LocalSize 1 1 1
  4552. OpExecutionMode %main MaximallyReconvergesKHR
  4553. %void = OpTypeVoid
  4554. %bool = OpTypeBool
  4555. %cond = OpUndef %bool
  4556. %void_fn = OpTypeFunction %void
  4557. %main = OpFunction %void None %void_fn
  4558. %main_entry = OpLabel
  4559. OpBranch %loop
  4560. %loop = OpLabel
  4561. OpLoopMerge %merge %continue None
  4562. OpBranchConditional %cond %merge %continue
  4563. %continue = OpLabel
  4564. OpBranchConditional %cond %loop %merge
  4565. %merge = OpLabel
  4566. OpReturn
  4567. OpFunctionEnd
  4568. )";
  4569. CompileSuccessfully(text);
  4570. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4571. }
  4572. TEST_F(ValidateCFG, MaximalReconvergenceCaseFallthroughMultiplePredsOk) {
  4573. const std::string text = R"(
  4574. OpCapability Shader
  4575. OpExtension "SPV_KHR_maximal_reconvergence"
  4576. OpMemoryModel Logical GLSL450
  4577. OpEntryPoint GLCompute %main "main"
  4578. OpExecutionMode %main LocalSize 1 1 1
  4579. OpExecutionMode %main MaximallyReconvergesKHR
  4580. %void = OpTypeVoid
  4581. %bool = OpTypeBool
  4582. %cond = OpUndef %bool
  4583. %int = OpTypeInt 32 0
  4584. %val = OpUndef %int
  4585. %void_fn = OpTypeFunction %void
  4586. %main = OpFunction %void None %void_fn
  4587. %main_entry = OpLabel
  4588. OpSelectionMerge %merge None
  4589. OpSwitch %val %merge 0 %case1 1 %case2
  4590. %case1 = OpLabel
  4591. OpBranch %case2
  4592. %case2 = OpLabel
  4593. OpBranch %merge
  4594. %merge = OpLabel
  4595. OpReturn
  4596. OpFunctionEnd
  4597. )";
  4598. CompileSuccessfully(text);
  4599. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4600. }
  4601. TEST_F(ValidateCFG, StructurallyUnreachableContinuePredecessor) {
  4602. const std::string text = R"(
  4603. OpCapability Shader
  4604. OpMemoryModel Logical GLSL450
  4605. OpEntryPoint Fragment %main "main"
  4606. OpExecutionMode %main OriginUpperLeft
  4607. OpSource ESSL 310
  4608. OpName %main "main"
  4609. %void = OpTypeVoid
  4610. %3 = OpTypeFunction %void
  4611. %int = OpTypeInt 32 1
  4612. %int_1 = OpConstant %int 1
  4613. %int_n7 = OpConstant %int -7
  4614. %bool = OpTypeBool
  4615. %main = OpFunction %void None %3
  4616. %8 = OpLabel
  4617. OpBranch %9
  4618. %9 = OpLabel
  4619. %10 = OpPhi %int %int_1 %8 %int_n7 %15
  4620. %12 = OpSGreaterThan %bool %10 %int_n7
  4621. OpLoopMerge %13 %15 None
  4622. OpBranchConditional %12 %14 %13
  4623. %14 = OpLabel
  4624. OpBranch %15
  4625. %15 = OpLabel
  4626. OpBranch %9
  4627. %17 = OpLabel
  4628. OpBranch %15
  4629. %13 = OpLabel
  4630. OpReturn
  4631. OpFunctionEnd
  4632. )";
  4633. CompileSuccessfully(text);
  4634. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4635. }
  4636. TEST_F(ValidateCFG, FullyLoopPrecedingSwitchToContinue) {
  4637. const std::string text = R"(
  4638. OpCapability Shader
  4639. OpMemoryModel Logical GLSL450
  4640. OpEntryPoint Fragment %main "main"
  4641. OpExecutionMode %main OriginUpperLeft
  4642. OpName %main "main"
  4643. %void = OpTypeVoid
  4644. %3 = OpTypeFunction %void
  4645. %bool = OpTypeBool
  4646. %true = OpConstantTrue %bool
  4647. %int = OpTypeInt 32 1
  4648. %int_0 = OpConstant %int 0
  4649. %int_1 = OpConstant %int 1
  4650. %main = OpFunction %void None %3
  4651. %4 = OpLabel
  4652. OpBranch %7
  4653. %7 = OpLabel
  4654. OpLoopMerge %8 %6 None
  4655. OpBranch %5
  4656. %5 = OpLabel
  4657. OpSelectionMerge %9 None
  4658. OpBranchConditional %true %10 %9
  4659. %10 = OpLabel
  4660. OpSelectionMerge %16 None
  4661. OpSwitch %int_0 %13
  4662. %13 = OpLabel
  4663. OpBranch %19
  4664. %19 = OpLabel
  4665. OpLoopMerge %20 %18 None
  4666. OpBranch %17
  4667. %17 = OpLabel
  4668. OpReturn
  4669. %18 = OpLabel
  4670. OpBranch %19
  4671. %20 = OpLabel
  4672. OpSelectionMerge %23 None
  4673. OpSwitch %int_1 %21
  4674. %21 = OpLabel
  4675. OpBranch %6
  4676. %23 = OpLabel
  4677. OpBranch %16
  4678. %16 = OpLabel
  4679. OpBranch %9
  4680. %9 = OpLabel
  4681. OpBranch %6
  4682. %6 = OpLabel
  4683. OpBranch %7
  4684. %8 = OpLabel
  4685. OpUnreachable
  4686. OpFunctionEnd
  4687. )";
  4688. CompileSuccessfully(text);
  4689. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4690. }
  4691. TEST_F(ValidateCFG, CaseBreak) {
  4692. const std::string text = R"(
  4693. OpCapability Shader
  4694. OpMemoryModel Logical GLSL450
  4695. OpEntryPoint Fragment %main "main"
  4696. OpExecutionMode %main OriginUpperLeft
  4697. OpName %main "main"
  4698. %void = OpTypeVoid
  4699. %3 = OpTypeFunction %void
  4700. %bool = OpTypeBool
  4701. %true = OpConstantTrue %bool
  4702. %int = OpTypeInt 32 1
  4703. %int_0 = OpConstant %int 0
  4704. %int_1 = OpConstant %int 1
  4705. %main = OpFunction %void None %3
  4706. %4 = OpLabel
  4707. OpSelectionMerge %merge None
  4708. OpSwitch %int_1 %case 2 %merge
  4709. %case = OpLabel
  4710. OpBranch %merge
  4711. %merge = OpLabel
  4712. OpReturn
  4713. OpFunctionEnd
  4714. )";
  4715. CompileSuccessfully(text);
  4716. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  4717. }
  4718. } // namespace
  4719. } // namespace val
  4720. } // namespace spvtools