struct_cfg_analysis_test.cpp 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531
  1. // Copyright (c) 2018 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/opt/struct_cfg_analysis.h"
  15. #include <string>
  16. #include "gmock/gmock.h"
  17. #include "test/opt/assembly_builder.h"
  18. #include "test/opt/pass_fixture.h"
  19. #include "test/opt/pass_utils.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. using StructCFGAnalysisTest = PassTest<::testing::Test>;
  24. using ::testing::UnorderedElementsAre;
  25. TEST_F(StructCFGAnalysisTest, BBInSelection) {
  26. const std::string text = R"(
  27. OpCapability Shader
  28. OpMemoryModel Logical GLSL450
  29. OpEntryPoint Fragment %main "main"
  30. %void = OpTypeVoid
  31. %bool = OpTypeBool
  32. %bool_undef = OpUndef %bool
  33. %uint = OpTypeInt 32 0
  34. %uint_undef = OpUndef %uint
  35. %void_func = OpTypeFunction %void
  36. %main = OpFunction %void None %void_func
  37. %1 = OpLabel
  38. OpSelectionMerge %3 None
  39. OpBranchConditional %undef_bool %2 %3
  40. %2 = OpLabel
  41. OpBranch %3
  42. %3 = OpLabel
  43. OpReturn
  44. OpFunctionEnd
  45. )";
  46. std::unique_ptr<IRContext> context =
  47. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  48. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  49. StructuredCFGAnalysis analysis(context.get());
  50. // The header is not in the construct.
  51. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  52. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  53. EXPECT_EQ(analysis.MergeBlock(1), 0);
  54. EXPECT_EQ(analysis.NestingDepth(1), 0);
  55. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  56. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  57. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  58. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  59. EXPECT_FALSE(analysis.IsContinueBlock(1));
  60. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  61. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  62. EXPECT_FALSE(analysis.IsMergeBlock(1));
  63. // BB2 is in the construct.
  64. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  65. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  66. EXPECT_EQ(analysis.MergeBlock(2), 3);
  67. EXPECT_EQ(analysis.NestingDepth(2), 1);
  68. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  69. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  70. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  71. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  72. EXPECT_FALSE(analysis.IsContinueBlock(2));
  73. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  74. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  75. EXPECT_FALSE(analysis.IsMergeBlock(2));
  76. // The merge node is not in the construct.
  77. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  78. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  79. EXPECT_EQ(analysis.MergeBlock(3), 0);
  80. EXPECT_EQ(analysis.NestingDepth(3), 0);
  81. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  82. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  83. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  84. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  85. EXPECT_FALSE(analysis.IsContinueBlock(3));
  86. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  87. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  88. EXPECT_TRUE(analysis.IsMergeBlock(3));
  89. }
  90. TEST_F(StructCFGAnalysisTest, BBInLoop) {
  91. const std::string text = R"(
  92. OpCapability Shader
  93. OpMemoryModel Logical GLSL450
  94. OpEntryPoint Fragment %main "main"
  95. %void = OpTypeVoid
  96. %bool = OpTypeBool
  97. %bool_undef = OpUndef %bool
  98. %uint = OpTypeInt 32 0
  99. %uint_undef = OpUndef %uint
  100. %void_func = OpTypeFunction %void
  101. %main = OpFunction %void None %void_func
  102. %entry_lab = OpLabel
  103. OpBranch %1
  104. %1 = OpLabel
  105. OpLoopMerge %3 %4 None
  106. OpBranchConditional %undef_bool %2 %3
  107. %2 = OpLabel
  108. OpBranch %3
  109. %4 = OpLabel
  110. OpBranch %1
  111. %3 = OpLabel
  112. OpReturn
  113. OpFunctionEnd
  114. )";
  115. std::unique_ptr<IRContext> context =
  116. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  117. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  118. StructuredCFGAnalysis analysis(context.get());
  119. // The header is not in the construct.
  120. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  121. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  122. EXPECT_EQ(analysis.MergeBlock(1), 0);
  123. EXPECT_EQ(analysis.NestingDepth(1), 0);
  124. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  125. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  126. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  127. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  128. EXPECT_FALSE(analysis.IsContinueBlock(1));
  129. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  130. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  131. EXPECT_FALSE(analysis.IsMergeBlock(1));
  132. // BB2 is in the construct.
  133. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  134. EXPECT_EQ(analysis.ContainingLoop(2), 1);
  135. EXPECT_EQ(analysis.MergeBlock(2), 3);
  136. EXPECT_EQ(analysis.NestingDepth(2), 1);
  137. EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
  138. EXPECT_EQ(analysis.LoopNestingDepth(2), 1);
  139. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  140. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  141. EXPECT_FALSE(analysis.IsContinueBlock(2));
  142. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  143. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  144. EXPECT_FALSE(analysis.IsMergeBlock(2));
  145. // The merge node is not in the construct.
  146. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  147. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  148. EXPECT_EQ(analysis.MergeBlock(3), 0);
  149. EXPECT_EQ(analysis.NestingDepth(3), 0);
  150. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  151. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  152. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  153. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  154. EXPECT_FALSE(analysis.IsContinueBlock(3));
  155. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  156. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  157. EXPECT_TRUE(analysis.IsMergeBlock(3));
  158. // The continue block is in the construct.
  159. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  160. EXPECT_EQ(analysis.ContainingLoop(4), 1);
  161. EXPECT_EQ(analysis.MergeBlock(4), 3);
  162. EXPECT_EQ(analysis.NestingDepth(4), 1);
  163. EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
  164. EXPECT_EQ(analysis.LoopNestingDepth(4), 1);
  165. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  166. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  167. EXPECT_TRUE(analysis.IsContinueBlock(4));
  168. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
  169. EXPECT_TRUE(analysis.IsInContinueConstruct(4));
  170. EXPECT_FALSE(analysis.IsMergeBlock(4));
  171. }
  172. TEST_F(StructCFGAnalysisTest, SelectionInLoop) {
  173. const std::string text = R"(
  174. OpCapability Shader
  175. OpMemoryModel Logical GLSL450
  176. OpEntryPoint Fragment %main "main"
  177. %void = OpTypeVoid
  178. %bool = OpTypeBool
  179. %bool_undef = OpUndef %bool
  180. %uint = OpTypeInt 32 0
  181. %uint_undef = OpUndef %uint
  182. %void_func = OpTypeFunction %void
  183. %main = OpFunction %void None %void_func
  184. %entry_lab = OpLabel
  185. OpBranch %1
  186. %1 = OpLabel
  187. OpLoopMerge %3 %4 None
  188. OpBranchConditional %undef_bool %2 %3
  189. %2 = OpLabel
  190. OpSelectionMerge %6 None
  191. OpBranchConditional %undef_bool %5 %6
  192. %5 = OpLabel
  193. OpBranch %6
  194. %6 = OpLabel
  195. OpBranch %3
  196. %4 = OpLabel
  197. OpBranch %1
  198. %3 = OpLabel
  199. OpReturn
  200. OpFunctionEnd
  201. )";
  202. std::unique_ptr<IRContext> context =
  203. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  204. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  205. StructuredCFGAnalysis analysis(context.get());
  206. // The loop header is not in either construct.
  207. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  208. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  209. EXPECT_EQ(analysis.MergeBlock(1), 0);
  210. EXPECT_EQ(analysis.NestingDepth(1), 0);
  211. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  212. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  213. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  214. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  215. EXPECT_FALSE(analysis.IsContinueBlock(1));
  216. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  217. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  218. EXPECT_FALSE(analysis.IsMergeBlock(1));
  219. // Selection header is in the loop only.
  220. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  221. EXPECT_EQ(analysis.ContainingLoop(2), 1);
  222. EXPECT_EQ(analysis.MergeBlock(2), 3);
  223. EXPECT_EQ(analysis.NestingDepth(2), 1);
  224. EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
  225. EXPECT_EQ(analysis.LoopNestingDepth(2), 1);
  226. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  227. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  228. EXPECT_FALSE(analysis.IsContinueBlock(2));
  229. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  230. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  231. EXPECT_FALSE(analysis.IsMergeBlock(2));
  232. // The loop merge node is not in either construct.
  233. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  234. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  235. EXPECT_EQ(analysis.MergeBlock(3), 0);
  236. EXPECT_EQ(analysis.NestingDepth(3), 0);
  237. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  238. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  239. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  240. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  241. EXPECT_FALSE(analysis.IsContinueBlock(3));
  242. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  243. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  244. EXPECT_TRUE(analysis.IsMergeBlock(3));
  245. // The continue block is in the loop only.
  246. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  247. EXPECT_EQ(analysis.ContainingLoop(4), 1);
  248. EXPECT_EQ(analysis.MergeBlock(4), 3);
  249. EXPECT_EQ(analysis.NestingDepth(4), 1);
  250. EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
  251. EXPECT_EQ(analysis.LoopNestingDepth(4), 1);
  252. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  253. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  254. EXPECT_TRUE(analysis.IsContinueBlock(4));
  255. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
  256. EXPECT_TRUE(analysis.IsInContinueConstruct(4));
  257. EXPECT_FALSE(analysis.IsMergeBlock(4));
  258. // BB5 is in the selection and the loop.
  259. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  260. EXPECT_EQ(analysis.ContainingLoop(5), 1);
  261. EXPECT_EQ(analysis.MergeBlock(5), 6);
  262. EXPECT_EQ(analysis.NestingDepth(5), 2);
  263. EXPECT_EQ(analysis.LoopMergeBlock(5), 3);
  264. EXPECT_EQ(analysis.LoopNestingDepth(5), 1);
  265. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  266. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  267. EXPECT_FALSE(analysis.IsContinueBlock(5));
  268. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
  269. EXPECT_FALSE(analysis.IsInContinueConstruct(5));
  270. EXPECT_FALSE(analysis.IsMergeBlock(5));
  271. // The selection merge is in the loop only.
  272. EXPECT_EQ(analysis.ContainingConstruct(6), 1);
  273. EXPECT_EQ(analysis.ContainingLoop(6), 1);
  274. EXPECT_EQ(analysis.MergeBlock(6), 3);
  275. EXPECT_EQ(analysis.NestingDepth(6), 1);
  276. EXPECT_EQ(analysis.LoopMergeBlock(6), 3);
  277. EXPECT_EQ(analysis.LoopNestingDepth(6), 1);
  278. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  279. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  280. EXPECT_FALSE(analysis.IsContinueBlock(6));
  281. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
  282. EXPECT_FALSE(analysis.IsInContinueConstruct(6));
  283. EXPECT_TRUE(analysis.IsMergeBlock(6));
  284. }
  285. TEST_F(StructCFGAnalysisTest, LoopInSelection) {
  286. const std::string text = R"(
  287. OpCapability Shader
  288. OpMemoryModel Logical GLSL450
  289. OpEntryPoint Fragment %main "main"
  290. %void = OpTypeVoid
  291. %bool = OpTypeBool
  292. %bool_undef = OpUndef %bool
  293. %uint = OpTypeInt 32 0
  294. %uint_undef = OpUndef %uint
  295. %void_func = OpTypeFunction %void
  296. %main = OpFunction %void None %void_func
  297. %entry_lab = OpLabel
  298. OpBranch %1
  299. %1 = OpLabel
  300. OpSelectionMerge %3 None
  301. OpBranchConditional %undef_bool %2 %3
  302. %2 = OpLabel
  303. OpLoopMerge %4 %5 None
  304. OpBranchConditional %undef_bool %4 %6
  305. %5 = OpLabel
  306. OpBranch %2
  307. %6 = OpLabel
  308. OpBranch %4
  309. %4 = OpLabel
  310. OpBranch %3
  311. %3 = OpLabel
  312. OpReturn
  313. OpFunctionEnd
  314. )";
  315. std::unique_ptr<IRContext> context =
  316. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  317. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  318. StructuredCFGAnalysis analysis(context.get());
  319. // The selection header is not in either construct.
  320. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  321. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  322. EXPECT_EQ(analysis.MergeBlock(1), 0);
  323. EXPECT_EQ(analysis.NestingDepth(1), 0);
  324. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  325. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  326. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  327. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  328. EXPECT_FALSE(analysis.IsContinueBlock(1));
  329. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  330. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  331. EXPECT_FALSE(analysis.IsMergeBlock(1));
  332. // Loop header is in the selection only.
  333. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  334. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  335. EXPECT_EQ(analysis.MergeBlock(2), 3);
  336. EXPECT_EQ(analysis.NestingDepth(2), 1);
  337. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  338. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  339. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  340. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  341. EXPECT_FALSE(analysis.IsContinueBlock(2));
  342. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  343. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  344. EXPECT_FALSE(analysis.IsMergeBlock(2));
  345. // The selection merge node is not in either construct.
  346. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  347. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  348. EXPECT_EQ(analysis.MergeBlock(3), 0);
  349. EXPECT_EQ(analysis.NestingDepth(3), 0);
  350. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  351. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  352. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  353. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  354. EXPECT_FALSE(analysis.IsContinueBlock(3));
  355. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  356. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  357. EXPECT_TRUE(analysis.IsMergeBlock(3));
  358. // The loop merge is in the selection only.
  359. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  360. EXPECT_EQ(analysis.ContainingLoop(4), 0);
  361. EXPECT_EQ(analysis.MergeBlock(4), 3);
  362. EXPECT_EQ(analysis.NestingDepth(4), 1);
  363. EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
  364. EXPECT_EQ(analysis.LoopNestingDepth(4), 0);
  365. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  366. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  367. EXPECT_FALSE(analysis.IsContinueBlock(4));
  368. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  369. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  370. EXPECT_TRUE(analysis.IsMergeBlock(4));
  371. // The loop continue target is in the loop.
  372. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  373. EXPECT_EQ(analysis.ContainingLoop(5), 2);
  374. EXPECT_EQ(analysis.MergeBlock(5), 4);
  375. EXPECT_EQ(analysis.NestingDepth(5), 2);
  376. EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
  377. EXPECT_EQ(analysis.LoopNestingDepth(5), 1);
  378. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  379. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  380. EXPECT_TRUE(analysis.IsContinueBlock(5));
  381. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
  382. EXPECT_TRUE(analysis.IsInContinueConstruct(5));
  383. EXPECT_FALSE(analysis.IsMergeBlock(5));
  384. // BB6 is in the loop.
  385. EXPECT_EQ(analysis.ContainingConstruct(6), 2);
  386. EXPECT_EQ(analysis.ContainingLoop(6), 2);
  387. EXPECT_EQ(analysis.MergeBlock(6), 4);
  388. EXPECT_EQ(analysis.NestingDepth(6), 2);
  389. EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
  390. EXPECT_EQ(analysis.LoopNestingDepth(6), 1);
  391. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  392. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  393. EXPECT_FALSE(analysis.IsContinueBlock(6));
  394. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
  395. EXPECT_FALSE(analysis.IsInContinueConstruct(6));
  396. EXPECT_FALSE(analysis.IsMergeBlock(6));
  397. }
  398. TEST_F(StructCFGAnalysisTest, SelectionInSelection) {
  399. const std::string text = R"(
  400. OpCapability Shader
  401. OpMemoryModel Logical GLSL450
  402. OpEntryPoint Fragment %main "main"
  403. %void = OpTypeVoid
  404. %bool = OpTypeBool
  405. %bool_undef = OpUndef %bool
  406. %uint = OpTypeInt 32 0
  407. %uint_undef = OpUndef %uint
  408. %void_func = OpTypeFunction %void
  409. %main = OpFunction %void None %void_func
  410. %entry_lab = OpLabel
  411. OpBranch %1
  412. %1 = OpLabel
  413. OpSelectionMerge %3 None
  414. OpBranchConditional %undef_bool %2 %3
  415. %2 = OpLabel
  416. OpSelectionMerge %4 None
  417. OpBranchConditional %undef_bool %4 %5
  418. %5 = OpLabel
  419. OpBranch %4
  420. %4 = OpLabel
  421. OpBranch %3
  422. %3 = OpLabel
  423. OpReturn
  424. OpFunctionEnd
  425. )";
  426. std::unique_ptr<IRContext> context =
  427. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  428. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  429. StructuredCFGAnalysis analysis(context.get());
  430. // The outer selection header is not in either construct.
  431. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  432. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  433. EXPECT_EQ(analysis.MergeBlock(1), 0);
  434. EXPECT_EQ(analysis.NestingDepth(1), 0);
  435. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  436. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  437. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  438. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  439. EXPECT_FALSE(analysis.IsContinueBlock(1));
  440. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  441. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  442. EXPECT_FALSE(analysis.IsMergeBlock(1));
  443. // The inner header is in the outer selection.
  444. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  445. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  446. EXPECT_EQ(analysis.MergeBlock(2), 3);
  447. EXPECT_EQ(analysis.NestingDepth(2), 1);
  448. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  449. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  450. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  451. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  452. EXPECT_FALSE(analysis.IsContinueBlock(2));
  453. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  454. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  455. EXPECT_FALSE(analysis.IsMergeBlock(2));
  456. // The outer merge node is not in either construct.
  457. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  458. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  459. EXPECT_EQ(analysis.MergeBlock(3), 0);
  460. EXPECT_EQ(analysis.NestingDepth(3), 0);
  461. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  462. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  463. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  464. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  465. EXPECT_FALSE(analysis.IsContinueBlock(3));
  466. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  467. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  468. EXPECT_TRUE(analysis.IsMergeBlock(3));
  469. // The inner merge is in the outer selection.
  470. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  471. EXPECT_EQ(analysis.ContainingLoop(4), 0);
  472. EXPECT_EQ(analysis.MergeBlock(4), 3);
  473. EXPECT_EQ(analysis.NestingDepth(4), 1);
  474. EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
  475. EXPECT_EQ(analysis.LoopNestingDepth(4), 0);
  476. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  477. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  478. EXPECT_FALSE(analysis.IsContinueBlock(4));
  479. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  480. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  481. EXPECT_TRUE(analysis.IsMergeBlock(4));
  482. // BB5 is in the inner selection.
  483. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  484. EXPECT_EQ(analysis.ContainingLoop(5), 0);
  485. EXPECT_EQ(analysis.MergeBlock(5), 4);
  486. EXPECT_EQ(analysis.NestingDepth(5), 2);
  487. EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
  488. EXPECT_EQ(analysis.LoopNestingDepth(5), 0);
  489. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  490. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  491. EXPECT_FALSE(analysis.IsContinueBlock(5));
  492. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
  493. EXPECT_FALSE(analysis.IsInContinueConstruct(5));
  494. EXPECT_FALSE(analysis.IsMergeBlock(5));
  495. }
  496. TEST_F(StructCFGAnalysisTest, LoopInLoop) {
  497. const std::string text = R"(
  498. OpCapability Shader
  499. OpMemoryModel Logical GLSL450
  500. OpEntryPoint Fragment %main "main"
  501. %void = OpTypeVoid
  502. %bool = OpTypeBool
  503. %bool_undef = OpUndef %bool
  504. %uint = OpTypeInt 32 0
  505. %uint_undef = OpUndef %uint
  506. %void_func = OpTypeFunction %void
  507. %main = OpFunction %void None %void_func
  508. %entry_lab = OpLabel
  509. OpBranch %1
  510. %1 = OpLabel
  511. OpLoopMerge %3 %7 None
  512. OpBranchConditional %undef_bool %2 %3
  513. %2 = OpLabel
  514. OpLoopMerge %4 %5 None
  515. OpBranchConditional %undef_bool %4 %6
  516. %5 = OpLabel
  517. OpBranch %2
  518. %6 = OpLabel
  519. OpBranch %4
  520. %4 = OpLabel
  521. OpBranch %3
  522. %7 = OpLabel
  523. OpBranch %1
  524. %3 = OpLabel
  525. OpReturn
  526. OpFunctionEnd
  527. )";
  528. std::unique_ptr<IRContext> context =
  529. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  530. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  531. StructuredCFGAnalysis analysis(context.get());
  532. // The outer loop header is not in either construct.
  533. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  534. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  535. EXPECT_EQ(analysis.MergeBlock(1), 0);
  536. EXPECT_EQ(analysis.NestingDepth(1), 0);
  537. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  538. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  539. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  540. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  541. EXPECT_FALSE(analysis.IsContinueBlock(1));
  542. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  543. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  544. EXPECT_FALSE(analysis.IsMergeBlock(1));
  545. // The inner loop header is in the outer loop.
  546. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  547. EXPECT_EQ(analysis.ContainingLoop(2), 1);
  548. EXPECT_EQ(analysis.MergeBlock(2), 3);
  549. EXPECT_EQ(analysis.NestingDepth(2), 1);
  550. EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
  551. EXPECT_EQ(analysis.LoopNestingDepth(2), 1);
  552. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  553. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  554. EXPECT_FALSE(analysis.IsContinueBlock(2));
  555. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  556. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  557. EXPECT_FALSE(analysis.IsMergeBlock(2));
  558. // The outer merge node is not in either construct.
  559. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  560. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  561. EXPECT_EQ(analysis.MergeBlock(3), 0);
  562. EXPECT_EQ(analysis.NestingDepth(3), 0);
  563. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  564. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  565. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  566. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  567. EXPECT_FALSE(analysis.IsContinueBlock(3));
  568. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  569. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  570. EXPECT_TRUE(analysis.IsMergeBlock(3));
  571. // The inner merge is in the outer loop.
  572. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  573. EXPECT_EQ(analysis.ContainingLoop(4), 1);
  574. EXPECT_EQ(analysis.MergeBlock(4), 3);
  575. EXPECT_EQ(analysis.NestingDepth(4), 1);
  576. EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
  577. EXPECT_EQ(analysis.LoopNestingDepth(4), 1);
  578. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  579. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  580. EXPECT_FALSE(analysis.IsContinueBlock(4));
  581. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  582. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  583. EXPECT_TRUE(analysis.IsMergeBlock(4));
  584. // The inner continue target is in the inner loop.
  585. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  586. EXPECT_EQ(analysis.ContainingLoop(5), 2);
  587. EXPECT_EQ(analysis.MergeBlock(5), 4);
  588. EXPECT_EQ(analysis.NestingDepth(5), 2);
  589. EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
  590. EXPECT_EQ(analysis.LoopNestingDepth(5), 2);
  591. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  592. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  593. EXPECT_TRUE(analysis.IsContinueBlock(5));
  594. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
  595. EXPECT_TRUE(analysis.IsInContinueConstruct(5));
  596. EXPECT_FALSE(analysis.IsMergeBlock(5));
  597. // BB6 is in the loop.
  598. EXPECT_EQ(analysis.ContainingConstruct(6), 2);
  599. EXPECT_EQ(analysis.ContainingLoop(6), 2);
  600. EXPECT_EQ(analysis.MergeBlock(6), 4);
  601. EXPECT_EQ(analysis.NestingDepth(6), 2);
  602. EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
  603. EXPECT_EQ(analysis.LoopNestingDepth(6), 2);
  604. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  605. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  606. EXPECT_FALSE(analysis.IsContinueBlock(6));
  607. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
  608. EXPECT_FALSE(analysis.IsInContinueConstruct(6));
  609. EXPECT_FALSE(analysis.IsMergeBlock(6));
  610. // The outer continue target is in the outer loop.
  611. EXPECT_EQ(analysis.ContainingConstruct(7), 1);
  612. EXPECT_EQ(analysis.ContainingLoop(7), 1);
  613. EXPECT_EQ(analysis.MergeBlock(7), 3);
  614. EXPECT_EQ(analysis.NestingDepth(7), 1);
  615. EXPECT_EQ(analysis.LoopMergeBlock(7), 3);
  616. EXPECT_EQ(analysis.LoopNestingDepth(7), 1);
  617. EXPECT_EQ(analysis.ContainingSwitch(7), 0);
  618. EXPECT_EQ(analysis.SwitchMergeBlock(7), 0);
  619. EXPECT_TRUE(analysis.IsContinueBlock(7));
  620. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7));
  621. EXPECT_TRUE(analysis.IsInContinueConstruct(7));
  622. EXPECT_FALSE(analysis.IsMergeBlock(7));
  623. }
  624. TEST_F(StructCFGAnalysisTest, KernelTest) {
  625. const std::string text = R"(
  626. OpCapability Kernel
  627. OpMemoryModel Logical GLSL450
  628. OpEntryPoint Fragment %main "main"
  629. %void = OpTypeVoid
  630. %bool = OpTypeBool
  631. %bool_undef = OpUndef %bool
  632. %void_func = OpTypeFunction %void
  633. %main = OpFunction %void None %void_func
  634. %1 = OpLabel
  635. OpBranchConditional %undef_bool %2 %3
  636. %2 = OpLabel
  637. OpBranch %3
  638. %3 = OpLabel
  639. OpReturn
  640. OpFunctionEnd
  641. )";
  642. std::unique_ptr<IRContext> context =
  643. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  644. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  645. StructuredCFGAnalysis analysis(context.get());
  646. // No structured control flow, so none of the basic block are in any
  647. // construct.
  648. for (uint32_t i = 1; i <= 3; i++) {
  649. EXPECT_EQ(analysis.ContainingConstruct(i), 0);
  650. EXPECT_EQ(analysis.ContainingLoop(i), 0);
  651. EXPECT_EQ(analysis.MergeBlock(i), 0);
  652. EXPECT_EQ(analysis.NestingDepth(i), 0);
  653. EXPECT_EQ(analysis.LoopMergeBlock(i), 0);
  654. EXPECT_EQ(analysis.LoopNestingDepth(i), 0);
  655. EXPECT_EQ(analysis.ContainingSwitch(i), 0);
  656. EXPECT_EQ(analysis.SwitchMergeBlock(i), 0);
  657. EXPECT_FALSE(analysis.IsContinueBlock(i));
  658. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(i));
  659. EXPECT_FALSE(analysis.IsInContinueConstruct(i));
  660. EXPECT_FALSE(analysis.IsMergeBlock(i));
  661. }
  662. }
  663. TEST_F(StructCFGAnalysisTest, EmptyFunctionTest) {
  664. const std::string text = R"(
  665. OpCapability Shader
  666. OpCapability Linkage
  667. OpMemoryModel Logical GLSL450
  668. OpDecorate %func LinkageAttributes "x" Import
  669. %void = OpTypeVoid
  670. %void_fn = OpTypeFunction %void
  671. %func = OpFunction %void None %void_fn
  672. OpFunctionEnd
  673. )";
  674. std::unique_ptr<IRContext> context =
  675. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  676. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  677. // #2451: This segfaulted on empty functions.
  678. StructuredCFGAnalysis analysis(context.get());
  679. }
  680. TEST_F(StructCFGAnalysisTest, BBInSwitch) {
  681. const std::string text = R"(
  682. OpCapability Shader
  683. OpMemoryModel Logical GLSL450
  684. OpEntryPoint Fragment %main "main"
  685. %void = OpTypeVoid
  686. %bool = OpTypeBool
  687. %bool_undef = OpUndef %bool
  688. %uint = OpTypeInt 32 0
  689. %uint_undef = OpUndef %uint
  690. %void_func = OpTypeFunction %void
  691. %main = OpFunction %void None %void_func
  692. %1 = OpLabel
  693. OpSelectionMerge %3 None
  694. OpSwitch %uint_undef %2 0 %3
  695. %2 = OpLabel
  696. OpBranch %3
  697. %3 = OpLabel
  698. OpReturn
  699. OpFunctionEnd
  700. )";
  701. std::unique_ptr<IRContext> context =
  702. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  703. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  704. StructuredCFGAnalysis analysis(context.get());
  705. // The header is not in the construct.
  706. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  707. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  708. EXPECT_EQ(analysis.MergeBlock(1), 0);
  709. EXPECT_EQ(analysis.NestingDepth(1), 0);
  710. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  711. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  712. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  713. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  714. EXPECT_FALSE(analysis.IsContinueBlock(1));
  715. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  716. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  717. EXPECT_FALSE(analysis.IsMergeBlock(1));
  718. // BB2 is in the construct.
  719. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  720. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  721. EXPECT_EQ(analysis.MergeBlock(2), 3);
  722. EXPECT_EQ(analysis.NestingDepth(2), 1);
  723. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  724. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  725. EXPECT_EQ(analysis.ContainingSwitch(2), 1);
  726. EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
  727. EXPECT_FALSE(analysis.IsContinueBlock(2));
  728. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  729. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  730. EXPECT_FALSE(analysis.IsMergeBlock(2));
  731. // The merge node is not in the construct.
  732. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  733. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  734. EXPECT_EQ(analysis.MergeBlock(3), 0);
  735. EXPECT_EQ(analysis.NestingDepth(3), 0);
  736. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  737. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  738. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  739. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  740. EXPECT_FALSE(analysis.IsContinueBlock(3));
  741. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  742. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  743. EXPECT_TRUE(analysis.IsMergeBlock(3));
  744. }
  745. TEST_F(StructCFGAnalysisTest, LoopInSwitch) {
  746. const std::string text = R"(
  747. OpCapability Shader
  748. OpMemoryModel Logical GLSL450
  749. OpEntryPoint Fragment %main "main"
  750. %void = OpTypeVoid
  751. %bool = OpTypeBool
  752. %bool_undef = OpUndef %bool
  753. %uint = OpTypeInt 32 0
  754. %uint_undef = OpUndef %uint
  755. %void_func = OpTypeFunction %void
  756. %main = OpFunction %void None %void_func
  757. %entry_lab = OpLabel
  758. OpBranch %1
  759. %1 = OpLabel
  760. OpSelectionMerge %3 None
  761. OpSwitch %uint_undef %2 1 %3
  762. %2 = OpLabel
  763. OpLoopMerge %4 %5 None
  764. OpBranchConditional %undef_bool %4 %6
  765. %5 = OpLabel
  766. OpBranch %2
  767. %6 = OpLabel
  768. OpBranch %4
  769. %4 = OpLabel
  770. OpBranch %3
  771. %3 = OpLabel
  772. OpReturn
  773. OpFunctionEnd
  774. )";
  775. std::unique_ptr<IRContext> context =
  776. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  777. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  778. StructuredCFGAnalysis analysis(context.get());
  779. // The selection header is not in either construct.
  780. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  781. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  782. EXPECT_EQ(analysis.MergeBlock(1), 0);
  783. EXPECT_EQ(analysis.NestingDepth(1), 0);
  784. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  785. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  786. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  787. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  788. EXPECT_FALSE(analysis.IsContinueBlock(1));
  789. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  790. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  791. EXPECT_FALSE(analysis.IsMergeBlock(1));
  792. // Loop header is in the selection only.
  793. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  794. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  795. EXPECT_EQ(analysis.MergeBlock(2), 3);
  796. EXPECT_EQ(analysis.NestingDepth(2), 1);
  797. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  798. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  799. EXPECT_EQ(analysis.ContainingSwitch(2), 1);
  800. EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
  801. EXPECT_FALSE(analysis.IsContinueBlock(2));
  802. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  803. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  804. EXPECT_FALSE(analysis.IsMergeBlock(2));
  805. // The selection merge node is not in either construct.
  806. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  807. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  808. EXPECT_EQ(analysis.MergeBlock(3), 0);
  809. EXPECT_EQ(analysis.NestingDepth(3), 0);
  810. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  811. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  812. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  813. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  814. EXPECT_FALSE(analysis.IsContinueBlock(3));
  815. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  816. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  817. EXPECT_TRUE(analysis.IsMergeBlock(3));
  818. // The loop merge is in the selection only.
  819. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  820. EXPECT_EQ(analysis.ContainingLoop(4), 0);
  821. EXPECT_EQ(analysis.MergeBlock(4), 3);
  822. EXPECT_EQ(analysis.NestingDepth(4), 1);
  823. EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
  824. EXPECT_EQ(analysis.LoopNestingDepth(4), 0);
  825. EXPECT_EQ(analysis.ContainingSwitch(4), 1);
  826. EXPECT_EQ(analysis.SwitchMergeBlock(4), 3);
  827. EXPECT_FALSE(analysis.IsContinueBlock(4));
  828. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  829. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  830. EXPECT_TRUE(analysis.IsMergeBlock(4));
  831. // The loop continue target is in the loop.
  832. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  833. EXPECT_EQ(analysis.ContainingLoop(5), 2);
  834. EXPECT_EQ(analysis.MergeBlock(5), 4);
  835. EXPECT_EQ(analysis.NestingDepth(5), 2);
  836. EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
  837. EXPECT_EQ(analysis.LoopNestingDepth(5), 1);
  838. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  839. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  840. EXPECT_TRUE(analysis.IsContinueBlock(5));
  841. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
  842. EXPECT_TRUE(analysis.IsInContinueConstruct(5));
  843. EXPECT_FALSE(analysis.IsMergeBlock(5));
  844. // BB6 is in the loop.
  845. EXPECT_EQ(analysis.ContainingConstruct(6), 2);
  846. EXPECT_EQ(analysis.ContainingLoop(6), 2);
  847. EXPECT_EQ(analysis.MergeBlock(6), 4);
  848. EXPECT_EQ(analysis.NestingDepth(6), 2);
  849. EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
  850. EXPECT_EQ(analysis.LoopNestingDepth(6), 1);
  851. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  852. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  853. EXPECT_FALSE(analysis.IsContinueBlock(6));
  854. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
  855. EXPECT_FALSE(analysis.IsInContinueConstruct(6));
  856. EXPECT_FALSE(analysis.IsMergeBlock(6));
  857. }
  858. TEST_F(StructCFGAnalysisTest, SelectionInSwitch) {
  859. const std::string text = R"(
  860. OpCapability Shader
  861. OpMemoryModel Logical GLSL450
  862. OpEntryPoint Fragment %main "main"
  863. %void = OpTypeVoid
  864. %bool = OpTypeBool
  865. %bool_undef = OpUndef %bool
  866. %uint = OpTypeInt 32 0
  867. %uint_undef = OpUndef %uint
  868. %void_func = OpTypeFunction %void
  869. %main = OpFunction %void None %void_func
  870. %entry_lab = OpLabel
  871. OpBranch %1
  872. %1 = OpLabel
  873. OpSelectionMerge %3 None
  874. OpSwitch %uint_undef %2 10 %3
  875. %2 = OpLabel
  876. OpSelectionMerge %4 None
  877. OpBranchConditional %undef_bool %4 %5
  878. %5 = OpLabel
  879. OpBranch %4
  880. %4 = OpLabel
  881. OpBranch %3
  882. %3 = OpLabel
  883. OpReturn
  884. OpFunctionEnd
  885. )";
  886. std::unique_ptr<IRContext> context =
  887. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  888. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  889. StructuredCFGAnalysis analysis(context.get());
  890. // The outer selection header is not in either construct.
  891. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  892. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  893. EXPECT_EQ(analysis.MergeBlock(1), 0);
  894. EXPECT_EQ(analysis.NestingDepth(1), 0);
  895. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  896. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  897. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  898. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  899. EXPECT_FALSE(analysis.IsContinueBlock(1));
  900. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  901. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  902. EXPECT_FALSE(analysis.IsMergeBlock(1));
  903. // The inner header is in the outer selection.
  904. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  905. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  906. EXPECT_EQ(analysis.MergeBlock(2), 3);
  907. EXPECT_EQ(analysis.NestingDepth(2), 1);
  908. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  909. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  910. EXPECT_EQ(analysis.ContainingSwitch(2), 1);
  911. EXPECT_EQ(analysis.SwitchMergeBlock(2), 3);
  912. EXPECT_FALSE(analysis.IsContinueBlock(2));
  913. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  914. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  915. EXPECT_FALSE(analysis.IsMergeBlock(2));
  916. // The outer merge node is not in either construct.
  917. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  918. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  919. EXPECT_EQ(analysis.MergeBlock(3), 0);
  920. EXPECT_EQ(analysis.NestingDepth(3), 0);
  921. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  922. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  923. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  924. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  925. EXPECT_FALSE(analysis.IsContinueBlock(3));
  926. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  927. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  928. EXPECT_TRUE(analysis.IsMergeBlock(3));
  929. // The inner merge is in the outer selection.
  930. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  931. EXPECT_EQ(analysis.ContainingLoop(4), 0);
  932. EXPECT_EQ(analysis.MergeBlock(4), 3);
  933. EXPECT_EQ(analysis.NestingDepth(4), 1);
  934. EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
  935. EXPECT_EQ(analysis.LoopNestingDepth(4), 0);
  936. EXPECT_EQ(analysis.ContainingSwitch(4), 1);
  937. EXPECT_EQ(analysis.SwitchMergeBlock(4), 3);
  938. EXPECT_FALSE(analysis.IsContinueBlock(4));
  939. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  940. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  941. EXPECT_TRUE(analysis.IsMergeBlock(4));
  942. // BB5 is in the inner selection.
  943. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  944. EXPECT_EQ(analysis.ContainingLoop(5), 0);
  945. EXPECT_EQ(analysis.MergeBlock(5), 4);
  946. EXPECT_EQ(analysis.NestingDepth(5), 2);
  947. EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
  948. EXPECT_EQ(analysis.LoopNestingDepth(5), 0);
  949. EXPECT_EQ(analysis.ContainingSwitch(5), 1);
  950. EXPECT_EQ(analysis.SwitchMergeBlock(5), 3);
  951. EXPECT_FALSE(analysis.IsContinueBlock(5));
  952. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
  953. EXPECT_FALSE(analysis.IsInContinueConstruct(5));
  954. EXPECT_FALSE(analysis.IsMergeBlock(5));
  955. }
  956. TEST_F(StructCFGAnalysisTest, SwitchInSelection) {
  957. const std::string text = R"(
  958. OpCapability Shader
  959. OpMemoryModel Logical GLSL450
  960. OpEntryPoint Fragment %main "main"
  961. %void = OpTypeVoid
  962. %bool = OpTypeBool
  963. %bool_undef = OpUndef %bool
  964. %uint = OpTypeInt 32 0
  965. %uint_undef = OpUndef %uint
  966. %void_func = OpTypeFunction %void
  967. %main = OpFunction %void None %void_func
  968. %entry_lab = OpLabel
  969. OpBranch %1
  970. %1 = OpLabel
  971. OpSelectionMerge %3 None
  972. OpBranchConditional %undef_bool %2 %3
  973. %2 = OpLabel
  974. OpSelectionMerge %4 None
  975. OpSwitch %uint_undef %4 7 %5
  976. %5 = OpLabel
  977. OpBranch %4
  978. %4 = OpLabel
  979. OpBranch %3
  980. %3 = OpLabel
  981. OpReturn
  982. OpFunctionEnd
  983. )";
  984. std::unique_ptr<IRContext> context =
  985. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  986. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  987. StructuredCFGAnalysis analysis(context.get());
  988. // The outer selection header is not in either construct.
  989. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  990. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  991. EXPECT_EQ(analysis.MergeBlock(1), 0);
  992. EXPECT_EQ(analysis.NestingDepth(1), 0);
  993. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  994. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  995. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  996. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  997. EXPECT_FALSE(analysis.IsContinueBlock(1));
  998. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  999. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  1000. EXPECT_FALSE(analysis.IsMergeBlock(1));
  1001. // The inner header is in the outer selection.
  1002. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  1003. EXPECT_EQ(analysis.ContainingLoop(2), 0);
  1004. EXPECT_EQ(analysis.MergeBlock(2), 3);
  1005. EXPECT_EQ(analysis.NestingDepth(2), 1);
  1006. EXPECT_EQ(analysis.LoopMergeBlock(2), 0);
  1007. EXPECT_EQ(analysis.LoopNestingDepth(2), 0);
  1008. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  1009. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  1010. EXPECT_FALSE(analysis.IsContinueBlock(2));
  1011. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  1012. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  1013. EXPECT_FALSE(analysis.IsMergeBlock(2));
  1014. // The outer merge node is not in either construct.
  1015. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  1016. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  1017. EXPECT_EQ(analysis.MergeBlock(3), 0);
  1018. EXPECT_EQ(analysis.NestingDepth(3), 0);
  1019. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  1020. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  1021. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  1022. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  1023. EXPECT_FALSE(analysis.IsContinueBlock(3));
  1024. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  1025. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  1026. EXPECT_TRUE(analysis.IsMergeBlock(3));
  1027. // The inner merge is in the outer selection.
  1028. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  1029. EXPECT_EQ(analysis.ContainingLoop(4), 0);
  1030. EXPECT_EQ(analysis.MergeBlock(4), 3);
  1031. EXPECT_EQ(analysis.NestingDepth(4), 1);
  1032. EXPECT_EQ(analysis.LoopMergeBlock(4), 0);
  1033. EXPECT_EQ(analysis.LoopNestingDepth(4), 0);
  1034. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  1035. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  1036. EXPECT_FALSE(analysis.IsContinueBlock(4));
  1037. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4));
  1038. EXPECT_FALSE(analysis.IsInContinueConstruct(4));
  1039. EXPECT_TRUE(analysis.IsMergeBlock(4));
  1040. // BB5 is in the inner selection.
  1041. EXPECT_EQ(analysis.ContainingConstruct(5), 2);
  1042. EXPECT_EQ(analysis.ContainingLoop(5), 0);
  1043. EXPECT_EQ(analysis.MergeBlock(5), 4);
  1044. EXPECT_EQ(analysis.NestingDepth(5), 2);
  1045. EXPECT_EQ(analysis.LoopMergeBlock(5), 0);
  1046. EXPECT_EQ(analysis.LoopNestingDepth(5), 0);
  1047. EXPECT_EQ(analysis.ContainingSwitch(5), 2);
  1048. EXPECT_EQ(analysis.SwitchMergeBlock(5), 4);
  1049. EXPECT_FALSE(analysis.IsContinueBlock(5));
  1050. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5));
  1051. EXPECT_FALSE(analysis.IsInContinueConstruct(5));
  1052. EXPECT_FALSE(analysis.IsMergeBlock(5));
  1053. }
  1054. TEST_F(StructCFGAnalysisTest, SelectionInContinue) {
  1055. const std::string text = R"(
  1056. OpCapability Shader
  1057. OpMemoryModel Logical GLSL450
  1058. OpEntryPoint Fragment %main "main"
  1059. %void = OpTypeVoid
  1060. %bool = OpTypeBool
  1061. %bool_undef = OpUndef %bool
  1062. %uint = OpTypeInt 32 0
  1063. %uint_undef = OpUndef %uint
  1064. %void_func = OpTypeFunction %void
  1065. %main = OpFunction %void None %void_func
  1066. %entry_lab = OpLabel
  1067. OpBranch %1
  1068. %1 = OpLabel
  1069. OpLoopMerge %3 %4 None
  1070. OpBranchConditional %undef_bool %2 %3
  1071. %2 = OpLabel
  1072. OpBranch %3
  1073. %4 = OpLabel
  1074. OpSelectionMerge %6 None
  1075. OpBranchConditional %undef_bool %5 %6
  1076. %5 = OpLabel
  1077. OpBranch %6
  1078. %6 = OpLabel
  1079. OpBranch %1
  1080. %3 = OpLabel
  1081. OpReturn
  1082. OpFunctionEnd
  1083. )";
  1084. std::unique_ptr<IRContext> context =
  1085. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1086. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1087. StructuredCFGAnalysis analysis(context.get());
  1088. // The loop header is not in either construct.
  1089. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  1090. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  1091. EXPECT_EQ(analysis.MergeBlock(1), 0);
  1092. EXPECT_EQ(analysis.NestingDepth(1), 0);
  1093. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  1094. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  1095. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  1096. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  1097. EXPECT_FALSE(analysis.IsContinueBlock(1));
  1098. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  1099. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  1100. EXPECT_FALSE(analysis.IsMergeBlock(1));
  1101. // Selection header is in the loop only.
  1102. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  1103. EXPECT_EQ(analysis.ContainingLoop(2), 1);
  1104. EXPECT_EQ(analysis.MergeBlock(2), 3);
  1105. EXPECT_EQ(analysis.NestingDepth(2), 1);
  1106. EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
  1107. EXPECT_EQ(analysis.LoopNestingDepth(2), 1);
  1108. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  1109. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  1110. EXPECT_FALSE(analysis.IsContinueBlock(2));
  1111. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  1112. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  1113. EXPECT_FALSE(analysis.IsMergeBlock(2));
  1114. // The loop merge node is not in either construct.
  1115. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  1116. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  1117. EXPECT_EQ(analysis.MergeBlock(3), 0);
  1118. EXPECT_EQ(analysis.NestingDepth(3), 0);
  1119. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  1120. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  1121. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  1122. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  1123. EXPECT_FALSE(analysis.IsContinueBlock(3));
  1124. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  1125. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  1126. EXPECT_TRUE(analysis.IsMergeBlock(3));
  1127. // The continue block is in the loop only.
  1128. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  1129. EXPECT_EQ(analysis.ContainingLoop(4), 1);
  1130. EXPECT_EQ(analysis.MergeBlock(4), 3);
  1131. EXPECT_EQ(analysis.NestingDepth(4), 1);
  1132. EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
  1133. EXPECT_EQ(analysis.LoopNestingDepth(4), 1);
  1134. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  1135. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  1136. EXPECT_TRUE(analysis.IsContinueBlock(4));
  1137. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
  1138. EXPECT_TRUE(analysis.IsInContinueConstruct(4));
  1139. EXPECT_FALSE(analysis.IsMergeBlock(4));
  1140. // BB5 is in the selection and the continue for the loop.
  1141. EXPECT_EQ(analysis.ContainingConstruct(5), 4);
  1142. EXPECT_EQ(analysis.ContainingLoop(5), 1);
  1143. EXPECT_EQ(analysis.MergeBlock(5), 6);
  1144. EXPECT_EQ(analysis.NestingDepth(5), 2);
  1145. EXPECT_EQ(analysis.LoopMergeBlock(5), 3);
  1146. EXPECT_EQ(analysis.LoopNestingDepth(5), 1);
  1147. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  1148. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  1149. EXPECT_FALSE(analysis.IsContinueBlock(5));
  1150. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
  1151. EXPECT_TRUE(analysis.IsInContinueConstruct(5));
  1152. EXPECT_FALSE(analysis.IsMergeBlock(5));
  1153. // BB5 is in the continue for the loop.
  1154. EXPECT_EQ(analysis.ContainingConstruct(6), 1);
  1155. EXPECT_EQ(analysis.ContainingLoop(6), 1);
  1156. EXPECT_EQ(analysis.MergeBlock(6), 3);
  1157. EXPECT_EQ(analysis.NestingDepth(6), 1);
  1158. EXPECT_EQ(analysis.LoopMergeBlock(6), 3);
  1159. EXPECT_EQ(analysis.LoopNestingDepth(6), 1);
  1160. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  1161. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  1162. EXPECT_FALSE(analysis.IsContinueBlock(6));
  1163. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(6));
  1164. EXPECT_TRUE(analysis.IsInContinueConstruct(6));
  1165. EXPECT_TRUE(analysis.IsMergeBlock(6));
  1166. }
  1167. TEST_F(StructCFGAnalysisTest, LoopInContinue) {
  1168. const std::string text = R"(
  1169. OpCapability Shader
  1170. OpMemoryModel Logical GLSL450
  1171. OpEntryPoint Fragment %main "main"
  1172. %void = OpTypeVoid
  1173. %bool = OpTypeBool
  1174. %bool_undef = OpUndef %bool
  1175. %uint = OpTypeInt 32 0
  1176. %uint_undef = OpUndef %uint
  1177. %void_func = OpTypeFunction %void
  1178. %main = OpFunction %void None %void_func
  1179. %entry_lab = OpLabel
  1180. OpBranch %1
  1181. %1 = OpLabel
  1182. OpLoopMerge %3 %7 None
  1183. OpBranchConditional %undef_bool %2 %3
  1184. %2 = OpLabel
  1185. OpBranchConditional %undef_bool %3 %7
  1186. %7 = OpLabel
  1187. OpLoopMerge %4 %5 None
  1188. OpBranchConditional %undef_bool %4 %6
  1189. %5 = OpLabel
  1190. OpBranch %7
  1191. %6 = OpLabel
  1192. OpBranch %4
  1193. %4 = OpLabel
  1194. OpBranch %1
  1195. %3 = OpLabel
  1196. OpReturn
  1197. OpFunctionEnd
  1198. )";
  1199. std::unique_ptr<IRContext> context =
  1200. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1201. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1202. StructuredCFGAnalysis analysis(context.get());
  1203. // The outer loop header is not in either construct.
  1204. EXPECT_EQ(analysis.ContainingConstruct(1), 0);
  1205. EXPECT_EQ(analysis.ContainingLoop(1), 0);
  1206. EXPECT_EQ(analysis.MergeBlock(1), 0);
  1207. EXPECT_EQ(analysis.NestingDepth(1), 0);
  1208. EXPECT_EQ(analysis.LoopMergeBlock(1), 0);
  1209. EXPECT_EQ(analysis.LoopNestingDepth(1), 0);
  1210. EXPECT_EQ(analysis.ContainingSwitch(1), 0);
  1211. EXPECT_EQ(analysis.SwitchMergeBlock(1), 0);
  1212. EXPECT_FALSE(analysis.IsContinueBlock(1));
  1213. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1));
  1214. EXPECT_FALSE(analysis.IsInContinueConstruct(1));
  1215. EXPECT_FALSE(analysis.IsMergeBlock(1));
  1216. // BB2 is a regular block in the inner loop.
  1217. EXPECT_EQ(analysis.ContainingConstruct(2), 1);
  1218. EXPECT_EQ(analysis.ContainingLoop(2), 1);
  1219. EXPECT_EQ(analysis.MergeBlock(2), 3);
  1220. EXPECT_EQ(analysis.NestingDepth(2), 1);
  1221. EXPECT_EQ(analysis.LoopMergeBlock(2), 3);
  1222. EXPECT_EQ(analysis.LoopNestingDepth(2), 1);
  1223. EXPECT_EQ(analysis.ContainingSwitch(2), 0);
  1224. EXPECT_EQ(analysis.SwitchMergeBlock(2), 0);
  1225. EXPECT_FALSE(analysis.IsContinueBlock(2));
  1226. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2));
  1227. EXPECT_FALSE(analysis.IsInContinueConstruct(2));
  1228. EXPECT_FALSE(analysis.IsMergeBlock(2));
  1229. // The outer merge node is not in either construct.
  1230. EXPECT_EQ(analysis.ContainingConstruct(3), 0);
  1231. EXPECT_EQ(analysis.ContainingLoop(3), 0);
  1232. EXPECT_EQ(analysis.MergeBlock(3), 0);
  1233. EXPECT_EQ(analysis.NestingDepth(3), 0);
  1234. EXPECT_EQ(analysis.LoopMergeBlock(3), 0);
  1235. EXPECT_EQ(analysis.LoopNestingDepth(3), 0);
  1236. EXPECT_EQ(analysis.ContainingSwitch(3), 0);
  1237. EXPECT_EQ(analysis.SwitchMergeBlock(3), 0);
  1238. EXPECT_FALSE(analysis.IsContinueBlock(3));
  1239. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3));
  1240. EXPECT_FALSE(analysis.IsInContinueConstruct(3));
  1241. EXPECT_TRUE(analysis.IsMergeBlock(3));
  1242. // The inner merge is in the continue of the outer loop.
  1243. EXPECT_EQ(analysis.ContainingConstruct(4), 1);
  1244. EXPECT_EQ(analysis.ContainingLoop(4), 1);
  1245. EXPECT_EQ(analysis.MergeBlock(4), 3);
  1246. EXPECT_EQ(analysis.NestingDepth(4), 1);
  1247. EXPECT_EQ(analysis.LoopMergeBlock(4), 3);
  1248. EXPECT_EQ(analysis.LoopNestingDepth(4), 1);
  1249. EXPECT_EQ(analysis.ContainingSwitch(4), 0);
  1250. EXPECT_EQ(analysis.SwitchMergeBlock(4), 0);
  1251. EXPECT_FALSE(analysis.IsContinueBlock(4));
  1252. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4));
  1253. EXPECT_TRUE(analysis.IsInContinueConstruct(4));
  1254. EXPECT_TRUE(analysis.IsMergeBlock(4));
  1255. // The inner continue target is in the inner loop.
  1256. EXPECT_EQ(analysis.ContainingConstruct(5), 7);
  1257. EXPECT_EQ(analysis.ContainingLoop(5), 7);
  1258. EXPECT_EQ(analysis.MergeBlock(5), 4);
  1259. EXPECT_EQ(analysis.NestingDepth(5), 2);
  1260. EXPECT_EQ(analysis.LoopMergeBlock(5), 4);
  1261. EXPECT_EQ(analysis.LoopNestingDepth(5), 2);
  1262. EXPECT_EQ(analysis.ContainingSwitch(5), 0);
  1263. EXPECT_EQ(analysis.SwitchMergeBlock(5), 0);
  1264. EXPECT_TRUE(analysis.IsContinueBlock(5));
  1265. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5));
  1266. EXPECT_TRUE(analysis.IsInContinueConstruct(5));
  1267. EXPECT_FALSE(analysis.IsMergeBlock(5));
  1268. // BB6 is a regular block in the inner loop.
  1269. EXPECT_EQ(analysis.ContainingConstruct(6), 7);
  1270. EXPECT_EQ(analysis.ContainingLoop(6), 7);
  1271. EXPECT_EQ(analysis.MergeBlock(6), 4);
  1272. EXPECT_EQ(analysis.NestingDepth(6), 2);
  1273. EXPECT_EQ(analysis.LoopMergeBlock(6), 4);
  1274. EXPECT_EQ(analysis.LoopNestingDepth(6), 2);
  1275. EXPECT_EQ(analysis.ContainingSwitch(6), 0);
  1276. EXPECT_EQ(analysis.SwitchMergeBlock(6), 0);
  1277. EXPECT_FALSE(analysis.IsContinueBlock(6));
  1278. EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6));
  1279. EXPECT_TRUE(analysis.IsInContinueConstruct(6));
  1280. EXPECT_FALSE(analysis.IsMergeBlock(6));
  1281. // The outer continue target is in the outer loop.
  1282. EXPECT_EQ(analysis.ContainingConstruct(7), 1);
  1283. EXPECT_EQ(analysis.ContainingLoop(7), 1);
  1284. EXPECT_EQ(analysis.MergeBlock(7), 3);
  1285. EXPECT_EQ(analysis.NestingDepth(7), 1);
  1286. EXPECT_EQ(analysis.LoopMergeBlock(7), 3);
  1287. EXPECT_EQ(analysis.LoopNestingDepth(7), 1);
  1288. EXPECT_EQ(analysis.ContainingSwitch(7), 0);
  1289. EXPECT_EQ(analysis.SwitchMergeBlock(7), 0);
  1290. EXPECT_TRUE(analysis.IsContinueBlock(7));
  1291. EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7));
  1292. EXPECT_TRUE(analysis.IsInContinueConstruct(7));
  1293. EXPECT_FALSE(analysis.IsMergeBlock(7));
  1294. }
  1295. TEST_F(StructCFGAnalysisTest, FuncCallInContinueDirect) {
  1296. const std::string text = R"(
  1297. OpCapability Shader
  1298. OpMemoryModel Logical GLSL450
  1299. OpEntryPoint Fragment %1 "main"
  1300. %void = OpTypeVoid
  1301. %bool = OpTypeBool
  1302. %4 = OpUndef %bool
  1303. %uint = OpTypeInt 32 0
  1304. %6 = OpUndef %uint
  1305. %7 = OpTypeFunction %void
  1306. %1 = OpFunction %void None %7
  1307. %8 = OpLabel
  1308. OpBranch %9
  1309. %9 = OpLabel
  1310. OpLoopMerge %10 %11 None
  1311. OpBranchConditional %12 %10 %11
  1312. %11 = OpLabel
  1313. %13 = OpFunctionCall %void %14
  1314. OpBranch %9
  1315. %10 = OpLabel
  1316. %15 = OpFunctionCall %void %16
  1317. OpReturn
  1318. OpFunctionEnd
  1319. %14 = OpFunction %void None %7
  1320. %17 = OpLabel
  1321. OpReturn
  1322. OpFunctionEnd
  1323. %16 = OpFunction %void None %7
  1324. %18 = OpLabel
  1325. OpReturn
  1326. OpFunctionEnd
  1327. )";
  1328. std::unique_ptr<IRContext> context =
  1329. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1330. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1331. StructuredCFGAnalysis analysis(context.get());
  1332. auto c = analysis.FindFuncsCalledFromContinue();
  1333. EXPECT_THAT(c, UnorderedElementsAre(14u));
  1334. }
  1335. TEST_F(StructCFGAnalysisTest, FuncCallInContinueIndirect) {
  1336. const std::string text = R"(
  1337. OpCapability Shader
  1338. OpMemoryModel Logical GLSL450
  1339. OpEntryPoint Fragment %1 "main"
  1340. %void = OpTypeVoid
  1341. %bool = OpTypeBool
  1342. %4 = OpUndef %bool
  1343. %uint = OpTypeInt 32 0
  1344. %6 = OpUndef %uint
  1345. %7 = OpTypeFunction %void
  1346. %1 = OpFunction %void None %7
  1347. %8 = OpLabel
  1348. OpBranch %9
  1349. %9 = OpLabel
  1350. OpLoopMerge %10 %11 None
  1351. OpBranchConditional %12 %10 %11
  1352. %11 = OpLabel
  1353. %13 = OpFunctionCall %void %14
  1354. OpBranch %9
  1355. %10 = OpLabel
  1356. %15 = OpFunctionCall %void %16
  1357. OpReturn
  1358. OpFunctionEnd
  1359. %14 = OpFunction %void None %7
  1360. %17 = OpLabel
  1361. %19 = OpFunctionCall %void %16
  1362. OpReturn
  1363. OpFunctionEnd
  1364. %16 = OpFunction %void None %7
  1365. %18 = OpLabel
  1366. %20 = OpFunctionCall %void %21
  1367. OpReturn
  1368. OpFunctionEnd
  1369. %21 = OpFunction %void None %7
  1370. %22 = OpLabel
  1371. OpReturn
  1372. OpFunctionEnd
  1373. )";
  1374. std::unique_ptr<IRContext> context =
  1375. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1376. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1377. StructuredCFGAnalysis analysis(context.get());
  1378. auto c = analysis.FindFuncsCalledFromContinue();
  1379. EXPECT_THAT(c, UnorderedElementsAre(14u, 16u, 21u));
  1380. }
  1381. TEST_F(StructCFGAnalysisTest, SingleBlockLoop) {
  1382. const std::string text = R"(
  1383. OpCapability Shader
  1384. OpCapability Linkage
  1385. OpMemoryModel Logical GLSL450
  1386. %void = OpTypeVoid
  1387. %bool = OpTypeBool
  1388. %undef = OpUndef %bool
  1389. %void_fn = OpTypeFunction %void
  1390. %main = OpFunction %void None %void_fn
  1391. %2 = OpLabel
  1392. OpBranch %3
  1393. %3 = OpLabel
  1394. OpLoopMerge %4 %3 None
  1395. OpBranchConditional %undef %3 %4
  1396. %4 = OpLabel
  1397. OpReturn
  1398. OpFunctionEnd
  1399. )";
  1400. std::unique_ptr<IRContext> context =
  1401. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1402. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1403. StructuredCFGAnalysis analysis(context.get());
  1404. EXPECT_TRUE(analysis.IsInContinueConstruct(3));
  1405. }
  1406. } // namespace
  1407. } // namespace opt
  1408. } // namespace spvtools