val_cfg_test.cpp 131 KB

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