struct_cfg_analysis_test.cpp 54 KB

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