val_cfg_test.cpp 121 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355
  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<SpvCapability>;
  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. SpvOp 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 instruciton that ends the block
  58. explicit Block(std::string label, SpvOp type = SpvOpBranch)
  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 SpvOpBranchConditional:
  78. out << "OpBranchConditional %cond ";
  79. for (Block& b : successors_) {
  80. out << "%" + b.label_ + " ";
  81. }
  82. break;
  83. case SpvOpSwitch: {
  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 SpvOpLoopMerge: {
  92. assert(successors_.size() == 2);
  93. out << "OpLoopMerge %" + successors_[0].label_ + " %" +
  94. successors_[0].label_ + "None";
  95. } break;
  96. case SpvOpReturn:
  97. assert(successors_.size() == 0);
  98. out << "OpReturn\n";
  99. break;
  100. case SpvOpUnreachable:
  101. assert(successors_.size() == 0);
  102. out << "OpUnreachable\n";
  103. break;
  104. case SpvOpBranch:
  105. assert(successors_.size() == 1);
  106. out << "OpBranch %" + successors_.front().label_;
  107. break;
  108. case SpvOpKill:
  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_ == SpvOpBranchConditional) {
  124. assert(successors.size() == 2);
  125. } else if (lhs.type_ == SpvOpSwitch) {
  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_ == SpvOpBranch);
  134. lhs.successors_.push_back(successor);
  135. return lhs;
  136. }
  137. const std::string& GetDefaultHeader(SpvCapability 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 == SpvCapabilityShader) ? 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(SpvCapabilityShader,
  161. SpvCapabilityKernel));
  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() == SpvCapabilityShader;
  236. Block entry("entry");
  237. Block loop("loop", SpvOpBranchConditional);
  238. Block cont("cont");
  239. Block merge("merge", SpvOpReturn);
  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", SpvOpReturn);
  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", SpvOpReturn);
  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() == SpvCapabilityShader;
  293. Block entry("entry");
  294. Block loop("loop", SpvOpBranchConditional);
  295. Block merge("merge", SpvOpReturn);
  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() == SpvCapabilityShader;
  312. Block entry("entry");
  313. Block cont("cont");
  314. Block branch("branch", SpvOpBranchConditional);
  315. Block merge("merge", SpvOpReturn);
  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() == SpvCapabilityShader;
  336. Block entry("entry");
  337. Block loop("loop");
  338. Block selection("selection", SpvOpBranchConditional);
  339. Block merge("merge", SpvOpReturn);
  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() == SpvCapabilityShader;
  366. Block entry("entry");
  367. Block loop("loop", SpvOpBranchConditional);
  368. Block selection("selection", SpvOpBranchConditional);
  369. Block merge("merge", SpvOpReturn);
  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", SpvOpReturn);
  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", SpvOpReturn);
  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", SpvOpBranchConditional);
  437. Block exit("exit", SpvOpReturn);
  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(getDiagnosticString(),
  451. MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] "
  452. "is targeted by block .\\[%bad\\]\n"
  453. " %Main = OpFunction %void None %10\n"));
  454. }
  455. TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) {
  456. Block entry("entry");
  457. Block bad("bad", SpvOpBranchConditional);
  458. Block t("t");
  459. Block merge("merge");
  460. Block end("end", SpvOpReturn);
  461. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  462. bad.SetBody("OpLoopMerge %merge %cont None\n");
  463. std::string str = GetDefaultHeader(GetParam()) +
  464. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  465. types_consts() +
  466. "%func = OpFunction %voidt None %funct\n";
  467. str += entry >> bad;
  468. str += bad >> std::vector<Block>({t, entry});
  469. str += merge >> end;
  470. str += end;
  471. str += "OpFunctionEnd\n";
  472. CompileSuccessfully(str);
  473. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  474. EXPECT_THAT(getDiagnosticString(),
  475. MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] "
  476. "is targeted by block .\\[%bad\\]\n"
  477. " %Main = OpFunction %void None %10\n"));
  478. }
  479. TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) {
  480. Block entry("entry");
  481. Block bad("bad", SpvOpSwitch);
  482. Block block1("block1");
  483. Block block2("block2");
  484. Block block3("block3");
  485. Block def("def"); // default block
  486. Block merge("merge");
  487. Block end("end", SpvOpReturn);
  488. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  489. bad.SetBody("OpSelectionMerge %merge None\n");
  490. std::string str = GetDefaultHeader(GetParam()) +
  491. nameOps("entry", "bad", std::make_pair("func", "Main")) +
  492. types_consts() +
  493. "%func = OpFunction %voidt None %funct\n";
  494. str += entry >> bad;
  495. str += bad >> std::vector<Block>({def, block1, block2, block3, entry});
  496. str += def >> merge;
  497. str += block1 >> merge;
  498. str += block2 >> merge;
  499. str += block3 >> merge;
  500. str += merge >> end;
  501. str += end;
  502. str += "OpFunctionEnd\n";
  503. CompileSuccessfully(str);
  504. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  505. EXPECT_THAT(getDiagnosticString(),
  506. MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] "
  507. "is targeted by block .\\[%bad\\]\n"
  508. " %Main = OpFunction %void None %10\n"));
  509. }
  510. TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) {
  511. Block entry("entry");
  512. Block middle("middle", SpvOpBranchConditional);
  513. Block end("end", SpvOpReturn);
  514. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  515. middle.SetBody("OpSelectionMerge %end None\n");
  516. Block entry2("entry2");
  517. Block middle2("middle2");
  518. Block end2("end2", SpvOpReturn);
  519. std::string str = GetDefaultHeader(GetParam()) +
  520. nameOps("middle2", std::make_pair("func", "Main")) +
  521. types_consts() +
  522. "%func = OpFunction %voidt None %funct\n";
  523. str += entry >> middle;
  524. str += middle >> std::vector<Block>({end, middle2});
  525. str += end;
  526. str += "OpFunctionEnd\n";
  527. str += "%func2 = OpFunction %voidt None %funct\n";
  528. str += entry2 >> middle2;
  529. str += middle2 >> end2;
  530. str += end2;
  531. str += "OpFunctionEnd\n";
  532. CompileSuccessfully(str);
  533. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  534. EXPECT_THAT(
  535. getDiagnosticString(),
  536. MatchesRegex("Block\\(s\\) \\{.\\[%middle2\\]\\} are referenced but not "
  537. "defined in function .\\[%Main\\]\n"
  538. " %Main = OpFunction %void None %9\n"));
  539. }
  540. TEST_P(ValidateCFG, HeaderDoesntDominatesMergeBad) {
  541. bool is_shader = GetParam() == SpvCapabilityShader;
  542. Block entry("entry");
  543. Block head("head", SpvOpBranchConditional);
  544. Block f("f");
  545. Block merge("merge", SpvOpReturn);
  546. head.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  547. if (is_shader) head.AppendBody("OpSelectionMerge %merge None\n");
  548. std::string str = GetDefaultHeader(GetParam()) +
  549. nameOps("head", "merge", std::make_pair("func", "Main")) +
  550. types_consts() +
  551. "%func = OpFunction %voidt None %funct\n";
  552. str += entry >> merge;
  553. str += head >> std::vector<Block>({merge, f});
  554. str += f >> merge;
  555. str += merge;
  556. str += "OpFunctionEnd\n";
  557. CompileSuccessfully(str);
  558. if (is_shader) {
  559. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  560. EXPECT_THAT(
  561. getDiagnosticString(),
  562. MatchesRegex("The selection construct with the selection header "
  563. ".\\[%head\\] does not dominate the merge block "
  564. ".\\[%merge\\]\n %merge = OpLabel\n"));
  565. } else {
  566. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  567. }
  568. }
  569. TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) {
  570. // If a merge block is reachable, then it must be strictly dominated by
  571. // its header block.
  572. bool is_shader = GetParam() == SpvCapabilityShader;
  573. Block head("head", SpvOpBranchConditional);
  574. Block exit("exit", SpvOpReturn);
  575. head.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  576. if (is_shader) head.AppendBody("OpSelectionMerge %head None\n");
  577. std::string str = GetDefaultHeader(GetParam()) +
  578. nameOps("head", "exit", std::make_pair("func", "Main")) +
  579. types_consts() +
  580. "%func = OpFunction %voidt None %funct\n";
  581. str += head >> std::vector<Block>({exit, exit});
  582. str += exit;
  583. str += "OpFunctionEnd\n";
  584. CompileSuccessfully(str);
  585. if (is_shader) {
  586. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  587. EXPECT_THAT(
  588. getDiagnosticString(),
  589. MatchesRegex("The selection construct with the selection header "
  590. ".\\[%head\\] does not strictly dominate the merge block "
  591. ".\\[%head\\]\n %head = OpLabel\n"));
  592. } else {
  593. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str;
  594. }
  595. }
  596. std::string GetUnreachableMergeNoMergeInst(SpvCapability cap) {
  597. std::string header = GetDefaultHeader(cap);
  598. Block entry("entry");
  599. Block branch("branch", SpvOpBranchConditional);
  600. Block t("t", SpvOpReturn);
  601. Block f("f", SpvOpReturn);
  602. Block merge("merge", SpvOpReturn);
  603. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  604. if (cap == SpvCapabilityShader)
  605. branch.AppendBody("OpSelectionMerge %merge None\n");
  606. std::string str = header;
  607. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  608. str += types_consts() + "%func = OpFunction %voidt None %funct\n";
  609. str += entry >> branch;
  610. str += branch >> std::vector<Block>({t, f});
  611. str += t;
  612. str += f;
  613. str += merge;
  614. str += "OpFunctionEnd\n";
  615. return str;
  616. }
  617. TEST_P(ValidateCFG, UnreachableMergeNoMergeInst) {
  618. CompileSuccessfully(GetUnreachableMergeNoMergeInst(GetParam()));
  619. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  620. }
  621. std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, SpvOp op) {
  622. std::string header = GetDefaultHeader(cap);
  623. Block entry("entry");
  624. Block branch("branch", SpvOpBranchConditional);
  625. Block t("t", SpvOpReturn);
  626. Block f("f", SpvOpReturn);
  627. Block merge("merge", op);
  628. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  629. std::string str = header;
  630. if (cap == SpvCapabilityShader)
  631. branch.AppendBody("OpSelectionMerge %merge None\n");
  632. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  633. str += types_consts();
  634. str += "%func = OpFunction %voidt None %funct\n";
  635. str += entry >> branch;
  636. str += branch >> std::vector<Block>({t, f});
  637. str += t;
  638. str += f;
  639. str += merge;
  640. str += "OpFunctionEnd\n";
  641. return str;
  642. }
  643. TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) {
  644. CompileSuccessfully(
  645. GetUnreachableMergeTerminatedBy(GetParam(), SpvOpUnreachable));
  646. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  647. }
  648. TEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) {
  649. CompileSuccessfully(
  650. GetUnreachableMergeTerminatedBy(SpvCapabilityShader, SpvOpKill));
  651. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  652. }
  653. TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) {
  654. CompileSuccessfully(GetUnreachableMergeTerminatedBy(GetParam(), SpvOpReturn));
  655. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  656. }
  657. std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, SpvOp op) {
  658. std::string header = GetDefaultHeader(cap);
  659. Block entry("entry");
  660. Block branch("branch", SpvOpBranch);
  661. Block merge("merge", SpvOpReturn);
  662. Block target("target", op);
  663. if (op == SpvOpBranch) target >> branch;
  664. std::string str = header;
  665. if (cap == SpvCapabilityShader)
  666. branch.AppendBody("OpLoopMerge %merge %target None\n");
  667. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  668. str += types_consts();
  669. str += "%func = OpFunction %voidt None %funct\n";
  670. str += entry >> branch;
  671. str += branch >> std::vector<Block>({merge});
  672. str += merge;
  673. str += target;
  674. str += "OpFunctionEnd\n";
  675. return str;
  676. }
  677. TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) {
  678. CompileSuccessfully(
  679. GetUnreachableContinueTerminatedBy(GetParam(), SpvOpUnreachable));
  680. if (GetParam() == SpvCapabilityShader) {
  681. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  682. EXPECT_THAT(getDiagnosticString(),
  683. HasSubstr("targeted by 0 back-edge blocks"));
  684. } else {
  685. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  686. }
  687. }
  688. TEST_F(ValidateCFG, UnreachableContinueTerminatedBySpvOpKill) {
  689. CompileSuccessfully(
  690. GetUnreachableContinueTerminatedBy(SpvCapabilityShader, SpvOpKill));
  691. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  692. EXPECT_THAT(getDiagnosticString(),
  693. HasSubstr("targeted by 0 back-edge blocks"));
  694. }
  695. TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpReturn) {
  696. CompileSuccessfully(
  697. GetUnreachableContinueTerminatedBy(GetParam(), SpvOpReturn));
  698. if (GetParam() == SpvCapabilityShader) {
  699. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  700. EXPECT_THAT(getDiagnosticString(),
  701. HasSubstr("targeted by 0 back-edge blocks"));
  702. } else {
  703. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  704. }
  705. }
  706. TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpBranch) {
  707. CompileSuccessfully(
  708. GetUnreachableContinueTerminatedBy(GetParam(), SpvOpBranch));
  709. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  710. }
  711. std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap) {
  712. std::string header = GetDefaultHeader(cap);
  713. Block body("body", SpvOpReturn);
  714. Block entry("entry");
  715. Block branch("branch", SpvOpBranchConditional);
  716. Block t("t", SpvOpReturn);
  717. Block f("f", SpvOpReturn);
  718. Block merge("merge", SpvOpUnreachable);
  719. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  720. std::string str = header;
  721. if (cap == SpvCapabilityShader)
  722. branch.AppendBody("OpSelectionMerge %merge None\n");
  723. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  724. str += types_consts();
  725. str += "%func = OpFunction %voidt None %funct\n";
  726. str += body;
  727. str += merge;
  728. str += entry >> branch;
  729. str += branch >> std::vector<Block>({t, f});
  730. str += t;
  731. str += f;
  732. str += "OpFunctionEnd\n";
  733. return str;
  734. }
  735. TEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) {
  736. CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(GetParam()));
  737. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  738. }
  739. std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap) {
  740. std::string header = GetDefaultHeader(cap);
  741. Block body("body", SpvOpReturn);
  742. Block entry("entry");
  743. Block branch("branch", SpvOpBranch);
  744. Block merge("merge", SpvOpReturn);
  745. Block target("target", SpvOpBranch);
  746. target >> branch;
  747. std::string str = header;
  748. if (cap == SpvCapabilityShader)
  749. branch.AppendBody("OpLoopMerge %merge %target None\n");
  750. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  751. str += types_consts();
  752. str += "%func = OpFunction %voidt None %funct\n";
  753. str += body;
  754. str += target;
  755. str += merge;
  756. str += entry >> branch;
  757. str += branch >> std::vector<Block>({merge});
  758. str += "OpFunctionEnd\n";
  759. return str;
  760. }
  761. TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) {
  762. CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(GetParam()));
  763. if (GetParam() == SpvCapabilityShader) {
  764. // Shader causes additional structured CFG checks that cause a failure.
  765. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  766. EXPECT_THAT(getDiagnosticString(),
  767. HasSubstr("Back-edges (1[%branch] -> 3[%target]) can only be "
  768. "formed between a block and a loop header."));
  769. } else {
  770. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  771. }
  772. }
  773. std::string GetUnreachableMergeWithComplexBody(SpvCapability cap) {
  774. std::string header = GetDefaultHeader(cap);
  775. Block entry("entry");
  776. Block branch("branch", SpvOpBranchConditional);
  777. Block t("t", SpvOpReturn);
  778. Block f("f", SpvOpReturn);
  779. Block merge("merge", SpvOpUnreachable);
  780. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  781. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  782. merge.AppendBody("OpStore %placeholder %one\n");
  783. std::string str = header;
  784. if (cap == SpvCapabilityShader)
  785. branch.AppendBody("OpSelectionMerge %merge None\n");
  786. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  787. str += types_consts();
  788. str += "%intptrt = OpTypePointer Function %intt\n";
  789. str += "%func = OpFunction %voidt None %funct\n";
  790. str += entry >> branch;
  791. str += branch >> std::vector<Block>({t, f});
  792. str += t;
  793. str += f;
  794. str += merge;
  795. str += "OpFunctionEnd\n";
  796. return str;
  797. }
  798. TEST_P(ValidateCFG, UnreachableMergeWithComplexBody) {
  799. CompileSuccessfully(GetUnreachableMergeWithComplexBody(GetParam()));
  800. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  801. }
  802. std::string GetUnreachableContinueWithComplexBody(SpvCapability cap) {
  803. std::string header = GetDefaultHeader(cap);
  804. Block entry("entry");
  805. Block branch("branch", SpvOpBranch);
  806. Block merge("merge", SpvOpReturn);
  807. Block target("target", SpvOpBranch);
  808. target >> branch;
  809. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  810. target.AppendBody("OpStore %placeholder %one\n");
  811. std::string str = header;
  812. if (cap == SpvCapabilityShader)
  813. branch.AppendBody("OpLoopMerge %merge %target None\n");
  814. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  815. str += types_consts();
  816. str += "%intptrt = OpTypePointer Function %intt\n";
  817. str += "%func = OpFunction %voidt None %funct\n";
  818. str += entry >> branch;
  819. str += branch >> std::vector<Block>({merge});
  820. str += merge;
  821. str += target;
  822. str += "OpFunctionEnd\n";
  823. return str;
  824. }
  825. TEST_P(ValidateCFG, UnreachableContinueWithComplexBody) {
  826. CompileSuccessfully(GetUnreachableContinueWithComplexBody(GetParam()));
  827. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  828. }
  829. std::string GetUnreachableMergeWithBranchUse(SpvCapability cap) {
  830. std::string header = GetDefaultHeader(cap);
  831. Block entry("entry");
  832. Block branch("branch", SpvOpBranchConditional);
  833. Block t("t", SpvOpBranch);
  834. Block f("f", SpvOpReturn);
  835. Block merge("merge", SpvOpUnreachable);
  836. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  837. std::string str = header;
  838. if (cap == SpvCapabilityShader)
  839. branch.AppendBody("OpSelectionMerge %merge None\n");
  840. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  841. str += types_consts();
  842. str += "%func = OpFunction %voidt None %funct\n";
  843. str += entry >> branch;
  844. str += branch >> std::vector<Block>({t, f});
  845. str += t >> merge;
  846. str += f;
  847. str += merge;
  848. str += "OpFunctionEnd\n";
  849. return str;
  850. }
  851. TEST_P(ValidateCFG, UnreachableMergeWithBranchUse) {
  852. CompileSuccessfully(GetUnreachableMergeWithBranchUse(GetParam()));
  853. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  854. }
  855. std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap) {
  856. std::string header = GetDefaultHeader(cap);
  857. Block entry("entry");
  858. Block branch("branch", SpvOpBranchConditional);
  859. Block t("t", SpvOpReturn);
  860. Block f("f", SpvOpReturn);
  861. Block merge("merge", SpvOpUnreachable);
  862. Block duplicate("duplicate", SpvOpBranchConditional);
  863. entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n");
  864. std::string str = header;
  865. if (cap == SpvCapabilityShader) {
  866. branch.AppendBody("OpSelectionMerge %merge None\n");
  867. duplicate.AppendBody("OpSelectionMerge %merge None\n");
  868. }
  869. str += nameOps("branch", "merge", std::make_pair("func", "Main"));
  870. str += types_consts();
  871. str += "%func = OpFunction %voidt None %funct\n";
  872. str += entry >> branch;
  873. str += branch >> std::vector<Block>({t, f});
  874. str += duplicate >> std::vector<Block>({t, f});
  875. str += t;
  876. str += f;
  877. str += merge;
  878. str += "OpFunctionEnd\n";
  879. return str;
  880. }
  881. TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) {
  882. CompileSuccessfully(GetUnreachableMergeWithMultipleUses(GetParam()));
  883. if (GetParam() == SpvCapabilityShader) {
  884. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  885. EXPECT_THAT(getDiagnosticString(),
  886. HasSubstr("is already a merge block for another header"));
  887. } else {
  888. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  889. }
  890. }
  891. std::string GetUnreachableContinueWithBranchUse(SpvCapability cap) {
  892. std::string header = GetDefaultHeader(cap);
  893. Block entry("entry");
  894. Block foo("foo", SpvOpBranch);
  895. Block branch("branch", SpvOpBranch);
  896. Block merge("merge", SpvOpReturn);
  897. Block target("target", SpvOpBranch);
  898. foo >> target;
  899. target >> branch;
  900. entry.AppendBody("%placeholder = OpVariable %intptrt Function\n");
  901. std::string str = header;
  902. if (cap == SpvCapabilityShader)
  903. branch.AppendBody("OpLoopMerge %merge %target None\n");
  904. str += nameOps("branch", "merge", "target", std::make_pair("func", "Main"));
  905. str += types_consts();
  906. str += "%intptrt = OpTypePointer Function %intt\n";
  907. str += "%func = OpFunction %voidt None %funct\n";
  908. str += entry >> branch;
  909. str += branch >> std::vector<Block>({merge});
  910. str += merge;
  911. str += target;
  912. str += foo;
  913. str += "OpFunctionEnd\n";
  914. return str;
  915. }
  916. TEST_P(ValidateCFG, UnreachableContinueWithBranchUse) {
  917. CompileSuccessfully(GetUnreachableContinueWithBranchUse(GetParam()));
  918. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  919. }
  920. std::string GetReachableMergeAndContinue(SpvCapability cap) {
  921. std::string header = GetDefaultHeader(cap);
  922. Block entry("entry");
  923. Block branch("branch", SpvOpBranch);
  924. Block merge("merge", SpvOpReturn);
  925. Block target("target", SpvOpBranch);
  926. Block body("body", SpvOpBranchConditional);
  927. Block t("t", SpvOpBranch);
  928. Block f("f", SpvOpBranch);
  929. target >> branch;
  930. body.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  931. t >> merge;
  932. f >> target;
  933. std::string str = header;
  934. if (cap == SpvCapabilityShader) {
  935. branch.AppendBody("OpLoopMerge %merge %target None\n");
  936. body.AppendBody("OpSelectionMerge %f None\n");
  937. }
  938. str += nameOps("branch", "merge", "target", "body", "t", "f",
  939. std::make_pair("func", "Main"));
  940. str += types_consts();
  941. str += "%func = OpFunction %voidt None %funct\n";
  942. str += entry >> branch;
  943. str += branch >> std::vector<Block>({body});
  944. str += body >> std::vector<Block>({t, f});
  945. str += t;
  946. str += f;
  947. str += merge;
  948. str += target;
  949. str += "OpFunctionEnd\n";
  950. return str;
  951. }
  952. TEST_P(ValidateCFG, ReachableMergeAndContinue) {
  953. CompileSuccessfully(GetReachableMergeAndContinue(GetParam()));
  954. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  955. }
  956. std::string GetUnreachableMergeAndContinue(SpvCapability cap) {
  957. std::string header = GetDefaultHeader(cap);
  958. Block entry("entry");
  959. Block branch("branch", SpvOpBranch);
  960. Block merge("merge", SpvOpReturn);
  961. Block target("target", SpvOpBranch);
  962. Block body("body", SpvOpBranchConditional);
  963. Block t("t", SpvOpReturn);
  964. Block f("f", SpvOpReturn);
  965. target >> branch;
  966. body.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  967. std::string str = header;
  968. if (cap == SpvCapabilityShader) {
  969. branch.AppendBody("OpLoopMerge %merge %target None\n");
  970. body.AppendBody("OpSelectionMerge %target None\n");
  971. }
  972. str += nameOps("branch", "merge", "target", "body", "t", "f",
  973. std::make_pair("func", "Main"));
  974. str += types_consts();
  975. str += "%func = OpFunction %voidt None %funct\n";
  976. str += entry >> branch;
  977. str += branch >> std::vector<Block>({body});
  978. str += body >> std::vector<Block>({t, f});
  979. str += t;
  980. str += f;
  981. str += merge;
  982. str += target;
  983. str += "OpFunctionEnd\n";
  984. return str;
  985. }
  986. TEST_P(ValidateCFG, UnreachableMergeAndContinue) {
  987. CompileSuccessfully(GetUnreachableMergeAndContinue(GetParam()));
  988. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  989. }
  990. std::string GetUnreachableBlock(SpvCapability cap) {
  991. std::string header = GetDefaultHeader(cap);
  992. Block entry("entry");
  993. Block unreachable("unreachable");
  994. Block exit("exit", SpvOpReturn);
  995. std::string str = header;
  996. str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
  997. str += types_consts();
  998. str += "%func = OpFunction %voidt None %funct\n";
  999. str += entry >> exit;
  1000. str += unreachable >> exit;
  1001. str += exit;
  1002. str += "OpFunctionEnd\n";
  1003. return str;
  1004. }
  1005. TEST_P(ValidateCFG, UnreachableBlock) {
  1006. CompileSuccessfully(GetUnreachableBlock(GetParam()));
  1007. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1008. }
  1009. std::string GetUnreachableBranch(SpvCapability cap) {
  1010. std::string header = GetDefaultHeader(cap);
  1011. Block entry("entry");
  1012. Block unreachable("unreachable", SpvOpBranchConditional);
  1013. Block unreachablechildt("unreachablechildt");
  1014. Block unreachablechildf("unreachablechildf");
  1015. Block merge("merge");
  1016. Block exit("exit", SpvOpReturn);
  1017. unreachable.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1018. if (cap == SpvCapabilityShader)
  1019. unreachable.AppendBody("OpSelectionMerge %merge None\n");
  1020. std::string str = header;
  1021. str += nameOps("unreachable", "exit", std::make_pair("func", "Main"));
  1022. str += types_consts();
  1023. str += "%func = OpFunction %voidt None %funct\n";
  1024. str += entry >> exit;
  1025. str +=
  1026. unreachable >> std::vector<Block>({unreachablechildt, unreachablechildf});
  1027. str += unreachablechildt >> merge;
  1028. str += unreachablechildf >> merge;
  1029. str += merge >> exit;
  1030. str += exit;
  1031. str += "OpFunctionEnd\n";
  1032. return str;
  1033. }
  1034. TEST_P(ValidateCFG, UnreachableBranch) {
  1035. CompileSuccessfully(GetUnreachableBranch(GetParam()));
  1036. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1037. }
  1038. TEST_P(ValidateCFG, EmptyFunction) {
  1039. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1040. R"(%func = OpFunction %voidt None %funct
  1041. %l = OpLabel
  1042. OpReturn
  1043. OpFunctionEnd)";
  1044. CompileSuccessfully(str);
  1045. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1046. }
  1047. TEST_P(ValidateCFG, SingleBlockLoop) {
  1048. bool is_shader = GetParam() == SpvCapabilityShader;
  1049. Block entry("entry");
  1050. Block loop("loop", SpvOpBranchConditional);
  1051. Block exit("exit", SpvOpReturn);
  1052. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1053. if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n");
  1054. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1055. "%func = OpFunction %voidt None %funct\n";
  1056. str += entry >> loop;
  1057. str += loop >> std::vector<Block>({loop, exit});
  1058. str += exit;
  1059. str += "OpFunctionEnd";
  1060. CompileSuccessfully(str);
  1061. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1062. }
  1063. TEST_P(ValidateCFG, NestedLoops) {
  1064. bool is_shader = GetParam() == SpvCapabilityShader;
  1065. Block entry("entry");
  1066. Block loop1("loop1");
  1067. Block loop1_cont_break_block("loop1_cont_break_block",
  1068. SpvOpBranchConditional);
  1069. Block loop2("loop2", SpvOpBranchConditional);
  1070. Block loop2_merge("loop2_merge");
  1071. Block loop1_merge("loop1_merge");
  1072. Block exit("exit", SpvOpReturn);
  1073. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1074. if (is_shader) {
  1075. loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n");
  1076. loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
  1077. }
  1078. std::string str = GetDefaultHeader(GetParam()) +
  1079. nameOps("loop2", "loop2_merge") + types_consts() +
  1080. "%func = OpFunction %voidt None %funct\n";
  1081. str += entry >> loop1;
  1082. str += loop1 >> loop1_cont_break_block;
  1083. str += loop1_cont_break_block >> std::vector<Block>({loop1_merge, loop2});
  1084. str += loop2 >> std::vector<Block>({loop2, loop2_merge});
  1085. str += loop2_merge >> loop1;
  1086. str += loop1_merge >> exit;
  1087. str += exit;
  1088. str += "OpFunctionEnd";
  1089. CompileSuccessfully(str);
  1090. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1091. }
  1092. TEST_P(ValidateCFG, NestedSelection) {
  1093. bool is_shader = GetParam() == SpvCapabilityShader;
  1094. Block entry("entry");
  1095. const int N = 256;
  1096. std::vector<Block> if_blocks;
  1097. std::vector<Block> merge_blocks;
  1098. Block inner("inner");
  1099. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1100. if_blocks.emplace_back("if0", SpvOpBranchConditional);
  1101. if (is_shader) if_blocks[0].SetBody("OpSelectionMerge %if_merge0 None\n");
  1102. merge_blocks.emplace_back("if_merge0", SpvOpReturn);
  1103. for (int i = 1; i < N; i++) {
  1104. std::stringstream ss;
  1105. ss << i;
  1106. if_blocks.emplace_back("if" + ss.str(), SpvOpBranchConditional);
  1107. if (is_shader)
  1108. if_blocks[i].SetBody("OpSelectionMerge %if_merge" + ss.str() + " None\n");
  1109. merge_blocks.emplace_back("if_merge" + ss.str(), SpvOpBranch);
  1110. }
  1111. std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) +
  1112. "%func = OpFunction %voidt None %funct\n";
  1113. str += entry >> if_blocks[0];
  1114. for (int i = 0; i < N - 1; i++) {
  1115. str +=
  1116. if_blocks[i] >> std::vector<Block>({if_blocks[i + 1], merge_blocks[i]});
  1117. }
  1118. str += if_blocks.back() >> std::vector<Block>({inner, merge_blocks.back()});
  1119. str += inner >> merge_blocks.back();
  1120. for (int i = N - 1; i > 0; i--) {
  1121. str += merge_blocks[i] >> merge_blocks[i - 1];
  1122. }
  1123. str += merge_blocks[0];
  1124. str += "OpFunctionEnd";
  1125. CompileSuccessfully(str);
  1126. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1127. }
  1128. TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) {
  1129. bool is_shader = GetParam() == SpvCapabilityShader;
  1130. Block entry("entry");
  1131. Block loop1("loop1", SpvOpBranchConditional);
  1132. Block loop2("loop2", SpvOpBranchConditional);
  1133. Block loop2_merge("loop2_merge");
  1134. Block loop1_cont("loop1_cont", SpvOpBranchConditional);
  1135. Block be_block("be_block");
  1136. Block exit("exit", SpvOpReturn);
  1137. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1138. if (is_shader) {
  1139. loop1.SetBody("OpLoopMerge %exit %loop1_cont None\n");
  1140. loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n");
  1141. }
  1142. std::string str =
  1143. GetDefaultHeader(GetParam()) +
  1144. nameOps("loop1", "loop2", "be_block", "loop1_cont", "loop2_merge") +
  1145. types_consts() + "%func = OpFunction %voidt None %funct\n";
  1146. str += entry >> loop1;
  1147. str += loop1 >> std::vector<Block>({loop2, exit});
  1148. str += loop2 >> std::vector<Block>({loop2, loop2_merge});
  1149. str += loop2_merge >> loop1_cont;
  1150. str += loop1_cont >> std::vector<Block>({be_block, exit});
  1151. str += be_block >> loop1;
  1152. str += exit;
  1153. str += "OpFunctionEnd";
  1154. CompileSuccessfully(str);
  1155. if (GetParam() == SpvCapabilityShader) {
  1156. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1157. EXPECT_THAT(getDiagnosticString(),
  1158. MatchesRegex("The continue construct with the continue target "
  1159. ".\\[%loop1_cont\\] is not post dominated by the "
  1160. "back-edge block .\\[%be_block\\]\n"
  1161. " %be_block = OpLabel\n"));
  1162. } else {
  1163. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1164. }
  1165. }
  1166. TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) {
  1167. bool is_shader = GetParam() == SpvCapabilityShader;
  1168. Block entry("entry");
  1169. Block split("split", SpvOpBranchConditional);
  1170. Block t("t");
  1171. Block f("f");
  1172. Block exit("exit", SpvOpReturn);
  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", "f") +
  1176. types_consts() +
  1177. "%func = OpFunction %voidt None %funct\n";
  1178. str += entry >> split;
  1179. str += split >> std::vector<Block>({t, f});
  1180. str += t >> exit;
  1181. str += f >> split;
  1182. str += exit;
  1183. str += "OpFunctionEnd";
  1184. CompileSuccessfully(str);
  1185. if (is_shader) {
  1186. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1187. EXPECT_THAT(
  1188. getDiagnosticString(),
  1189. MatchesRegex("Back-edges \\(.\\[%f\\] -> .\\[%split\\]\\) can only "
  1190. "be formed between a block and a loop header.\n"
  1191. " %f = OpLabel\n"));
  1192. } else {
  1193. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1194. }
  1195. }
  1196. TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) {
  1197. bool is_shader = GetParam() == SpvCapabilityShader;
  1198. Block entry("entry");
  1199. Block split("split", SpvOpBranchConditional);
  1200. Block exit("exit", SpvOpReturn);
  1201. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1202. if (is_shader) split.SetBody("OpSelectionMerge %exit None\n");
  1203. std::string str = GetDefaultHeader(GetParam()) + nameOps("split") +
  1204. types_consts() +
  1205. "%func = OpFunction %voidt None %funct\n";
  1206. str += entry >> split;
  1207. str += split >> std::vector<Block>({split, exit});
  1208. str += exit;
  1209. str += "OpFunctionEnd";
  1210. CompileSuccessfully(str);
  1211. if (is_shader) {
  1212. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1213. EXPECT_THAT(
  1214. getDiagnosticString(),
  1215. MatchesRegex(
  1216. "Back-edges \\(.\\[%split\\] -> .\\[%split\\]\\) can only be "
  1217. "formed between a block and a loop header.\n %split = OpLabel\n"));
  1218. } else {
  1219. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1220. }
  1221. }
  1222. TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) {
  1223. bool is_shader = GetParam() == SpvCapabilityShader;
  1224. Block entry("entry");
  1225. Block loop("loop", SpvOpBranchConditional);
  1226. Block back0("back0");
  1227. Block back1("back1");
  1228. Block merge("merge", SpvOpReturn);
  1229. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1230. if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n");
  1231. std::string str = GetDefaultHeader(GetParam()) +
  1232. nameOps("loop", "back0", "back1") + types_consts() +
  1233. "%func = OpFunction %voidt None %funct\n";
  1234. str += entry >> loop;
  1235. str += loop >> std::vector<Block>({back0, back1});
  1236. str += back0 >> loop;
  1237. str += back1 >> loop;
  1238. str += merge;
  1239. str += "OpFunctionEnd";
  1240. CompileSuccessfully(str);
  1241. if (is_shader) {
  1242. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1243. EXPECT_THAT(
  1244. getDiagnosticString(),
  1245. MatchesRegex(
  1246. "Loop header .\\[%loop\\] is targeted by 2 back-edge blocks but "
  1247. "the standard requires exactly one\n %loop = OpLabel\n"))
  1248. << str;
  1249. } else {
  1250. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1251. }
  1252. }
  1253. TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) {
  1254. bool is_shader = GetParam() == SpvCapabilityShader;
  1255. Block entry("entry");
  1256. Block loop("loop", SpvOpBranchConditional);
  1257. Block cheader("cheader", SpvOpBranchConditional);
  1258. Block be_block("be_block");
  1259. Block merge("merge", SpvOpReturn);
  1260. Block exit("exit", SpvOpReturn);
  1261. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1262. if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n");
  1263. std::string str = GetDefaultHeader(GetParam()) +
  1264. nameOps("cheader", "be_block") + types_consts() +
  1265. "%func = OpFunction %voidt None %funct\n";
  1266. str += entry >> loop;
  1267. str += loop >> std::vector<Block>({cheader, merge});
  1268. str += cheader >> std::vector<Block>({exit, be_block});
  1269. str += exit; // Branches out of a continue construct
  1270. str += be_block >> loop;
  1271. str += merge;
  1272. str += "OpFunctionEnd";
  1273. CompileSuccessfully(str);
  1274. if (is_shader) {
  1275. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1276. EXPECT_THAT(getDiagnosticString(),
  1277. MatchesRegex("The continue construct with the continue target "
  1278. ".\\[%cheader\\] is not post dominated by the "
  1279. "back-edge block .\\[%be_block\\]\n"
  1280. " %be_block = OpLabel\n"));
  1281. } else {
  1282. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1283. }
  1284. }
  1285. TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) {
  1286. bool is_shader = GetParam() == SpvCapabilityShader;
  1287. Block entry("entry");
  1288. Block loop("loop", SpvOpBranchConditional);
  1289. Block cont("cont", SpvOpBranchConditional);
  1290. Block merge("merge", SpvOpReturn);
  1291. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1292. if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
  1293. std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") +
  1294. types_consts() +
  1295. "%func = OpFunction %voidt None %funct\n";
  1296. str += entry >> loop;
  1297. str += loop >> std::vector<Block>({cont, merge});
  1298. str += cont >> std::vector<Block>({loop, merge});
  1299. str += merge;
  1300. str += "OpFunctionEnd";
  1301. CompileSuccessfully(str);
  1302. if (is_shader) {
  1303. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1304. EXPECT_THAT(getDiagnosticString(),
  1305. MatchesRegex("The continue construct with the continue target "
  1306. ".\\[%loop\\] is not post dominated by the "
  1307. "back-edge block .\\[%cont\\]\n"
  1308. " %cont = OpLabel\n"))
  1309. << str;
  1310. } else {
  1311. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1312. }
  1313. }
  1314. TEST_P(ValidateCFG, BranchOutOfConstructBad) {
  1315. bool is_shader = GetParam() == SpvCapabilityShader;
  1316. Block entry("entry");
  1317. Block loop("loop", SpvOpBranchConditional);
  1318. Block cont("cont", SpvOpBranchConditional);
  1319. Block merge("merge");
  1320. Block exit("exit", SpvOpReturn);
  1321. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1322. if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n");
  1323. std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") +
  1324. types_consts() +
  1325. "%func = OpFunction %voidt None %funct\n";
  1326. str += entry >> loop;
  1327. str += loop >> std::vector<Block>({cont, merge});
  1328. str += cont >> std::vector<Block>({loop, exit});
  1329. str += merge >> exit;
  1330. str += exit;
  1331. str += "OpFunctionEnd";
  1332. CompileSuccessfully(str);
  1333. if (is_shader) {
  1334. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1335. EXPECT_THAT(getDiagnosticString(),
  1336. MatchesRegex("The continue construct with the continue target "
  1337. ".\\[%loop\\] is not post dominated by the "
  1338. "back-edge block .\\[%cont\\]\n"
  1339. " %cont = OpLabel\n"));
  1340. } else {
  1341. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1342. }
  1343. }
  1344. TEST_F(ValidateCFG, OpSwitchToUnreachableBlock) {
  1345. Block entry("entry", SpvOpSwitch);
  1346. Block case0("case0");
  1347. Block case1("case1");
  1348. Block case2("case2");
  1349. Block def("default", SpvOpUnreachable);
  1350. Block phi("phi", SpvOpReturn);
  1351. std::string str = R"(
  1352. OpCapability Shader
  1353. OpMemoryModel Logical GLSL450
  1354. OpEntryPoint GLCompute %main "main" %id
  1355. OpExecutionMode %main LocalSize 1 1 1
  1356. OpSource GLSL 430
  1357. OpName %main "main"
  1358. OpDecorate %id BuiltIn GlobalInvocationId
  1359. %void = OpTypeVoid
  1360. %voidf = OpTypeFunction %void
  1361. %u32 = OpTypeInt 32 0
  1362. %f32 = OpTypeFloat 32
  1363. %uvec3 = OpTypeVector %u32 3
  1364. %fvec3 = OpTypeVector %f32 3
  1365. %uvec3ptr = OpTypePointer Input %uvec3
  1366. %id = OpVariable %uvec3ptr Input
  1367. %one = OpConstant %u32 1
  1368. %three = OpConstant %u32 3
  1369. %main = OpFunction %void None %voidf
  1370. )";
  1371. entry.SetBody(
  1372. "%idval = OpLoad %uvec3 %id\n"
  1373. "%x = OpCompositeExtract %u32 %idval 0\n"
  1374. "%selector = OpUMod %u32 %x %three\n"
  1375. "OpSelectionMerge %phi None\n");
  1376. str += entry >> std::vector<Block>({def, case0, case1, case2});
  1377. str += case1 >> phi;
  1378. str += def;
  1379. str += phi;
  1380. str += case0 >> phi;
  1381. str += case2 >> phi;
  1382. str += "OpFunctionEnd";
  1383. CompileSuccessfully(str);
  1384. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  1385. }
  1386. TEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) {
  1387. std::string str = R"(
  1388. OpCapability Shader
  1389. OpMemoryModel Logical GLSL450
  1390. OpEntryPoint Fragment %main "main"
  1391. OpExecutionMode %main OriginUpperLeft
  1392. OpName %loop "loop"
  1393. %voidt = OpTypeVoid
  1394. %funct = OpTypeFunction %voidt
  1395. %main = OpFunction %voidt None %funct
  1396. %loop = OpLabel
  1397. OpLoopMerge %exit %loop None
  1398. OpBranch %exit
  1399. %exit = OpLabel
  1400. OpReturn
  1401. OpFunctionEnd
  1402. )";
  1403. CompileSuccessfully(str);
  1404. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1405. EXPECT_THAT(
  1406. getDiagnosticString(),
  1407. MatchesRegex("Loop header .\\[%loop\\] is targeted by "
  1408. "0 back-edge blocks but the standard requires exactly "
  1409. "one\n %loop = OpLabel\n"));
  1410. }
  1411. TEST_F(ValidateCFG, LoopWithBackEdgeFromUnreachableContinueConstructGood) {
  1412. std::string str = R"(
  1413. OpCapability Shader
  1414. OpMemoryModel Logical GLSL450
  1415. OpEntryPoint Fragment %main "main"
  1416. OpExecutionMode %main OriginUpperLeft
  1417. OpName %loop "loop"
  1418. %voidt = OpTypeVoid
  1419. %funct = OpTypeFunction %voidt
  1420. %floatt = OpTypeFloat 32
  1421. %boolt = OpTypeBool
  1422. %one = OpConstant %floatt 1
  1423. %two = OpConstant %floatt 2
  1424. %main = OpFunction %voidt None %funct
  1425. %entry = OpLabel
  1426. OpBranch %loop
  1427. %loop = OpLabel
  1428. OpLoopMerge %exit %cont None
  1429. OpBranch %16
  1430. %16 = OpLabel
  1431. %cond = OpFOrdLessThan %boolt %one %two
  1432. OpBranchConditional %cond %body %exit
  1433. %body = OpLabel
  1434. OpReturn
  1435. %cont = OpLabel ; Reachable only from OpLoopMerge ContinueTarget parameter
  1436. OpBranch %loop ; Should be considered a back-edge
  1437. %exit = OpLabel
  1438. OpReturn
  1439. OpFunctionEnd
  1440. )";
  1441. CompileSuccessfully(str);
  1442. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  1443. }
  1444. TEST_P(ValidateCFG,
  1445. NestedConstructWithUnreachableMergeBlockBranchingToOuterMergeBlock) {
  1446. // Test for https://github.com/KhronosGroup/SPIRV-Tools/issues/297
  1447. // The nested construct has an unreachable merge block. In the
  1448. // augmented CFG that merge block
  1449. // we still determine that the
  1450. bool is_shader = GetParam() == SpvCapabilityShader;
  1451. Block entry("entry", SpvOpBranchConditional);
  1452. Block inner_head("inner_head", SpvOpBranchConditional);
  1453. Block inner_true("inner_true", SpvOpReturn);
  1454. Block inner_false("inner_false", SpvOpReturn);
  1455. Block inner_merge("inner_merge");
  1456. Block exit("exit", SpvOpReturn);
  1457. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1458. if (is_shader) {
  1459. entry.AppendBody("OpSelectionMerge %exit None\n");
  1460. inner_head.SetBody("OpSelectionMerge %inner_merge None\n");
  1461. }
  1462. std::string str = GetDefaultHeader(GetParam()) +
  1463. nameOps("entry", "inner_merge", "exit") + types_consts() +
  1464. "%func = OpFunction %voidt None %funct\n";
  1465. str += entry >> std::vector<Block>({inner_head, exit});
  1466. str += inner_head >> std::vector<Block>({inner_true, inner_false});
  1467. str += inner_true;
  1468. str += inner_false;
  1469. str += inner_merge >> exit;
  1470. str += exit;
  1471. str += "OpFunctionEnd";
  1472. CompileSuccessfully(str);
  1473. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  1474. }
  1475. TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructure) {
  1476. // The continue construct cannot be the merge target of a nested selection
  1477. // because the loop construct must contain "if_merge" because it contains
  1478. // "if_head".
  1479. bool is_shader = GetParam() == SpvCapabilityShader;
  1480. Block entry("entry");
  1481. Block loop("loop");
  1482. Block if_head("if_head", SpvOpBranchConditional);
  1483. Block if_true("if_true");
  1484. Block if_merge("if_merge", SpvOpBranchConditional);
  1485. Block merge("merge", SpvOpReturn);
  1486. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1487. if (is_shader) {
  1488. loop.SetBody("OpLoopMerge %merge %if_merge None\n");
  1489. if_head.SetBody("OpSelectionMerge %if_merge None\n");
  1490. }
  1491. std::string str =
  1492. GetDefaultHeader(GetParam()) +
  1493. nameOps("entry", "loop", "if_head", "if_true", "if_merge", "merge") +
  1494. types_consts() + "%func = OpFunction %voidt None %funct\n";
  1495. str += entry >> loop;
  1496. str += loop >> if_head;
  1497. str += if_head >> std::vector<Block>({if_true, if_merge});
  1498. str += if_true >> if_merge;
  1499. str += if_merge >> std::vector<Block>({loop, merge});
  1500. str += merge;
  1501. str += "OpFunctionEnd";
  1502. CompileSuccessfully(str);
  1503. if (is_shader) {
  1504. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1505. EXPECT_THAT(
  1506. getDiagnosticString(),
  1507. HasSubstr("Header block 3[%if_head] is contained in the loop construct "
  1508. "headed "
  1509. "by 2[%loop], but its merge block 5[%if_merge] is not"));
  1510. } else {
  1511. EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
  1512. }
  1513. }
  1514. TEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) {
  1515. // This test case ensures we allow both branches of a loop latch block
  1516. // to go back to the loop header. It still counts as a single back edge.
  1517. bool is_shader = GetParam() == SpvCapabilityShader;
  1518. Block entry("entry");
  1519. Block loop("loop", SpvOpBranchConditional);
  1520. Block latch("latch", SpvOpBranchConditional);
  1521. Block merge("merge", SpvOpReturn);
  1522. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1523. if (is_shader) {
  1524. loop.SetBody("OpLoopMerge %merge %latch None\n");
  1525. }
  1526. std::string str = GetDefaultHeader(GetParam()) +
  1527. nameOps("entry", "loop", "latch", "merge") +
  1528. types_consts() +
  1529. "%func = OpFunction %voidt None %funct\n";
  1530. str += entry >> loop;
  1531. str += loop >> std::vector<Block>({latch, merge});
  1532. str += latch >> std::vector<Block>({loop, loop}); // This is the key
  1533. str += merge;
  1534. str += "OpFunctionEnd";
  1535. CompileSuccessfully(str);
  1536. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions())
  1537. << str << getDiagnosticString();
  1538. }
  1539. TEST_P(ValidateCFG, SingleLatchBlockHeaderContinueTargetIsItselfGood) {
  1540. // This test case ensures we don't count a Continue Target from a loop
  1541. // header to itself as a self-loop when computing back edges.
  1542. // Also, it detects that there is an edge from %latch to the pseudo-exit
  1543. // node, rather than from %loop. In particular, it detects that we
  1544. // have used the *reverse* textual order of blocks when computing
  1545. // predecessor traversal roots.
  1546. bool is_shader = GetParam() == SpvCapabilityShader;
  1547. Block entry("entry");
  1548. Block loop("loop");
  1549. Block latch("latch");
  1550. Block merge("merge", SpvOpReturn);
  1551. entry.SetBody("%cond = OpSLessThan %boolt %one %two\n");
  1552. if (is_shader) {
  1553. loop.SetBody("OpLoopMerge %merge %loop None\n");
  1554. }
  1555. std::string str = GetDefaultHeader(GetParam()) +
  1556. nameOps("entry", "loop", "latch", "merge") +
  1557. types_consts() +
  1558. "%func = OpFunction %voidt None %funct\n";
  1559. str += entry >> loop;
  1560. str += loop >> latch;
  1561. str += latch >> loop;
  1562. str += merge;
  1563. str += "OpFunctionEnd";
  1564. CompileSuccessfully(str);
  1565. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions())
  1566. << str << getDiagnosticString();
  1567. }
  1568. // Unit test to check the case where a basic block is the entry block of 2
  1569. // different constructs. In this case, the basic block is the entry block of a
  1570. // continue construct as well as a selection construct. See issue# 517 for more
  1571. // details.
  1572. TEST_F(ValidateCFG, BasicBlockIsEntryBlockOfTwoConstructsGood) {
  1573. std::string spirv = R"(
  1574. OpCapability Shader
  1575. OpCapability Linkage
  1576. OpMemoryModel Logical GLSL450
  1577. %void = OpTypeVoid
  1578. %bool = OpTypeBool
  1579. %int = OpTypeInt 32 1
  1580. %void_func = OpTypeFunction %void
  1581. %int_0 = OpConstant %int 0
  1582. %testfun = OpFunction %void None %void_func
  1583. %label_1 = OpLabel
  1584. OpBranch %start
  1585. %start = OpLabel
  1586. %cond = OpSLessThan %bool %int_0 %int_0
  1587. ;
  1588. ; Note: In this case, the "target" block is both the entry block of
  1589. ; the continue construct of the loop as well as the entry block of
  1590. ; the selection construct.
  1591. ;
  1592. OpLoopMerge %loop_merge %target None
  1593. OpBranchConditional %cond %target %loop_merge
  1594. %loop_merge = OpLabel
  1595. OpReturn
  1596. %target = OpLabel
  1597. OpSelectionMerge %selection_merge None
  1598. OpBranchConditional %cond %do_stuff %do_other_stuff
  1599. %do_other_stuff = OpLabel
  1600. OpBranch %selection_merge
  1601. %selection_merge = OpLabel
  1602. OpBranch %start
  1603. %do_stuff = OpLabel
  1604. OpBranch %selection_merge
  1605. OpFunctionEnd
  1606. )";
  1607. CompileSuccessfully(spirv);
  1608. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  1609. }
  1610. TEST_F(ValidateCFG, OpReturnInNonVoidFunc) {
  1611. std::string spirv = R"(
  1612. OpCapability Shader
  1613. OpCapability Linkage
  1614. OpMemoryModel Logical GLSL450
  1615. %int = OpTypeInt 32 1
  1616. %int_func = OpTypeFunction %int
  1617. %testfun = OpFunction %int None %int_func
  1618. %label_1 = OpLabel
  1619. OpReturn
  1620. OpFunctionEnd
  1621. )";
  1622. CompileSuccessfully(spirv);
  1623. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1624. EXPECT_THAT(
  1625. getDiagnosticString(),
  1626. HasSubstr(
  1627. "OpReturn can only be called from a function with void return type.\n"
  1628. " OpReturn"));
  1629. }
  1630. TEST_F(ValidateCFG, StructuredCFGBranchIntoSelectionBody) {
  1631. std::string spirv = R"(
  1632. OpCapability Shader
  1633. OpMemoryModel Logical GLSL450
  1634. OpEntryPoint Fragment %func "func"
  1635. OpExecutionMode %func OriginUpperLeft
  1636. %void = OpTypeVoid
  1637. %bool = OpTypeBool
  1638. %true = OpConstantTrue %bool
  1639. %functy = OpTypeFunction %void
  1640. %func = OpFunction %void None %functy
  1641. %entry = OpLabel
  1642. OpSelectionMerge %merge None
  1643. OpBranchConditional %true %then %merge
  1644. %merge = OpLabel
  1645. OpBranch %then
  1646. %then = OpLabel
  1647. OpReturn
  1648. OpFunctionEnd
  1649. )";
  1650. CompileSuccessfully(spirv);
  1651. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1652. EXPECT_THAT(getDiagnosticString(),
  1653. HasSubstr("branches to the selection construct, but not to the "
  1654. "selection header <ID> 6\n %7 = OpLabel"));
  1655. }
  1656. TEST_F(ValidateCFG, SwitchDefaultOnly) {
  1657. std::string text = R"(
  1658. OpCapability Shader
  1659. OpCapability Linkage
  1660. OpMemoryModel Logical GLSL450
  1661. %1 = OpTypeVoid
  1662. %2 = OpTypeInt 32 0
  1663. %3 = OpConstant %2 0
  1664. %4 = OpTypeFunction %1
  1665. %5 = OpFunction %1 None %4
  1666. %6 = OpLabel
  1667. OpSelectionMerge %7 None
  1668. OpSwitch %3 %7
  1669. %7 = OpLabel
  1670. OpReturn
  1671. OpFunctionEnd
  1672. )";
  1673. CompileSuccessfully(text);
  1674. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1675. }
  1676. TEST_F(ValidateCFG, SwitchSingleCase) {
  1677. std::string text = R"(
  1678. OpCapability Shader
  1679. OpCapability Linkage
  1680. OpMemoryModel Logical GLSL450
  1681. %1 = OpTypeVoid
  1682. %2 = OpTypeInt 32 0
  1683. %3 = OpConstant %2 0
  1684. %4 = OpTypeFunction %1
  1685. %5 = OpFunction %1 None %4
  1686. %6 = OpLabel
  1687. OpSelectionMerge %7 None
  1688. OpSwitch %3 %7 0 %8
  1689. %8 = OpLabel
  1690. OpBranch %7
  1691. %7 = OpLabel
  1692. OpReturn
  1693. OpFunctionEnd
  1694. )";
  1695. CompileSuccessfully(text);
  1696. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1697. }
  1698. TEST_F(ValidateCFG, MultipleFallThroughBlocks) {
  1699. std::string text = R"(
  1700. OpCapability Shader
  1701. OpCapability Linkage
  1702. OpMemoryModel Logical GLSL450
  1703. %1 = OpTypeVoid
  1704. %2 = OpTypeInt 32 0
  1705. %3 = OpConstant %2 0
  1706. %4 = OpTypeFunction %1
  1707. %5 = OpTypeBool
  1708. %6 = OpConstantTrue %5
  1709. %7 = OpFunction %1 None %4
  1710. %8 = OpLabel
  1711. OpSelectionMerge %9 None
  1712. OpSwitch %3 %10 0 %11 1 %12
  1713. %10 = OpLabel
  1714. OpBranchConditional %6 %11 %12
  1715. %11 = OpLabel
  1716. OpBranch %9
  1717. %12 = OpLabel
  1718. OpBranch %9
  1719. %9 = OpLabel
  1720. OpReturn
  1721. OpFunctionEnd
  1722. )";
  1723. CompileSuccessfully(text);
  1724. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1725. EXPECT_THAT(
  1726. getDiagnosticString(),
  1727. HasSubstr(
  1728. "Case construct that targets 10[%10] has branches to multiple other "
  1729. "case construct targets 12[%12] and 11[%11]\n %10 = OpLabel"));
  1730. }
  1731. TEST_F(ValidateCFG, MultipleFallThroughToDefault) {
  1732. std::string text = R"(
  1733. OpCapability Shader
  1734. OpCapability Linkage
  1735. OpMemoryModel Logical GLSL450
  1736. %1 = OpTypeVoid
  1737. %2 = OpTypeInt 32 0
  1738. %3 = OpConstant %2 0
  1739. %4 = OpTypeFunction %1
  1740. %5 = OpTypeBool
  1741. %6 = OpConstantTrue %5
  1742. %7 = OpFunction %1 None %4
  1743. %8 = OpLabel
  1744. OpSelectionMerge %9 None
  1745. OpSwitch %3 %10 0 %11 1 %12
  1746. %10 = OpLabel
  1747. OpBranch %9
  1748. %11 = OpLabel
  1749. OpBranch %10
  1750. %12 = OpLabel
  1751. OpBranch %10
  1752. %9 = OpLabel
  1753. OpReturn
  1754. OpFunctionEnd
  1755. )";
  1756. CompileSuccessfully(text);
  1757. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1758. EXPECT_THAT(
  1759. getDiagnosticString(),
  1760. HasSubstr("Multiple case constructs have branches to the case construct "
  1761. "that targets 10[%10]\n %10 = OpLabel"));
  1762. }
  1763. TEST_F(ValidateCFG, MultipleFallThroughToNonDefault) {
  1764. std::string text = R"(
  1765. OpCapability Shader
  1766. OpCapability Linkage
  1767. OpMemoryModel Logical GLSL450
  1768. %1 = OpTypeVoid
  1769. %2 = OpTypeInt 32 0
  1770. %3 = OpConstant %2 0
  1771. %4 = OpTypeFunction %1
  1772. %5 = OpTypeBool
  1773. %6 = OpConstantTrue %5
  1774. %7 = OpFunction %1 None %4
  1775. %8 = OpLabel
  1776. OpSelectionMerge %9 None
  1777. OpSwitch %3 %10 0 %11 1 %12
  1778. %10 = OpLabel
  1779. OpBranch %12
  1780. %11 = OpLabel
  1781. OpBranch %12
  1782. %12 = OpLabel
  1783. OpBranch %9
  1784. %9 = OpLabel
  1785. OpReturn
  1786. OpFunctionEnd
  1787. )";
  1788. CompileSuccessfully(text);
  1789. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1790. EXPECT_THAT(
  1791. getDiagnosticString(),
  1792. HasSubstr("Multiple case constructs have branches to the case construct "
  1793. "that targets 12[%12]\n %12 = OpLabel"));
  1794. }
  1795. TEST_F(ValidateCFG, DuplicateTargetWithFallThrough) {
  1796. std::string text = R"(
  1797. OpCapability Shader
  1798. OpCapability Linkage
  1799. OpMemoryModel Logical GLSL450
  1800. %1 = OpTypeVoid
  1801. %2 = OpTypeInt 32 0
  1802. %3 = OpConstant %2 0
  1803. %4 = OpTypeFunction %1
  1804. %5 = OpTypeBool
  1805. %6 = OpConstantTrue %5
  1806. %7 = OpFunction %1 None %4
  1807. %8 = OpLabel
  1808. OpSelectionMerge %9 None
  1809. OpSwitch %3 %10 0 %10 1 %11
  1810. %10 = OpLabel
  1811. OpBranch %11
  1812. %11 = OpLabel
  1813. OpBranch %9
  1814. %9 = OpLabel
  1815. OpReturn
  1816. OpFunctionEnd
  1817. )";
  1818. CompileSuccessfully(text);
  1819. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  1820. }
  1821. TEST_F(ValidateCFG, WrongOperandList) {
  1822. std::string text = R"(
  1823. OpCapability Shader
  1824. OpCapability Linkage
  1825. OpMemoryModel Logical GLSL450
  1826. %1 = OpTypeVoid
  1827. %2 = OpTypeInt 32 0
  1828. %3 = OpConstant %2 0
  1829. %4 = OpTypeFunction %1
  1830. %5 = OpTypeBool
  1831. %6 = OpConstantTrue %5
  1832. %7 = OpFunction %1 None %4
  1833. %8 = OpLabel
  1834. OpSelectionMerge %9 None
  1835. OpSwitch %3 %10 0 %11 1 %12
  1836. %10 = OpLabel
  1837. OpBranch %9
  1838. %12 = OpLabel
  1839. OpBranch %11
  1840. %11 = OpLabel
  1841. OpBranch %9
  1842. %9 = OpLabel
  1843. OpReturn
  1844. OpFunctionEnd
  1845. )";
  1846. CompileSuccessfully(text);
  1847. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1848. EXPECT_THAT(
  1849. getDiagnosticString(),
  1850. HasSubstr("Case construct that targets 12[%12] has branches to the case "
  1851. "construct that targets 11[%11], but does not immediately "
  1852. "precede it in the OpSwitch's target list\n"
  1853. " OpSwitch %uint_0 %10 0 %11 1 %12"));
  1854. }
  1855. TEST_F(ValidateCFG, WrongOperandListThroughDefault) {
  1856. std::string text = R"(
  1857. OpCapability Shader
  1858. OpCapability Linkage
  1859. OpMemoryModel Logical GLSL450
  1860. %1 = OpTypeVoid
  1861. %2 = OpTypeInt 32 0
  1862. %3 = OpConstant %2 0
  1863. %4 = OpTypeFunction %1
  1864. %5 = OpTypeBool
  1865. %6 = OpConstantTrue %5
  1866. %7 = OpFunction %1 None %4
  1867. %8 = OpLabel
  1868. OpSelectionMerge %9 None
  1869. OpSwitch %3 %10 0 %11 1 %12
  1870. %10 = OpLabel
  1871. OpBranch %11
  1872. %12 = OpLabel
  1873. OpBranch %10
  1874. %11 = OpLabel
  1875. OpBranch %9
  1876. %9 = OpLabel
  1877. OpReturn
  1878. OpFunctionEnd
  1879. )";
  1880. CompileSuccessfully(text);
  1881. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1882. EXPECT_THAT(
  1883. getDiagnosticString(),
  1884. HasSubstr("Case construct that targets 12[%12] has branches to the case "
  1885. "construct that targets 11[%11], but does not immediately "
  1886. "precede it in the OpSwitch's target list\n"
  1887. " OpSwitch %uint_0 %10 0 %11 1 %12"));
  1888. }
  1889. TEST_F(ValidateCFG, WrongOperandListNotLast) {
  1890. std::string text = R"(
  1891. OpCapability Shader
  1892. OpCapability Linkage
  1893. OpMemoryModel Logical GLSL450
  1894. %1 = OpTypeVoid
  1895. %2 = OpTypeInt 32 0
  1896. %3 = OpConstant %2 0
  1897. %4 = OpTypeFunction %1
  1898. %5 = OpTypeBool
  1899. %6 = OpConstantTrue %5
  1900. %7 = OpFunction %1 None %4
  1901. %8 = OpLabel
  1902. OpSelectionMerge %9 None
  1903. OpSwitch %3 %10 0 %11 1 %12 2 %13
  1904. %10 = OpLabel
  1905. OpBranch %9
  1906. %12 = OpLabel
  1907. OpBranch %11
  1908. %11 = OpLabel
  1909. OpBranch %9
  1910. %13 = OpLabel
  1911. OpBranch %9
  1912. %9 = OpLabel
  1913. OpReturn
  1914. OpFunctionEnd
  1915. )";
  1916. CompileSuccessfully(text);
  1917. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1918. EXPECT_THAT(
  1919. getDiagnosticString(),
  1920. HasSubstr("Case construct that targets 12[%12] has branches to the case "
  1921. "construct that targets 11[%11], but does not immediately "
  1922. "precede it in the OpSwitch's target list\n"
  1923. " OpSwitch %uint_0 %10 0 %11 1 %12 2 %13"));
  1924. }
  1925. TEST_F(ValidateCFG, GoodUnreachableSwitch) {
  1926. const std::string text = R"(
  1927. OpCapability Shader
  1928. OpMemoryModel Logical GLSL450
  1929. OpEntryPoint Fragment %2 "main"
  1930. OpExecutionMode %2 OriginUpperLeft
  1931. %3 = OpTypeVoid
  1932. %4 = OpTypeFunction %3
  1933. %5 = OpTypeBool
  1934. %6 = OpConstantTrue %5
  1935. %7 = OpTypeInt 32 1
  1936. %9 = OpConstant %7 0
  1937. %2 = OpFunction %3 None %4
  1938. %10 = OpLabel
  1939. OpSelectionMerge %11 None
  1940. OpBranchConditional %6 %12 %13
  1941. %12 = OpLabel
  1942. OpReturn
  1943. %13 = OpLabel
  1944. OpReturn
  1945. %11 = OpLabel
  1946. OpSelectionMerge %14 None
  1947. OpSwitch %9 %14 0 %15
  1948. %15 = OpLabel
  1949. OpBranch %14
  1950. %14 = OpLabel
  1951. OpReturn
  1952. OpFunctionEnd
  1953. )";
  1954. CompileSuccessfully(text);
  1955. EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
  1956. }
  1957. TEST_F(ValidateCFG, InvalidCaseExit) {
  1958. const std::string text = R"(
  1959. OpCapability Shader
  1960. OpMemoryModel Logical GLSL450
  1961. OpEntryPoint Fragment %1 "func"
  1962. OpExecutionMode %1 OriginUpperLeft
  1963. %2 = OpTypeVoid
  1964. %3 = OpTypeInt 32 0
  1965. %4 = OpTypeFunction %2
  1966. %5 = OpConstant %3 0
  1967. %1 = OpFunction %2 None %4
  1968. %6 = OpLabel
  1969. OpSelectionMerge %7 None
  1970. OpSwitch %5 %7 0 %8 1 %9
  1971. %8 = OpLabel
  1972. OpBranch %10
  1973. %9 = OpLabel
  1974. OpBranch %10
  1975. %10 = OpLabel
  1976. OpReturn
  1977. %7 = OpLabel
  1978. OpReturn
  1979. OpFunctionEnd
  1980. )";
  1981. CompileSuccessfully(text);
  1982. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  1983. EXPECT_THAT(getDiagnosticString(),
  1984. HasSubstr("Case construct that targets 8[%8] has invalid branch "
  1985. "to block 10[%10] (not another case construct, "
  1986. "corresponding merge, outer loop merge or outer loop "
  1987. "continue)"));
  1988. }
  1989. TEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) {
  1990. const std::string text = R"(
  1991. OpCapability Shader
  1992. OpMemoryModel Logical GLSL450
  1993. OpEntryPoint Fragment %func "func"
  1994. OpExecutionMode %func OriginUpperLeft
  1995. %void = OpTypeVoid
  1996. %bool = OpTypeBool
  1997. %true = OpConstantTrue %bool
  1998. %int = OpTypeInt 32 0
  1999. %int0 = OpConstant %int 0
  2000. %func_ty = OpTypeFunction %void
  2001. %func = OpFunction %void None %func_ty
  2002. %1 = OpLabel
  2003. OpBranch %2
  2004. %2 = OpLabel
  2005. OpLoopMerge %7 %6 None
  2006. OpBranch %3
  2007. %3 = OpLabel
  2008. OpSelectionMerge %5 None
  2009. OpSwitch %int0 %5 0 %4
  2010. %4 = OpLabel
  2011. OpBranchConditional %true %6 %7
  2012. %5 = OpLabel
  2013. OpBranchConditional %true %6 %7
  2014. %6 = OpLabel
  2015. OpBranch %2
  2016. %7 = OpLabel
  2017. OpReturn
  2018. OpFunctionEnd
  2019. )";
  2020. CompileSuccessfully(text);
  2021. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  2022. }
  2023. TEST_F(ValidateCFG, SwitchCaseOrderingBad1) {
  2024. const std::string text = R"(
  2025. OpCapability Shader
  2026. OpCapability Linkage
  2027. OpMemoryModel Logical GLSL450
  2028. OpName %default "default"
  2029. OpName %other "other"
  2030. %void = OpTypeVoid
  2031. %int = OpTypeInt 32 0
  2032. %undef = OpUndef %int
  2033. %void_fn = OpTypeFunction %void
  2034. %func = OpFunction %void None %void_fn
  2035. %entry = OpLabel
  2036. OpSelectionMerge %merge None
  2037. OpSwitch %undef %default 0 %other 1 %default
  2038. %default = OpLabel
  2039. OpBranch %other
  2040. %other = OpLabel
  2041. OpBranch %merge
  2042. %merge = OpLabel
  2043. OpReturn
  2044. OpFunctionEnd
  2045. )";
  2046. CompileSuccessfully(text);
  2047. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2048. EXPECT_THAT(
  2049. getDiagnosticString(),
  2050. HasSubstr("Case construct that targets 1[%default] has branches to the "
  2051. "case construct that targets 2[%other], but does not "
  2052. "immediately precede it in the OpSwitch's target list"));
  2053. }
  2054. TEST_F(ValidateCFG, SwitchCaseOrderingBad2) {
  2055. const std::string text = R"(
  2056. OpCapability Shader
  2057. OpCapability Linkage
  2058. OpMemoryModel Logical GLSL450
  2059. OpName %default "default"
  2060. OpName %other "other"
  2061. %void = OpTypeVoid
  2062. %int = OpTypeInt 32 0
  2063. %undef = OpUndef %int
  2064. %void_fn = OpTypeFunction %void
  2065. %func = OpFunction %void None %void_fn
  2066. %entry = OpLabel
  2067. OpSelectionMerge %merge None
  2068. OpSwitch %undef %default 0 %default 1 %other
  2069. %other = OpLabel
  2070. OpBranch %default
  2071. %default = OpLabel
  2072. OpBranch %merge
  2073. %merge = OpLabel
  2074. OpReturn
  2075. OpFunctionEnd
  2076. )";
  2077. CompileSuccessfully(text);
  2078. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2079. EXPECT_THAT(
  2080. getDiagnosticString(),
  2081. HasSubstr("Case construct that targets 2[%other] has branches to the "
  2082. "case construct that targets 1[%default], but does not "
  2083. "immediately precede it in the OpSwitch's target list"));
  2084. }
  2085. TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughGood) {
  2086. const std::string text = R"(
  2087. OpCapability Shader
  2088. OpCapability Linkage
  2089. OpMemoryModel Logical GLSL450
  2090. OpName %first "first"
  2091. OpName %second "second"
  2092. OpName %third "third"
  2093. %void = OpTypeVoid
  2094. %int = OpTypeInt 32 0
  2095. %undef = OpUndef %int
  2096. %void_fn = OpTypeFunction %void
  2097. %func = OpFunction %void None %void_fn
  2098. %entry = OpLabel
  2099. OpSelectionMerge %merge None
  2100. OpSwitch %undef %second 0 %first 1 %second 2 %third
  2101. %first = OpLabel
  2102. OpBranch %second
  2103. %second = OpLabel
  2104. OpBranch %third
  2105. %third = OpLabel
  2106. OpBranch %merge
  2107. %merge = OpLabel
  2108. OpReturn
  2109. OpFunctionEnd
  2110. )";
  2111. CompileSuccessfully(text);
  2112. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2113. }
  2114. TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughBad) {
  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 %second 1 %first 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_ERROR_INVALID_CFG, ValidateInstructions());
  2142. }
  2143. TEST_F(ValidateCFG, GoodUnreachableSelection) {
  2144. const std::string text = R"(
  2145. OpCapability Shader
  2146. %1 = OpExtInstImport "GLSL.std.450"
  2147. OpMemoryModel Logical GLSL450
  2148. OpEntryPoint Fragment %main "main"
  2149. OpExecutionMode %main OriginUpperLeft
  2150. %void = OpTypeVoid
  2151. %8 = OpTypeFunction %void
  2152. %bool = OpTypeBool
  2153. %false = OpConstantFalse %bool
  2154. %main = OpFunction %void None %8
  2155. %15 = OpLabel
  2156. OpBranch %16
  2157. %16 = OpLabel
  2158. OpLoopMerge %17 %18 None
  2159. OpBranch %19
  2160. %19 = OpLabel
  2161. OpBranchConditional %false %21 %17
  2162. %21 = OpLabel
  2163. OpSelectionMerge %22 None
  2164. OpBranchConditional %false %23 %22
  2165. %23 = OpLabel
  2166. OpBranch %24
  2167. %24 = OpLabel
  2168. OpLoopMerge %25 %26 None
  2169. OpBranch %27
  2170. %27 = OpLabel
  2171. OpReturn
  2172. %26 = OpLabel
  2173. OpBranchConditional %false %24 %25
  2174. %25 = OpLabel
  2175. OpSelectionMerge %28 None
  2176. OpBranchConditional %false %18 %28
  2177. %28 = OpLabel
  2178. OpBranch %22
  2179. %22 = OpLabel
  2180. OpBranch %18
  2181. %18 = OpLabel
  2182. OpBranch %16
  2183. %17 = OpLabel
  2184. OpReturn
  2185. OpFunctionEnd
  2186. )";
  2187. CompileSuccessfully(text);
  2188. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  2189. }
  2190. TEST_F(ValidateCFG, ShaderWithPhiPtr) {
  2191. const std::string text = R"(
  2192. OpCapability Shader
  2193. OpMemoryModel Logical GLSL450
  2194. OpEntryPoint GLCompute %1 "main"
  2195. OpExecutionMode %1 LocalSize 1 1 1
  2196. OpSource HLSL 600
  2197. %bool = OpTypeBool
  2198. %_ptr_Function_bool = OpTypePointer Function %bool
  2199. %void = OpTypeVoid
  2200. %5 = OpTypeFunction %void
  2201. %1 = OpFunction %void None %5
  2202. %6 = OpLabel
  2203. %7 = OpVariable %_ptr_Function_bool Function
  2204. %8 = OpVariable %_ptr_Function_bool Function
  2205. %9 = OpUndef %bool
  2206. OpSelectionMerge %10 None
  2207. OpBranchConditional %9 %11 %10
  2208. %11 = OpLabel
  2209. OpBranch %10
  2210. %10 = OpLabel
  2211. %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11
  2212. OpReturn
  2213. OpFunctionEnd
  2214. )";
  2215. CompileSuccessfully(text);
  2216. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  2217. EXPECT_THAT(getDiagnosticString(),
  2218. HasSubstr("Using pointers with OpPhi requires capability "
  2219. "VariablePointers or VariablePointersStorageBuffer"));
  2220. }
  2221. TEST_F(ValidateCFG, VarPtrShaderWithPhiPtr) {
  2222. const std::string text = R"(
  2223. OpCapability Shader
  2224. OpCapability VariablePointers
  2225. OpExtension "SPV_KHR_variable_pointers"
  2226. OpMemoryModel Logical GLSL450
  2227. OpEntryPoint GLCompute %1 "main"
  2228. OpExecutionMode %1 LocalSize 1 1 1
  2229. OpSource HLSL 600
  2230. %bool = OpTypeBool
  2231. %_ptr_Function_bool = OpTypePointer Function %bool
  2232. %void = OpTypeVoid
  2233. %5 = OpTypeFunction %void
  2234. %1 = OpFunction %void None %5
  2235. %6 = OpLabel
  2236. %7 = OpVariable %_ptr_Function_bool Function
  2237. %8 = OpVariable %_ptr_Function_bool Function
  2238. %9 = OpUndef %bool
  2239. OpSelectionMerge %10 None
  2240. OpBranchConditional %9 %11 %10
  2241. %11 = OpLabel
  2242. OpBranch %10
  2243. %10 = OpLabel
  2244. %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11
  2245. OpReturn
  2246. OpFunctionEnd
  2247. )";
  2248. CompileSuccessfully(text);
  2249. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2250. }
  2251. TEST_F(ValidateCFG, VarPtrStgBufShaderWithPhiStgBufPtr) {
  2252. const std::string text = R"(
  2253. OpCapability Shader
  2254. OpCapability VariablePointersStorageBuffer
  2255. OpExtension "SPV_KHR_variable_pointers"
  2256. OpMemoryModel Logical GLSL450
  2257. OpEntryPoint GLCompute %1 "main"
  2258. OpExecutionMode %1 LocalSize 1 1 1
  2259. OpSource HLSL 600
  2260. %bool = OpTypeBool
  2261. %float = OpTypeFloat 32
  2262. %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
  2263. %7 = OpVariable %_ptr_StorageBuffer_float StorageBuffer
  2264. %8 = OpVariable %_ptr_StorageBuffer_float StorageBuffer
  2265. %void = OpTypeVoid
  2266. %5 = OpTypeFunction %void
  2267. %1 = OpFunction %void None %5
  2268. %6 = OpLabel
  2269. %9 = OpUndef %bool
  2270. OpSelectionMerge %10 None
  2271. OpBranchConditional %9 %11 %10
  2272. %11 = OpLabel
  2273. OpBranch %10
  2274. %10 = OpLabel
  2275. %12 = OpPhi %_ptr_StorageBuffer_float %7 %6 %8 %11
  2276. OpReturn
  2277. OpFunctionEnd
  2278. )";
  2279. CompileSuccessfully(text);
  2280. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2281. }
  2282. TEST_F(ValidateCFG, KernelWithPhiPtr) {
  2283. const std::string text = R"(
  2284. OpCapability Kernel
  2285. OpCapability Addresses
  2286. OpMemoryModel Physical32 OpenCL
  2287. OpEntryPoint Kernel %1 "main"
  2288. OpExecutionMode %1 LocalSize 1 1 1
  2289. OpSource HLSL 600
  2290. %bool = OpTypeBool
  2291. %_ptr_Function_bool = OpTypePointer Function %bool
  2292. %void = OpTypeVoid
  2293. %5 = OpTypeFunction %void
  2294. %1 = OpFunction %void None %5
  2295. %6 = OpLabel
  2296. %7 = OpVariable %_ptr_Function_bool Function
  2297. %8 = OpVariable %_ptr_Function_bool Function
  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_Function_bool %7 %6 %8 %11
  2305. OpReturn
  2306. OpFunctionEnd
  2307. )";
  2308. CompileSuccessfully(text);
  2309. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2310. }
  2311. TEST_F(ValidateCFG, SwitchTargetMustBeLabel) {
  2312. const std::string text = R"(
  2313. OpCapability Shader
  2314. OpMemoryModel Logical GLSL450
  2315. OpEntryPoint GLCompute %1 "foo"
  2316. %uint = OpTypeInt 32 0
  2317. %uint_0 = OpConstant %uint 0
  2318. %void = OpTypeVoid
  2319. %5 = OpTypeFunction %void
  2320. %1 = OpFunction %void None %5
  2321. %6 = OpLabel
  2322. %7 = OpCopyObject %uint %uint_0
  2323. OpSelectionMerge %8 None
  2324. OpSwitch %uint_0 %8 0 %7
  2325. %8 = OpLabel
  2326. OpReturn
  2327. OpFunctionEnd
  2328. )";
  2329. CompileSuccessfully(text);
  2330. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2331. EXPECT_THAT(getDiagnosticString(),
  2332. HasSubstr("'Target Label' operands for OpSwitch must "
  2333. "be IDs of an OpLabel instruction"));
  2334. }
  2335. TEST_F(ValidateCFG, BranchTargetMustBeLabel) {
  2336. const std::string text = R"(
  2337. OpCapability Shader
  2338. OpMemoryModel Logical GLSL450
  2339. OpEntryPoint GLCompute %1 "foo"
  2340. %uint = OpTypeInt 32 0
  2341. %uint_0 = OpConstant %uint 0
  2342. %void = OpTypeVoid
  2343. %5 = OpTypeFunction %void
  2344. %1 = OpFunction %void None %5
  2345. %2 = OpLabel
  2346. %7 = OpCopyObject %uint %uint_0
  2347. OpBranch %7
  2348. %8 = OpLabel
  2349. OpReturn
  2350. OpFunctionEnd
  2351. )";
  2352. CompileSuccessfully(text);
  2353. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2354. EXPECT_THAT(getDiagnosticString(),
  2355. HasSubstr("'Target Label' operands for OpBranch must "
  2356. "be the ID of an OpLabel instruction"));
  2357. }
  2358. TEST_F(ValidateCFG, ReachableOpUnreachableOneBlock) {
  2359. const std::string text = R"(
  2360. OpCapability Shader
  2361. OpCapability Linkage
  2362. OpMemoryModel Logical GLSL450
  2363. %void = OpTypeVoid
  2364. %void_fn = OpTypeFunction %void
  2365. %func = OpFunction %void None %void_fn
  2366. %entry = OpLabel
  2367. OpUnreachable
  2368. OpFunctionEnd
  2369. )";
  2370. CompileSuccessfully(text);
  2371. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2372. }
  2373. TEST_F(ValidateCFG, ReachableOpUnreachableOpBranch) {
  2374. const std::string text = R"(
  2375. OpCapability Shader
  2376. OpCapability Linkage
  2377. OpMemoryModel Logical GLSL450
  2378. %void = OpTypeVoid
  2379. %void_fn = OpTypeFunction %void
  2380. %func = OpFunction %void None %void_fn
  2381. %entry = OpLabel
  2382. OpBranch %block
  2383. %block = OpLabel
  2384. OpUnreachable
  2385. OpFunctionEnd
  2386. )";
  2387. CompileSuccessfully(text);
  2388. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2389. }
  2390. TEST_F(ValidateCFG, ReachableOpUnreachableOpBranchConditional) {
  2391. const std::string text = R"(
  2392. OpCapability Shader
  2393. OpCapability Linkage
  2394. OpMemoryModel Logical GLSL450
  2395. %void = OpTypeVoid
  2396. %void_fn = OpTypeFunction %void
  2397. %bool = OpTypeBool
  2398. %undef = OpUndef %bool
  2399. %func = OpFunction %void None %void_fn
  2400. %entry = OpLabel
  2401. OpSelectionMerge %block None
  2402. OpBranchConditional %undef %block %unreachable
  2403. %block = OpLabel
  2404. OpReturn
  2405. %unreachable = OpLabel
  2406. OpUnreachable
  2407. OpFunctionEnd
  2408. )";
  2409. CompileSuccessfully(text);
  2410. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2411. }
  2412. TEST_F(ValidateCFG, ReachableOpUnreachableOpSwitch) {
  2413. const std::string text = R"(
  2414. OpCapability Shader
  2415. OpCapability Linkage
  2416. OpMemoryModel Logical GLSL450
  2417. %void = OpTypeVoid
  2418. %void_fn = OpTypeFunction %void
  2419. %int = OpTypeInt 32 0
  2420. %undef = OpUndef %int
  2421. %func = OpFunction %void None %void_fn
  2422. %entry = OpLabel
  2423. OpSelectionMerge %block1 None
  2424. OpSwitch %undef %block1 0 %unreachable 1 %block2
  2425. %block1 = OpLabel
  2426. OpReturn
  2427. %unreachable = OpLabel
  2428. OpUnreachable
  2429. %block2 = OpLabel
  2430. OpReturn
  2431. OpFunctionEnd
  2432. )";
  2433. CompileSuccessfully(text);
  2434. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2435. }
  2436. TEST_F(ValidateCFG, ReachableOpUnreachableLoop) {
  2437. const std::string text = R"(
  2438. OpCapability Shader
  2439. OpCapability Linkage
  2440. OpMemoryModel Logical GLSL450
  2441. %void = OpTypeVoid
  2442. %void_fn = OpTypeFunction %void
  2443. %bool = OpTypeBool
  2444. %undef = OpUndef %bool
  2445. %func = OpFunction %void None %void_fn
  2446. %entry = OpLabel
  2447. OpBranch %loop
  2448. %loop = OpLabel
  2449. OpLoopMerge %unreachable %loop None
  2450. OpBranchConditional %undef %loop %unreachable
  2451. %unreachable = OpLabel
  2452. OpUnreachable
  2453. OpFunctionEnd
  2454. )";
  2455. CompileSuccessfully(text);
  2456. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2457. }
  2458. TEST_F(ValidateCFG, UnreachableLoopBadBackedge) {
  2459. const std::string text = R"(
  2460. OpCapability Shader
  2461. OpMemoryModel Logical GLSL450
  2462. OpEntryPoint Fragment %2 "main"
  2463. OpExecutionMode %2 OriginUpperLeft
  2464. %4 = OpTypeVoid
  2465. %5 = OpTypeFunction %4
  2466. %8 = OpTypeBool
  2467. %13 = OpConstantTrue %8
  2468. %2 = OpFunction %4 None %5
  2469. %14 = OpLabel
  2470. OpSelectionMerge %15 None
  2471. OpBranchConditional %13 %15 %15
  2472. %16 = OpLabel
  2473. OpLoopMerge %17 %18 None
  2474. OpBranch %17
  2475. %18 = OpLabel
  2476. OpBranch %17
  2477. %17 = OpLabel
  2478. OpBranch %15
  2479. %15 = OpLabel
  2480. OpReturn
  2481. OpFunctionEnd
  2482. )";
  2483. // The back-edge in this test is bad, but the validator fails to identify it
  2484. // because it is in an entirely unreachable section of code. Prior to #2488
  2485. // this code failed an assert in Construct::blocks().
  2486. CompileSuccessfully(text);
  2487. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2488. }
  2489. TEST_F(ValidateCFG, OneContinueTwoBackedges) {
  2490. const std::string text = R"(
  2491. OpCapability Shader
  2492. OpMemoryModel Logical GLSL450
  2493. OpEntryPoint GLCompute %1 "main"
  2494. OpExecutionMode %1 LocalSize 1 1 1
  2495. %void = OpTypeVoid
  2496. %bool = OpTypeBool
  2497. %true = OpConstantTrue %bool
  2498. %5 = OpTypeFunction %void
  2499. %1 = OpFunction %void None %5
  2500. %6 = OpLabel
  2501. OpBranch %7
  2502. %7 = OpLabel
  2503. OpLoopMerge %8 %9 None
  2504. OpBranch %10
  2505. %10 = OpLabel
  2506. OpLoopMerge %11 %9 None
  2507. OpBranchConditional %true %11 %9
  2508. %9 = OpLabel
  2509. OpBranchConditional %true %10 %7
  2510. %11 = OpLabel
  2511. OpBranch %8
  2512. %8 = OpLabel
  2513. OpReturn
  2514. OpFunctionEnd
  2515. )";
  2516. CompileSuccessfully(text);
  2517. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2518. EXPECT_THAT(getDiagnosticString(),
  2519. HasSubstr("block <ID> 9 branches to the loop construct, but not "
  2520. "to the loop header <ID> 7"));
  2521. }
  2522. TEST_F(ValidateCFG, LoopMergeMergeBlockNotLabel) {
  2523. const std::string text = R"(
  2524. OpCapability Shader
  2525. OpCapability Linkage
  2526. OpMemoryModel Logical GLSL450
  2527. OpName %undef "undef"
  2528. %void = OpTypeVoid
  2529. %bool = OpTypeBool
  2530. %undef = OpUndef %bool
  2531. %void_fn = OpTypeFunction %void
  2532. %func = OpFunction %void None %void_fn
  2533. %1 = OpLabel
  2534. OpLoopMerge %undef %2 None
  2535. OpBranchConditional %undef %2 %2
  2536. %2 = OpLabel
  2537. OpReturn
  2538. OpFunctionEnd
  2539. )";
  2540. CompileSuccessfully(text);
  2541. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2542. EXPECT_THAT(getDiagnosticString(),
  2543. HasSubstr("Merge Block 1[%undef] must be an OpLabel"));
  2544. }
  2545. TEST_F(ValidateCFG, LoopMergeContinueTargetNotLabel) {
  2546. const std::string text = R"(
  2547. OpCapability Shader
  2548. OpCapability Linkage
  2549. OpMemoryModel Logical GLSL450
  2550. OpName %undef "undef"
  2551. %void = OpTypeVoid
  2552. %bool = OpTypeBool
  2553. %undef = OpUndef %bool
  2554. %void_fn = OpTypeFunction %void
  2555. %func = OpFunction %void None %void_fn
  2556. %1 = OpLabel
  2557. OpLoopMerge %2 %undef None
  2558. OpBranchConditional %undef %2 %2
  2559. %2 = OpLabel
  2560. OpReturn
  2561. OpFunctionEnd
  2562. )";
  2563. CompileSuccessfully(text);
  2564. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2565. EXPECT_THAT(getDiagnosticString(),
  2566. HasSubstr("Continue Target 1[%undef] must be an OpLabel"));
  2567. }
  2568. TEST_F(ValidateCFG, LoopMergeMergeBlockContinueTargetSameLabel) {
  2569. const std::string text = R"(
  2570. OpCapability Shader
  2571. OpCapability Linkage
  2572. OpMemoryModel Logical GLSL450
  2573. OpName %undef "undef"
  2574. %void = OpTypeVoid
  2575. %bool = OpTypeBool
  2576. %undef = OpUndef %bool
  2577. %void_fn = OpTypeFunction %void
  2578. %func = OpFunction %void None %void_fn
  2579. %1 = OpLabel
  2580. OpLoopMerge %2 %2 None
  2581. OpBranchConditional %undef %2 %2
  2582. %2 = OpLabel
  2583. OpReturn
  2584. OpFunctionEnd
  2585. )";
  2586. CompileSuccessfully(text);
  2587. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2588. EXPECT_THAT(
  2589. getDiagnosticString(),
  2590. HasSubstr("Merge Block and Continue Target must be different ids"));
  2591. }
  2592. TEST_F(ValidateCFG, LoopMergeUnrollAndDontUnroll) {
  2593. const std::string text = R"(
  2594. OpCapability Shader
  2595. OpCapability Linkage
  2596. OpMemoryModel Logical GLSL450
  2597. OpName %undef "undef"
  2598. %void = OpTypeVoid
  2599. %bool = OpTypeBool
  2600. %undef = OpUndef %bool
  2601. %void_fn = OpTypeFunction %void
  2602. %func = OpFunction %void None %void_fn
  2603. %5 = OpLabel
  2604. OpBranch %1
  2605. %1 = OpLabel
  2606. OpLoopMerge %2 %3 Unroll|DontUnroll
  2607. OpBranchConditional %undef %2 %3
  2608. %3 = OpLabel
  2609. OpBranch %1
  2610. %2 = OpLabel
  2611. OpReturn
  2612. OpFunctionEnd
  2613. )";
  2614. CompileSuccessfully(text);
  2615. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  2616. EXPECT_THAT(
  2617. getDiagnosticString(),
  2618. HasSubstr(
  2619. "Unroll and DontUnroll loop controls must not both be specified"));
  2620. }
  2621. TEST_F(ValidateCFG, LoopMergePeelCountAndDontUnroll) {
  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 DontUnroll|PeelCount 1
  2636. OpBranchConditional %undef %2 %3
  2637. %3 = OpLabel
  2638. OpBranch %1
  2639. %2 = OpLabel
  2640. OpReturn
  2641. OpFunctionEnd
  2642. )";
  2643. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2644. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2645. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2646. EXPECT_THAT(
  2647. getDiagnosticString(),
  2648. HasSubstr(
  2649. "PeelCount and DontUnroll loop controls must not both be specified"));
  2650. }
  2651. TEST_F(ValidateCFG, LoopMergePartialCountAndDontUnroll) {
  2652. const std::string text = R"(
  2653. OpCapability Shader
  2654. OpCapability Linkage
  2655. OpMemoryModel Logical GLSL450
  2656. OpName %undef "undef"
  2657. %void = OpTypeVoid
  2658. %bool = OpTypeBool
  2659. %undef = OpUndef %bool
  2660. %void_fn = OpTypeFunction %void
  2661. %func = OpFunction %void None %void_fn
  2662. %5 = OpLabel
  2663. OpBranch %1
  2664. %1 = OpLabel
  2665. OpLoopMerge %2 %3 DontUnroll|PartialCount 1
  2666. OpBranchConditional %undef %2 %3
  2667. %3 = OpLabel
  2668. OpBranch %1
  2669. %2 = OpLabel
  2670. OpReturn
  2671. OpFunctionEnd
  2672. )";
  2673. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2674. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2675. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2676. EXPECT_THAT(getDiagnosticString(),
  2677. HasSubstr("PartialCount and DontUnroll loop controls must not "
  2678. "both be specified"));
  2679. }
  2680. TEST_F(ValidateCFG, LoopMergeIterationMultipleZero) {
  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 IterationMultiple 0
  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(
  2706. getDiagnosticString(),
  2707. HasSubstr(
  2708. "IterationMultiple loop control operand must be greater than zero"));
  2709. }
  2710. TEST_F(ValidateCFG, LoopMergeIterationMultipleZeroMoreOperands) {
  2711. const std::string text = R"(
  2712. OpCapability Shader
  2713. OpCapability Linkage
  2714. OpMemoryModel Logical GLSL450
  2715. OpName %undef "undef"
  2716. %void = OpTypeVoid
  2717. %bool = OpTypeBool
  2718. %undef = OpUndef %bool
  2719. %void_fn = OpTypeFunction %void
  2720. %func = OpFunction %void None %void_fn
  2721. %5 = OpLabel
  2722. OpBranch %1
  2723. %1 = OpLabel
  2724. OpLoopMerge %2 %3 MaxIterations|IterationMultiple 4 0
  2725. OpBranchConditional %undef %2 %3
  2726. %3 = OpLabel
  2727. OpBranch %1
  2728. %2 = OpLabel
  2729. OpReturn
  2730. OpFunctionEnd
  2731. )";
  2732. CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
  2733. EXPECT_EQ(SPV_ERROR_INVALID_DATA,
  2734. ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
  2735. EXPECT_THAT(
  2736. getDiagnosticString(),
  2737. HasSubstr(
  2738. "IterationMultiple loop control operand must be greater than zero"));
  2739. }
  2740. TEST_F(ValidateCFG, LoopMergeTargetsHeader) {
  2741. const std::string text = R"(
  2742. OpCapability Shader
  2743. OpCapability Linkage
  2744. OpMemoryModel Logical GLSL450
  2745. %void = OpTypeVoid
  2746. %bool = OpTypeBool
  2747. %undef = OpUndef %bool
  2748. %void_fn = OpTypeFunction %void
  2749. %fn = OpFunction %void None %void_fn
  2750. %entry = OpLabel
  2751. OpBranch %loop
  2752. %loop = OpLabel
  2753. OpLoopMerge %loop %continue None
  2754. OpBranch %body
  2755. %continue = OpLabel
  2756. OpBranch %loop
  2757. %body = OpLabel
  2758. OpReturn
  2759. OpFunctionEnd
  2760. )";
  2761. CompileSuccessfully(text);
  2762. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  2763. EXPECT_THAT(
  2764. getDiagnosticString(),
  2765. HasSubstr("Merge Block may not be the block containing the OpLoopMerge"));
  2766. }
  2767. TEST_F(ValidateCFG, InvalidSelectionExit) {
  2768. const std::string text = R"(
  2769. OpCapability Shader
  2770. OpMemoryModel Logical GLSL450
  2771. OpEntryPoint Fragment %1 "main"
  2772. OpExecutionMode %1 OriginUpperLeft
  2773. %2 = OpTypeVoid
  2774. %3 = OpTypeBool
  2775. %4 = OpConstantTrue %3
  2776. %5 = OpTypeFunction %2
  2777. %1 = OpFunction %2 None %5
  2778. %6 = OpLabel
  2779. OpSelectionMerge %7 None
  2780. OpBranchConditional %4 %7 %8
  2781. %8 = OpLabel
  2782. OpSelectionMerge %9 None
  2783. OpBranchConditional %4 %10 %9
  2784. %10 = OpLabel
  2785. OpBranch %7
  2786. %9 = OpLabel
  2787. OpBranch %7
  2788. %7 = OpLabel
  2789. OpReturn
  2790. OpFunctionEnd
  2791. )";
  2792. CompileSuccessfully(text);
  2793. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2794. EXPECT_THAT(getDiagnosticString(),
  2795. HasSubstr("block <ID> 10[%10] exits the selection headed by <ID> "
  2796. "8[%8], but not via a structured exit"));
  2797. }
  2798. TEST_F(ValidateCFG, InvalidLoopExit) {
  2799. const std::string text = R"(
  2800. OpCapability Shader
  2801. OpMemoryModel Logical GLSL450
  2802. OpEntryPoint Fragment %1 "main"
  2803. OpExecutionMode %1 OriginUpperLeft
  2804. %2 = OpTypeVoid
  2805. %3 = OpTypeBool
  2806. %4 = OpConstantTrue %3
  2807. %5 = OpTypeFunction %2
  2808. %1 = OpFunction %2 None %5
  2809. %6 = OpLabel
  2810. OpSelectionMerge %7 None
  2811. OpBranchConditional %4 %7 %8
  2812. %8 = OpLabel
  2813. OpLoopMerge %9 %10 None
  2814. OpBranchConditional %4 %9 %11
  2815. %11 = OpLabel
  2816. OpBranchConditional %4 %7 %10
  2817. %10 = OpLabel
  2818. OpBranch %8
  2819. %9 = OpLabel
  2820. OpBranch %7
  2821. %7 = OpLabel
  2822. OpReturn
  2823. OpFunctionEnd
  2824. )";
  2825. CompileSuccessfully(text);
  2826. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2827. EXPECT_THAT(getDiagnosticString(),
  2828. HasSubstr("block <ID> 11[%11] exits the loop headed by <ID> "
  2829. "8[%8], but not via a structured exit"));
  2830. }
  2831. TEST_F(ValidateCFG, InvalidContinueExit) {
  2832. const std::string text = R"(
  2833. OpCapability Shader
  2834. OpMemoryModel Logical GLSL450
  2835. OpEntryPoint Fragment %1 "main"
  2836. OpExecutionMode %1 OriginUpperLeft
  2837. %2 = OpTypeVoid
  2838. %3 = OpTypeBool
  2839. %4 = OpConstantTrue %3
  2840. %5 = OpTypeFunction %2
  2841. %1 = OpFunction %2 None %5
  2842. %6 = OpLabel
  2843. OpSelectionMerge %7 None
  2844. OpBranchConditional %4 %7 %8
  2845. %8 = OpLabel
  2846. OpLoopMerge %9 %10 None
  2847. OpBranchConditional %4 %9 %10
  2848. %10 = OpLabel
  2849. OpBranch %11
  2850. %11 = OpLabel
  2851. OpBranchConditional %4 %8 %7
  2852. %9 = OpLabel
  2853. OpBranch %7
  2854. %7 = OpLabel
  2855. OpReturn
  2856. OpFunctionEnd
  2857. )";
  2858. CompileSuccessfully(text);
  2859. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2860. EXPECT_THAT(getDiagnosticString(),
  2861. HasSubstr("block <ID> 11[%11] exits the continue headed by <ID> "
  2862. "10[%10], but not via a structured exit"));
  2863. }
  2864. TEST_F(ValidateCFG, InvalidSelectionExitBackedge) {
  2865. const std::string text = R"(
  2866. OpCapability Shader
  2867. OpCapability Linkage
  2868. OpMemoryModel Logical GLSL450
  2869. %1 = OpTypeVoid
  2870. %2 = OpTypeBool
  2871. %3 = OpUndef %2
  2872. %4 = OpTypeFunction %1
  2873. %5 = OpFunction %1 None %4
  2874. %6 = OpLabel
  2875. OpBranch %7
  2876. %7 = OpLabel
  2877. OpLoopMerge %8 %9 None
  2878. OpBranchConditional %3 %8 %9
  2879. %9 = OpLabel
  2880. OpSelectionMerge %10 None
  2881. OpBranchConditional %3 %11 %12
  2882. %11 = OpLabel
  2883. OpBranch %13
  2884. %12 = OpLabel
  2885. OpBranch %13
  2886. %13 = OpLabel
  2887. OpBranch %7
  2888. %10 = OpLabel
  2889. OpUnreachable
  2890. %8 = OpLabel
  2891. OpReturn
  2892. OpFunctionEnd
  2893. )";
  2894. CompileSuccessfully(text);
  2895. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2896. EXPECT_THAT(getDiagnosticString(),
  2897. HasSubstr("block <ID> 13[%13] exits the selection headed by <ID> "
  2898. "9[%9], but not via a structured exit"));
  2899. }
  2900. TEST_F(ValidateCFG, BreakFromSwitch) {
  2901. const std::string text = R"(
  2902. OpCapability Shader
  2903. OpCapability Linkage
  2904. OpMemoryModel Logical GLSL450
  2905. %1 = OpTypeVoid
  2906. %2 = OpTypeBool
  2907. %3 = OpTypeInt 32 0
  2908. %4 = OpUndef %2
  2909. %5 = OpUndef %3
  2910. %6 = OpTypeFunction %1
  2911. %7 = OpFunction %1 None %6
  2912. %8 = OpLabel
  2913. OpSelectionMerge %9 None
  2914. OpSwitch %5 %9 0 %10
  2915. %10 = OpLabel
  2916. OpSelectionMerge %11 None
  2917. OpBranchConditional %4 %11 %12
  2918. %12 = OpLabel
  2919. OpBranch %9
  2920. %11 = OpLabel
  2921. OpBranch %9
  2922. %9 = OpLabel
  2923. OpReturn
  2924. OpFunctionEnd
  2925. )";
  2926. CompileSuccessfully(text);
  2927. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  2928. }
  2929. TEST_F(ValidateCFG, InvalidBreakFromSwitch) {
  2930. const std::string text = R"(
  2931. OpCapability Shader
  2932. OpCapability Linkage
  2933. OpMemoryModel Logical GLSL450
  2934. %1 = OpTypeVoid
  2935. %2 = OpTypeBool
  2936. %3 = OpTypeInt 32 0
  2937. %4 = OpUndef %2
  2938. %5 = OpUndef %3
  2939. %6 = OpTypeFunction %1
  2940. %7 = OpFunction %1 None %6
  2941. %8 = OpLabel
  2942. OpSelectionMerge %9 None
  2943. OpSwitch %5 %9 0 %10
  2944. %10 = OpLabel
  2945. OpSelectionMerge %11 None
  2946. OpSwitch %5 %11 0 %12
  2947. %12 = OpLabel
  2948. OpBranch %9
  2949. %11 = OpLabel
  2950. OpBranch %9
  2951. %9 = OpLabel
  2952. OpReturn
  2953. OpFunctionEnd
  2954. )";
  2955. CompileSuccessfully(text);
  2956. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2957. EXPECT_THAT(getDiagnosticString(),
  2958. HasSubstr("block <ID> 12[%12] exits the selection headed by <ID> "
  2959. "10[%10], but not via a structured exit"));
  2960. }
  2961. TEST_F(ValidateCFG, BreakToOuterSwitch) {
  2962. const std::string text = R"(
  2963. OpCapability Shader
  2964. OpCapability Linkage
  2965. OpMemoryModel Logical GLSL450
  2966. %1 = OpTypeVoid
  2967. %2 = OpTypeBool
  2968. %3 = OpTypeInt 32 0
  2969. %4 = OpUndef %2
  2970. %5 = OpUndef %3
  2971. %6 = OpTypeFunction %1
  2972. %7 = OpFunction %1 None %6
  2973. %8 = OpLabel
  2974. OpSelectionMerge %9 None
  2975. OpSwitch %5 %9 0 %10
  2976. %10 = OpLabel
  2977. OpSelectionMerge %11 None
  2978. OpSwitch %5 %11 0 %12
  2979. %12 = OpLabel
  2980. OpSelectionMerge %13 None
  2981. OpBranchConditional %4 %13 %14
  2982. %14 = OpLabel
  2983. OpBranch %9
  2984. %13 = OpLabel
  2985. OpBranch %11
  2986. %11 = OpLabel
  2987. OpBranch %9
  2988. %9 = OpLabel
  2989. OpReturn
  2990. OpFunctionEnd
  2991. )";
  2992. CompileSuccessfully(text);
  2993. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  2994. EXPECT_THAT(getDiagnosticString(),
  2995. HasSubstr("block <ID> 14[%14] exits the selection headed by <ID> "
  2996. "10[%10], but not via a structured exit"));
  2997. }
  2998. TEST_F(ValidateCFG, BreakToOuterLoop) {
  2999. const std::string text = R"(
  3000. OpCapability Shader
  3001. OpCapability Linkage
  3002. OpMemoryModel Logical GLSL450
  3003. %1 = OpTypeVoid
  3004. %2 = OpTypeBool
  3005. %3 = OpUndef %2
  3006. %4 = OpTypeFunction %1
  3007. %5 = OpFunction %1 None %4
  3008. %6 = OpLabel
  3009. OpBranch %7
  3010. %7 = OpLabel
  3011. OpLoopMerge %8 %9 None
  3012. OpBranch %10
  3013. %10 = OpLabel
  3014. OpLoopMerge %11 %12 None
  3015. OpBranch %13
  3016. %13 = OpLabel
  3017. OpSelectionMerge %14 None
  3018. OpBranchConditional %3 %14 %15
  3019. %15 = OpLabel
  3020. OpBranch %8
  3021. %14 = OpLabel
  3022. OpBranch %12
  3023. %12 = OpLabel
  3024. OpBranchConditional %3 %10 %11
  3025. %11 = OpLabel
  3026. OpBranch %9
  3027. %9 = OpLabel
  3028. OpBranchConditional %3 %7 %8
  3029. %8 = OpLabel
  3030. OpReturn
  3031. OpFunctionEnd
  3032. )";
  3033. CompileSuccessfully(text);
  3034. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3035. EXPECT_THAT(getDiagnosticString(),
  3036. HasSubstr("block <ID> 15[%15] exits the loop headed by <ID> "
  3037. "10[%10], but not via a structured exit"));
  3038. }
  3039. TEST_F(ValidateCFG, ContinueFromNestedSelection) {
  3040. const std::string text = R"(
  3041. OpCapability Shader
  3042. OpCapability Linkage
  3043. OpMemoryModel Logical GLSL450
  3044. %void = OpTypeVoid
  3045. %void_fn = OpTypeFunction %void
  3046. %bool = OpTypeBool
  3047. %undef = OpUndef %bool
  3048. %4 = OpFunction %void None %void_fn
  3049. %5 = OpLabel
  3050. OpBranch %48
  3051. %48 = OpLabel
  3052. OpLoopMerge %47 %50 None
  3053. OpBranch %10
  3054. %10 = OpLabel
  3055. OpLoopMerge %12 %37 None
  3056. OpBranchConditional %undef %11 %12
  3057. %11 = OpLabel
  3058. OpSelectionMerge %31 None
  3059. OpBranchConditional %undef %30 %31
  3060. %30 = OpLabel
  3061. OpSelectionMerge %38 None
  3062. OpBranchConditional %undef %36 %38
  3063. %36 = OpLabel
  3064. OpBranch %38
  3065. %38 = OpLabel
  3066. OpBranch %37
  3067. %37 = OpLabel
  3068. OpBranch %10
  3069. %31 = OpLabel
  3070. OpBranch %12
  3071. %12 = OpLabel
  3072. OpSelectionMerge %55 None
  3073. OpBranchConditional %undef %47 %55
  3074. %55 = OpLabel
  3075. OpBranch %47
  3076. %50 = OpLabel
  3077. OpBranch %48
  3078. %47 = OpLabel
  3079. OpReturn
  3080. OpFunctionEnd
  3081. )";
  3082. CompileSuccessfully(text);
  3083. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3084. }
  3085. TEST_F(ValidateCFG, MissingMergeConditionalBranchBad) {
  3086. const std::string text = R"(
  3087. OpCapability Shader
  3088. OpCapability Linkage
  3089. OpMemoryModel Logical GLSL450
  3090. %void = OpTypeVoid
  3091. %void_fn = OpTypeFunction %void
  3092. %bool = OpTypeBool
  3093. %undef = OpUndef %bool
  3094. %func = OpFunction %void None %void_fn
  3095. %entry = OpLabel
  3096. OpBranchConditional %undef %then %else
  3097. %then = OpLabel
  3098. OpReturn
  3099. %else = OpLabel
  3100. OpReturn
  3101. OpFunctionEnd
  3102. )";
  3103. CompileSuccessfully(text);
  3104. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3105. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3106. }
  3107. TEST_F(ValidateCFG, MissingMergeSwitchBad) {
  3108. const std::string text = R"(
  3109. OpCapability Shader
  3110. OpCapability Linkage
  3111. OpMemoryModel Logical GLSL450
  3112. %void = OpTypeVoid
  3113. %void_fn = OpTypeFunction %void
  3114. %int = OpTypeInt 32 0
  3115. %undef = OpUndef %int
  3116. %func = OpFunction %void None %void_fn
  3117. %entry = OpLabel
  3118. OpSwitch %undef %then 0 %else
  3119. %then = OpLabel
  3120. OpReturn
  3121. %else = OpLabel
  3122. OpReturn
  3123. OpFunctionEnd
  3124. )";
  3125. CompileSuccessfully(text);
  3126. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3127. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3128. }
  3129. TEST_F(ValidateCFG, MissingMergeSwitchBad2) {
  3130. const std::string text = R"(
  3131. OpCapability Shader
  3132. OpCapability Linkage
  3133. OpMemoryModel Logical GLSL450
  3134. %void = OpTypeVoid
  3135. %void_fn = OpTypeFunction %void
  3136. %int = OpTypeInt 32 0
  3137. %undef = OpUndef %int
  3138. %func = OpFunction %void None %void_fn
  3139. %entry = OpLabel
  3140. OpSwitch %undef %then 0 %then 1 %then 2 %else
  3141. %then = OpLabel
  3142. OpReturn
  3143. %else = OpLabel
  3144. OpReturn
  3145. OpFunctionEnd
  3146. )";
  3147. CompileSuccessfully(text);
  3148. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3149. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3150. }
  3151. TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) {
  3152. const std::string text = R"(
  3153. OpCapability Shader
  3154. OpCapability Linkage
  3155. OpMemoryModel Logical GLSL450
  3156. %void = OpTypeVoid
  3157. %void_fn = OpTypeFunction %void
  3158. %bool = OpTypeBool
  3159. %undef = OpUndef %bool
  3160. %func = OpFunction %void None %void_fn
  3161. %entry = OpLabel
  3162. OpSelectionMerge %b3 None
  3163. OpBranchConditional %undef %b1 %b2
  3164. %b1 = OpLabel
  3165. OpBranchConditional %undef %b2 %b3
  3166. %b2 = OpLabel
  3167. OpBranch %b3
  3168. %b3 = OpLabel
  3169. OpReturn
  3170. OpFunctionEnd
  3171. )";
  3172. CompileSuccessfully(text);
  3173. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3174. }
  3175. TEST_F(ValidateCFG, MissingMergeSameTargetConditionalBranchGood) {
  3176. const std::string text = R"(
  3177. OpCapability Shader
  3178. OpCapability Linkage
  3179. OpMemoryModel Logical GLSL450
  3180. %void = OpTypeVoid
  3181. %void_fn = OpTypeFunction %void
  3182. %bool = OpTypeBool
  3183. %undef = OpUndef %bool
  3184. %func = OpFunction %void None %void_fn
  3185. %entry = OpLabel
  3186. OpBranchConditional %undef %then %then
  3187. %then = OpLabel
  3188. OpReturn
  3189. OpFunctionEnd
  3190. )";
  3191. CompileSuccessfully(text);
  3192. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3193. }
  3194. TEST_F(ValidateCFG, MissingMergeOneTargetSwitchGood) {
  3195. const std::string text = R"(
  3196. OpCapability Shader
  3197. OpCapability Linkage
  3198. OpMemoryModel Logical GLSL450
  3199. %void = OpTypeVoid
  3200. %void_fn = OpTypeFunction %void
  3201. %int = OpTypeInt 32 0
  3202. %undef = OpUndef %int
  3203. %func = OpFunction %void None %void_fn
  3204. %entry = OpLabel
  3205. OpSwitch %undef %then 0 %then 1 %then
  3206. %then = OpLabel
  3207. OpReturn
  3208. OpFunctionEnd
  3209. )";
  3210. CompileSuccessfully(text);
  3211. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3212. }
  3213. TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchGood) {
  3214. const std::string text = R"(
  3215. OpCapability Shader
  3216. OpCapability Linkage
  3217. OpMemoryModel Logical GLSL450
  3218. %void = OpTypeVoid
  3219. %void_fn = OpTypeFunction %void
  3220. %int = OpTypeInt 32 0
  3221. %undef_int = OpUndef %int
  3222. %bool = OpTypeBool
  3223. %undef_bool = OpUndef %bool
  3224. %func = OpFunction %void None %void_fn
  3225. %entry = OpLabel
  3226. OpSelectionMerge %merge None
  3227. OpBranchConditional %undef_bool %merge %b1
  3228. %b1 = OpLabel
  3229. OpSwitch %undef_int %b2 0 %b2 1 %merge 2 %b2
  3230. %b2 = OpLabel
  3231. OpBranch %merge
  3232. %merge = OpLabel
  3233. OpReturn
  3234. OpFunctionEnd
  3235. )";
  3236. CompileSuccessfully(text);
  3237. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3238. }
  3239. TEST_F(ValidateCFG, MissingMergeLoopBreakGood) {
  3240. const std::string text = R"(
  3241. OpCapability Shader
  3242. OpCapability Linkage
  3243. OpMemoryModel Logical GLSL450
  3244. %void = OpTypeVoid
  3245. %void_fn = OpTypeFunction %void
  3246. %bool = OpTypeBool
  3247. %undef = OpUndef %bool
  3248. %func = OpFunction %void None %void_fn
  3249. %entry = OpLabel
  3250. OpBranch %loop
  3251. %loop = OpLabel
  3252. OpLoopMerge %exit %continue None
  3253. OpBranch %body
  3254. %body = OpLabel
  3255. OpBranchConditional %undef %body2 %exit
  3256. %body2 = OpLabel
  3257. OpBranch %continue
  3258. %continue = OpLabel
  3259. OpBranch %loop
  3260. %exit = OpLabel
  3261. OpReturn
  3262. OpFunctionEnd
  3263. )";
  3264. CompileSuccessfully(text);
  3265. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3266. }
  3267. TEST_F(ValidateCFG, MissingMergeLoopContinueGood) {
  3268. const std::string text = R"(
  3269. OpCapability Shader
  3270. OpCapability Linkage
  3271. OpMemoryModel Logical GLSL450
  3272. %void = OpTypeVoid
  3273. %void_fn = OpTypeFunction %void
  3274. %bool = OpTypeBool
  3275. %undef = OpUndef %bool
  3276. %func = OpFunction %void None %void_fn
  3277. %entry = OpLabel
  3278. OpBranch %loop
  3279. %loop = OpLabel
  3280. OpLoopMerge %exit %continue None
  3281. OpBranch %body
  3282. %body = OpLabel
  3283. OpBranchConditional %undef %body2 %continue
  3284. %body2 = OpLabel
  3285. OpBranch %continue
  3286. %continue = OpLabel
  3287. OpBranch %loop
  3288. %exit = OpLabel
  3289. OpReturn
  3290. OpFunctionEnd
  3291. )";
  3292. CompileSuccessfully(text);
  3293. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3294. }
  3295. TEST_F(ValidateCFG, MissingMergeSwitchBreakGood) {
  3296. const std::string text = R"(
  3297. OpCapability Shader
  3298. OpCapability Linkage
  3299. OpMemoryModel Logical GLSL450
  3300. %void = OpTypeVoid
  3301. %void_fn = OpTypeFunction %void
  3302. %bool = OpTypeBool
  3303. %undef = OpUndef %bool
  3304. %int = OpTypeInt 32 0
  3305. %int_0 = OpConstant %int 0
  3306. %func = OpFunction %void None %void_fn
  3307. %entry = OpLabel
  3308. OpSelectionMerge %merge None
  3309. OpSwitch %int_0 %merge 1 %b1
  3310. %b1 = OpLabel
  3311. OpBranchConditional %undef %merge %b2
  3312. %b2 = OpLabel
  3313. OpBranch %merge
  3314. %merge = OpLabel
  3315. OpReturn
  3316. OpFunctionEnd
  3317. )";
  3318. CompileSuccessfully(text);
  3319. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3320. }
  3321. TEST_F(ValidateCFG, MissingMergeSwitchFallThroughGood) {
  3322. const std::string text = R"(
  3323. OpCapability Shader
  3324. OpCapability Linkage
  3325. OpMemoryModel Logical GLSL450
  3326. %void = OpTypeVoid
  3327. %void_fn = OpTypeFunction %void
  3328. %bool = OpTypeBool
  3329. %undef = OpUndef %bool
  3330. %int = OpTypeInt 32 0
  3331. %int_0 = OpConstant %int 0
  3332. %func = OpFunction %void None %void_fn
  3333. %entry = OpLabel
  3334. OpSelectionMerge %merge None
  3335. OpSwitch %int_0 %b1 1 %b2
  3336. %b1 = OpLabel
  3337. OpBranchConditional %undef %b3 %b2
  3338. %b2 = OpLabel
  3339. OpBranch %merge
  3340. %b3 = OpLabel
  3341. OpBranch %merge
  3342. %merge = OpLabel
  3343. OpReturn
  3344. OpFunctionEnd
  3345. )";
  3346. CompileSuccessfully(text);
  3347. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3348. }
  3349. TEST_F(ValidateCFG, MissingMergeInALoopBad) {
  3350. const std::string text = R"(
  3351. OpCapability Shader
  3352. OpCapability Linkage
  3353. OpMemoryModel Logical GLSL450
  3354. %void = OpTypeVoid
  3355. %void_fn = OpTypeFunction %void
  3356. %bool = OpTypeBool
  3357. %undef = OpUndef %bool
  3358. %func = OpFunction %void None %void_fn
  3359. %entry = OpLabel
  3360. OpBranch %loop
  3361. %loop = OpLabel
  3362. OpLoopMerge %exit %continue None
  3363. OpBranch %body
  3364. %body = OpLabel
  3365. OpBranchConditional %undef %b1 %b2
  3366. %b1 = OpLabel
  3367. OpBranch %exit
  3368. %b2 = OpLabel
  3369. OpBranch %continue
  3370. %continue = OpLabel
  3371. OpBranch %loop
  3372. %exit = OpLabel
  3373. OpReturn
  3374. OpFunctionEnd
  3375. )";
  3376. CompileSuccessfully(text);
  3377. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3378. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3379. }
  3380. TEST_F(ValidateCFG, MissingMergeCrissCrossBad) {
  3381. const std::string text = R"(
  3382. OpCapability Shader
  3383. OpCapability Linkage
  3384. OpMemoryModel Logical GLSL450
  3385. %void = OpTypeVoid
  3386. %void_fn = OpTypeFunction %void
  3387. %bool = OpTypeBool
  3388. %undef = OpUndef %bool
  3389. %func = OpFunction %void None %void_fn
  3390. %entry = OpLabel
  3391. OpSelectionMerge %merge None
  3392. OpBranchConditional %undef %b1 %b2
  3393. %b1 = OpLabel
  3394. OpBranchConditional %undef %b3 %b4
  3395. %b2 = OpLabel
  3396. OpBranchConditional %undef %b3 %b4
  3397. %b3 = OpLabel
  3398. OpBranch %merge
  3399. %b4 = OpLabel
  3400. OpBranch %merge
  3401. %merge = OpLabel
  3402. OpReturn
  3403. OpFunctionEnd
  3404. )";
  3405. CompileSuccessfully(text);
  3406. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3407. EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
  3408. }
  3409. TEST_F(ValidateCFG, ContinueCannotBeSelectionMergeTarget) {
  3410. const std::string text = R"(
  3411. OpCapability Shader
  3412. OpCapability Linkage
  3413. OpMemoryModel Logical GLSL450
  3414. OpName %loop "loop"
  3415. OpName %continue "continue"
  3416. OpName %body "body"
  3417. %void = OpTypeVoid
  3418. %void_fn = OpTypeFunction %void
  3419. %bool = OpTypeBool
  3420. %undef = OpUndef %bool
  3421. %func = OpFunction %void None %void_fn
  3422. %entry = OpLabel
  3423. OpBranch %loop
  3424. %loop = OpLabel
  3425. OpLoopMerge %exit %continue None
  3426. OpBranch %body
  3427. %body = OpLabel
  3428. OpSelectionMerge %continue None
  3429. OpBranchConditional %undef %exit %continue
  3430. %continue = OpLabel
  3431. OpBranch %loop
  3432. %exit = OpLabel
  3433. OpReturn
  3434. OpFunctionEnd
  3435. )";
  3436. CompileSuccessfully(text);
  3437. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3438. EXPECT_THAT(
  3439. getDiagnosticString(),
  3440. HasSubstr(
  3441. "Header block 3[%body] is contained in the loop construct headed by "
  3442. "1[%loop], but its merge block 2[%continue] is not"));
  3443. }
  3444. TEST_F(ValidateCFG, ContinueCannotBeLoopMergeTarget) {
  3445. const std::string text = R"(
  3446. OpCapability Shader
  3447. OpCapability Linkage
  3448. OpMemoryModel Logical GLSL450
  3449. OpName %loop "loop"
  3450. OpName %continue "continue"
  3451. OpName %inner "inner"
  3452. %void = OpTypeVoid
  3453. %void_fn = OpTypeFunction %void
  3454. %bool = OpTypeBool
  3455. %undef = OpUndef %bool
  3456. %func = OpFunction %void None %void_fn
  3457. %entry = OpLabel
  3458. OpBranch %loop
  3459. %loop = OpLabel
  3460. OpLoopMerge %exit %continue None
  3461. OpBranchConditional %undef %exit %inner
  3462. %inner = OpLabel
  3463. OpLoopMerge %continue %inner None
  3464. OpBranchConditional %undef %inner %continue
  3465. %continue = OpLabel
  3466. OpBranch %loop
  3467. %exit = OpLabel
  3468. OpReturn
  3469. OpFunctionEnd
  3470. )";
  3471. CompileSuccessfully(text);
  3472. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  3473. EXPECT_THAT(
  3474. getDiagnosticString(),
  3475. HasSubstr(
  3476. "Header block 3[%inner] is contained in the loop construct headed by "
  3477. "1[%loop], but its merge block 2[%continue] is not"));
  3478. }
  3479. TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge) {
  3480. const std::string text = R"(
  3481. OpCapability Shader
  3482. OpCapability Linkage
  3483. OpMemoryModel Logical GLSL450
  3484. %void = OpTypeVoid
  3485. %2 = OpTypeFunction %void
  3486. %int = OpTypeInt 32 1
  3487. %4 = OpUndef %int
  3488. %bool = OpTypeBool
  3489. %6 = OpUndef %bool
  3490. %7 = OpFunction %void None %2
  3491. %8 = OpLabel
  3492. OpSelectionMerge %9 None
  3493. OpSwitch %4 %10 0 %11
  3494. %10 = OpLabel
  3495. OpBranch %9
  3496. %11 = OpLabel
  3497. OpBranch %12
  3498. %12 = OpLabel
  3499. OpLoopMerge %13 %14 None
  3500. OpBranch %15
  3501. %15 = OpLabel
  3502. OpSelectionMerge %16 None
  3503. OpSwitch %4 %17 1 %18 2 %19
  3504. %17 = OpLabel
  3505. OpBranch %16
  3506. %18 = OpLabel
  3507. OpBranch %14
  3508. %19 = OpLabel
  3509. OpBranch %16
  3510. %16 = OpLabel
  3511. OpBranch %14
  3512. %14 = OpLabel
  3513. OpBranchConditional %6 %12 %13
  3514. %13 = OpLabel
  3515. OpSelectionMerge %20 None
  3516. OpBranchConditional %6 %21 %20
  3517. %21 = OpLabel
  3518. OpBranch %9
  3519. %20 = OpLabel
  3520. OpBranch %10
  3521. %9 = OpLabel
  3522. OpReturn
  3523. OpFunctionEnd
  3524. )";
  3525. CompileSuccessfully(text);
  3526. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3527. }
  3528. TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge2) {
  3529. const std::string text = R"(
  3530. OpCapability Shader
  3531. %1 = OpExtInstImport "GLSL.std.450"
  3532. OpMemoryModel Logical GLSL450
  3533. OpEntryPoint Fragment %2 "main"
  3534. OpExecutionMode %2 OriginUpperLeft
  3535. %void = OpTypeVoid
  3536. %4 = OpTypeFunction %void
  3537. %int = OpTypeInt 32 1
  3538. %6 = OpUndef %int
  3539. %bool = OpTypeBool
  3540. %8 = OpUndef %bool
  3541. %2 = OpFunction %void None %4
  3542. %9 = OpLabel
  3543. OpSelectionMerge %10 None
  3544. OpSwitch %6 %11 0 %12
  3545. %11 = OpLabel
  3546. OpBranch %10
  3547. %12 = OpLabel
  3548. OpBranch %13
  3549. %13 = OpLabel
  3550. OpLoopMerge %14 %15 None
  3551. OpBranch %16
  3552. %16 = OpLabel
  3553. OpSelectionMerge %17 None
  3554. OpSwitch %6 %18 1 %19 2 %20
  3555. %18 = OpLabel
  3556. OpBranch %17
  3557. %19 = OpLabel
  3558. OpBranch %15
  3559. %20 = OpLabel
  3560. OpBranch %17
  3561. %17 = OpLabel
  3562. OpBranch %15
  3563. %15 = OpLabel
  3564. OpBranchConditional %8 %13 %14
  3565. %14 = OpLabel
  3566. OpSelectionMerge %21 None
  3567. OpBranchConditional %8 %22 %21
  3568. %22 = OpLabel
  3569. OpSelectionMerge %23 None
  3570. OpBranchConditional %8 %24 %23
  3571. %24 = OpLabel
  3572. OpBranch %10
  3573. %23 = OpLabel
  3574. OpBranch %21
  3575. %21 = OpLabel
  3576. OpBranch %11
  3577. %10 = OpLabel
  3578. OpReturn
  3579. OpFunctionEnd
  3580. )";
  3581. CompileSuccessfully(text);
  3582. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  3583. }
  3584. TEST_F(ValidateCFG, PhiResultInvalidSampler) {
  3585. const std::string text = R"(
  3586. OpCapability Shader
  3587. OpCapability Linkage
  3588. OpMemoryModel Logical GLSL450
  3589. %void = OpTypeVoid
  3590. %bool = OpTypeBool
  3591. %f32 = OpTypeFloat 32
  3592. %sampler = OpTypeSampler
  3593. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3594. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3595. %undef_bool = OpUndef %bool
  3596. %undef_sampler = OpUndef %sampler
  3597. %void_fn = OpTypeFunction %void
  3598. %fn = OpFunction %void None %void_fn
  3599. %entry = OpLabel
  3600. %ld_sampler = OpLoad %sampler %sampler_var
  3601. OpBranch %loop
  3602. %loop = OpLabel
  3603. %phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop
  3604. OpLoopMerge %exit %loop None
  3605. OpBranchConditional %undef_bool %exit %loop
  3606. %exit = OpLabel
  3607. OpReturn
  3608. OpFunctionEnd
  3609. )";
  3610. CompileSuccessfully(text);
  3611. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3612. EXPECT_THAT(getDiagnosticString(),
  3613. HasSubstr("Result type cannot be OpTypeSampler"));
  3614. }
  3615. TEST_F(ValidateCFG, PhiResultInvalidImage) {
  3616. const std::string text = R"(
  3617. OpCapability Shader
  3618. OpCapability Linkage
  3619. OpMemoryModel Logical GLSL450
  3620. %void = OpTypeVoid
  3621. %bool = OpTypeBool
  3622. %f32 = OpTypeFloat 32
  3623. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3624. %ptr_uc_image = OpTypePointer UniformConstant %image
  3625. %image_var = OpVariable %ptr_uc_image UniformConstant
  3626. %undef_bool = OpUndef %bool
  3627. %undef_image = OpUndef %image
  3628. %void_fn = OpTypeFunction %void
  3629. %fn = OpFunction %void None %void_fn
  3630. %entry = OpLabel
  3631. %ld_image = OpLoad %image %image_var
  3632. OpBranch %loop
  3633. %loop = OpLabel
  3634. %phi = OpPhi %image %undef_image %entry %ld_image %loop
  3635. OpLoopMerge %exit %loop None
  3636. OpBranchConditional %undef_bool %exit %loop
  3637. %exit = OpLabel
  3638. OpReturn
  3639. OpFunctionEnd
  3640. )";
  3641. CompileSuccessfully(text);
  3642. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3643. EXPECT_THAT(getDiagnosticString(),
  3644. HasSubstr("Result type cannot be OpTypeImage"));
  3645. }
  3646. TEST_F(ValidateCFG, PhiResultInvalidSampledImage) {
  3647. const std::string text = R"(
  3648. OpCapability Shader
  3649. OpCapability Linkage
  3650. OpMemoryModel Logical GLSL450
  3651. %void = OpTypeVoid
  3652. %bool = OpTypeBool
  3653. %f32 = OpTypeFloat 32
  3654. %sampler = OpTypeSampler
  3655. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3656. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3657. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3658. %ptr_uc_image = OpTypePointer UniformConstant %image
  3659. %image_var = OpVariable %ptr_uc_image UniformConstant
  3660. %sampled_image = OpTypeSampledImage %image
  3661. %undef_bool = OpUndef %bool
  3662. %undef_sampled_image = OpUndef %sampled_image
  3663. %void_fn = OpTypeFunction %void
  3664. %fn = OpFunction %void None %void_fn
  3665. %entry = OpLabel
  3666. %ld_image = OpLoad %image %image_var
  3667. %ld_sampler = OpLoad %sampler %sampler_var
  3668. OpBranch %loop
  3669. %loop = OpLabel
  3670. %phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop
  3671. %sample = OpSampledImage %sampled_image %ld_image %ld_sampler
  3672. OpLoopMerge %exit %loop None
  3673. OpBranchConditional %undef_bool %exit %loop
  3674. %exit = OpLabel
  3675. OpReturn
  3676. OpFunctionEnd
  3677. )";
  3678. CompileSuccessfully(text);
  3679. ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3680. EXPECT_THAT(getDiagnosticString(),
  3681. HasSubstr("Result type cannot be OpTypeSampledImage"));
  3682. }
  3683. TEST_F(ValidateCFG, PhiResultValidPreLegalizationSampler) {
  3684. const std::string text = R"(
  3685. OpCapability Shader
  3686. OpCapability Linkage
  3687. OpMemoryModel Logical GLSL450
  3688. %void = OpTypeVoid
  3689. %bool = OpTypeBool
  3690. %f32 = OpTypeFloat 32
  3691. %sampler = OpTypeSampler
  3692. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3693. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3694. %undef_bool = OpUndef %bool
  3695. %undef_sampler = OpUndef %sampler
  3696. %void_fn = OpTypeFunction %void
  3697. %fn = OpFunction %void None %void_fn
  3698. %entry = OpLabel
  3699. %ld_sampler = OpLoad %sampler %sampler_var
  3700. OpBranch %loop
  3701. %loop = OpLabel
  3702. %phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop
  3703. OpLoopMerge %exit %loop None
  3704. OpBranchConditional %undef_bool %exit %loop
  3705. %exit = OpLabel
  3706. OpReturn
  3707. OpFunctionEnd
  3708. )";
  3709. options_->before_hlsl_legalization = true;
  3710. CompileSuccessfully(text);
  3711. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3712. }
  3713. TEST_F(ValidateCFG, PhiResultValidPreLegalizationImage) {
  3714. const std::string text = R"(
  3715. OpCapability Shader
  3716. OpCapability Linkage
  3717. OpMemoryModel Logical GLSL450
  3718. %void = OpTypeVoid
  3719. %bool = OpTypeBool
  3720. %f32 = OpTypeFloat 32
  3721. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3722. %ptr_uc_image = OpTypePointer UniformConstant %image
  3723. %image_var = OpVariable %ptr_uc_image UniformConstant
  3724. %undef_bool = OpUndef %bool
  3725. %undef_image = OpUndef %image
  3726. %void_fn = OpTypeFunction %void
  3727. %fn = OpFunction %void None %void_fn
  3728. %entry = OpLabel
  3729. %ld_image = OpLoad %image %image_var
  3730. OpBranch %loop
  3731. %loop = OpLabel
  3732. %phi = OpPhi %image %undef_image %entry %ld_image %loop
  3733. OpLoopMerge %exit %loop None
  3734. OpBranchConditional %undef_bool %exit %loop
  3735. %exit = OpLabel
  3736. OpReturn
  3737. OpFunctionEnd
  3738. )";
  3739. options_->before_hlsl_legalization = true;
  3740. CompileSuccessfully(text);
  3741. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3742. }
  3743. TEST_F(ValidateCFG, PhiResultValidPreLegalizationSampledImage) {
  3744. const std::string text = R"(
  3745. OpCapability Shader
  3746. OpCapability Linkage
  3747. OpMemoryModel Logical GLSL450
  3748. %void = OpTypeVoid
  3749. %bool = OpTypeBool
  3750. %f32 = OpTypeFloat 32
  3751. %sampler = OpTypeSampler
  3752. %ptr_uc_sampler = OpTypePointer UniformConstant %sampler
  3753. %sampler_var = OpVariable %ptr_uc_sampler UniformConstant
  3754. %image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
  3755. %ptr_uc_image = OpTypePointer UniformConstant %image
  3756. %image_var = OpVariable %ptr_uc_image UniformConstant
  3757. %sampled_image = OpTypeSampledImage %image
  3758. %undef_bool = OpUndef %bool
  3759. %undef_sampled_image = OpUndef %sampled_image
  3760. %void_fn = OpTypeFunction %void
  3761. %fn = OpFunction %void None %void_fn
  3762. %entry = OpLabel
  3763. %ld_image = OpLoad %image %image_var
  3764. %ld_sampler = OpLoad %sampler %sampler_var
  3765. OpBranch %loop
  3766. %loop = OpLabel
  3767. %phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop
  3768. %sample = OpSampledImage %sampled_image %ld_image %ld_sampler
  3769. OpLoopMerge %exit %loop None
  3770. OpBranchConditional %undef_bool %exit %loop
  3771. %exit = OpLabel
  3772. OpReturn
  3773. OpFunctionEnd
  3774. )";
  3775. options_->before_hlsl_legalization = true;
  3776. CompileSuccessfully(text);
  3777. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  3778. }
  3779. TEST_F(ValidateCFG, UnreachableIsStaticallyReachable) {
  3780. const std::string text = R"(
  3781. OpCapability Shader
  3782. OpCapability Linkage
  3783. OpMemoryModel Logical GLSL450
  3784. %1 = OpTypeVoid
  3785. %2 = OpTypeFunction %1
  3786. %3 = OpFunction %1 None %2
  3787. %4 = OpLabel
  3788. OpBranch %5
  3789. %5 = OpLabel
  3790. OpUnreachable
  3791. OpFunctionEnd
  3792. )";
  3793. CompileSuccessfully(text);
  3794. EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
  3795. auto f = vstate_->function(3);
  3796. auto entry = f->GetBlock(4).first;
  3797. ASSERT_TRUE(entry->reachable());
  3798. auto end = f->GetBlock(5).first;
  3799. ASSERT_TRUE(end->reachable());
  3800. }
  3801. TEST_F(ValidateCFG, BlockOrderDoesNotAffectReachability) {
  3802. const std::string text = R"(
  3803. OpCapability Shader
  3804. OpCapability Linkage
  3805. OpMemoryModel Logical GLSL450
  3806. %1 = OpTypeVoid
  3807. %2 = OpTypeFunction %1
  3808. %3 = OpTypeBool
  3809. %4 = OpUndef %3
  3810. %5 = OpFunction %1 None %2
  3811. %6 = OpLabel
  3812. OpBranch %7
  3813. %7 = OpLabel
  3814. OpSelectionMerge %8 None
  3815. OpBranchConditional %4 %9 %10
  3816. %8 = OpLabel
  3817. OpReturn
  3818. %9 = OpLabel
  3819. OpBranch %8
  3820. %10 = OpLabel
  3821. OpBranch %8
  3822. %11 = OpLabel
  3823. OpUnreachable
  3824. OpFunctionEnd
  3825. )";
  3826. CompileSuccessfully(text);
  3827. EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
  3828. auto f = vstate_->function(5);
  3829. auto b6 = f->GetBlock(6).first;
  3830. auto b7 = f->GetBlock(7).first;
  3831. auto b8 = f->GetBlock(8).first;
  3832. auto b9 = f->GetBlock(9).first;
  3833. auto b10 = f->GetBlock(10).first;
  3834. auto b11 = f->GetBlock(11).first;
  3835. ASSERT_TRUE(b6->reachable());
  3836. ASSERT_TRUE(b7->reachable());
  3837. ASSERT_TRUE(b8->reachable());
  3838. ASSERT_TRUE(b9->reachable());
  3839. ASSERT_TRUE(b10->reachable());
  3840. ASSERT_FALSE(b11->reachable());
  3841. }
  3842. TEST_F(ValidateCFG, PhiInstructionWithDuplicateIncomingEdges) {
  3843. const std::string text = R"(
  3844. OpCapability Shader
  3845. %1 = OpExtInstImport "GLSL.std.450"
  3846. OpMemoryModel Logical GLSL450
  3847. OpEntryPoint Fragment %4 "main"
  3848. OpExecutionMode %4 OriginUpperLeft
  3849. OpSource ESSL 320
  3850. %2 = OpTypeVoid
  3851. %3 = OpTypeFunction %2
  3852. %6 = OpTypeBool
  3853. %7 = OpConstantTrue %6
  3854. %4 = OpFunction %2 None %3
  3855. %5 = OpLabel
  3856. OpSelectionMerge %10 None
  3857. OpBranchConditional %7 %8 %9
  3858. %8 = OpLabel
  3859. OpBranch %10
  3860. %9 = OpLabel
  3861. OpBranch %10
  3862. %10 = OpLabel
  3863. %11 = OpPhi %6 %7 %8 %7 %8
  3864. OpReturn
  3865. OpFunctionEnd
  3866. )";
  3867. CompileSuccessfully(text);
  3868. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  3869. EXPECT_THAT(getDiagnosticString(),
  3870. HasSubstr("OpPhi references incoming basic block <id> "));
  3871. EXPECT_THAT(getDiagnosticString(), HasSubstr("multiple times."));
  3872. }
  3873. TEST_F(ValidateCFG, PhiOnVoid) {
  3874. const std::string text = R"(
  3875. OpCapability Shader
  3876. %1 = OpExtInstImport "GLSL.std.450"
  3877. OpMemoryModel Logical GLSL450
  3878. OpEntryPoint Fragment %4 "main"
  3879. OpExecutionMode %4 OriginUpperLeft
  3880. OpSource ESSL 320
  3881. OpName %4 "main"
  3882. OpName %6 "foo("
  3883. %2 = OpTypeVoid
  3884. %3 = OpTypeFunction %2
  3885. %4 = OpFunction %2 None %3
  3886. %5 = OpLabel
  3887. %8 = OpFunctionCall %2 %6
  3888. OpBranch %20
  3889. %20 = OpLabel
  3890. %21 = OpPhi %2 %8 %20
  3891. OpReturn
  3892. OpFunctionEnd
  3893. %6 = OpFunction %2 None %3
  3894. %7 = OpLabel
  3895. OpReturn
  3896. OpFunctionEnd
  3897. )";
  3898. CompileSuccessfully(text);
  3899. EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
  3900. EXPECT_THAT(getDiagnosticString(),
  3901. HasSubstr("OpPhi must not have void result type"));
  3902. }
  3903. } // namespace
  3904. } // namespace val
  3905. } // namespace spvtools