transformation_add_dead_break_test.cpp 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884
  1. // Copyright (c) 2019 Google LLC
  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. #include "source/fuzz/transformation_add_dead_break.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "test/fuzz/fuzz_test_util.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. namespace {
  21. TEST(TransformationAddDeadBreakTest, BreaksOutOfSimpleIf) {
  22. // For a simple if-then-else, checks that some dead break scenarios are
  23. // possible, and that some invalid scenarios are indeed not allowed.
  24. // The SPIR-V for this test is adapted from the following GLSL, by separating
  25. // some assignments into their own basic blocks, and adding constants for true
  26. // and false:
  27. //
  28. // void main() {
  29. // int x;
  30. // int y;
  31. // x = 1;
  32. // if (x < y) {
  33. // x = 2;
  34. // x = 3;
  35. // } else {
  36. // y = 2;
  37. // y = 3;
  38. // }
  39. // x = y;
  40. // }
  41. std::string shader = R"(
  42. OpCapability Shader
  43. %1 = OpExtInstImport "GLSL.std.450"
  44. OpMemoryModel Logical GLSL450
  45. OpEntryPoint Fragment %4 "main"
  46. OpExecutionMode %4 OriginUpperLeft
  47. OpSource ESSL 310
  48. OpName %4 "main"
  49. OpName %8 "x"
  50. OpName %11 "y"
  51. %2 = OpTypeVoid
  52. %3 = OpTypeFunction %2
  53. %6 = OpTypeInt 32 1
  54. %7 = OpTypePointer Function %6
  55. %9 = OpConstant %6 1
  56. %13 = OpTypeBool
  57. %17 = OpConstant %6 2
  58. %18 = OpConstant %6 3
  59. %25 = OpConstantTrue %13
  60. %26 = OpConstantFalse %13
  61. %4 = OpFunction %2 None %3
  62. %5 = OpLabel
  63. %8 = OpVariable %7 Function
  64. %11 = OpVariable %7 Function
  65. OpStore %8 %9
  66. %10 = OpLoad %6 %8
  67. %12 = OpLoad %6 %11
  68. %14 = OpSLessThan %13 %10 %12
  69. OpSelectionMerge %16 None
  70. OpBranchConditional %14 %15 %19
  71. %15 = OpLabel
  72. OpStore %8 %17
  73. OpBranch %21
  74. %21 = OpLabel
  75. OpStore %8 %18
  76. OpBranch %22
  77. %22 = OpLabel
  78. OpBranch %16
  79. %19 = OpLabel
  80. OpStore %11 %17
  81. OpBranch %23
  82. %23 = OpLabel
  83. OpStore %11 %18
  84. OpBranch %24
  85. %24 = OpLabel
  86. OpBranch %16
  87. %16 = OpLabel
  88. %20 = OpLoad %6 %11
  89. OpStore %8 %20
  90. OpReturn
  91. OpFunctionEnd
  92. )";
  93. const auto env = SPV_ENV_UNIVERSAL_1_3;
  94. const auto consumer = nullptr;
  95. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  96. spvtools::ValidatorOptions validator_options;
  97. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  98. kConsoleMessageConsumer));
  99. TransformationContext transformation_context(
  100. MakeUnique<FactManager>(context.get()), validator_options);
  101. const uint32_t merge_block = 16;
  102. // These are all possibilities.
  103. ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, true, {})
  104. .IsApplicable(context.get(), transformation_context));
  105. ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, false, {})
  106. .IsApplicable(context.get(), transformation_context));
  107. ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, true, {})
  108. .IsApplicable(context.get(), transformation_context));
  109. ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, false, {})
  110. .IsApplicable(context.get(), transformation_context));
  111. ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, true, {})
  112. .IsApplicable(context.get(), transformation_context));
  113. ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, false, {})
  114. .IsApplicable(context.get(), transformation_context));
  115. ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, true, {})
  116. .IsApplicable(context.get(), transformation_context));
  117. ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, false, {})
  118. .IsApplicable(context.get(), transformation_context));
  119. ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, true, {})
  120. .IsApplicable(context.get(), transformation_context));
  121. ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, false, {})
  122. .IsApplicable(context.get(), transformation_context));
  123. ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, true, {})
  124. .IsApplicable(context.get(), transformation_context));
  125. ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, false, {})
  126. .IsApplicable(context.get(), transformation_context));
  127. // Inapplicable: 100 is not a block id.
  128. ASSERT_FALSE(TransformationAddDeadBreak(100, merge_block, true, {})
  129. .IsApplicable(context.get(), transformation_context));
  130. ASSERT_FALSE(TransformationAddDeadBreak(15, 100, true, {})
  131. .IsApplicable(context.get(), transformation_context));
  132. // Inapplicable: 24 is not a merge block.
  133. ASSERT_FALSE(TransformationAddDeadBreak(15, 24, true, {})
  134. .IsApplicable(context.get(), transformation_context));
  135. // These are the transformations we will apply.
  136. auto transformation1 = TransformationAddDeadBreak(15, merge_block, true, {});
  137. auto transformation2 = TransformationAddDeadBreak(21, merge_block, false, {});
  138. auto transformation3 = TransformationAddDeadBreak(22, merge_block, true, {});
  139. auto transformation4 = TransformationAddDeadBreak(19, merge_block, false, {});
  140. auto transformation5 = TransformationAddDeadBreak(23, merge_block, true, {});
  141. auto transformation6 = TransformationAddDeadBreak(24, merge_block, false, {});
  142. ASSERT_TRUE(
  143. transformation1.IsApplicable(context.get(), transformation_context));
  144. ApplyAndCheckFreshIds(transformation1, context.get(),
  145. &transformation_context);
  146. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  147. kConsoleMessageConsumer));
  148. ASSERT_TRUE(
  149. transformation2.IsApplicable(context.get(), transformation_context));
  150. ApplyAndCheckFreshIds(transformation2, context.get(),
  151. &transformation_context);
  152. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  153. kConsoleMessageConsumer));
  154. ASSERT_TRUE(
  155. transformation3.IsApplicable(context.get(), transformation_context));
  156. ApplyAndCheckFreshIds(transformation3, context.get(),
  157. &transformation_context);
  158. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  159. kConsoleMessageConsumer));
  160. ASSERT_TRUE(
  161. transformation4.IsApplicable(context.get(), transformation_context));
  162. ApplyAndCheckFreshIds(transformation4, context.get(),
  163. &transformation_context);
  164. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  165. kConsoleMessageConsumer));
  166. ASSERT_TRUE(
  167. transformation5.IsApplicable(context.get(), transformation_context));
  168. ApplyAndCheckFreshIds(transformation5, context.get(),
  169. &transformation_context);
  170. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  171. kConsoleMessageConsumer));
  172. ASSERT_TRUE(
  173. transformation6.IsApplicable(context.get(), transformation_context));
  174. ApplyAndCheckFreshIds(transformation6, context.get(),
  175. &transformation_context);
  176. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  177. kConsoleMessageConsumer));
  178. std::string after_transformation = R"(
  179. OpCapability Shader
  180. %1 = OpExtInstImport "GLSL.std.450"
  181. OpMemoryModel Logical GLSL450
  182. OpEntryPoint Fragment %4 "main"
  183. OpExecutionMode %4 OriginUpperLeft
  184. OpSource ESSL 310
  185. OpName %4 "main"
  186. OpName %8 "x"
  187. OpName %11 "y"
  188. %2 = OpTypeVoid
  189. %3 = OpTypeFunction %2
  190. %6 = OpTypeInt 32 1
  191. %7 = OpTypePointer Function %6
  192. %9 = OpConstant %6 1
  193. %13 = OpTypeBool
  194. %17 = OpConstant %6 2
  195. %18 = OpConstant %6 3
  196. %25 = OpConstantTrue %13
  197. %26 = OpConstantFalse %13
  198. %4 = OpFunction %2 None %3
  199. %5 = OpLabel
  200. %8 = OpVariable %7 Function
  201. %11 = OpVariable %7 Function
  202. OpStore %8 %9
  203. %10 = OpLoad %6 %8
  204. %12 = OpLoad %6 %11
  205. %14 = OpSLessThan %13 %10 %12
  206. OpSelectionMerge %16 None
  207. OpBranchConditional %14 %15 %19
  208. %15 = OpLabel
  209. OpStore %8 %17
  210. OpBranchConditional %25 %21 %16
  211. %21 = OpLabel
  212. OpStore %8 %18
  213. OpBranchConditional %26 %16 %22
  214. %22 = OpLabel
  215. OpBranchConditional %25 %16 %16
  216. %19 = OpLabel
  217. OpStore %11 %17
  218. OpBranchConditional %26 %16 %23
  219. %23 = OpLabel
  220. OpStore %11 %18
  221. OpBranchConditional %25 %24 %16
  222. %24 = OpLabel
  223. OpBranchConditional %26 %16 %16
  224. %16 = OpLabel
  225. %20 = OpLoad %6 %11
  226. OpStore %8 %20
  227. OpReturn
  228. OpFunctionEnd
  229. )";
  230. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  231. }
  232. TEST(TransformationAddDeadBreakTest, BreakOutOfNestedIfs) {
  233. // Checks some allowed and disallowed scenarios for nests of ifs.
  234. // The SPIR-V for this test is adapted from the following GLSL:
  235. //
  236. // void main() {
  237. // int x;
  238. // int y;
  239. // x = 1;
  240. // if (x < y) {
  241. // x = 2;
  242. // x = 3;
  243. // if (x == y) {
  244. // y = 3;
  245. // }
  246. // } else {
  247. // y = 2;
  248. // y = 3;
  249. // }
  250. // if (x == y) {
  251. // x = 2;
  252. // }
  253. // x = y;
  254. // }
  255. std::string shader = R"(
  256. OpCapability Shader
  257. %1 = OpExtInstImport "GLSL.std.450"
  258. OpMemoryModel Logical GLSL450
  259. OpEntryPoint Fragment %4 "main"
  260. OpExecutionMode %4 OriginUpperLeft
  261. OpSource ESSL 310
  262. OpName %4 "main"
  263. OpName %8 "x"
  264. OpName %11 "y"
  265. %2 = OpTypeVoid
  266. %3 = OpTypeFunction %2
  267. %6 = OpTypeInt 32 1
  268. %7 = OpTypePointer Function %6
  269. %9 = OpConstant %6 1
  270. %13 = OpTypeBool
  271. %17 = OpConstant %6 2
  272. %18 = OpConstant %6 3
  273. %31 = OpConstantTrue %13
  274. %32 = OpConstantFalse %13
  275. %4 = OpFunction %2 None %3
  276. %5 = OpLabel
  277. %8 = OpVariable %7 Function
  278. %11 = OpVariable %7 Function
  279. OpStore %8 %9
  280. %10 = OpLoad %6 %8
  281. %12 = OpLoad %6 %11
  282. %14 = OpSLessThan %13 %10 %12
  283. OpSelectionMerge %16 None
  284. OpBranchConditional %14 %15 %24
  285. %15 = OpLabel
  286. OpStore %8 %17
  287. OpBranch %33
  288. %33 = OpLabel
  289. OpStore %8 %18
  290. %19 = OpLoad %6 %8
  291. OpBranch %34
  292. %34 = OpLabel
  293. %20 = OpLoad %6 %11
  294. %21 = OpIEqual %13 %19 %20
  295. OpSelectionMerge %23 None
  296. OpBranchConditional %21 %22 %23
  297. %22 = OpLabel
  298. OpStore %11 %18
  299. OpBranch %35
  300. %35 = OpLabel
  301. OpBranch %23
  302. %23 = OpLabel
  303. OpBranch %16
  304. %24 = OpLabel
  305. OpStore %11 %17
  306. OpBranch %36
  307. %36 = OpLabel
  308. OpStore %11 %18
  309. OpBranch %16
  310. %16 = OpLabel
  311. %25 = OpLoad %6 %8
  312. OpBranch %37
  313. %37 = OpLabel
  314. %26 = OpLoad %6 %11
  315. %27 = OpIEqual %13 %25 %26
  316. OpSelectionMerge %29 None
  317. OpBranchConditional %27 %28 %29
  318. %28 = OpLabel
  319. OpStore %8 %17
  320. OpBranch %38
  321. %38 = OpLabel
  322. OpBranch %29
  323. %29 = OpLabel
  324. %30 = OpLoad %6 %11
  325. OpStore %8 %30
  326. OpReturn
  327. OpFunctionEnd
  328. )";
  329. const auto env = SPV_ENV_UNIVERSAL_1_3;
  330. const auto consumer = nullptr;
  331. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  332. spvtools::ValidatorOptions validator_options;
  333. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  334. kConsoleMessageConsumer));
  335. TransformationContext transformation_context(
  336. MakeUnique<FactManager>(context.get()), validator_options);
  337. // The header and merge blocks
  338. const uint32_t header_inner = 34;
  339. const uint32_t merge_inner = 23;
  340. const uint32_t header_outer = 5;
  341. const uint32_t merge_outer = 16;
  342. const uint32_t header_after = 37;
  343. const uint32_t merge_after = 29;
  344. // The non-merge-nor-header blocks in each construct
  345. const uint32_t inner_block_1 = 22;
  346. const uint32_t inner_block_2 = 35;
  347. const uint32_t outer_block_1 = 15;
  348. const uint32_t outer_block_2 = 33;
  349. const uint32_t outer_block_3 = 24;
  350. const uint32_t outer_block_4 = 36;
  351. const uint32_t after_block_1 = 28;
  352. const uint32_t after_block_2 = 38;
  353. // Fine to break from a construct to its merge
  354. ASSERT_TRUE(TransformationAddDeadBreak(inner_block_1, merge_inner, true, {})
  355. .IsApplicable(context.get(), transformation_context));
  356. ASSERT_TRUE(TransformationAddDeadBreak(inner_block_2, merge_inner, false, {})
  357. .IsApplicable(context.get(), transformation_context));
  358. ASSERT_TRUE(TransformationAddDeadBreak(outer_block_1, merge_outer, true, {})
  359. .IsApplicable(context.get(), transformation_context));
  360. ASSERT_TRUE(TransformationAddDeadBreak(outer_block_2, merge_outer, false, {})
  361. .IsApplicable(context.get(), transformation_context));
  362. ASSERT_TRUE(TransformationAddDeadBreak(outer_block_3, merge_outer, true, {})
  363. .IsApplicable(context.get(), transformation_context));
  364. ASSERT_TRUE(TransformationAddDeadBreak(outer_block_4, merge_outer, false, {})
  365. .IsApplicable(context.get(), transformation_context));
  366. ASSERT_TRUE(TransformationAddDeadBreak(after_block_1, merge_after, true, {})
  367. .IsApplicable(context.get(), transformation_context));
  368. ASSERT_TRUE(TransformationAddDeadBreak(after_block_2, merge_after, false, {})
  369. .IsApplicable(context.get(), transformation_context));
  370. // Not OK to break to the wrong merge (whether enclosing or not)
  371. ASSERT_FALSE(TransformationAddDeadBreak(inner_block_1, merge_outer, true, {})
  372. .IsApplicable(context.get(), transformation_context));
  373. ASSERT_FALSE(TransformationAddDeadBreak(inner_block_2, merge_after, false, {})
  374. .IsApplicable(context.get(), transformation_context));
  375. ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, merge_inner, true, {})
  376. .IsApplicable(context.get(), transformation_context));
  377. ASSERT_FALSE(TransformationAddDeadBreak(outer_block_2, merge_after, false, {})
  378. .IsApplicable(context.get(), transformation_context));
  379. ASSERT_FALSE(TransformationAddDeadBreak(after_block_1, merge_inner, true, {})
  380. .IsApplicable(context.get(), transformation_context));
  381. ASSERT_FALSE(TransformationAddDeadBreak(after_block_2, merge_outer, false, {})
  382. .IsApplicable(context.get(), transformation_context));
  383. // Not OK to break from header (as it does not branch unconditionally)
  384. ASSERT_FALSE(TransformationAddDeadBreak(header_inner, merge_inner, true, {})
  385. .IsApplicable(context.get(), transformation_context));
  386. ASSERT_FALSE(TransformationAddDeadBreak(header_outer, merge_outer, false, {})
  387. .IsApplicable(context.get(), transformation_context));
  388. ASSERT_FALSE(TransformationAddDeadBreak(header_after, merge_after, true, {})
  389. .IsApplicable(context.get(), transformation_context));
  390. // Not OK to break to non-merge
  391. ASSERT_FALSE(
  392. TransformationAddDeadBreak(inner_block_1, inner_block_2, true, {})
  393. .IsApplicable(context.get(), transformation_context));
  394. ASSERT_FALSE(
  395. TransformationAddDeadBreak(outer_block_2, after_block_1, false, {})
  396. .IsApplicable(context.get(), transformation_context));
  397. ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, header_after, true, {})
  398. .IsApplicable(context.get(), transformation_context));
  399. auto transformation1 =
  400. TransformationAddDeadBreak(inner_block_1, merge_inner, true, {});
  401. auto transformation2 =
  402. TransformationAddDeadBreak(inner_block_2, merge_inner, false, {});
  403. auto transformation3 =
  404. TransformationAddDeadBreak(outer_block_1, merge_outer, true, {});
  405. auto transformation4 =
  406. TransformationAddDeadBreak(outer_block_2, merge_outer, false, {});
  407. auto transformation5 =
  408. TransformationAddDeadBreak(outer_block_3, merge_outer, true, {});
  409. auto transformation6 =
  410. TransformationAddDeadBreak(outer_block_4, merge_outer, false, {});
  411. auto transformation7 =
  412. TransformationAddDeadBreak(after_block_1, merge_after, true, {});
  413. auto transformation8 =
  414. TransformationAddDeadBreak(after_block_2, merge_after, false, {});
  415. ASSERT_TRUE(
  416. transformation1.IsApplicable(context.get(), transformation_context));
  417. ApplyAndCheckFreshIds(transformation1, context.get(),
  418. &transformation_context);
  419. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  420. kConsoleMessageConsumer));
  421. ASSERT_TRUE(
  422. transformation2.IsApplicable(context.get(), transformation_context));
  423. ApplyAndCheckFreshIds(transformation2, context.get(),
  424. &transformation_context);
  425. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  426. kConsoleMessageConsumer));
  427. ASSERT_TRUE(
  428. transformation3.IsApplicable(context.get(), transformation_context));
  429. ApplyAndCheckFreshIds(transformation3, context.get(),
  430. &transformation_context);
  431. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  432. kConsoleMessageConsumer));
  433. ASSERT_TRUE(
  434. transformation4.IsApplicable(context.get(), transformation_context));
  435. ApplyAndCheckFreshIds(transformation4, context.get(),
  436. &transformation_context);
  437. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  438. kConsoleMessageConsumer));
  439. ASSERT_TRUE(
  440. transformation5.IsApplicable(context.get(), transformation_context));
  441. ApplyAndCheckFreshIds(transformation5, context.get(),
  442. &transformation_context);
  443. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  444. kConsoleMessageConsumer));
  445. ASSERT_TRUE(
  446. transformation6.IsApplicable(context.get(), transformation_context));
  447. ApplyAndCheckFreshIds(transformation6, context.get(),
  448. &transformation_context);
  449. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  450. kConsoleMessageConsumer));
  451. ASSERT_TRUE(
  452. transformation7.IsApplicable(context.get(), transformation_context));
  453. ApplyAndCheckFreshIds(transformation7, context.get(),
  454. &transformation_context);
  455. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  456. kConsoleMessageConsumer));
  457. ASSERT_TRUE(
  458. transformation8.IsApplicable(context.get(), transformation_context));
  459. ApplyAndCheckFreshIds(transformation8, context.get(),
  460. &transformation_context);
  461. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  462. kConsoleMessageConsumer));
  463. std::string after_transformation = R"(
  464. OpCapability Shader
  465. %1 = OpExtInstImport "GLSL.std.450"
  466. OpMemoryModel Logical GLSL450
  467. OpEntryPoint Fragment %4 "main"
  468. OpExecutionMode %4 OriginUpperLeft
  469. OpSource ESSL 310
  470. OpName %4 "main"
  471. OpName %8 "x"
  472. OpName %11 "y"
  473. %2 = OpTypeVoid
  474. %3 = OpTypeFunction %2
  475. %6 = OpTypeInt 32 1
  476. %7 = OpTypePointer Function %6
  477. %9 = OpConstant %6 1
  478. %13 = OpTypeBool
  479. %17 = OpConstant %6 2
  480. %18 = OpConstant %6 3
  481. %31 = OpConstantTrue %13
  482. %32 = OpConstantFalse %13
  483. %4 = OpFunction %2 None %3
  484. %5 = OpLabel
  485. %8 = OpVariable %7 Function
  486. %11 = OpVariable %7 Function
  487. OpStore %8 %9
  488. %10 = OpLoad %6 %8
  489. %12 = OpLoad %6 %11
  490. %14 = OpSLessThan %13 %10 %12
  491. OpSelectionMerge %16 None
  492. OpBranchConditional %14 %15 %24
  493. %15 = OpLabel
  494. OpStore %8 %17
  495. OpBranchConditional %31 %33 %16
  496. %33 = OpLabel
  497. OpStore %8 %18
  498. %19 = OpLoad %6 %8
  499. OpBranchConditional %32 %16 %34
  500. %34 = OpLabel
  501. %20 = OpLoad %6 %11
  502. %21 = OpIEqual %13 %19 %20
  503. OpSelectionMerge %23 None
  504. OpBranchConditional %21 %22 %23
  505. %22 = OpLabel
  506. OpStore %11 %18
  507. OpBranchConditional %31 %35 %23
  508. %35 = OpLabel
  509. OpBranchConditional %32 %23 %23
  510. %23 = OpLabel
  511. OpBranch %16
  512. %24 = OpLabel
  513. OpStore %11 %17
  514. OpBranchConditional %31 %36 %16
  515. %36 = OpLabel
  516. OpStore %11 %18
  517. OpBranchConditional %32 %16 %16
  518. %16 = OpLabel
  519. %25 = OpLoad %6 %8
  520. OpBranch %37
  521. %37 = OpLabel
  522. %26 = OpLoad %6 %11
  523. %27 = OpIEqual %13 %25 %26
  524. OpSelectionMerge %29 None
  525. OpBranchConditional %27 %28 %29
  526. %28 = OpLabel
  527. OpStore %8 %17
  528. OpBranchConditional %31 %38 %29
  529. %38 = OpLabel
  530. OpBranchConditional %32 %29 %29
  531. %29 = OpLabel
  532. %30 = OpLoad %6 %11
  533. OpStore %8 %30
  534. OpReturn
  535. OpFunctionEnd
  536. )";
  537. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  538. }
  539. TEST(TransformationAddDeadBreakTest, BreakOutOfNestedSwitches) {
  540. // Checks some allowed and disallowed scenarios for nests of switches.
  541. // The SPIR-V for this test is adapted from the following GLSL:
  542. //
  543. // void main() {
  544. // int x;
  545. // int y;
  546. // x = 1;
  547. // if (x < y) {
  548. // switch (x) {
  549. // case 0:
  550. // case 1:
  551. // if (x == y) {
  552. // }
  553. // x = 2;
  554. // break;
  555. // case 3:
  556. // if (y == 4) {
  557. // y = 2;
  558. // x = 3;
  559. // }
  560. // case 10:
  561. // break;
  562. // default:
  563. // switch (y) {
  564. // case 1:
  565. // break;
  566. // case 2:
  567. // x = 4;
  568. // y = 2;
  569. // default:
  570. // x = 3;
  571. // break;
  572. // }
  573. // }
  574. // } else {
  575. // switch (y) {
  576. // case 1:
  577. // x = 4;
  578. // case 2:
  579. // y = 3;
  580. // default:
  581. // x = y;
  582. // break;
  583. // }
  584. // }
  585. // }
  586. std::string shader = R"(
  587. OpCapability Shader
  588. %1 = OpExtInstImport "GLSL.std.450"
  589. OpMemoryModel Logical GLSL450
  590. OpEntryPoint Fragment %4 "main"
  591. OpExecutionMode %4 OriginUpperLeft
  592. OpSource ESSL 310
  593. OpName %4 "main"
  594. OpName %8 "x"
  595. OpName %11 "y"
  596. %2 = OpTypeVoid
  597. %3 = OpTypeFunction %2
  598. %6 = OpTypeInt 32 1
  599. %7 = OpTypePointer Function %6
  600. %9 = OpConstant %6 1
  601. %13 = OpTypeBool
  602. %29 = OpConstant %6 2
  603. %32 = OpConstant %6 4
  604. %36 = OpConstant %6 3
  605. %60 = OpConstantTrue %13
  606. %61 = OpConstantFalse %13
  607. %4 = OpFunction %2 None %3
  608. %5 = OpLabel
  609. %8 = OpVariable %7 Function
  610. %11 = OpVariable %7 Function
  611. OpStore %8 %9
  612. %10 = OpLoad %6 %8
  613. %12 = OpLoad %6 %11
  614. %14 = OpSLessThan %13 %10 %12
  615. OpSelectionMerge %16 None
  616. OpBranchConditional %14 %15 %47
  617. %15 = OpLabel
  618. %17 = OpLoad %6 %8
  619. OpSelectionMerge %22 None
  620. OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20
  621. %21 = OpLabel
  622. %38 = OpLoad %6 %11
  623. OpSelectionMerge %42 None
  624. OpSwitch %38 %41 1 %39 2 %40
  625. %41 = OpLabel
  626. OpStore %8 %36
  627. OpBranch %42
  628. %39 = OpLabel
  629. OpBranch %42
  630. %40 = OpLabel
  631. OpStore %8 %32
  632. OpStore %11 %29
  633. OpBranch %41
  634. %42 = OpLabel
  635. OpBranch %22
  636. %18 = OpLabel
  637. %23 = OpLoad %6 %8
  638. OpBranch %63
  639. %63 = OpLabel
  640. %24 = OpLoad %6 %11
  641. %25 = OpIEqual %13 %23 %24
  642. OpSelectionMerge %27 None
  643. OpBranchConditional %25 %26 %27
  644. %26 = OpLabel
  645. OpBranch %27
  646. %27 = OpLabel
  647. OpStore %8 %29
  648. OpBranch %22
  649. %19 = OpLabel
  650. %31 = OpLoad %6 %11
  651. %33 = OpIEqual %13 %31 %32
  652. OpSelectionMerge %35 None
  653. OpBranchConditional %33 %34 %35
  654. %34 = OpLabel
  655. OpStore %11 %29
  656. OpBranch %62
  657. %62 = OpLabel
  658. OpStore %8 %36
  659. OpBranch %35
  660. %35 = OpLabel
  661. OpBranch %20
  662. %20 = OpLabel
  663. OpBranch %22
  664. %22 = OpLabel
  665. OpBranch %16
  666. %47 = OpLabel
  667. %48 = OpLoad %6 %11
  668. OpSelectionMerge %52 None
  669. OpSwitch %48 %51 1 %49 2 %50
  670. %51 = OpLabel
  671. %53 = OpLoad %6 %11
  672. OpStore %8 %53
  673. OpBranch %52
  674. %49 = OpLabel
  675. OpStore %8 %32
  676. OpBranch %50
  677. %50 = OpLabel
  678. OpStore %11 %36
  679. OpBranch %51
  680. %52 = OpLabel
  681. OpBranch %16
  682. %16 = OpLabel
  683. OpReturn
  684. OpFunctionEnd
  685. )";
  686. const auto env = SPV_ENV_UNIVERSAL_1_3;
  687. const auto consumer = nullptr;
  688. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  689. spvtools::ValidatorOptions validator_options;
  690. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  691. kConsoleMessageConsumer));
  692. TransformationContext transformation_context(
  693. MakeUnique<FactManager>(context.get()), validator_options);
  694. // The header and merge blocks
  695. const uint32_t header_outer_if = 5;
  696. const uint32_t merge_outer_if = 16;
  697. const uint32_t header_then_outer_switch = 15;
  698. const uint32_t merge_then_outer_switch = 22;
  699. const uint32_t header_then_inner_switch = 21;
  700. const uint32_t merge_then_inner_switch = 42;
  701. const uint32_t header_else_switch = 47;
  702. const uint32_t merge_else_switch = 52;
  703. const uint32_t header_inner_if_1 = 19;
  704. const uint32_t merge_inner_if_1 = 35;
  705. const uint32_t header_inner_if_2 = 63;
  706. const uint32_t merge_inner_if_2 = 27;
  707. // The non-merge-nor-header blocks in each construct
  708. const uint32_t then_outer_switch_block_1 = 18;
  709. const uint32_t then_inner_switch_block_1 = 39;
  710. const uint32_t then_inner_switch_block_2 = 40;
  711. const uint32_t then_inner_switch_block_3 = 41;
  712. const uint32_t else_switch_block_1 = 49;
  713. const uint32_t else_switch_block_2 = 50;
  714. const uint32_t else_switch_block_3 = 51;
  715. const uint32_t inner_if_1_block_1 = 34;
  716. const uint32_t inner_if_1_block_2 = 62;
  717. const uint32_t inner_if_2_block_1 = 26;
  718. // Fine to branch straight to direct merge block for a construct
  719. ASSERT_TRUE(TransformationAddDeadBreak(then_outer_switch_block_1,
  720. merge_then_outer_switch, true, {})
  721. .IsApplicable(context.get(), transformation_context));
  722. ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_1,
  723. merge_then_inner_switch, false, {})
  724. .IsApplicable(context.get(), transformation_context));
  725. ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_2,
  726. merge_then_inner_switch, true, {})
  727. .IsApplicable(context.get(), transformation_context));
  728. ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_3,
  729. merge_then_inner_switch, true, {})
  730. .IsApplicable(context.get(), transformation_context));
  731. ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_1, merge_else_switch,
  732. false, {})
  733. .IsApplicable(context.get(), transformation_context));
  734. ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_2, merge_else_switch,
  735. true, {})
  736. .IsApplicable(context.get(), transformation_context));
  737. ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_3, merge_else_switch,
  738. false, {})
  739. .IsApplicable(context.get(), transformation_context));
  740. ASSERT_TRUE(
  741. TransformationAddDeadBreak(inner_if_1_block_1, merge_inner_if_1, true, {})
  742. .IsApplicable(context.get(), transformation_context));
  743. ASSERT_TRUE(TransformationAddDeadBreak(inner_if_1_block_2, merge_inner_if_1,
  744. false, {})
  745. .IsApplicable(context.get(), transformation_context));
  746. ASSERT_TRUE(
  747. TransformationAddDeadBreak(inner_if_2_block_1, merge_inner_if_2, true, {})
  748. .IsApplicable(context.get(), transformation_context));
  749. // Not OK to break out of a switch from a selection construct inside the
  750. // switch.
  751. ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_1,
  752. merge_then_outer_switch, true, {})
  753. .IsApplicable(context.get(), transformation_context));
  754. ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_2,
  755. merge_then_outer_switch, false, {})
  756. .IsApplicable(context.get(), transformation_context));
  757. ASSERT_FALSE(TransformationAddDeadBreak(inner_if_2_block_1,
  758. merge_then_outer_switch, true, {})
  759. .IsApplicable(context.get(), transformation_context));
  760. // Some miscellaneous inapplicable cases.
  761. ASSERT_FALSE(
  762. TransformationAddDeadBreak(header_outer_if, merge_outer_if, true, {})
  763. .IsApplicable(context.get(), transformation_context));
  764. ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_1, inner_if_1_block_2,
  765. false, {})
  766. .IsApplicable(context.get(), transformation_context));
  767. ASSERT_FALSE(TransformationAddDeadBreak(header_then_inner_switch,
  768. header_then_outer_switch, false, {})
  769. .IsApplicable(context.get(), transformation_context));
  770. ASSERT_FALSE(TransformationAddDeadBreak(header_else_switch,
  771. then_inner_switch_block_3, false, {})
  772. .IsApplicable(context.get(), transformation_context));
  773. ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_2, header_inner_if_2,
  774. false, {})
  775. .IsApplicable(context.get(), transformation_context));
  776. auto transformation1 = TransformationAddDeadBreak(
  777. then_outer_switch_block_1, merge_then_outer_switch, true, {});
  778. auto transformation2 = TransformationAddDeadBreak(
  779. then_inner_switch_block_1, merge_then_inner_switch, false, {});
  780. auto transformation3 = TransformationAddDeadBreak(
  781. then_inner_switch_block_2, merge_then_inner_switch, true, {});
  782. auto transformation4 = TransformationAddDeadBreak(
  783. then_inner_switch_block_3, merge_then_inner_switch, true, {});
  784. auto transformation5 = TransformationAddDeadBreak(
  785. else_switch_block_1, merge_else_switch, false, {});
  786. auto transformation6 = TransformationAddDeadBreak(
  787. else_switch_block_2, merge_else_switch, true, {});
  788. auto transformation7 = TransformationAddDeadBreak(
  789. else_switch_block_3, merge_else_switch, false, {});
  790. auto transformation8 = TransformationAddDeadBreak(inner_if_1_block_1,
  791. merge_inner_if_1, true, {});
  792. auto transformation9 = TransformationAddDeadBreak(
  793. inner_if_1_block_2, merge_inner_if_1, false, {});
  794. auto transformation10 = TransformationAddDeadBreak(
  795. inner_if_2_block_1, merge_inner_if_2, true, {});
  796. ASSERT_TRUE(
  797. transformation1.IsApplicable(context.get(), transformation_context));
  798. ApplyAndCheckFreshIds(transformation1, context.get(),
  799. &transformation_context);
  800. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  801. kConsoleMessageConsumer));
  802. ASSERT_TRUE(
  803. transformation2.IsApplicable(context.get(), transformation_context));
  804. ApplyAndCheckFreshIds(transformation2, context.get(),
  805. &transformation_context);
  806. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  807. kConsoleMessageConsumer));
  808. ASSERT_TRUE(
  809. transformation3.IsApplicable(context.get(), transformation_context));
  810. ApplyAndCheckFreshIds(transformation3, context.get(),
  811. &transformation_context);
  812. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  813. kConsoleMessageConsumer));
  814. ASSERT_TRUE(
  815. transformation4.IsApplicable(context.get(), transformation_context));
  816. ApplyAndCheckFreshIds(transformation4, context.get(),
  817. &transformation_context);
  818. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  819. kConsoleMessageConsumer));
  820. ASSERT_TRUE(
  821. transformation5.IsApplicable(context.get(), transformation_context));
  822. ApplyAndCheckFreshIds(transformation5, context.get(),
  823. &transformation_context);
  824. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  825. kConsoleMessageConsumer));
  826. ASSERT_TRUE(
  827. transformation6.IsApplicable(context.get(), transformation_context));
  828. ApplyAndCheckFreshIds(transformation6, context.get(),
  829. &transformation_context);
  830. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  831. kConsoleMessageConsumer));
  832. ASSERT_TRUE(
  833. transformation7.IsApplicable(context.get(), transformation_context));
  834. ApplyAndCheckFreshIds(transformation7, context.get(),
  835. &transformation_context);
  836. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  837. kConsoleMessageConsumer));
  838. ASSERT_TRUE(
  839. transformation8.IsApplicable(context.get(), transformation_context));
  840. ApplyAndCheckFreshIds(transformation8, context.get(),
  841. &transformation_context);
  842. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  843. kConsoleMessageConsumer));
  844. ASSERT_TRUE(
  845. transformation9.IsApplicable(context.get(), transformation_context));
  846. ApplyAndCheckFreshIds(transformation9, context.get(),
  847. &transformation_context);
  848. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  849. kConsoleMessageConsumer));
  850. ASSERT_TRUE(
  851. transformation10.IsApplicable(context.get(), transformation_context));
  852. ApplyAndCheckFreshIds(transformation10, context.get(),
  853. &transformation_context);
  854. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  855. kConsoleMessageConsumer));
  856. std::string after_transformation = R"(
  857. OpCapability Shader
  858. %1 = OpExtInstImport "GLSL.std.450"
  859. OpMemoryModel Logical GLSL450
  860. OpEntryPoint Fragment %4 "main"
  861. OpExecutionMode %4 OriginUpperLeft
  862. OpSource ESSL 310
  863. OpName %4 "main"
  864. OpName %8 "x"
  865. OpName %11 "y"
  866. %2 = OpTypeVoid
  867. %3 = OpTypeFunction %2
  868. %6 = OpTypeInt 32 1
  869. %7 = OpTypePointer Function %6
  870. %9 = OpConstant %6 1
  871. %13 = OpTypeBool
  872. %29 = OpConstant %6 2
  873. %32 = OpConstant %6 4
  874. %36 = OpConstant %6 3
  875. %60 = OpConstantTrue %13
  876. %61 = OpConstantFalse %13
  877. %4 = OpFunction %2 None %3
  878. %5 = OpLabel
  879. %8 = OpVariable %7 Function
  880. %11 = OpVariable %7 Function
  881. OpStore %8 %9
  882. %10 = OpLoad %6 %8
  883. %12 = OpLoad %6 %11
  884. %14 = OpSLessThan %13 %10 %12
  885. OpSelectionMerge %16 None
  886. OpBranchConditional %14 %15 %47
  887. %15 = OpLabel
  888. %17 = OpLoad %6 %8
  889. OpSelectionMerge %22 None
  890. OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20
  891. %21 = OpLabel
  892. %38 = OpLoad %6 %11
  893. OpSelectionMerge %42 None
  894. OpSwitch %38 %41 1 %39 2 %40
  895. %41 = OpLabel
  896. OpStore %8 %36
  897. OpBranchConditional %60 %42 %42
  898. %39 = OpLabel
  899. OpBranchConditional %61 %42 %42
  900. %40 = OpLabel
  901. OpStore %8 %32
  902. OpStore %11 %29
  903. OpBranchConditional %60 %41 %42
  904. %42 = OpLabel
  905. OpBranch %22
  906. %18 = OpLabel
  907. %23 = OpLoad %6 %8
  908. OpBranchConditional %60 %63 %22
  909. %63 = OpLabel
  910. %24 = OpLoad %6 %11
  911. %25 = OpIEqual %13 %23 %24
  912. OpSelectionMerge %27 None
  913. OpBranchConditional %25 %26 %27
  914. %26 = OpLabel
  915. OpBranchConditional %60 %27 %27
  916. %27 = OpLabel
  917. OpStore %8 %29
  918. OpBranch %22
  919. %19 = OpLabel
  920. %31 = OpLoad %6 %11
  921. %33 = OpIEqual %13 %31 %32
  922. OpSelectionMerge %35 None
  923. OpBranchConditional %33 %34 %35
  924. %34 = OpLabel
  925. OpStore %11 %29
  926. OpBranchConditional %60 %62 %35
  927. %62 = OpLabel
  928. OpStore %8 %36
  929. OpBranchConditional %61 %35 %35
  930. %35 = OpLabel
  931. OpBranch %20
  932. %20 = OpLabel
  933. OpBranch %22
  934. %22 = OpLabel
  935. OpBranch %16
  936. %47 = OpLabel
  937. %48 = OpLoad %6 %11
  938. OpSelectionMerge %52 None
  939. OpSwitch %48 %51 1 %49 2 %50
  940. %51 = OpLabel
  941. %53 = OpLoad %6 %11
  942. OpStore %8 %53
  943. OpBranchConditional %61 %52 %52
  944. %49 = OpLabel
  945. OpStore %8 %32
  946. OpBranchConditional %61 %52 %50
  947. %50 = OpLabel
  948. OpStore %11 %36
  949. OpBranchConditional %60 %51 %52
  950. %52 = OpLabel
  951. OpBranch %16
  952. %16 = OpLabel
  953. OpReturn
  954. OpFunctionEnd
  955. )";
  956. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  957. }
  958. TEST(TransformationAddDeadBreakTest, BreakOutOfLoopNest) {
  959. // Checks some allowed and disallowed scenarios for a nest of loops, including
  960. // breaking from an if or switch right out of a loop.
  961. // The SPIR-V for this test is adapted from the following GLSL:
  962. //
  963. // void main() {
  964. // int x, y;
  965. // do {
  966. // x++;
  967. // for (int j = 0; j < 100; j++) {
  968. // y++;
  969. // if (x == y) {
  970. // x++;
  971. // if (x == 2) {
  972. // y++;
  973. // }
  974. // switch (x) {
  975. // case 0:
  976. // x = 2;
  977. // default:
  978. // break;
  979. // }
  980. // }
  981. // }
  982. // } while (x > y);
  983. //
  984. // for (int i = 0; i < 100; i++) {
  985. // x++;
  986. // }
  987. // }
  988. std::string shader = R"(
  989. OpCapability Shader
  990. %1 = OpExtInstImport "GLSL.std.450"
  991. OpMemoryModel Logical GLSL450
  992. OpEntryPoint Fragment %4 "main"
  993. OpExecutionMode %4 OriginUpperLeft
  994. OpSource ESSL 310
  995. OpName %4 "main"
  996. OpName %12 "x"
  997. OpName %16 "j"
  998. OpName %27 "y"
  999. OpName %55 "i"
  1000. %2 = OpTypeVoid
  1001. %3 = OpTypeFunction %2
  1002. %10 = OpTypeInt 32 1
  1003. %11 = OpTypePointer Function %10
  1004. %14 = OpConstant %10 1
  1005. %17 = OpConstant %10 0
  1006. %24 = OpConstant %10 100
  1007. %25 = OpTypeBool
  1008. %38 = OpConstant %10 2
  1009. %67 = OpConstantTrue %25
  1010. %68 = OpConstantFalse %25
  1011. %4 = OpFunction %2 None %3
  1012. %5 = OpLabel
  1013. %12 = OpVariable %11 Function
  1014. %16 = OpVariable %11 Function
  1015. %27 = OpVariable %11 Function
  1016. %55 = OpVariable %11 Function
  1017. OpBranch %6
  1018. %6 = OpLabel
  1019. OpLoopMerge %8 %9 None
  1020. OpBranch %7
  1021. %7 = OpLabel
  1022. %13 = OpLoad %10 %12
  1023. %15 = OpIAdd %10 %13 %14
  1024. OpStore %12 %15
  1025. OpStore %16 %17
  1026. OpBranch %18
  1027. %18 = OpLabel
  1028. OpLoopMerge %20 %21 None
  1029. OpBranch %22
  1030. %22 = OpLabel
  1031. %23 = OpLoad %10 %16
  1032. %26 = OpSLessThan %25 %23 %24
  1033. OpBranchConditional %26 %19 %20
  1034. %19 = OpLabel
  1035. %28 = OpLoad %10 %27
  1036. %29 = OpIAdd %10 %28 %14
  1037. OpStore %27 %29
  1038. %30 = OpLoad %10 %12
  1039. %31 = OpLoad %10 %27
  1040. %32 = OpIEqual %25 %30 %31
  1041. OpSelectionMerge %34 None
  1042. OpBranchConditional %32 %33 %34
  1043. %33 = OpLabel
  1044. %35 = OpLoad %10 %12
  1045. %36 = OpIAdd %10 %35 %14
  1046. OpStore %12 %36
  1047. %37 = OpLoad %10 %12
  1048. %39 = OpIEqual %25 %37 %38
  1049. OpSelectionMerge %41 None
  1050. OpBranchConditional %39 %40 %41
  1051. %40 = OpLabel
  1052. %42 = OpLoad %10 %27
  1053. %43 = OpIAdd %10 %42 %14
  1054. OpStore %27 %43
  1055. OpBranch %41
  1056. %41 = OpLabel
  1057. %44 = OpLoad %10 %12
  1058. OpSelectionMerge %47 None
  1059. OpSwitch %44 %46 0 %45
  1060. %46 = OpLabel
  1061. OpBranch %47
  1062. %45 = OpLabel
  1063. OpStore %12 %38
  1064. OpBranch %46
  1065. %47 = OpLabel
  1066. OpBranch %34
  1067. %34 = OpLabel
  1068. OpBranch %21
  1069. %21 = OpLabel
  1070. %50 = OpLoad %10 %16
  1071. %51 = OpIAdd %10 %50 %14
  1072. OpStore %16 %51
  1073. OpBranch %18
  1074. %20 = OpLabel
  1075. OpBranch %9
  1076. %9 = OpLabel
  1077. %52 = OpLoad %10 %12
  1078. %53 = OpLoad %10 %27
  1079. %54 = OpSGreaterThan %25 %52 %53
  1080. OpBranchConditional %54 %6 %8
  1081. %8 = OpLabel
  1082. OpStore %55 %17
  1083. OpBranch %56
  1084. %56 = OpLabel
  1085. OpLoopMerge %58 %59 None
  1086. OpBranch %60
  1087. %60 = OpLabel
  1088. %61 = OpLoad %10 %55
  1089. %62 = OpSLessThan %25 %61 %24
  1090. OpBranchConditional %62 %57 %58
  1091. %57 = OpLabel
  1092. %63 = OpLoad %10 %12
  1093. %64 = OpIAdd %10 %63 %14
  1094. OpStore %12 %64
  1095. OpBranch %59
  1096. %59 = OpLabel
  1097. %65 = OpLoad %10 %55
  1098. %66 = OpIAdd %10 %65 %14
  1099. OpStore %55 %66
  1100. OpBranch %56
  1101. %58 = OpLabel
  1102. OpReturn
  1103. OpFunctionEnd
  1104. )";
  1105. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1106. const auto consumer = nullptr;
  1107. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1108. spvtools::ValidatorOptions validator_options;
  1109. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1110. kConsoleMessageConsumer));
  1111. TransformationContext transformation_context(
  1112. MakeUnique<FactManager>(context.get()), validator_options);
  1113. // The header and merge blocks
  1114. const uint32_t header_do_while = 6;
  1115. const uint32_t merge_do_while = 8;
  1116. const uint32_t header_for_j = 18;
  1117. const uint32_t merge_for_j = 20;
  1118. const uint32_t header_for_i = 56;
  1119. const uint32_t merge_for_i = 58;
  1120. const uint32_t header_switch = 41;
  1121. const uint32_t merge_switch = 47;
  1122. const uint32_t header_if_x_eq_y = 19;
  1123. const uint32_t merge_if_x_eq_y = 34;
  1124. const uint32_t header_if_x_eq_2 = 33;
  1125. const uint32_t merge_if_x_eq_2 = 41;
  1126. // Loop continue targets
  1127. const uint32_t continue_do_while = 9;
  1128. const uint32_t continue_for_j = 21;
  1129. const uint32_t continue_for_i = 59;
  1130. // Some blocks in these constructs
  1131. const uint32_t block_in_inner_if = 40;
  1132. const uint32_t block_switch_case = 46;
  1133. const uint32_t block_switch_default = 45;
  1134. const uint32_t block_in_for_i_loop = 57;
  1135. // Fine to break from any loop header to its merge
  1136. ASSERT_TRUE(
  1137. TransformationAddDeadBreak(header_do_while, merge_do_while, true, {})
  1138. .IsApplicable(context.get(), transformation_context));
  1139. ASSERT_TRUE(TransformationAddDeadBreak(header_for_i, merge_for_i, false, {})
  1140. .IsApplicable(context.get(), transformation_context));
  1141. ASSERT_TRUE(TransformationAddDeadBreak(header_for_j, merge_for_j, true, {})
  1142. .IsApplicable(context.get(), transformation_context));
  1143. // Fine to break from any of the blocks in constructs in the "for j" loop to
  1144. // that loop's merge
  1145. ASSERT_TRUE(
  1146. TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {})
  1147. .IsApplicable(context.get(), transformation_context));
  1148. ASSERT_TRUE(
  1149. TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {})
  1150. .IsApplicable(context.get(), transformation_context));
  1151. ASSERT_TRUE(
  1152. TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {})
  1153. .IsApplicable(context.get(), transformation_context));
  1154. // Fine to break from the body of the "for i" loop to that loop's merge
  1155. ASSERT_TRUE(
  1156. TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {})
  1157. .IsApplicable(context.get(), transformation_context));
  1158. // Not OK to break from multiple loops
  1159. ASSERT_FALSE(
  1160. TransformationAddDeadBreak(block_in_inner_if, merge_do_while, false, {})
  1161. .IsApplicable(context.get(), transformation_context));
  1162. ASSERT_FALSE(
  1163. TransformationAddDeadBreak(block_switch_case, merge_do_while, true, {})
  1164. .IsApplicable(context.get(), transformation_context));
  1165. ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_do_while,
  1166. false, {})
  1167. .IsApplicable(context.get(), transformation_context));
  1168. ASSERT_FALSE(
  1169. TransformationAddDeadBreak(header_for_j, merge_do_while, true, {})
  1170. .IsApplicable(context.get(), transformation_context));
  1171. // Not OK to break loop from its continue construct, except from the back-edge
  1172. // block.
  1173. ASSERT_FALSE(
  1174. TransformationAddDeadBreak(continue_do_while, merge_do_while, true, {})
  1175. .IsApplicable(context.get(), transformation_context));
  1176. ASSERT_TRUE(TransformationAddDeadBreak(continue_for_j, merge_for_j, false, {})
  1177. .IsApplicable(context.get(), transformation_context));
  1178. ASSERT_TRUE(TransformationAddDeadBreak(continue_for_i, merge_for_i, true, {})
  1179. .IsApplicable(context.get(), transformation_context));
  1180. // Not OK to break out of multiple non-loop constructs if not breaking to a
  1181. // loop merge
  1182. ASSERT_FALSE(
  1183. TransformationAddDeadBreak(block_in_inner_if, merge_if_x_eq_y, false, {})
  1184. .IsApplicable(context.get(), transformation_context));
  1185. ASSERT_FALSE(
  1186. TransformationAddDeadBreak(block_switch_case, merge_if_x_eq_y, true, {})
  1187. .IsApplicable(context.get(), transformation_context));
  1188. ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_if_x_eq_y,
  1189. false, {})
  1190. .IsApplicable(context.get(), transformation_context));
  1191. // Some miscellaneous inapplicable transformations
  1192. ASSERT_FALSE(
  1193. TransformationAddDeadBreak(header_if_x_eq_2, header_if_x_eq_y, false, {})
  1194. .IsApplicable(context.get(), transformation_context));
  1195. ASSERT_FALSE(
  1196. TransformationAddDeadBreak(merge_if_x_eq_2, merge_switch, false, {})
  1197. .IsApplicable(context.get(), transformation_context));
  1198. ASSERT_FALSE(
  1199. TransformationAddDeadBreak(header_switch, header_switch, false, {})
  1200. .IsApplicable(context.get(), transformation_context));
  1201. auto transformation1 =
  1202. TransformationAddDeadBreak(header_do_while, merge_do_while, true, {});
  1203. auto transformation2 =
  1204. TransformationAddDeadBreak(header_for_i, merge_for_i, false, {});
  1205. auto transformation3 =
  1206. TransformationAddDeadBreak(header_for_j, merge_for_j, true, {});
  1207. auto transformation4 =
  1208. TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {});
  1209. auto transformation5 =
  1210. TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {});
  1211. auto transformation6 =
  1212. TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {});
  1213. auto transformation7 =
  1214. TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {});
  1215. ASSERT_TRUE(
  1216. transformation1.IsApplicable(context.get(), transformation_context));
  1217. ApplyAndCheckFreshIds(transformation1, context.get(),
  1218. &transformation_context);
  1219. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1220. kConsoleMessageConsumer));
  1221. ASSERT_TRUE(
  1222. transformation2.IsApplicable(context.get(), transformation_context));
  1223. ApplyAndCheckFreshIds(transformation2, context.get(),
  1224. &transformation_context);
  1225. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1226. kConsoleMessageConsumer));
  1227. ASSERT_TRUE(
  1228. transformation3.IsApplicable(context.get(), transformation_context));
  1229. ApplyAndCheckFreshIds(transformation3, context.get(),
  1230. &transformation_context);
  1231. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1232. kConsoleMessageConsumer));
  1233. ASSERT_TRUE(
  1234. transformation4.IsApplicable(context.get(), transformation_context));
  1235. ApplyAndCheckFreshIds(transformation4, context.get(),
  1236. &transformation_context);
  1237. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1238. kConsoleMessageConsumer));
  1239. ASSERT_TRUE(
  1240. transformation5.IsApplicable(context.get(), transformation_context));
  1241. ApplyAndCheckFreshIds(transformation5, context.get(),
  1242. &transformation_context);
  1243. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1244. kConsoleMessageConsumer));
  1245. ASSERT_TRUE(
  1246. transformation6.IsApplicable(context.get(), transformation_context));
  1247. ApplyAndCheckFreshIds(transformation6, context.get(),
  1248. &transformation_context);
  1249. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1250. kConsoleMessageConsumer));
  1251. ASSERT_TRUE(
  1252. transformation7.IsApplicable(context.get(), transformation_context));
  1253. ApplyAndCheckFreshIds(transformation7, context.get(),
  1254. &transformation_context);
  1255. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1256. kConsoleMessageConsumer));
  1257. std::string after_transformation = R"(
  1258. OpCapability Shader
  1259. %1 = OpExtInstImport "GLSL.std.450"
  1260. OpMemoryModel Logical GLSL450
  1261. OpEntryPoint Fragment %4 "main"
  1262. OpExecutionMode %4 OriginUpperLeft
  1263. OpSource ESSL 310
  1264. OpName %4 "main"
  1265. OpName %12 "x"
  1266. OpName %16 "j"
  1267. OpName %27 "y"
  1268. OpName %55 "i"
  1269. %2 = OpTypeVoid
  1270. %3 = OpTypeFunction %2
  1271. %10 = OpTypeInt 32 1
  1272. %11 = OpTypePointer Function %10
  1273. %14 = OpConstant %10 1
  1274. %17 = OpConstant %10 0
  1275. %24 = OpConstant %10 100
  1276. %25 = OpTypeBool
  1277. %38 = OpConstant %10 2
  1278. %67 = OpConstantTrue %25
  1279. %68 = OpConstantFalse %25
  1280. %4 = OpFunction %2 None %3
  1281. %5 = OpLabel
  1282. %12 = OpVariable %11 Function
  1283. %16 = OpVariable %11 Function
  1284. %27 = OpVariable %11 Function
  1285. %55 = OpVariable %11 Function
  1286. OpBranch %6
  1287. %6 = OpLabel
  1288. OpLoopMerge %8 %9 None
  1289. OpBranchConditional %67 %7 %8
  1290. %7 = OpLabel
  1291. %13 = OpLoad %10 %12
  1292. %15 = OpIAdd %10 %13 %14
  1293. OpStore %12 %15
  1294. OpStore %16 %17
  1295. OpBranch %18
  1296. %18 = OpLabel
  1297. OpLoopMerge %20 %21 None
  1298. OpBranchConditional %67 %22 %20
  1299. %22 = OpLabel
  1300. %23 = OpLoad %10 %16
  1301. %26 = OpSLessThan %25 %23 %24
  1302. OpBranchConditional %26 %19 %20
  1303. %19 = OpLabel
  1304. %28 = OpLoad %10 %27
  1305. %29 = OpIAdd %10 %28 %14
  1306. OpStore %27 %29
  1307. %30 = OpLoad %10 %12
  1308. %31 = OpLoad %10 %27
  1309. %32 = OpIEqual %25 %30 %31
  1310. OpSelectionMerge %34 None
  1311. OpBranchConditional %32 %33 %34
  1312. %33 = OpLabel
  1313. %35 = OpLoad %10 %12
  1314. %36 = OpIAdd %10 %35 %14
  1315. OpStore %12 %36
  1316. %37 = OpLoad %10 %12
  1317. %39 = OpIEqual %25 %37 %38
  1318. OpSelectionMerge %41 None
  1319. OpBranchConditional %39 %40 %41
  1320. %40 = OpLabel
  1321. %42 = OpLoad %10 %27
  1322. %43 = OpIAdd %10 %42 %14
  1323. OpStore %27 %43
  1324. OpBranchConditional %68 %20 %41
  1325. %41 = OpLabel
  1326. %44 = OpLoad %10 %12
  1327. OpSelectionMerge %47 None
  1328. OpSwitch %44 %46 0 %45
  1329. %46 = OpLabel
  1330. OpBranchConditional %67 %47 %20
  1331. %45 = OpLabel
  1332. OpStore %12 %38
  1333. OpBranchConditional %68 %20 %46
  1334. %47 = OpLabel
  1335. OpBranch %34
  1336. %34 = OpLabel
  1337. OpBranch %21
  1338. %21 = OpLabel
  1339. %50 = OpLoad %10 %16
  1340. %51 = OpIAdd %10 %50 %14
  1341. OpStore %16 %51
  1342. OpBranch %18
  1343. %20 = OpLabel
  1344. OpBranch %9
  1345. %9 = OpLabel
  1346. %52 = OpLoad %10 %12
  1347. %53 = OpLoad %10 %27
  1348. %54 = OpSGreaterThan %25 %52 %53
  1349. OpBranchConditional %54 %6 %8
  1350. %8 = OpLabel
  1351. OpStore %55 %17
  1352. OpBranch %56
  1353. %56 = OpLabel
  1354. OpLoopMerge %58 %59 None
  1355. OpBranchConditional %68 %58 %60
  1356. %60 = OpLabel
  1357. %61 = OpLoad %10 %55
  1358. %62 = OpSLessThan %25 %61 %24
  1359. OpBranchConditional %62 %57 %58
  1360. %57 = OpLabel
  1361. %63 = OpLoad %10 %12
  1362. %64 = OpIAdd %10 %63 %14
  1363. OpStore %12 %64
  1364. OpBranchConditional %67 %59 %58
  1365. %59 = OpLabel
  1366. %65 = OpLoad %10 %55
  1367. %66 = OpIAdd %10 %65 %14
  1368. OpStore %55 %66
  1369. OpBranch %56
  1370. %58 = OpLabel
  1371. OpReturn
  1372. OpFunctionEnd
  1373. )";
  1374. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1375. }
  1376. TEST(TransformationAddDeadBreakTest, NoBreakFromContinueConstruct) {
  1377. // Checks that it is illegal to break straight from a continue construct.
  1378. // The SPIR-V for this test is adapted from the following GLSL:
  1379. //
  1380. // void main() {
  1381. // for (int i = 0; i < 100; i++) {
  1382. // }
  1383. // }
  1384. std::string shader = R"(
  1385. OpCapability Shader
  1386. %1 = OpExtInstImport "GLSL.std.450"
  1387. OpMemoryModel Logical GLSL450
  1388. OpEntryPoint Fragment %4 "main"
  1389. OpExecutionMode %4 OriginUpperLeft
  1390. OpSource ESSL 310
  1391. OpName %4 "main"
  1392. OpName %8 "i"
  1393. OpDecorate %8 RelaxedPrecision
  1394. OpDecorate %15 RelaxedPrecision
  1395. OpDecorate %19 RelaxedPrecision
  1396. OpDecorate %21 RelaxedPrecision
  1397. %2 = OpTypeVoid
  1398. %3 = OpTypeFunction %2
  1399. %6 = OpTypeInt 32 1
  1400. %7 = OpTypePointer Function %6
  1401. %9 = OpConstant %6 0
  1402. %16 = OpConstant %6 100
  1403. %17 = OpTypeBool
  1404. %22 = OpConstantTrue %17
  1405. %20 = OpConstant %6 1
  1406. %4 = OpFunction %2 None %3
  1407. %5 = OpLabel
  1408. %8 = OpVariable %7 Function
  1409. OpStore %8 %9
  1410. OpBranch %10
  1411. %10 = OpLabel
  1412. OpLoopMerge %12 %13 None
  1413. OpBranch %14
  1414. %14 = OpLabel
  1415. %15 = OpLoad %6 %8
  1416. %18 = OpSLessThan %17 %15 %16
  1417. OpBranchConditional %18 %11 %12
  1418. %11 = OpLabel
  1419. OpBranch %13
  1420. %13 = OpLabel
  1421. %19 = OpLoad %6 %8
  1422. %21 = OpIAdd %6 %19 %20
  1423. OpBranch %23
  1424. %23 = OpLabel
  1425. OpStore %8 %21
  1426. OpBranch %10
  1427. %12 = OpLabel
  1428. OpReturn
  1429. OpFunctionEnd
  1430. )";
  1431. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1432. const auto consumer = nullptr;
  1433. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1434. spvtools::ValidatorOptions validator_options;
  1435. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1436. kConsoleMessageConsumer));
  1437. TransformationContext transformation_context(
  1438. MakeUnique<FactManager>(context.get()), validator_options);
  1439. // Not OK to break loop from its continue construct, except from the back-edge
  1440. // block.
  1441. ASSERT_FALSE(TransformationAddDeadBreak(13, 12, true, {})
  1442. .IsApplicable(context.get(), transformation_context));
  1443. ASSERT_TRUE(TransformationAddDeadBreak(23, 12, true, {})
  1444. .IsApplicable(context.get(), transformation_context));
  1445. }
  1446. TEST(TransformationAddDeadBreakTest, BreakFromBackEdgeBlock) {
  1447. std::string reference_shader = R"(
  1448. OpCapability Shader
  1449. %1 = OpExtInstImport "GLSL.std.450"
  1450. OpMemoryModel Logical GLSL450
  1451. OpEntryPoint Vertex %10 "main"
  1452. ; Types
  1453. %2 = OpTypeVoid
  1454. %3 = OpTypeFunction %2
  1455. %4 = OpTypeInt 32 0
  1456. %5 = OpTypeBool
  1457. %6 = OpTypePointer Function %4
  1458. ; Constants
  1459. %7 = OpConstant %4 0
  1460. %8 = OpConstant %4 1
  1461. %9 = OpConstantTrue %5
  1462. ; main function
  1463. %10 = OpFunction %2 None %3
  1464. %11 = OpLabel
  1465. %12 = OpVariable %6 Function
  1466. OpStore %12 %7
  1467. OpBranch %13
  1468. %13 = OpLabel
  1469. OpLoopMerge %21 %18 None ; structured loop
  1470. OpBranch %14
  1471. %14 = OpLabel
  1472. %15 = OpLoad %4 %12
  1473. %16 = OpULessThan %5 %15 %8 ; i < 1 ?
  1474. OpBranchConditional %16 %17 %21 ; body or break
  1475. %17 = OpLabel ; body
  1476. OpBranch %18
  1477. %18 = OpLabel ; continue target does not strictly dominates the back-edge block
  1478. %19 = OpLoad %4 %12
  1479. %20 = OpIAdd %4 %19 %8 ; ++i
  1480. OpStore %12 %20
  1481. OpBranch %13
  1482. %21 = OpLabel
  1483. OpReturn
  1484. OpFunctionEnd
  1485. )";
  1486. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1487. const auto consumer = nullptr;
  1488. const auto context =
  1489. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  1490. spvtools::ValidatorOptions validator_options;
  1491. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1492. kConsoleMessageConsumer));
  1493. TransformationContext transformation_context(
  1494. MakeUnique<FactManager>(context.get()), validator_options);
  1495. auto transformation = TransformationAddDeadBreak(18, 21, true, {});
  1496. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1497. std::string variant_shader = R"(
  1498. OpCapability Shader
  1499. %1 = OpExtInstImport "GLSL.std.450"
  1500. OpMemoryModel Logical GLSL450
  1501. OpEntryPoint Vertex %10 "main"
  1502. ; Types
  1503. %2 = OpTypeVoid
  1504. %3 = OpTypeFunction %2
  1505. %4 = OpTypeInt 32 0
  1506. %5 = OpTypeBool
  1507. %6 = OpTypePointer Function %4
  1508. ; Constants
  1509. %7 = OpConstant %4 0
  1510. %8 = OpConstant %4 1
  1511. %9 = OpConstantTrue %5
  1512. ; main function
  1513. %10 = OpFunction %2 None %3
  1514. %11 = OpLabel
  1515. %12 = OpVariable %6 Function
  1516. OpStore %12 %7
  1517. OpBranch %13
  1518. %13 = OpLabel
  1519. OpLoopMerge %21 %18 None ; structured loop
  1520. OpBranch %14
  1521. %14 = OpLabel
  1522. %15 = OpLoad %4 %12
  1523. %16 = OpULessThan %5 %15 %8 ; i < 1 ?
  1524. OpBranchConditional %16 %17 %21 ; body or break
  1525. %17 = OpLabel ; body
  1526. OpBranch %18
  1527. %18 = OpLabel ; continue target does not strictly dominates the back-edge block
  1528. %19 = OpLoad %4 %12
  1529. %20 = OpIAdd %4 %19 %8 ; ++i
  1530. OpStore %12 %20
  1531. OpBranchConditional %9 %13 %21
  1532. %21 = OpLabel
  1533. OpReturn
  1534. OpFunctionEnd
  1535. )";
  1536. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1537. kConsoleMessageConsumer));
  1538. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  1539. }
  1540. TEST(TransformationAddDeadBreakTest, SelectionInContinueConstruct) {
  1541. // Considers some scenarios where there is a selection construct in a loop's
  1542. // continue construct.
  1543. // The SPIR-V for this test is adapted from the following GLSL:
  1544. //
  1545. // void main() {
  1546. // for (int i = 0; i < 100; i = (i < 50 ? i + 2 : i + 1)) {
  1547. // }
  1548. // }
  1549. std::string shader = R"(
  1550. OpCapability Shader
  1551. %1 = OpExtInstImport "GLSL.std.450"
  1552. OpMemoryModel Logical GLSL450
  1553. OpEntryPoint Fragment %4 "main"
  1554. OpExecutionMode %4 OriginUpperLeft
  1555. OpSource ESSL 310
  1556. OpName %4 "main"
  1557. OpName %8 "i"
  1558. %2 = OpTypeVoid
  1559. %3 = OpTypeFunction %2
  1560. %6 = OpTypeInt 32 1
  1561. %7 = OpTypePointer Function %6
  1562. %9 = OpConstant %6 0
  1563. %16 = OpConstant %6 100
  1564. %17 = OpTypeBool
  1565. %99 = OpConstantTrue %17
  1566. %20 = OpConstant %6 50
  1567. %26 = OpConstant %6 2
  1568. %30 = OpConstant %6 1
  1569. %4 = OpFunction %2 None %3
  1570. %5 = OpLabel
  1571. %8 = OpVariable %7 Function
  1572. %22 = OpVariable %7 Function
  1573. OpStore %8 %9
  1574. OpBranch %10
  1575. %10 = OpLabel
  1576. OpLoopMerge %12 %13 None
  1577. OpBranch %14
  1578. %14 = OpLabel
  1579. %15 = OpLoad %6 %8
  1580. %18 = OpSLessThan %17 %15 %16
  1581. OpBranchConditional %18 %11 %12
  1582. %11 = OpLabel
  1583. OpBranch %13
  1584. %13 = OpLabel
  1585. %19 = OpLoad %6 %8
  1586. %21 = OpSLessThan %17 %19 %20
  1587. OpSelectionMerge %24 None
  1588. OpBranchConditional %21 %23 %28
  1589. %23 = OpLabel
  1590. %25 = OpLoad %6 %8
  1591. OpBranch %100
  1592. %100 = OpLabel
  1593. %27 = OpIAdd %6 %25 %26
  1594. OpStore %22 %27
  1595. OpBranch %24
  1596. %28 = OpLabel
  1597. %29 = OpLoad %6 %8
  1598. OpBranch %101
  1599. %101 = OpLabel
  1600. %31 = OpIAdd %6 %29 %30
  1601. OpStore %22 %31
  1602. OpBranch %24
  1603. %24 = OpLabel
  1604. %32 = OpLoad %6 %22
  1605. OpStore %8 %32
  1606. OpBranch %10
  1607. %12 = OpLabel
  1608. OpReturn
  1609. OpFunctionEnd
  1610. )";
  1611. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1612. const auto consumer = nullptr;
  1613. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1614. spvtools::ValidatorOptions validator_options;
  1615. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1616. kConsoleMessageConsumer));
  1617. TransformationContext transformation_context(
  1618. MakeUnique<FactManager>(context.get()), validator_options);
  1619. const uint32_t loop_merge = 12;
  1620. const uint32_t selection_merge = 24;
  1621. const uint32_t in_selection_1 = 23;
  1622. const uint32_t in_selection_2 = 100;
  1623. const uint32_t in_selection_3 = 28;
  1624. const uint32_t in_selection_4 = 101;
  1625. // Not OK to jump from the selection to the loop merge, as this would break
  1626. // from the loop's continue construct.
  1627. ASSERT_FALSE(TransformationAddDeadBreak(in_selection_1, loop_merge, true, {})
  1628. .IsApplicable(context.get(), transformation_context));
  1629. ASSERT_FALSE(TransformationAddDeadBreak(in_selection_2, loop_merge, true, {})
  1630. .IsApplicable(context.get(), transformation_context));
  1631. ASSERT_FALSE(TransformationAddDeadBreak(in_selection_3, loop_merge, true, {})
  1632. .IsApplicable(context.get(), transformation_context));
  1633. ASSERT_FALSE(TransformationAddDeadBreak(in_selection_4, loop_merge, true, {})
  1634. .IsApplicable(context.get(), transformation_context));
  1635. // But fine to jump from the selection to its merge.
  1636. auto transformation1 =
  1637. TransformationAddDeadBreak(in_selection_1, selection_merge, true, {});
  1638. auto transformation2 =
  1639. TransformationAddDeadBreak(in_selection_2, selection_merge, true, {});
  1640. auto transformation3 =
  1641. TransformationAddDeadBreak(in_selection_3, selection_merge, true, {});
  1642. auto transformation4 =
  1643. TransformationAddDeadBreak(in_selection_4, selection_merge, true, {});
  1644. ASSERT_TRUE(
  1645. transformation1.IsApplicable(context.get(), transformation_context));
  1646. ApplyAndCheckFreshIds(transformation1, context.get(),
  1647. &transformation_context);
  1648. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1649. kConsoleMessageConsumer));
  1650. ASSERT_TRUE(
  1651. transformation2.IsApplicable(context.get(), transformation_context));
  1652. ApplyAndCheckFreshIds(transformation2, context.get(),
  1653. &transformation_context);
  1654. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1655. kConsoleMessageConsumer));
  1656. ASSERT_TRUE(
  1657. transformation3.IsApplicable(context.get(), transformation_context));
  1658. ApplyAndCheckFreshIds(transformation3, context.get(),
  1659. &transformation_context);
  1660. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1661. kConsoleMessageConsumer));
  1662. ASSERT_TRUE(
  1663. transformation4.IsApplicable(context.get(), transformation_context));
  1664. ApplyAndCheckFreshIds(transformation4, context.get(),
  1665. &transformation_context);
  1666. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1667. kConsoleMessageConsumer));
  1668. std::string after_transformation = R"(
  1669. OpCapability Shader
  1670. %1 = OpExtInstImport "GLSL.std.450"
  1671. OpMemoryModel Logical GLSL450
  1672. OpEntryPoint Fragment %4 "main"
  1673. OpExecutionMode %4 OriginUpperLeft
  1674. OpSource ESSL 310
  1675. OpName %4 "main"
  1676. OpName %8 "i"
  1677. %2 = OpTypeVoid
  1678. %3 = OpTypeFunction %2
  1679. %6 = OpTypeInt 32 1
  1680. %7 = OpTypePointer Function %6
  1681. %9 = OpConstant %6 0
  1682. %16 = OpConstant %6 100
  1683. %17 = OpTypeBool
  1684. %99 = OpConstantTrue %17
  1685. %20 = OpConstant %6 50
  1686. %26 = OpConstant %6 2
  1687. %30 = OpConstant %6 1
  1688. %4 = OpFunction %2 None %3
  1689. %5 = OpLabel
  1690. %8 = OpVariable %7 Function
  1691. %22 = OpVariable %7 Function
  1692. OpStore %8 %9
  1693. OpBranch %10
  1694. %10 = OpLabel
  1695. OpLoopMerge %12 %13 None
  1696. OpBranch %14
  1697. %14 = OpLabel
  1698. %15 = OpLoad %6 %8
  1699. %18 = OpSLessThan %17 %15 %16
  1700. OpBranchConditional %18 %11 %12
  1701. %11 = OpLabel
  1702. OpBranch %13
  1703. %13 = OpLabel
  1704. %19 = OpLoad %6 %8
  1705. %21 = OpSLessThan %17 %19 %20
  1706. OpSelectionMerge %24 None
  1707. OpBranchConditional %21 %23 %28
  1708. %23 = OpLabel
  1709. %25 = OpLoad %6 %8
  1710. OpBranchConditional %99 %100 %24
  1711. %100 = OpLabel
  1712. %27 = OpIAdd %6 %25 %26
  1713. OpStore %22 %27
  1714. OpBranchConditional %99 %24 %24
  1715. %28 = OpLabel
  1716. %29 = OpLoad %6 %8
  1717. OpBranchConditional %99 %101 %24
  1718. %101 = OpLabel
  1719. %31 = OpIAdd %6 %29 %30
  1720. OpStore %22 %31
  1721. OpBranchConditional %99 %24 %24
  1722. %24 = OpLabel
  1723. %32 = OpLoad %6 %22
  1724. OpStore %8 %32
  1725. OpBranch %10
  1726. %12 = OpLabel
  1727. OpReturn
  1728. OpFunctionEnd
  1729. )";
  1730. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1731. }
  1732. TEST(TransformationAddDeadBreakTest, LoopInContinueConstruct) {
  1733. // Considers some scenarios where there is a loop in a loop's continue
  1734. // construct.
  1735. // The SPIR-V for this test is adapted from the following GLSL, with inlining
  1736. // applied so that the loop from foo is in the main loop's continue construct:
  1737. //
  1738. // int foo() {
  1739. // int result = 0;
  1740. // for (int j = 0; j < 10; j++) {
  1741. // result++;
  1742. // }
  1743. // return result;
  1744. // }
  1745. //
  1746. // void main() {
  1747. // for (int i = 0; i < 100; i += foo()) {
  1748. // }
  1749. // }
  1750. std::string shader = R"(
  1751. OpCapability Shader
  1752. %1 = OpExtInstImport "GLSL.std.450"
  1753. OpMemoryModel Logical GLSL450
  1754. OpEntryPoint Fragment %4 "main"
  1755. OpExecutionMode %4 OriginUpperLeft
  1756. OpSource ESSL 310
  1757. OpName %4 "main"
  1758. OpName %31 "i"
  1759. %2 = OpTypeVoid
  1760. %3 = OpTypeFunction %2
  1761. %6 = OpTypeInt 32 1
  1762. %7 = OpTypeFunction %6
  1763. %10 = OpTypePointer Function %6
  1764. %12 = OpConstant %6 0
  1765. %20 = OpConstant %6 10
  1766. %21 = OpTypeBool
  1767. %100 = OpConstantTrue %21
  1768. %24 = OpConstant %6 1
  1769. %38 = OpConstant %6 100
  1770. %4 = OpFunction %2 None %3
  1771. %5 = OpLabel
  1772. %43 = OpVariable %10 Function
  1773. %44 = OpVariable %10 Function
  1774. %45 = OpVariable %10 Function
  1775. %31 = OpVariable %10 Function
  1776. OpStore %31 %12
  1777. OpBranch %32
  1778. %32 = OpLabel
  1779. OpLoopMerge %34 %35 None
  1780. OpBranch %36
  1781. %36 = OpLabel
  1782. %37 = OpLoad %6 %31
  1783. %39 = OpSLessThan %21 %37 %38
  1784. OpBranchConditional %39 %33 %34
  1785. %33 = OpLabel
  1786. OpBranch %35
  1787. %35 = OpLabel
  1788. OpStore %43 %12
  1789. OpStore %44 %12
  1790. OpBranch %46
  1791. %46 = OpLabel
  1792. OpLoopMerge %47 %48 None
  1793. OpBranch %49
  1794. %49 = OpLabel
  1795. %50 = OpLoad %6 %44
  1796. %51 = OpSLessThan %21 %50 %20
  1797. OpBranchConditional %51 %52 %47
  1798. %52 = OpLabel
  1799. %53 = OpLoad %6 %43
  1800. OpBranch %101
  1801. %101 = OpLabel
  1802. %54 = OpIAdd %6 %53 %24
  1803. OpStore %43 %54
  1804. OpBranch %48
  1805. %48 = OpLabel
  1806. %55 = OpLoad %6 %44
  1807. %56 = OpIAdd %6 %55 %24
  1808. OpStore %44 %56
  1809. OpBranch %46
  1810. %47 = OpLabel
  1811. %57 = OpLoad %6 %43
  1812. OpStore %45 %57
  1813. %40 = OpLoad %6 %45
  1814. %41 = OpLoad %6 %31
  1815. %42 = OpIAdd %6 %41 %40
  1816. OpStore %31 %42
  1817. OpBranch %32
  1818. %34 = OpLabel
  1819. OpReturn
  1820. OpFunctionEnd
  1821. )";
  1822. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1823. const auto consumer = nullptr;
  1824. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1825. spvtools::ValidatorOptions validator_options;
  1826. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1827. kConsoleMessageConsumer));
  1828. TransformationContext transformation_context(
  1829. MakeUnique<FactManager>(context.get()), validator_options);
  1830. const uint32_t outer_loop_merge = 34;
  1831. const uint32_t outer_loop_block = 33;
  1832. const uint32_t inner_loop_merge = 47;
  1833. const uint32_t inner_loop_block = 52;
  1834. // Some inapplicable cases
  1835. ASSERT_FALSE(
  1836. TransformationAddDeadBreak(inner_loop_block, outer_loop_merge, true, {})
  1837. .IsApplicable(context.get(), transformation_context));
  1838. ASSERT_FALSE(
  1839. TransformationAddDeadBreak(outer_loop_block, inner_loop_merge, true, {})
  1840. .IsApplicable(context.get(), transformation_context));
  1841. auto transformation1 =
  1842. TransformationAddDeadBreak(inner_loop_block, inner_loop_merge, true, {});
  1843. auto transformation2 =
  1844. TransformationAddDeadBreak(outer_loop_block, outer_loop_merge, true, {});
  1845. ASSERT_TRUE(
  1846. transformation1.IsApplicable(context.get(), transformation_context));
  1847. ApplyAndCheckFreshIds(transformation1, context.get(),
  1848. &transformation_context);
  1849. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1850. kConsoleMessageConsumer));
  1851. ASSERT_TRUE(
  1852. transformation2.IsApplicable(context.get(), transformation_context));
  1853. ApplyAndCheckFreshIds(transformation2, context.get(),
  1854. &transformation_context);
  1855. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1856. kConsoleMessageConsumer));
  1857. std::string after_transformation = R"(
  1858. OpCapability Shader
  1859. %1 = OpExtInstImport "GLSL.std.450"
  1860. OpMemoryModel Logical GLSL450
  1861. OpEntryPoint Fragment %4 "main"
  1862. OpExecutionMode %4 OriginUpperLeft
  1863. OpSource ESSL 310
  1864. OpName %4 "main"
  1865. OpName %31 "i"
  1866. %2 = OpTypeVoid
  1867. %3 = OpTypeFunction %2
  1868. %6 = OpTypeInt 32 1
  1869. %7 = OpTypeFunction %6
  1870. %10 = OpTypePointer Function %6
  1871. %12 = OpConstant %6 0
  1872. %20 = OpConstant %6 10
  1873. %21 = OpTypeBool
  1874. %100 = OpConstantTrue %21
  1875. %24 = OpConstant %6 1
  1876. %38 = OpConstant %6 100
  1877. %4 = OpFunction %2 None %3
  1878. %5 = OpLabel
  1879. %43 = OpVariable %10 Function
  1880. %44 = OpVariable %10 Function
  1881. %45 = OpVariable %10 Function
  1882. %31 = OpVariable %10 Function
  1883. OpStore %31 %12
  1884. OpBranch %32
  1885. %32 = OpLabel
  1886. OpLoopMerge %34 %35 None
  1887. OpBranch %36
  1888. %36 = OpLabel
  1889. %37 = OpLoad %6 %31
  1890. %39 = OpSLessThan %21 %37 %38
  1891. OpBranchConditional %39 %33 %34
  1892. %33 = OpLabel
  1893. OpBranchConditional %100 %35 %34
  1894. %35 = OpLabel
  1895. OpStore %43 %12
  1896. OpStore %44 %12
  1897. OpBranch %46
  1898. %46 = OpLabel
  1899. OpLoopMerge %47 %48 None
  1900. OpBranch %49
  1901. %49 = OpLabel
  1902. %50 = OpLoad %6 %44
  1903. %51 = OpSLessThan %21 %50 %20
  1904. OpBranchConditional %51 %52 %47
  1905. %52 = OpLabel
  1906. %53 = OpLoad %6 %43
  1907. OpBranchConditional %100 %101 %47
  1908. %101 = OpLabel
  1909. %54 = OpIAdd %6 %53 %24
  1910. OpStore %43 %54
  1911. OpBranch %48
  1912. %48 = OpLabel
  1913. %55 = OpLoad %6 %44
  1914. %56 = OpIAdd %6 %55 %24
  1915. OpStore %44 %56
  1916. OpBranch %46
  1917. %47 = OpLabel
  1918. %57 = OpLoad %6 %43
  1919. OpStore %45 %57
  1920. %40 = OpLoad %6 %45
  1921. %41 = OpLoad %6 %31
  1922. %42 = OpIAdd %6 %41 %40
  1923. OpStore %31 %42
  1924. OpBranch %32
  1925. %34 = OpLabel
  1926. OpReturn
  1927. OpFunctionEnd
  1928. )";
  1929. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1930. }
  1931. TEST(TransformationAddDeadBreakTest, PhiInstructions) {
  1932. // Checks that the transformation works in the presence of phi instructions.
  1933. // The SPIR-V for this test is adapted from the following GLSL, with a bit of
  1934. // extra and artificial work to get some interesting uses of OpPhi:
  1935. //
  1936. // void main() {
  1937. // int x; int y;
  1938. // float f;
  1939. // x = 2;
  1940. // f = 3.0;
  1941. // if (x > y) {
  1942. // x = 3;
  1943. // f = 4.0;
  1944. // } else {
  1945. // x = x + 2;
  1946. // f = f + 10.0;
  1947. // }
  1948. // while (x < y) {
  1949. // x = x + 1;
  1950. // f = f + 1.0;
  1951. // }
  1952. // y = x;
  1953. // f = f + 3.0;
  1954. // }
  1955. std::string shader = R"(
  1956. OpCapability Shader
  1957. %1 = OpExtInstImport "GLSL.std.450"
  1958. OpMemoryModel Logical GLSL450
  1959. OpEntryPoint Fragment %4 "main"
  1960. OpExecutionMode %4 OriginUpperLeft
  1961. OpSource ESSL 310
  1962. OpName %4 "main"
  1963. OpName %8 "x"
  1964. OpName %12 "f"
  1965. OpName %15 "y"
  1966. %2 = OpTypeVoid
  1967. %3 = OpTypeFunction %2
  1968. %6 = OpTypeInt 32 1
  1969. %7 = OpTypePointer Function %6
  1970. %9 = OpConstant %6 2
  1971. %10 = OpTypeFloat 32
  1972. %11 = OpTypePointer Function %10
  1973. %13 = OpConstant %10 3
  1974. %17 = OpTypeBool
  1975. %80 = OpConstantTrue %17
  1976. %21 = OpConstant %6 3
  1977. %22 = OpConstant %10 4
  1978. %27 = OpConstant %10 10
  1979. %38 = OpConstant %6 1
  1980. %41 = OpConstant %10 1
  1981. %46 = OpUndef %6
  1982. %4 = OpFunction %2 None %3
  1983. %5 = OpLabel
  1984. %8 = OpVariable %7 Function
  1985. %12 = OpVariable %11 Function
  1986. %15 = OpVariable %7 Function
  1987. OpStore %8 %9
  1988. OpStore %12 %13
  1989. %18 = OpSGreaterThan %17 %9 %46
  1990. OpSelectionMerge %20 None
  1991. OpBranchConditional %18 %19 %23
  1992. %19 = OpLabel
  1993. OpStore %8 %21
  1994. OpStore %12 %22
  1995. OpBranch %20
  1996. %23 = OpLabel
  1997. %25 = OpIAdd %6 %9 %9
  1998. OpStore %8 %25
  1999. OpBranch %70
  2000. %70 = OpLabel
  2001. %28 = OpFAdd %10 %13 %27
  2002. OpStore %12 %28
  2003. OpBranch %20
  2004. %20 = OpLabel
  2005. %52 = OpPhi %10 %22 %19 %28 %70
  2006. %48 = OpPhi %6 %21 %19 %25 %70
  2007. OpBranch %29
  2008. %29 = OpLabel
  2009. %51 = OpPhi %10 %52 %20 %42 %32
  2010. %47 = OpPhi %6 %48 %20 %39 %32
  2011. OpLoopMerge %31 %32 None
  2012. OpBranch %33
  2013. %33 = OpLabel
  2014. %36 = OpSLessThan %17 %47 %46
  2015. OpBranchConditional %36 %30 %31
  2016. %30 = OpLabel
  2017. %39 = OpIAdd %6 %47 %38
  2018. OpStore %8 %39
  2019. OpBranch %75
  2020. %75 = OpLabel
  2021. %42 = OpFAdd %10 %51 %41
  2022. OpStore %12 %42
  2023. OpBranch %32
  2024. %32 = OpLabel
  2025. OpBranch %29
  2026. %31 = OpLabel
  2027. %71 = OpPhi %6 %47 %33
  2028. %72 = OpPhi %10 %51 %33
  2029. OpStore %15 %71
  2030. %45 = OpFAdd %10 %72 %13
  2031. OpStore %12 %45
  2032. OpReturn
  2033. OpFunctionEnd
  2034. )";
  2035. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2036. const auto consumer = nullptr;
  2037. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2038. spvtools::ValidatorOptions validator_options;
  2039. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2040. kConsoleMessageConsumer));
  2041. TransformationContext transformation_context(
  2042. MakeUnique<FactManager>(context.get()), validator_options);
  2043. // Some inapplicable transformations
  2044. // Not applicable because there is already an edge 19->20, so the OpPhis at 20
  2045. // do not need to be updated
  2046. ASSERT_FALSE(TransformationAddDeadBreak(19, 20, true, {13, 21})
  2047. .IsApplicable(context.get(), transformation_context));
  2048. // Not applicable because two OpPhis (not zero) need to be updated at 20
  2049. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {})
  2050. .IsApplicable(context.get(), transformation_context));
  2051. // Not applicable because two OpPhis (not just one) need to be updated at 20
  2052. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {13})
  2053. .IsApplicable(context.get(), transformation_context));
  2054. // Not applicable because the given ids do not have types that match the
  2055. // OpPhis at 20, in order
  2056. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 13})
  2057. .IsApplicable(context.get(), transformation_context));
  2058. // Not applicable because id 23 is a label
  2059. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 23})
  2060. .IsApplicable(context.get(), transformation_context));
  2061. // Not applicable because 101 is not an id
  2062. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 101})
  2063. .IsApplicable(context.get(), transformation_context));
  2064. // Not applicable because ids 51 and 47 are not available at the end of block
  2065. // 23
  2066. ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {51, 47})
  2067. .IsApplicable(context.get(), transformation_context));
  2068. // Not applicable because OpConstantFalse is not present in the module
  2069. ASSERT_FALSE(TransformationAddDeadBreak(19, 20, false, {})
  2070. .IsApplicable(context.get(), transformation_context));
  2071. auto transformation1 = TransformationAddDeadBreak(19, 20, true, {});
  2072. auto transformation2 = TransformationAddDeadBreak(23, 20, true, {13, 21});
  2073. auto transformation3 = TransformationAddDeadBreak(70, 20, true, {});
  2074. auto transformation4 = TransformationAddDeadBreak(30, 31, true, {21, 13});
  2075. auto transformation5 = TransformationAddDeadBreak(75, 31, true, {47, 51});
  2076. ASSERT_TRUE(
  2077. transformation1.IsApplicable(context.get(), transformation_context));
  2078. ApplyAndCheckFreshIds(transformation1, context.get(),
  2079. &transformation_context);
  2080. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2081. kConsoleMessageConsumer));
  2082. ASSERT_TRUE(
  2083. transformation2.IsApplicable(context.get(), transformation_context));
  2084. ApplyAndCheckFreshIds(transformation2, context.get(),
  2085. &transformation_context);
  2086. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2087. kConsoleMessageConsumer));
  2088. ASSERT_TRUE(
  2089. transformation3.IsApplicable(context.get(), transformation_context));
  2090. ApplyAndCheckFreshIds(transformation3, context.get(),
  2091. &transformation_context);
  2092. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2093. kConsoleMessageConsumer));
  2094. ASSERT_TRUE(
  2095. transformation4.IsApplicable(context.get(), transformation_context));
  2096. ApplyAndCheckFreshIds(transformation4, context.get(),
  2097. &transformation_context);
  2098. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2099. kConsoleMessageConsumer));
  2100. ASSERT_TRUE(
  2101. transformation5.IsApplicable(context.get(), transformation_context));
  2102. ApplyAndCheckFreshIds(transformation5, context.get(),
  2103. &transformation_context);
  2104. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2105. kConsoleMessageConsumer));
  2106. std::string after_transformation = R"(
  2107. OpCapability Shader
  2108. %1 = OpExtInstImport "GLSL.std.450"
  2109. OpMemoryModel Logical GLSL450
  2110. OpEntryPoint Fragment %4 "main"
  2111. OpExecutionMode %4 OriginUpperLeft
  2112. OpSource ESSL 310
  2113. OpName %4 "main"
  2114. OpName %8 "x"
  2115. OpName %12 "f"
  2116. OpName %15 "y"
  2117. %2 = OpTypeVoid
  2118. %3 = OpTypeFunction %2
  2119. %6 = OpTypeInt 32 1
  2120. %7 = OpTypePointer Function %6
  2121. %9 = OpConstant %6 2
  2122. %10 = OpTypeFloat 32
  2123. %11 = OpTypePointer Function %10
  2124. %13 = OpConstant %10 3
  2125. %17 = OpTypeBool
  2126. %80 = OpConstantTrue %17
  2127. %21 = OpConstant %6 3
  2128. %22 = OpConstant %10 4
  2129. %27 = OpConstant %10 10
  2130. %38 = OpConstant %6 1
  2131. %41 = OpConstant %10 1
  2132. %46 = OpUndef %6
  2133. %4 = OpFunction %2 None %3
  2134. %5 = OpLabel
  2135. %8 = OpVariable %7 Function
  2136. %12 = OpVariable %11 Function
  2137. %15 = OpVariable %7 Function
  2138. OpStore %8 %9
  2139. OpStore %12 %13
  2140. %18 = OpSGreaterThan %17 %9 %46
  2141. OpSelectionMerge %20 None
  2142. OpBranchConditional %18 %19 %23
  2143. %19 = OpLabel
  2144. OpStore %8 %21
  2145. OpStore %12 %22
  2146. OpBranchConditional %80 %20 %20
  2147. %23 = OpLabel
  2148. %25 = OpIAdd %6 %9 %9
  2149. OpStore %8 %25
  2150. OpBranchConditional %80 %70 %20
  2151. %70 = OpLabel
  2152. %28 = OpFAdd %10 %13 %27
  2153. OpStore %12 %28
  2154. OpBranchConditional %80 %20 %20
  2155. %20 = OpLabel
  2156. %52 = OpPhi %10 %22 %19 %28 %70 %13 %23
  2157. %48 = OpPhi %6 %21 %19 %25 %70 %21 %23
  2158. OpBranch %29
  2159. %29 = OpLabel
  2160. %51 = OpPhi %10 %52 %20 %42 %32
  2161. %47 = OpPhi %6 %48 %20 %39 %32
  2162. OpLoopMerge %31 %32 None
  2163. OpBranch %33
  2164. %33 = OpLabel
  2165. %36 = OpSLessThan %17 %47 %46
  2166. OpBranchConditional %36 %30 %31
  2167. %30 = OpLabel
  2168. %39 = OpIAdd %6 %47 %38
  2169. OpStore %8 %39
  2170. OpBranchConditional %80 %75 %31
  2171. %75 = OpLabel
  2172. %42 = OpFAdd %10 %51 %41
  2173. OpStore %12 %42
  2174. OpBranchConditional %80 %32 %31
  2175. %32 = OpLabel
  2176. OpBranch %29
  2177. %31 = OpLabel
  2178. %71 = OpPhi %6 %47 %33 %21 %30 %47 %75
  2179. %72 = OpPhi %10 %51 %33 %13 %30 %51 %75
  2180. OpStore %15 %71
  2181. %45 = OpFAdd %10 %72 %13
  2182. OpStore %12 %45
  2183. OpReturn
  2184. OpFunctionEnd
  2185. )";
  2186. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  2187. }
  2188. TEST(TransformationAddDeadBreakTest, RespectDominanceRules1) {
  2189. // Right after the loop, an OpCopyObject defined by the loop is used. Adding
  2190. // a dead break would prevent that use from being dominated by its definition,
  2191. // so is not allowed.
  2192. std::string shader = R"(
  2193. OpCapability Shader
  2194. %1 = OpExtInstImport "GLSL.std.450"
  2195. OpMemoryModel Logical GLSL450
  2196. OpEntryPoint Fragment %4 "main"
  2197. OpExecutionMode %4 OriginUpperLeft
  2198. OpSource ESSL 310
  2199. OpName %4 "main"
  2200. %2 = OpTypeVoid
  2201. %3 = OpTypeFunction %2
  2202. %10 = OpTypeBool
  2203. %11 = OpConstantFalse %10
  2204. %4 = OpFunction %2 None %3
  2205. %5 = OpLabel
  2206. OpBranch %100
  2207. %100 = OpLabel
  2208. OpLoopMerge %101 %102 None
  2209. OpBranch %103
  2210. %103 = OpLabel
  2211. %200 = OpCopyObject %10 %11
  2212. OpBranch %104
  2213. %104 = OpLabel
  2214. OpBranch %102
  2215. %102 = OpLabel
  2216. OpBranchConditional %11 %100 %101
  2217. %101 = OpLabel
  2218. %201 = OpCopyObject %10 %200
  2219. OpReturn
  2220. OpFunctionEnd
  2221. )";
  2222. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2223. const auto consumer = nullptr;
  2224. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2225. spvtools::ValidatorOptions validator_options;
  2226. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2227. kConsoleMessageConsumer));
  2228. TransformationContext transformation_context(
  2229. MakeUnique<FactManager>(context.get()), validator_options);
  2230. auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {});
  2231. ASSERT_FALSE(
  2232. bad_transformation.IsApplicable(context.get(), transformation_context));
  2233. }
  2234. TEST(TransformationAddDeadBreakTest, RespectDominanceRules2) {
  2235. // This example captures the following idiom:
  2236. //
  2237. // if {
  2238. // L1:
  2239. // }
  2240. // definition;
  2241. // L2:
  2242. // use;
  2243. //
  2244. // Adding a dead jump from L1 to L2 would lead to 'definition' no longer
  2245. // dominating 'use', and so is not allowed.
  2246. std::string shader = R"(
  2247. OpCapability Shader
  2248. %1 = OpExtInstImport "GLSL.std.450"
  2249. OpMemoryModel Logical GLSL450
  2250. OpEntryPoint Fragment %4 "main"
  2251. OpExecutionMode %4 OriginUpperLeft
  2252. OpSource ESSL 310
  2253. OpName %4 "main"
  2254. %2 = OpTypeVoid
  2255. %3 = OpTypeFunction %2
  2256. %10 = OpTypeBool
  2257. %11 = OpConstantFalse %10
  2258. %4 = OpFunction %2 None %3
  2259. %5 = OpLabel
  2260. OpBranch %100
  2261. %100 = OpLabel
  2262. OpSelectionMerge %101 None
  2263. OpBranchConditional %11 %102 %103
  2264. %102 = OpLabel
  2265. OpBranch %103
  2266. %103 = OpLabel
  2267. %200 = OpCopyObject %10 %11
  2268. OpBranch %101
  2269. %101 = OpLabel
  2270. %201 = OpCopyObject %10 %200
  2271. OpReturn
  2272. OpFunctionEnd
  2273. )";
  2274. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2275. const auto consumer = nullptr;
  2276. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2277. spvtools::ValidatorOptions validator_options;
  2278. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2279. kConsoleMessageConsumer));
  2280. TransformationContext transformation_context(
  2281. MakeUnique<FactManager>(context.get()), validator_options);
  2282. auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
  2283. ASSERT_FALSE(
  2284. bad_transformation.IsApplicable(context.get(), transformation_context));
  2285. }
  2286. TEST(TransformationAddDeadBreakTest, RespectDominanceRules3) {
  2287. // Right after the loop, an OpCopyObject defined by the loop is used in an
  2288. // OpPhi. Adding a dead break is OK in this case, due to the use being in an
  2289. // OpPhi.
  2290. std::string shader = R"(
  2291. OpCapability Shader
  2292. %1 = OpExtInstImport "GLSL.std.450"
  2293. OpMemoryModel Logical GLSL450
  2294. OpEntryPoint Fragment %4 "main"
  2295. OpExecutionMode %4 OriginUpperLeft
  2296. OpSource ESSL 310
  2297. OpName %4 "main"
  2298. %2 = OpTypeVoid
  2299. %3 = OpTypeFunction %2
  2300. %10 = OpTypeBool
  2301. %11 = OpConstantFalse %10
  2302. %4 = OpFunction %2 None %3
  2303. %5 = OpLabel
  2304. OpBranch %100
  2305. %100 = OpLabel
  2306. OpLoopMerge %101 %102 None
  2307. OpBranch %103
  2308. %103 = OpLabel
  2309. %200 = OpCopyObject %10 %11
  2310. OpBranch %104
  2311. %104 = OpLabel
  2312. OpBranch %102
  2313. %102 = OpLabel
  2314. OpBranchConditional %11 %100 %101
  2315. %101 = OpLabel
  2316. %201 = OpPhi %10 %200 %102
  2317. OpReturn
  2318. OpFunctionEnd
  2319. )";
  2320. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2321. const auto consumer = nullptr;
  2322. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2323. spvtools::ValidatorOptions validator_options;
  2324. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2325. kConsoleMessageConsumer));
  2326. TransformationContext transformation_context(
  2327. MakeUnique<FactManager>(context.get()), validator_options);
  2328. auto good_transformation = TransformationAddDeadBreak(100, 101, false, {11});
  2329. ASSERT_TRUE(
  2330. good_transformation.IsApplicable(context.get(), transformation_context));
  2331. ApplyAndCheckFreshIds(good_transformation, context.get(),
  2332. &transformation_context);
  2333. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2334. kConsoleMessageConsumer));
  2335. std::string after_transformation = R"(
  2336. OpCapability Shader
  2337. %1 = OpExtInstImport "GLSL.std.450"
  2338. OpMemoryModel Logical GLSL450
  2339. OpEntryPoint Fragment %4 "main"
  2340. OpExecutionMode %4 OriginUpperLeft
  2341. OpSource ESSL 310
  2342. OpName %4 "main"
  2343. %2 = OpTypeVoid
  2344. %3 = OpTypeFunction %2
  2345. %10 = OpTypeBool
  2346. %11 = OpConstantFalse %10
  2347. %4 = OpFunction %2 None %3
  2348. %5 = OpLabel
  2349. OpBranch %100
  2350. %100 = OpLabel
  2351. OpLoopMerge %101 %102 None
  2352. OpBranchConditional %11 %101 %103
  2353. %103 = OpLabel
  2354. %200 = OpCopyObject %10 %11
  2355. OpBranch %104
  2356. %104 = OpLabel
  2357. OpBranch %102
  2358. %102 = OpLabel
  2359. OpBranchConditional %11 %100 %101
  2360. %101 = OpLabel
  2361. %201 = OpPhi %10 %200 %102 %11 %100
  2362. OpReturn
  2363. OpFunctionEnd
  2364. )";
  2365. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  2366. }
  2367. TEST(TransformationAddDeadBreakTest, RespectDominanceRules4) {
  2368. // This example captures the following idiom:
  2369. //
  2370. // if {
  2371. // L1:
  2372. // }
  2373. // definition;
  2374. // L2:
  2375. // use in OpPhi;
  2376. //
  2377. // Adding a dead jump from L1 to L2 is OK, due to 'use' being in an OpPhi.
  2378. std::string shader = R"(
  2379. OpCapability Shader
  2380. %1 = OpExtInstImport "GLSL.std.450"
  2381. OpMemoryModel Logical GLSL450
  2382. OpEntryPoint Fragment %4 "main"
  2383. OpExecutionMode %4 OriginUpperLeft
  2384. OpSource ESSL 310
  2385. OpName %4 "main"
  2386. %2 = OpTypeVoid
  2387. %3 = OpTypeFunction %2
  2388. %10 = OpTypeBool
  2389. %11 = OpConstantFalse %10
  2390. %4 = OpFunction %2 None %3
  2391. %5 = OpLabel
  2392. OpBranch %100
  2393. %100 = OpLabel
  2394. OpSelectionMerge %101 None
  2395. OpBranchConditional %11 %102 %103
  2396. %102 = OpLabel
  2397. OpBranch %103
  2398. %103 = OpLabel
  2399. %200 = OpCopyObject %10 %11
  2400. OpBranch %101
  2401. %101 = OpLabel
  2402. %201 = OpPhi %10 %200 %103
  2403. OpReturn
  2404. OpFunctionEnd
  2405. )";
  2406. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2407. const auto consumer = nullptr;
  2408. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2409. spvtools::ValidatorOptions validator_options;
  2410. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2411. kConsoleMessageConsumer));
  2412. TransformationContext transformation_context(
  2413. MakeUnique<FactManager>(context.get()), validator_options);
  2414. auto good_transformation = TransformationAddDeadBreak(102, 101, false, {11});
  2415. ASSERT_TRUE(
  2416. good_transformation.IsApplicable(context.get(), transformation_context));
  2417. ApplyAndCheckFreshIds(good_transformation, context.get(),
  2418. &transformation_context);
  2419. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2420. kConsoleMessageConsumer));
  2421. std::string after_transformation = R"(
  2422. OpCapability Shader
  2423. %1 = OpExtInstImport "GLSL.std.450"
  2424. OpMemoryModel Logical GLSL450
  2425. OpEntryPoint Fragment %4 "main"
  2426. OpExecutionMode %4 OriginUpperLeft
  2427. OpSource ESSL 310
  2428. OpName %4 "main"
  2429. %2 = OpTypeVoid
  2430. %3 = OpTypeFunction %2
  2431. %10 = OpTypeBool
  2432. %11 = OpConstantFalse %10
  2433. %4 = OpFunction %2 None %3
  2434. %5 = OpLabel
  2435. OpBranch %100
  2436. %100 = OpLabel
  2437. OpSelectionMerge %101 None
  2438. OpBranchConditional %11 %102 %103
  2439. %102 = OpLabel
  2440. OpBranchConditional %11 %101 %103
  2441. %103 = OpLabel
  2442. %200 = OpCopyObject %10 %11
  2443. OpBranch %101
  2444. %101 = OpLabel
  2445. %201 = OpPhi %10 %200 %103 %11 %102
  2446. OpReturn
  2447. OpFunctionEnd
  2448. )";
  2449. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  2450. }
  2451. TEST(TransformationAddDeadBreakTest, RespectDominanceRules5) {
  2452. // After, but not right after, the loop, an OpCopyObject defined by the loop
  2453. // is used in an OpPhi. Adding a dead break is not OK in this case.
  2454. std::string shader = R"(
  2455. OpCapability Shader
  2456. %1 = OpExtInstImport "GLSL.std.450"
  2457. OpMemoryModel Logical GLSL450
  2458. OpEntryPoint Fragment %4 "main"
  2459. OpExecutionMode %4 OriginUpperLeft
  2460. OpSource ESSL 310
  2461. OpName %4 "main"
  2462. %2 = OpTypeVoid
  2463. %3 = OpTypeFunction %2
  2464. %10 = OpTypeBool
  2465. %11 = OpConstantFalse %10
  2466. %4 = OpFunction %2 None %3
  2467. %5 = OpLabel
  2468. OpBranch %100
  2469. %100 = OpLabel
  2470. OpLoopMerge %101 %102 None
  2471. OpBranch %103
  2472. %103 = OpLabel
  2473. %200 = OpCopyObject %10 %11
  2474. OpBranch %104
  2475. %104 = OpLabel
  2476. OpBranch %102
  2477. %102 = OpLabel
  2478. OpBranchConditional %11 %100 %101
  2479. %101 = OpLabel
  2480. OpBranch %105
  2481. %105 = OpLabel
  2482. %201 = OpPhi %10 %200 %101
  2483. OpReturn
  2484. OpFunctionEnd
  2485. )";
  2486. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2487. const auto consumer = nullptr;
  2488. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2489. spvtools::ValidatorOptions validator_options;
  2490. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2491. kConsoleMessageConsumer));
  2492. TransformationContext transformation_context(
  2493. MakeUnique<FactManager>(context.get()), validator_options);
  2494. auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {});
  2495. ASSERT_FALSE(
  2496. bad_transformation.IsApplicable(context.get(), transformation_context));
  2497. }
  2498. TEST(TransformationAddDeadBreakTest, RespectDominanceRules6) {
  2499. // This example captures the following idiom:
  2500. //
  2501. // if {
  2502. // L1:
  2503. // }
  2504. // definition;
  2505. // L2:
  2506. // goto L3;
  2507. // L3:
  2508. // use in OpPhi;
  2509. //
  2510. // Adding a dead jump from L1 to L2 not OK, due to the use in an OpPhi being
  2511. // in L3.
  2512. std::string shader = R"(
  2513. OpCapability Shader
  2514. %1 = OpExtInstImport "GLSL.std.450"
  2515. OpMemoryModel Logical GLSL450
  2516. OpEntryPoint Fragment %4 "main"
  2517. OpExecutionMode %4 OriginUpperLeft
  2518. OpSource ESSL 310
  2519. OpName %4 "main"
  2520. %2 = OpTypeVoid
  2521. %3 = OpTypeFunction %2
  2522. %10 = OpTypeBool
  2523. %11 = OpConstantFalse %10
  2524. %4 = OpFunction %2 None %3
  2525. %5 = OpLabel
  2526. OpBranch %100
  2527. %100 = OpLabel
  2528. OpSelectionMerge %101 None
  2529. OpBranchConditional %11 %102 %103
  2530. %102 = OpLabel
  2531. OpBranch %103
  2532. %103 = OpLabel
  2533. %200 = OpCopyObject %10 %11
  2534. OpBranch %101
  2535. %101 = OpLabel
  2536. OpBranch %150
  2537. %150 = OpLabel
  2538. %201 = OpPhi %10 %200 %101
  2539. OpReturn
  2540. OpFunctionEnd
  2541. )";
  2542. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2543. const auto consumer = nullptr;
  2544. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2545. spvtools::ValidatorOptions validator_options;
  2546. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2547. kConsoleMessageConsumer));
  2548. TransformationContext transformation_context(
  2549. MakeUnique<FactManager>(context.get()), validator_options);
  2550. auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
  2551. ASSERT_FALSE(
  2552. bad_transformation.IsApplicable(context.get(), transformation_context));
  2553. }
  2554. TEST(TransformationAddDeadBreakTest, RespectDominanceRules7) {
  2555. // This example - a variation on an earlier test - captures the following
  2556. // idiom:
  2557. //
  2558. // loop {
  2559. // L1:
  2560. // }
  2561. // definition;
  2562. // L2:
  2563. // use;
  2564. //
  2565. // Adding a dead jump from L1 to L2 would lead to 'definition' no longer
  2566. // dominating 'use', and so is not allowed.
  2567. //
  2568. // This version of the test captures the case where L1 appears after the
  2569. // loop merge (which SPIR-V dominance rules allow).
  2570. std::string shader = R"(
  2571. OpCapability Shader
  2572. %1 = OpExtInstImport "GLSL.std.450"
  2573. OpMemoryModel Logical GLSL450
  2574. OpEntryPoint Fragment %4 "main"
  2575. OpExecutionMode %4 OriginUpperLeft
  2576. OpSource ESSL 310
  2577. OpName %4 "main"
  2578. %2 = OpTypeVoid
  2579. %3 = OpTypeFunction %2
  2580. %10 = OpTypeBool
  2581. %11 = OpConstantFalse %10
  2582. %4 = OpFunction %2 None %3
  2583. %5 = OpLabel
  2584. OpBranch %100
  2585. %100 = OpLabel
  2586. OpLoopMerge %101 %104 None
  2587. OpBranch %105
  2588. %105 = OpLabel
  2589. OpSelectionMerge %106 None
  2590. OpBranchConditional %11 %102 %103
  2591. %103 = OpLabel
  2592. %200 = OpCopyObject %10 %11
  2593. OpBranch %101
  2594. %101 = OpLabel
  2595. %201 = OpCopyObject %10 %200
  2596. OpReturn
  2597. %102 = OpLabel
  2598. OpBranch %103
  2599. %106 = OpLabel
  2600. OpUnreachable
  2601. %104 = OpLabel
  2602. OpBranch %100
  2603. OpFunctionEnd
  2604. )";
  2605. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2606. const auto consumer = nullptr;
  2607. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2608. spvtools::ValidatorOptions validator_options;
  2609. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2610. kConsoleMessageConsumer));
  2611. TransformationContext transformation_context(
  2612. MakeUnique<FactManager>(context.get()), validator_options);
  2613. auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
  2614. ASSERT_FALSE(
  2615. bad_transformation.IsApplicable(context.get(), transformation_context));
  2616. }
  2617. TEST(TransformationAddDeadBreakTest, RespectDominanceRules8) {
  2618. // A variation of RespectDominanceRules8 where the defining block appears
  2619. // in the loop, but after the definition of interest.
  2620. std::string shader = R"(
  2621. OpCapability Shader
  2622. %1 = OpExtInstImport "GLSL.std.450"
  2623. OpMemoryModel Logical GLSL450
  2624. OpEntryPoint Fragment %4 "main"
  2625. OpExecutionMode %4 OriginUpperLeft
  2626. OpSource ESSL 310
  2627. OpName %4 "main"
  2628. %2 = OpTypeVoid
  2629. %3 = OpTypeFunction %2
  2630. %10 = OpTypeBool
  2631. %11 = OpConstantFalse %10
  2632. %4 = OpFunction %2 None %3
  2633. %5 = OpLabel
  2634. OpBranch %100
  2635. %100 = OpLabel
  2636. OpLoopMerge %101 %104 None
  2637. OpBranch %105
  2638. %105 = OpLabel
  2639. OpSelectionMerge %106 None
  2640. OpBranchConditional %11 %102 %103
  2641. %103 = OpLabel
  2642. %200 = OpCopyObject %10 %11
  2643. OpBranch %101
  2644. %102 = OpLabel
  2645. OpBranch %103
  2646. %106 = OpLabel
  2647. OpUnreachable
  2648. %101 = OpLabel
  2649. %201 = OpCopyObject %10 %200
  2650. OpReturn
  2651. %104 = OpLabel
  2652. OpBranch %100
  2653. OpFunctionEnd
  2654. )";
  2655. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2656. const auto consumer = nullptr;
  2657. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2658. spvtools::ValidatorOptions validator_options;
  2659. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2660. kConsoleMessageConsumer));
  2661. TransformationContext transformation_context(
  2662. MakeUnique<FactManager>(context.get()), validator_options);
  2663. auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {});
  2664. ASSERT_FALSE(
  2665. bad_transformation.IsApplicable(context.get(), transformation_context));
  2666. }
  2667. TEST(TransformationAddDeadBreakTest,
  2668. BreakWouldDisobeyDominanceBlockOrderingRules) {
  2669. std::string shader = R"(
  2670. OpCapability Shader
  2671. %1 = OpExtInstImport "GLSL.std.450"
  2672. OpMemoryModel Logical GLSL450
  2673. OpEntryPoint Fragment %4 "main"
  2674. OpExecutionMode %4 OriginUpperLeft
  2675. OpSource ESSL 310
  2676. %2 = OpTypeVoid
  2677. %3 = OpTypeFunction %2
  2678. %6 = OpTypeBool
  2679. %9 = OpConstantTrue %6
  2680. %4 = OpFunction %2 None %3
  2681. %5 = OpLabel
  2682. OpBranch %10
  2683. %10 = OpLabel
  2684. OpLoopMerge %16 %15 None
  2685. OpBranch %11
  2686. %11 = OpLabel
  2687. OpSelectionMerge %14 None
  2688. OpBranchConditional %9 %12 %13
  2689. %14 = OpLabel
  2690. OpBranch %15
  2691. %12 = OpLabel
  2692. OpBranch %16
  2693. %13 = OpLabel
  2694. OpBranch %16
  2695. %15 = OpLabel
  2696. OpBranch %10
  2697. %16 = OpLabel
  2698. OpReturn
  2699. OpFunctionEnd
  2700. )";
  2701. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2702. const auto consumer = nullptr;
  2703. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2704. spvtools::ValidatorOptions validator_options;
  2705. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2706. kConsoleMessageConsumer));
  2707. TransformationContext transformation_context(
  2708. MakeUnique<FactManager>(context.get()), validator_options);
  2709. // Bad because 14 comes before 12 in the module, and 14 has no predecessors.
  2710. // This means that an edge from 12 to 14 will lead to 12 dominating 14, which
  2711. // is illegal if 12 appears after 14.
  2712. auto bad_transformation = TransformationAddDeadBreak(12, 14, true, {});
  2713. ASSERT_FALSE(
  2714. bad_transformation.IsApplicable(context.get(), transformation_context));
  2715. }
  2716. } // namespace
  2717. } // namespace fuzz
  2718. } // namespace spvtools