fusion_compatibility.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782
  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 <memory>
  15. #include <vector>
  16. #include "gmock/gmock.h"
  17. #include "source/opt/loop_descriptor.h"
  18. #include "source/opt/loop_fusion.h"
  19. #include "test/opt/pass_fixture.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. using FusionCompatibilityTest = PassTest<::testing::Test>;
  24. /*
  25. Generated from the following GLSL + --eliminate-local-multi-store
  26. #version 440 core
  27. void main() {
  28. int i = 0; // Can't fuse, i=0 in first & i=10 in second
  29. for (; i < 10; i++) {}
  30. for (; i < 10; i++) {}
  31. }
  32. */
  33. TEST_F(FusionCompatibilityTest, SameInductionVariableDifferentBounds) {
  34. const std::string text = R"(
  35. OpCapability Shader
  36. %1 = OpExtInstImport "GLSL.std.450"
  37. OpMemoryModel Logical GLSL450
  38. OpEntryPoint Fragment %4 "main"
  39. OpExecutionMode %4 OriginUpperLeft
  40. OpSource GLSL 440
  41. OpName %4 "main"
  42. OpName %8 "i"
  43. %2 = OpTypeVoid
  44. %3 = OpTypeFunction %2
  45. %6 = OpTypeInt 32 1
  46. %7 = OpTypePointer Function %6
  47. %9 = OpConstant %6 0
  48. %16 = OpConstant %6 10
  49. %17 = OpTypeBool
  50. %20 = OpConstant %6 1
  51. %4 = OpFunction %2 None %3
  52. %5 = OpLabel
  53. %8 = OpVariable %7 Function
  54. OpStore %8 %9
  55. OpBranch %10
  56. %10 = OpLabel
  57. %31 = OpPhi %6 %9 %5 %21 %13
  58. OpLoopMerge %12 %13 None
  59. OpBranch %14
  60. %14 = OpLabel
  61. %18 = OpSLessThan %17 %31 %16
  62. OpBranchConditional %18 %11 %12
  63. %11 = OpLabel
  64. OpBranch %13
  65. %13 = OpLabel
  66. %21 = OpIAdd %6 %31 %20
  67. OpStore %8 %21
  68. OpBranch %10
  69. %12 = OpLabel
  70. OpBranch %22
  71. %22 = OpLabel
  72. %32 = OpPhi %6 %31 %12 %30 %25
  73. OpLoopMerge %24 %25 None
  74. OpBranch %26
  75. %26 = OpLabel
  76. %28 = OpSLessThan %17 %32 %16
  77. OpBranchConditional %28 %23 %24
  78. %23 = OpLabel
  79. OpBranch %25
  80. %25 = OpLabel
  81. %30 = OpIAdd %6 %32 %20
  82. OpStore %8 %30
  83. OpBranch %22
  84. %24 = OpLabel
  85. OpReturn
  86. OpFunctionEnd
  87. )";
  88. std::unique_ptr<IRContext> context =
  89. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  90. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  91. Module* module = context->module();
  92. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  93. << text << std::endl;
  94. Function& f = *module->begin();
  95. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  96. EXPECT_EQ(ld.NumLoops(), 2u);
  97. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  98. LoopFusion fusion(context.get(), loops[0], loops[1]);
  99. EXPECT_FALSE(fusion.AreCompatible());
  100. }
  101. /*
  102. Generated from the following GLSL + --eliminate-local-multi-store
  103. // 1
  104. #version 440 core
  105. void main() {
  106. for (int i = 0; i < 10; i++) {}
  107. for (int i = 0; i < 10; i++) {}
  108. }
  109. */
  110. TEST_F(FusionCompatibilityTest, Compatible) {
  111. const std::string text = R"(
  112. OpCapability Shader
  113. %1 = OpExtInstImport "GLSL.std.450"
  114. OpMemoryModel Logical GLSL450
  115. OpEntryPoint Fragment %4 "main"
  116. OpExecutionMode %4 OriginUpperLeft
  117. OpSource GLSL 440
  118. OpName %4 "main"
  119. OpName %8 "i"
  120. OpName %22 "i"
  121. %2 = OpTypeVoid
  122. %3 = OpTypeFunction %2
  123. %6 = OpTypeInt 32 1
  124. %7 = OpTypePointer Function %6
  125. %9 = OpConstant %6 0
  126. %16 = OpConstant %6 10
  127. %17 = OpTypeBool
  128. %20 = OpConstant %6 1
  129. %4 = OpFunction %2 None %3
  130. %5 = OpLabel
  131. %8 = OpVariable %7 Function
  132. %22 = OpVariable %7 Function
  133. OpStore %8 %9
  134. OpBranch %10
  135. %10 = OpLabel
  136. %32 = OpPhi %6 %9 %5 %21 %13
  137. OpLoopMerge %12 %13 None
  138. OpBranch %14
  139. %14 = OpLabel
  140. %18 = OpSLessThan %17 %32 %16
  141. OpBranchConditional %18 %11 %12
  142. %11 = OpLabel
  143. OpBranch %13
  144. %13 = OpLabel
  145. %21 = OpIAdd %6 %32 %20
  146. OpStore %8 %21
  147. OpBranch %10
  148. %12 = OpLabel
  149. OpStore %22 %9
  150. OpBranch %23
  151. %23 = OpLabel
  152. %33 = OpPhi %6 %9 %12 %31 %26
  153. OpLoopMerge %25 %26 None
  154. OpBranch %27
  155. %27 = OpLabel
  156. %29 = OpSLessThan %17 %33 %16
  157. OpBranchConditional %29 %24 %25
  158. %24 = OpLabel
  159. OpBranch %26
  160. %26 = OpLabel
  161. %31 = OpIAdd %6 %33 %20
  162. OpStore %22 %31
  163. OpBranch %23
  164. %25 = OpLabel
  165. OpReturn
  166. OpFunctionEnd
  167. )";
  168. std::unique_ptr<IRContext> context =
  169. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  170. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  171. Module* module = context->module();
  172. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  173. << text << std::endl;
  174. Function& f = *module->begin();
  175. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  176. EXPECT_EQ(ld.NumLoops(), 2u);
  177. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  178. LoopFusion fusion(context.get(), loops[0], loops[1]);
  179. EXPECT_TRUE(fusion.AreCompatible());
  180. }
  181. /*
  182. Generated from the following GLSL + --eliminate-local-multi-store
  183. // 2
  184. #version 440 core
  185. void main() {
  186. for (int i = 0; i < 10; i++) {}
  187. for (int j = 0; j < 10; j++) {}
  188. }
  189. */
  190. TEST_F(FusionCompatibilityTest, DifferentName) {
  191. const std::string text = R"(
  192. OpCapability Shader
  193. %1 = OpExtInstImport "GLSL.std.450"
  194. OpMemoryModel Logical GLSL450
  195. OpEntryPoint Fragment %4 "main"
  196. OpExecutionMode %4 OriginUpperLeft
  197. OpSource GLSL 440
  198. OpName %4 "main"
  199. OpName %8 "i"
  200. OpName %22 "j"
  201. %2 = OpTypeVoid
  202. %3 = OpTypeFunction %2
  203. %6 = OpTypeInt 32 1
  204. %7 = OpTypePointer Function %6
  205. %9 = OpConstant %6 0
  206. %16 = OpConstant %6 10
  207. %17 = OpTypeBool
  208. %20 = OpConstant %6 1
  209. %4 = OpFunction %2 None %3
  210. %5 = OpLabel
  211. %8 = OpVariable %7 Function
  212. %22 = OpVariable %7 Function
  213. OpStore %8 %9
  214. OpBranch %10
  215. %10 = OpLabel
  216. %32 = OpPhi %6 %9 %5 %21 %13
  217. OpLoopMerge %12 %13 None
  218. OpBranch %14
  219. %14 = OpLabel
  220. %18 = OpSLessThan %17 %32 %16
  221. OpBranchConditional %18 %11 %12
  222. %11 = OpLabel
  223. OpBranch %13
  224. %13 = OpLabel
  225. %21 = OpIAdd %6 %32 %20
  226. OpStore %8 %21
  227. OpBranch %10
  228. %12 = OpLabel
  229. OpStore %22 %9
  230. OpBranch %23
  231. %23 = OpLabel
  232. %33 = OpPhi %6 %9 %12 %31 %26
  233. OpLoopMerge %25 %26 None
  234. OpBranch %27
  235. %27 = OpLabel
  236. %29 = OpSLessThan %17 %33 %16
  237. OpBranchConditional %29 %24 %25
  238. %24 = OpLabel
  239. OpBranch %26
  240. %26 = OpLabel
  241. %31 = OpIAdd %6 %33 %20
  242. OpStore %22 %31
  243. OpBranch %23
  244. %25 = OpLabel
  245. OpReturn
  246. OpFunctionEnd
  247. )";
  248. std::unique_ptr<IRContext> context =
  249. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  250. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  251. Module* module = context->module();
  252. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  253. << text << std::endl;
  254. Function& f = *module->begin();
  255. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  256. EXPECT_EQ(ld.NumLoops(), 2u);
  257. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  258. LoopFusion fusion(context.get(), loops[0], loops[1]);
  259. EXPECT_TRUE(fusion.AreCompatible());
  260. }
  261. /*
  262. Generated from the following GLSL + --eliminate-local-multi-store
  263. #version 440 core
  264. void main() {
  265. // Can't fuse, different step
  266. for (int i = 0; i < 10; i++) {}
  267. for (int j = 0; j < 10; j=j+2) {}
  268. }
  269. */
  270. TEST_F(FusionCompatibilityTest, SameBoundsDifferentStep) {
  271. const std::string text = R"(
  272. OpCapability Shader
  273. %1 = OpExtInstImport "GLSL.std.450"
  274. OpMemoryModel Logical GLSL450
  275. OpEntryPoint Fragment %4 "main"
  276. OpExecutionMode %4 OriginUpperLeft
  277. OpSource GLSL 440
  278. OpName %4 "main"
  279. OpName %8 "i"
  280. OpName %22 "j"
  281. %2 = OpTypeVoid
  282. %3 = OpTypeFunction %2
  283. %6 = OpTypeInt 32 1
  284. %7 = OpTypePointer Function %6
  285. %9 = OpConstant %6 0
  286. %16 = OpConstant %6 10
  287. %17 = OpTypeBool
  288. %20 = OpConstant %6 1
  289. %31 = OpConstant %6 2
  290. %4 = OpFunction %2 None %3
  291. %5 = OpLabel
  292. %8 = OpVariable %7 Function
  293. %22 = OpVariable %7 Function
  294. OpStore %8 %9
  295. OpBranch %10
  296. %10 = OpLabel
  297. %33 = OpPhi %6 %9 %5 %21 %13
  298. OpLoopMerge %12 %13 None
  299. OpBranch %14
  300. %14 = OpLabel
  301. %18 = OpSLessThan %17 %33 %16
  302. OpBranchConditional %18 %11 %12
  303. %11 = OpLabel
  304. OpBranch %13
  305. %13 = OpLabel
  306. %21 = OpIAdd %6 %33 %20
  307. OpStore %8 %21
  308. OpBranch %10
  309. %12 = OpLabel
  310. OpStore %22 %9
  311. OpBranch %23
  312. %23 = OpLabel
  313. %34 = OpPhi %6 %9 %12 %32 %26
  314. OpLoopMerge %25 %26 None
  315. OpBranch %27
  316. %27 = OpLabel
  317. %29 = OpSLessThan %17 %34 %16
  318. OpBranchConditional %29 %24 %25
  319. %24 = OpLabel
  320. OpBranch %26
  321. %26 = OpLabel
  322. %32 = OpIAdd %6 %34 %31
  323. OpStore %22 %32
  324. OpBranch %23
  325. %25 = OpLabel
  326. OpReturn
  327. OpFunctionEnd
  328. )";
  329. std::unique_ptr<IRContext> context =
  330. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  331. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  332. Module* module = context->module();
  333. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  334. << text << std::endl;
  335. Function& f = *module->begin();
  336. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  337. EXPECT_EQ(ld.NumLoops(), 2u);
  338. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  339. LoopFusion fusion(context.get(), loops[0], loops[1]);
  340. EXPECT_FALSE(fusion.AreCompatible());
  341. }
  342. /*
  343. Generated from the following GLSL + --eliminate-local-multi-store
  344. // 4
  345. #version 440 core
  346. void main() {
  347. // Can't fuse, different upper bound
  348. for (int i = 0; i < 10; i++) {}
  349. for (int j = 0; j < 20; j++) {}
  350. }
  351. */
  352. TEST_F(FusionCompatibilityTest, DifferentUpperBound) {
  353. const std::string text = R"(
  354. OpCapability Shader
  355. %1 = OpExtInstImport "GLSL.std.450"
  356. OpMemoryModel Logical GLSL450
  357. OpEntryPoint Fragment %4 "main"
  358. OpExecutionMode %4 OriginUpperLeft
  359. OpSource GLSL 440
  360. OpName %4 "main"
  361. OpName %8 "i"
  362. OpName %22 "j"
  363. %2 = OpTypeVoid
  364. %3 = OpTypeFunction %2
  365. %6 = OpTypeInt 32 1
  366. %7 = OpTypePointer Function %6
  367. %9 = OpConstant %6 0
  368. %16 = OpConstant %6 10
  369. %17 = OpTypeBool
  370. %20 = OpConstant %6 1
  371. %29 = OpConstant %6 20
  372. %4 = OpFunction %2 None %3
  373. %5 = OpLabel
  374. %8 = OpVariable %7 Function
  375. %22 = OpVariable %7 Function
  376. OpStore %8 %9
  377. OpBranch %10
  378. %10 = OpLabel
  379. %33 = OpPhi %6 %9 %5 %21 %13
  380. OpLoopMerge %12 %13 None
  381. OpBranch %14
  382. %14 = OpLabel
  383. %18 = OpSLessThan %17 %33 %16
  384. OpBranchConditional %18 %11 %12
  385. %11 = OpLabel
  386. OpBranch %13
  387. %13 = OpLabel
  388. %21 = OpIAdd %6 %33 %20
  389. OpStore %8 %21
  390. OpBranch %10
  391. %12 = OpLabel
  392. OpStore %22 %9
  393. OpBranch %23
  394. %23 = OpLabel
  395. %34 = OpPhi %6 %9 %12 %32 %26
  396. OpLoopMerge %25 %26 None
  397. OpBranch %27
  398. %27 = OpLabel
  399. %30 = OpSLessThan %17 %34 %29
  400. OpBranchConditional %30 %24 %25
  401. %24 = OpLabel
  402. OpBranch %26
  403. %26 = OpLabel
  404. %32 = OpIAdd %6 %34 %20
  405. OpStore %22 %32
  406. OpBranch %23
  407. %25 = OpLabel
  408. OpReturn
  409. OpFunctionEnd
  410. )";
  411. std::unique_ptr<IRContext> context =
  412. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  413. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  414. Module* module = context->module();
  415. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  416. << text << std::endl;
  417. Function& f = *module->begin();
  418. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  419. EXPECT_EQ(ld.NumLoops(), 2u);
  420. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  421. LoopFusion fusion(context.get(), loops[0], loops[1]);
  422. EXPECT_FALSE(fusion.AreCompatible());
  423. }
  424. /*
  425. Generated from the following GLSL + --eliminate-local-multi-store
  426. // 5
  427. #version 440 core
  428. void main() {
  429. // Can't fuse, different lower bound
  430. for (int i = 5; i < 10; i++) {}
  431. for (int j = 0; j < 10; j++) {}
  432. }
  433. */
  434. TEST_F(FusionCompatibilityTest, DifferentLowerBound) {
  435. const std::string text = R"(
  436. OpCapability Shader
  437. %1 = OpExtInstImport "GLSL.std.450"
  438. OpMemoryModel Logical GLSL450
  439. OpEntryPoint Fragment %4 "main"
  440. OpExecutionMode %4 OriginUpperLeft
  441. OpSource GLSL 440
  442. OpName %4 "main"
  443. OpName %8 "i"
  444. OpName %22 "j"
  445. %2 = OpTypeVoid
  446. %3 = OpTypeFunction %2
  447. %6 = OpTypeInt 32 1
  448. %7 = OpTypePointer Function %6
  449. %9 = OpConstant %6 5
  450. %16 = OpConstant %6 10
  451. %17 = OpTypeBool
  452. %20 = OpConstant %6 1
  453. %23 = OpConstant %6 0
  454. %4 = OpFunction %2 None %3
  455. %5 = OpLabel
  456. %8 = OpVariable %7 Function
  457. %22 = OpVariable %7 Function
  458. OpStore %8 %9
  459. OpBranch %10
  460. %10 = OpLabel
  461. %33 = OpPhi %6 %9 %5 %21 %13
  462. OpLoopMerge %12 %13 None
  463. OpBranch %14
  464. %14 = OpLabel
  465. %18 = OpSLessThan %17 %33 %16
  466. OpBranchConditional %18 %11 %12
  467. %11 = OpLabel
  468. OpBranch %13
  469. %13 = OpLabel
  470. %21 = OpIAdd %6 %33 %20
  471. OpStore %8 %21
  472. OpBranch %10
  473. %12 = OpLabel
  474. OpStore %22 %23
  475. OpBranch %24
  476. %24 = OpLabel
  477. %34 = OpPhi %6 %23 %12 %32 %27
  478. OpLoopMerge %26 %27 None
  479. OpBranch %28
  480. %28 = OpLabel
  481. %30 = OpSLessThan %17 %34 %16
  482. OpBranchConditional %30 %25 %26
  483. %25 = OpLabel
  484. OpBranch %27
  485. %27 = OpLabel
  486. %32 = OpIAdd %6 %34 %20
  487. OpStore %22 %32
  488. OpBranch %24
  489. %26 = OpLabel
  490. OpReturn
  491. OpFunctionEnd
  492. )";
  493. std::unique_ptr<IRContext> context =
  494. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  495. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  496. Module* module = context->module();
  497. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  498. << text << std::endl;
  499. Function& f = *module->begin();
  500. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  501. EXPECT_EQ(ld.NumLoops(), 2u);
  502. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  503. LoopFusion fusion(context.get(), loops[0], loops[1]);
  504. EXPECT_FALSE(fusion.AreCompatible());
  505. }
  506. /*
  507. Generated from the following GLSL + --eliminate-local-multi-store
  508. // 6
  509. #version 440 core
  510. void main() {
  511. // Can't fuse, break in first loop
  512. for (int i = 0; i < 10; i++) {
  513. if (i == 5) {
  514. break;
  515. }
  516. }
  517. for (int j = 0; j < 10; j++) {}
  518. }
  519. */
  520. TEST_F(FusionCompatibilityTest, Break) {
  521. const std::string text = R"(
  522. OpCapability Shader
  523. %1 = OpExtInstImport "GLSL.std.450"
  524. OpMemoryModel Logical GLSL450
  525. OpEntryPoint Fragment %4 "main"
  526. OpExecutionMode %4 OriginUpperLeft
  527. OpSource GLSL 440
  528. OpName %4 "main"
  529. OpName %8 "i"
  530. OpName %28 "j"
  531. %2 = OpTypeVoid
  532. %3 = OpTypeFunction %2
  533. %6 = OpTypeInt 32 1
  534. %7 = OpTypePointer Function %6
  535. %9 = OpConstant %6 0
  536. %16 = OpConstant %6 10
  537. %17 = OpTypeBool
  538. %20 = OpConstant %6 5
  539. %26 = OpConstant %6 1
  540. %4 = OpFunction %2 None %3
  541. %5 = OpLabel
  542. %8 = OpVariable %7 Function
  543. %28 = OpVariable %7 Function
  544. OpStore %8 %9
  545. OpBranch %10
  546. %10 = OpLabel
  547. %38 = OpPhi %6 %9 %5 %27 %13
  548. OpLoopMerge %12 %13 None
  549. OpBranch %14
  550. %14 = OpLabel
  551. %18 = OpSLessThan %17 %38 %16
  552. OpBranchConditional %18 %11 %12
  553. %11 = OpLabel
  554. %21 = OpIEqual %17 %38 %20
  555. OpSelectionMerge %23 None
  556. OpBranchConditional %21 %22 %23
  557. %22 = OpLabel
  558. OpBranch %12
  559. %23 = OpLabel
  560. OpBranch %13
  561. %13 = OpLabel
  562. %27 = OpIAdd %6 %38 %26
  563. OpStore %8 %27
  564. OpBranch %10
  565. %12 = OpLabel
  566. OpStore %28 %9
  567. OpBranch %29
  568. %29 = OpLabel
  569. %39 = OpPhi %6 %9 %12 %37 %32
  570. OpLoopMerge %31 %32 None
  571. OpBranch %33
  572. %33 = OpLabel
  573. %35 = OpSLessThan %17 %39 %16
  574. OpBranchConditional %35 %30 %31
  575. %30 = OpLabel
  576. OpBranch %32
  577. %32 = OpLabel
  578. %37 = OpIAdd %6 %39 %26
  579. OpStore %28 %37
  580. OpBranch %29
  581. %31 = OpLabel
  582. OpReturn
  583. OpFunctionEnd
  584. )";
  585. std::unique_ptr<IRContext> context =
  586. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  587. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  588. Module* module = context->module();
  589. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  590. << text << std::endl;
  591. Function& f = *module->begin();
  592. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  593. EXPECT_EQ(ld.NumLoops(), 2u);
  594. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  595. LoopFusion fusion(context.get(), loops[0], loops[1]);
  596. EXPECT_FALSE(fusion.AreCompatible());
  597. }
  598. /*
  599. Generated from the following GLSL + --eliminate-local-multi-store
  600. #version 440 core
  601. layout(location = 0) in vec4 c;
  602. void main() {
  603. int N = int(c.x);
  604. for (int i = 0; i < N; i++) {}
  605. for (int j = 0; j < N; j++) {}
  606. }
  607. */
  608. TEST_F(FusionCompatibilityTest, UnknownButSameUpperBound) {
  609. const std::string text = R"(
  610. OpCapability Shader
  611. %1 = OpExtInstImport "GLSL.std.450"
  612. OpMemoryModel Logical GLSL450
  613. OpEntryPoint Fragment %4 "main" %12
  614. OpExecutionMode %4 OriginUpperLeft
  615. OpSource GLSL 440
  616. OpName %4 "main"
  617. OpName %8 "N"
  618. OpName %12 "c"
  619. OpName %19 "i"
  620. OpName %33 "j"
  621. OpDecorate %12 Location 0
  622. %2 = OpTypeVoid
  623. %3 = OpTypeFunction %2
  624. %6 = OpTypeInt 32 1
  625. %7 = OpTypePointer Function %6
  626. %9 = OpTypeFloat 32
  627. %10 = OpTypeVector %9 4
  628. %11 = OpTypePointer Input %10
  629. %12 = OpVariable %11 Input
  630. %13 = OpTypeInt 32 0
  631. %14 = OpConstant %13 0
  632. %15 = OpTypePointer Input %9
  633. %20 = OpConstant %6 0
  634. %28 = OpTypeBool
  635. %31 = OpConstant %6 1
  636. %4 = OpFunction %2 None %3
  637. %5 = OpLabel
  638. %8 = OpVariable %7 Function
  639. %19 = OpVariable %7 Function
  640. %33 = OpVariable %7 Function
  641. %16 = OpAccessChain %15 %12 %14
  642. %17 = OpLoad %9 %16
  643. %18 = OpConvertFToS %6 %17
  644. OpStore %8 %18
  645. OpStore %19 %20
  646. OpBranch %21
  647. %21 = OpLabel
  648. %44 = OpPhi %6 %20 %5 %32 %24
  649. OpLoopMerge %23 %24 None
  650. OpBranch %25
  651. %25 = OpLabel
  652. %29 = OpSLessThan %28 %44 %18
  653. OpBranchConditional %29 %22 %23
  654. %22 = OpLabel
  655. OpBranch %24
  656. %24 = OpLabel
  657. %32 = OpIAdd %6 %44 %31
  658. OpStore %19 %32
  659. OpBranch %21
  660. %23 = OpLabel
  661. OpStore %33 %20
  662. OpBranch %34
  663. %34 = OpLabel
  664. %46 = OpPhi %6 %20 %23 %43 %37
  665. OpLoopMerge %36 %37 None
  666. OpBranch %38
  667. %38 = OpLabel
  668. %41 = OpSLessThan %28 %46 %18
  669. OpBranchConditional %41 %35 %36
  670. %35 = OpLabel
  671. OpBranch %37
  672. %37 = OpLabel
  673. %43 = OpIAdd %6 %46 %31
  674. OpStore %33 %43
  675. OpBranch %34
  676. %36 = OpLabel
  677. OpReturn
  678. OpFunctionEnd
  679. )";
  680. std::unique_ptr<IRContext> context =
  681. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  682. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  683. Module* module = context->module();
  684. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  685. << text << std::endl;
  686. Function& f = *module->begin();
  687. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  688. EXPECT_EQ(ld.NumLoops(), 2u);
  689. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  690. LoopFusion fusion(context.get(), loops[0], loops[1]);
  691. EXPECT_TRUE(fusion.AreCompatible());
  692. }
  693. /*
  694. Generated from the following GLSL + --eliminate-local-multi-store
  695. #version 440 core
  696. layout(location = 0) in vec4 c;
  697. void main() {
  698. int N = int(c.x);
  699. for (int i = 0; N > j; i++) {}
  700. for (int j = 0; N > j; j++) {}
  701. }
  702. */
  703. TEST_F(FusionCompatibilityTest, UnknownButSameUpperBoundReverseCondition) {
  704. const std::string text = R"(
  705. OpCapability Shader
  706. %1 = OpExtInstImport "GLSL.std.450"
  707. OpMemoryModel Logical GLSL450
  708. OpEntryPoint Fragment %4 "main" %12
  709. OpExecutionMode %4 OriginUpperLeft
  710. OpSource GLSL 440
  711. OpName %4 "main"
  712. OpName %8 "N"
  713. OpName %12 "c"
  714. OpName %19 "i"
  715. OpName %33 "j"
  716. OpDecorate %12 Location 0
  717. %2 = OpTypeVoid
  718. %3 = OpTypeFunction %2
  719. %6 = OpTypeInt 32 1
  720. %7 = OpTypePointer Function %6
  721. %9 = OpTypeFloat 32
  722. %10 = OpTypeVector %9 4
  723. %11 = OpTypePointer Input %10
  724. %12 = OpVariable %11 Input
  725. %13 = OpTypeInt 32 0
  726. %14 = OpConstant %13 0
  727. %15 = OpTypePointer Input %9
  728. %20 = OpConstant %6 0
  729. %28 = OpTypeBool
  730. %31 = OpConstant %6 1
  731. %4 = OpFunction %2 None %3
  732. %5 = OpLabel
  733. %8 = OpVariable %7 Function
  734. %19 = OpVariable %7 Function
  735. %33 = OpVariable %7 Function
  736. %16 = OpAccessChain %15 %12 %14
  737. %17 = OpLoad %9 %16
  738. %18 = OpConvertFToS %6 %17
  739. OpStore %8 %18
  740. OpStore %19 %20
  741. OpBranch %21
  742. %21 = OpLabel
  743. %45 = OpPhi %6 %20 %5 %32 %24
  744. OpLoopMerge %23 %24 None
  745. OpBranch %25
  746. %25 = OpLabel
  747. %29 = OpSGreaterThan %28 %18 %45
  748. OpBranchConditional %29 %22 %23
  749. %22 = OpLabel
  750. OpBranch %24
  751. %24 = OpLabel
  752. %32 = OpIAdd %6 %45 %31
  753. OpStore %19 %32
  754. OpBranch %21
  755. %23 = OpLabel
  756. OpStore %33 %20
  757. OpBranch %34
  758. %34 = OpLabel
  759. %47 = OpPhi %6 %20 %23 %43 %37
  760. OpLoopMerge %36 %37 None
  761. OpBranch %38
  762. %38 = OpLabel
  763. %41 = OpSGreaterThan %28 %18 %47
  764. OpBranchConditional %41 %35 %36
  765. %35 = OpLabel
  766. OpBranch %37
  767. %37 = OpLabel
  768. %43 = OpIAdd %6 %47 %31
  769. OpStore %33 %43
  770. OpBranch %34
  771. %36 = 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. Module* module = context->module();
  779. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  780. << text << std::endl;
  781. Function& f = *module->begin();
  782. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  783. EXPECT_EQ(ld.NumLoops(), 2u);
  784. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  785. LoopFusion fusion(context.get(), loops[0], loops[1]);
  786. EXPECT_TRUE(fusion.AreCompatible());
  787. }
  788. /*
  789. Generated from the following GLSL + --eliminate-local-multi-store
  790. #version 440 core
  791. layout(location = 0) in vec4 c;
  792. void main() {
  793. // Can't fuse different bound
  794. int N = int(c.x);
  795. for (int i = 0; i < N; i++) {}
  796. for (int j = 0; j < N+1; j++) {}
  797. }
  798. */
  799. TEST_F(FusionCompatibilityTest, UnknownUpperBoundAddition) {
  800. const std::string text = R"(
  801. OpCapability Shader
  802. %1 = OpExtInstImport "GLSL.std.450"
  803. OpMemoryModel Logical GLSL450
  804. OpEntryPoint Fragment %4 "main" %12
  805. OpExecutionMode %4 OriginUpperLeft
  806. OpSource GLSL 440
  807. OpName %4 "main"
  808. OpName %8 "N"
  809. OpName %12 "c"
  810. OpName %19 "i"
  811. OpName %33 "j"
  812. OpDecorate %12 Location 0
  813. %2 = OpTypeVoid
  814. %3 = OpTypeFunction %2
  815. %6 = OpTypeInt 32 1
  816. %7 = OpTypePointer Function %6
  817. %9 = OpTypeFloat 32
  818. %10 = OpTypeVector %9 4
  819. %11 = OpTypePointer Input %10
  820. %12 = OpVariable %11 Input
  821. %13 = OpTypeInt 32 0
  822. %14 = OpConstant %13 0
  823. %15 = OpTypePointer Input %9
  824. %20 = OpConstant %6 0
  825. %28 = OpTypeBool
  826. %31 = OpConstant %6 1
  827. %4 = OpFunction %2 None %3
  828. %5 = OpLabel
  829. %8 = OpVariable %7 Function
  830. %19 = OpVariable %7 Function
  831. %33 = OpVariable %7 Function
  832. %16 = OpAccessChain %15 %12 %14
  833. %17 = OpLoad %9 %16
  834. %18 = OpConvertFToS %6 %17
  835. OpStore %8 %18
  836. OpStore %19 %20
  837. OpBranch %21
  838. %21 = OpLabel
  839. %45 = OpPhi %6 %20 %5 %32 %24
  840. OpLoopMerge %23 %24 None
  841. OpBranch %25
  842. %25 = OpLabel
  843. %29 = OpSLessThan %28 %45 %18
  844. OpBranchConditional %29 %22 %23
  845. %22 = OpLabel
  846. OpBranch %24
  847. %24 = OpLabel
  848. %32 = OpIAdd %6 %45 %31
  849. OpStore %19 %32
  850. OpBranch %21
  851. %23 = OpLabel
  852. OpStore %33 %20
  853. OpBranch %34
  854. %34 = OpLabel
  855. %47 = OpPhi %6 %20 %23 %44 %37
  856. OpLoopMerge %36 %37 None
  857. OpBranch %38
  858. %38 = OpLabel
  859. %41 = OpIAdd %6 %18 %31
  860. %42 = OpSLessThan %28 %47 %41
  861. OpBranchConditional %42 %35 %36
  862. %35 = OpLabel
  863. OpBranch %37
  864. %37 = OpLabel
  865. %44 = OpIAdd %6 %47 %31
  866. OpStore %33 %44
  867. OpBranch %34
  868. %36 = OpLabel
  869. OpReturn
  870. OpFunctionEnd
  871. )";
  872. std::unique_ptr<IRContext> context =
  873. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  874. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  875. Module* module = context->module();
  876. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  877. << text << std::endl;
  878. Function& f = *module->begin();
  879. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  880. EXPECT_EQ(ld.NumLoops(), 2u);
  881. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  882. LoopFusion fusion(context.get(), loops[0], loops[1]);
  883. EXPECT_FALSE(fusion.AreCompatible());
  884. }
  885. /*
  886. Generated from the following GLSL + --eliminate-local-multi-store
  887. // 10
  888. #version 440 core
  889. void main() {
  890. for (int i = 0; i < 10; i++) {}
  891. for (int j = 0; j < 10; j++) {}
  892. for (int k = 0; k < 10; k++) {}
  893. }
  894. */
  895. TEST_F(FusionCompatibilityTest, SeveralAdjacentLoops) {
  896. const std::string text = R"(
  897. OpCapability Shader
  898. %1 = OpExtInstImport "GLSL.std.450"
  899. OpMemoryModel Logical GLSL450
  900. OpEntryPoint Fragment %4 "main"
  901. OpExecutionMode %4 OriginUpperLeft
  902. OpSource GLSL 440
  903. OpName %4 "main"
  904. OpName %8 "i"
  905. OpName %22 "j"
  906. OpName %32 "k"
  907. %2 = OpTypeVoid
  908. %3 = OpTypeFunction %2
  909. %6 = OpTypeInt 32 1
  910. %7 = OpTypePointer Function %6
  911. %9 = OpConstant %6 0
  912. %16 = OpConstant %6 10
  913. %17 = OpTypeBool
  914. %20 = OpConstant %6 1
  915. %4 = OpFunction %2 None %3
  916. %5 = OpLabel
  917. %8 = OpVariable %7 Function
  918. %22 = OpVariable %7 Function
  919. %32 = OpVariable %7 Function
  920. OpStore %8 %9
  921. OpBranch %10
  922. %10 = OpLabel
  923. %42 = OpPhi %6 %9 %5 %21 %13
  924. OpLoopMerge %12 %13 None
  925. OpBranch %14
  926. %14 = OpLabel
  927. %18 = OpSLessThan %17 %42 %16
  928. OpBranchConditional %18 %11 %12
  929. %11 = OpLabel
  930. OpBranch %13
  931. %13 = OpLabel
  932. %21 = OpIAdd %6 %42 %20
  933. OpStore %8 %21
  934. OpBranch %10
  935. %12 = OpLabel
  936. OpStore %22 %9
  937. OpBranch %23
  938. %23 = OpLabel
  939. %43 = OpPhi %6 %9 %12 %31 %26
  940. OpLoopMerge %25 %26 None
  941. OpBranch %27
  942. %27 = OpLabel
  943. %29 = OpSLessThan %17 %43 %16
  944. OpBranchConditional %29 %24 %25
  945. %24 = OpLabel
  946. OpBranch %26
  947. %26 = OpLabel
  948. %31 = OpIAdd %6 %43 %20
  949. OpStore %22 %31
  950. OpBranch %23
  951. %25 = OpLabel
  952. OpStore %32 %9
  953. OpBranch %33
  954. %33 = OpLabel
  955. %44 = OpPhi %6 %9 %25 %41 %36
  956. OpLoopMerge %35 %36 None
  957. OpBranch %37
  958. %37 = OpLabel
  959. %39 = OpSLessThan %17 %44 %16
  960. OpBranchConditional %39 %34 %35
  961. %34 = OpLabel
  962. OpBranch %36
  963. %36 = OpLabel
  964. %41 = OpIAdd %6 %44 %20
  965. OpStore %32 %41
  966. OpBranch %33
  967. %35 = OpLabel
  968. OpReturn
  969. OpFunctionEnd
  970. )";
  971. std::unique_ptr<IRContext> context =
  972. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  973. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  974. Module* module = context->module();
  975. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  976. << text << std::endl;
  977. Function& f = *module->begin();
  978. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  979. EXPECT_EQ(ld.NumLoops(), 3u);
  980. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  981. auto loop_0 = loops[0];
  982. auto loop_1 = loops[1];
  983. auto loop_2 = loops[2];
  984. EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_0).AreCompatible());
  985. EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_2).AreCompatible());
  986. EXPECT_FALSE(LoopFusion(context.get(), loop_1, loop_0).AreCompatible());
  987. EXPECT_TRUE(LoopFusion(context.get(), loop_0, loop_1).AreCompatible());
  988. EXPECT_TRUE(LoopFusion(context.get(), loop_1, loop_2).AreCompatible());
  989. }
  990. /*
  991. Generated from the following GLSL + --eliminate-local-multi-store
  992. #version 440 core
  993. void main() {
  994. // Can't fuse, not adjacent
  995. int x = 0;
  996. for (int i = 0; i < 10; i++) {
  997. if (i > 10) {
  998. x++;
  999. }
  1000. }
  1001. x++;
  1002. for (int j = 0; j < 10; j++) {}
  1003. for (int k = 0; k < 10; k++) {}
  1004. }
  1005. */
  1006. TEST_F(FusionCompatibilityTest, NonAdjacentLoops) {
  1007. const std::string text = R"(
  1008. OpCapability Shader
  1009. %1 = OpExtInstImport "GLSL.std.450"
  1010. OpMemoryModel Logical GLSL450
  1011. OpEntryPoint Fragment %4 "main"
  1012. OpExecutionMode %4 OriginUpperLeft
  1013. OpSource GLSL 440
  1014. OpName %4 "main"
  1015. OpName %8 "x"
  1016. OpName %10 "i"
  1017. OpName %31 "j"
  1018. OpName %41 "k"
  1019. %2 = OpTypeVoid
  1020. %3 = OpTypeFunction %2
  1021. %6 = OpTypeInt 32 1
  1022. %7 = OpTypePointer Function %6
  1023. %9 = OpConstant %6 0
  1024. %17 = OpConstant %6 10
  1025. %18 = OpTypeBool
  1026. %25 = OpConstant %6 1
  1027. %4 = OpFunction %2 None %3
  1028. %5 = OpLabel
  1029. %8 = OpVariable %7 Function
  1030. %10 = OpVariable %7 Function
  1031. %31 = OpVariable %7 Function
  1032. %41 = OpVariable %7 Function
  1033. OpStore %8 %9
  1034. OpStore %10 %9
  1035. OpBranch %11
  1036. %11 = OpLabel
  1037. %52 = OpPhi %6 %9 %5 %56 %14
  1038. %51 = OpPhi %6 %9 %5 %28 %14
  1039. OpLoopMerge %13 %14 None
  1040. OpBranch %15
  1041. %15 = OpLabel
  1042. %19 = OpSLessThan %18 %51 %17
  1043. OpBranchConditional %19 %12 %13
  1044. %12 = OpLabel
  1045. %21 = OpSGreaterThan %18 %52 %17
  1046. OpSelectionMerge %23 None
  1047. OpBranchConditional %21 %22 %23
  1048. %22 = OpLabel
  1049. %26 = OpIAdd %6 %52 %25
  1050. OpStore %8 %26
  1051. OpBranch %23
  1052. %23 = OpLabel
  1053. %56 = OpPhi %6 %52 %12 %26 %22
  1054. OpBranch %14
  1055. %14 = OpLabel
  1056. %28 = OpIAdd %6 %51 %25
  1057. OpStore %10 %28
  1058. OpBranch %11
  1059. %13 = OpLabel
  1060. %30 = OpIAdd %6 %52 %25
  1061. OpStore %8 %30
  1062. OpStore %31 %9
  1063. OpBranch %32
  1064. %32 = OpLabel
  1065. %53 = OpPhi %6 %9 %13 %40 %35
  1066. OpLoopMerge %34 %35 None
  1067. OpBranch %36
  1068. %36 = OpLabel
  1069. %38 = OpSLessThan %18 %53 %17
  1070. OpBranchConditional %38 %33 %34
  1071. %33 = OpLabel
  1072. OpBranch %35
  1073. %35 = OpLabel
  1074. %40 = OpIAdd %6 %53 %25
  1075. OpStore %31 %40
  1076. OpBranch %32
  1077. %34 = OpLabel
  1078. OpStore %41 %9
  1079. OpBranch %42
  1080. %42 = OpLabel
  1081. %54 = OpPhi %6 %9 %34 %50 %45
  1082. OpLoopMerge %44 %45 None
  1083. OpBranch %46
  1084. %46 = OpLabel
  1085. %48 = OpSLessThan %18 %54 %17
  1086. OpBranchConditional %48 %43 %44
  1087. %43 = OpLabel
  1088. OpBranch %45
  1089. %45 = OpLabel
  1090. %50 = OpIAdd %6 %54 %25
  1091. OpStore %41 %50
  1092. OpBranch %42
  1093. %44 = OpLabel
  1094. OpReturn
  1095. OpFunctionEnd
  1096. )";
  1097. std::unique_ptr<IRContext> context =
  1098. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1099. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1100. Module* module = context->module();
  1101. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1102. << text << std::endl;
  1103. Function& f = *module->begin();
  1104. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1105. EXPECT_EQ(ld.NumLoops(), 3u);
  1106. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1107. auto loop_0 = loops[0];
  1108. auto loop_1 = loops[1];
  1109. auto loop_2 = loops[2];
  1110. EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_0).AreCompatible());
  1111. EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_2).AreCompatible());
  1112. EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_1).AreCompatible());
  1113. EXPECT_TRUE(LoopFusion(context.get(), loop_1, loop_2).AreCompatible());
  1114. }
  1115. /*
  1116. Generated from the following GLSL + --eliminate-local-multi-store
  1117. // 12
  1118. #version 440 core
  1119. void main() {
  1120. int j = 0;
  1121. int i = 0;
  1122. for (; i < 10; i++) {}
  1123. for (; j < 10; j++) {}
  1124. }
  1125. */
  1126. TEST_F(FusionCompatibilityTest, CompatibleInitDeclaredBeforeLoops) {
  1127. const std::string text = R"(
  1128. OpCapability Shader
  1129. %1 = OpExtInstImport "GLSL.std.450"
  1130. OpMemoryModel Logical GLSL450
  1131. OpEntryPoint Fragment %4 "main"
  1132. OpExecutionMode %4 OriginUpperLeft
  1133. OpSource GLSL 440
  1134. OpName %4 "main"
  1135. OpName %8 "j"
  1136. OpName %10 "i"
  1137. %2 = OpTypeVoid
  1138. %3 = OpTypeFunction %2
  1139. %6 = OpTypeInt 32 1
  1140. %7 = OpTypePointer Function %6
  1141. %9 = OpConstant %6 0
  1142. %17 = OpConstant %6 10
  1143. %18 = OpTypeBool
  1144. %21 = OpConstant %6 1
  1145. %4 = OpFunction %2 None %3
  1146. %5 = OpLabel
  1147. %8 = OpVariable %7 Function
  1148. %10 = OpVariable %7 Function
  1149. OpStore %8 %9
  1150. OpStore %10 %9
  1151. OpBranch %11
  1152. %11 = OpLabel
  1153. %32 = OpPhi %6 %9 %5 %22 %14
  1154. OpLoopMerge %13 %14 None
  1155. OpBranch %15
  1156. %15 = OpLabel
  1157. %19 = OpSLessThan %18 %32 %17
  1158. OpBranchConditional %19 %12 %13
  1159. %12 = OpLabel
  1160. OpBranch %14
  1161. %14 = OpLabel
  1162. %22 = OpIAdd %6 %32 %21
  1163. OpStore %10 %22
  1164. OpBranch %11
  1165. %13 = OpLabel
  1166. OpBranch %23
  1167. %23 = OpLabel
  1168. %33 = OpPhi %6 %9 %13 %31 %26
  1169. OpLoopMerge %25 %26 None
  1170. OpBranch %27
  1171. %27 = OpLabel
  1172. %29 = OpSLessThan %18 %33 %17
  1173. OpBranchConditional %29 %24 %25
  1174. %24 = OpLabel
  1175. OpBranch %26
  1176. %26 = OpLabel
  1177. %31 = OpIAdd %6 %33 %21
  1178. OpStore %8 %31
  1179. OpBranch %23
  1180. %25 = OpLabel
  1181. OpReturn
  1182. OpFunctionEnd
  1183. )";
  1184. std::unique_ptr<IRContext> context =
  1185. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1186. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1187. Module* module = context->module();
  1188. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1189. << text << std::endl;
  1190. Function& f = *module->begin();
  1191. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1192. EXPECT_EQ(ld.NumLoops(), 2u);
  1193. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1194. EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1195. }
  1196. /*
  1197. Generated from the following GLSL + --eliminate-local-multi-store
  1198. // 13 regenerate!
  1199. #version 440 core
  1200. void main() {
  1201. int[10] a;
  1202. int[10] b;
  1203. // Can't fuse, several induction variables
  1204. for (int j = 0; j < 10; j++) {
  1205. b[i] = a[i];
  1206. }
  1207. for (int i = 0, j = 0; i < 10; i++, j = j+2) {
  1208. }
  1209. }
  1210. */
  1211. TEST_F(FusionCompatibilityTest, SeveralInductionVariables) {
  1212. const std::string text = R"(
  1213. OpCapability Shader
  1214. %1 = OpExtInstImport "GLSL.std.450"
  1215. OpMemoryModel Logical GLSL450
  1216. OpEntryPoint Fragment %4 "main"
  1217. OpExecutionMode %4 OriginUpperLeft
  1218. OpSource GLSL 440
  1219. OpName %4 "main"
  1220. OpName %8 "j"
  1221. OpName %23 "b"
  1222. OpName %25 "a"
  1223. OpName %33 "i"
  1224. OpName %34 "j"
  1225. %2 = OpTypeVoid
  1226. %3 = OpTypeFunction %2
  1227. %6 = OpTypeInt 32 1
  1228. %7 = OpTypePointer Function %6
  1229. %9 = OpConstant %6 0
  1230. %16 = OpConstant %6 10
  1231. %17 = OpTypeBool
  1232. %19 = OpTypeInt 32 0
  1233. %20 = OpConstant %19 10
  1234. %21 = OpTypeArray %6 %20
  1235. %22 = OpTypePointer Function %21
  1236. %31 = OpConstant %6 1
  1237. %48 = OpConstant %6 2
  1238. %4 = OpFunction %2 None %3
  1239. %5 = OpLabel
  1240. %8 = OpVariable %7 Function
  1241. %23 = OpVariable %22 Function
  1242. %25 = OpVariable %22 Function
  1243. %33 = OpVariable %7 Function
  1244. %34 = OpVariable %7 Function
  1245. OpStore %8 %9
  1246. OpBranch %10
  1247. %10 = OpLabel
  1248. %50 = OpPhi %6 %9 %5 %32 %13
  1249. OpLoopMerge %12 %13 None
  1250. OpBranch %14
  1251. %14 = OpLabel
  1252. %18 = OpSLessThan %17 %50 %16
  1253. OpBranchConditional %18 %11 %12
  1254. %11 = OpLabel
  1255. %27 = OpAccessChain %7 %25 %50
  1256. %28 = OpLoad %6 %27
  1257. %29 = OpAccessChain %7 %23 %50
  1258. OpStore %29 %28
  1259. OpBranch %13
  1260. %13 = OpLabel
  1261. %32 = OpIAdd %6 %50 %31
  1262. OpStore %8 %32
  1263. OpBranch %10
  1264. %12 = OpLabel
  1265. OpStore %33 %9
  1266. OpStore %34 %9
  1267. OpBranch %35
  1268. %35 = OpLabel
  1269. %52 = OpPhi %6 %9 %12 %49 %38
  1270. %51 = OpPhi %6 %9 %12 %46 %38
  1271. OpLoopMerge %37 %38 None
  1272. OpBranch %39
  1273. %39 = OpLabel
  1274. %41 = OpSLessThan %17 %51 %16
  1275. OpBranchConditional %41 %36 %37
  1276. %36 = OpLabel
  1277. %44 = OpAccessChain %7 %25 %52
  1278. OpStore %44 %51
  1279. OpBranch %38
  1280. %38 = OpLabel
  1281. %46 = OpIAdd %6 %51 %31
  1282. OpStore %33 %46
  1283. %49 = OpIAdd %6 %52 %48
  1284. OpStore %34 %49
  1285. OpBranch %35
  1286. %37 = OpLabel
  1287. OpReturn
  1288. OpFunctionEnd
  1289. )";
  1290. std::unique_ptr<IRContext> context =
  1291. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1292. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1293. Module* module = context->module();
  1294. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1295. << text << std::endl;
  1296. Function& f = *module->begin();
  1297. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1298. EXPECT_EQ(ld.NumLoops(), 2u);
  1299. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1300. EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1301. }
  1302. /*
  1303. Generated from the following GLSL + --eliminate-local-multi-store
  1304. // 14
  1305. #version 440 core
  1306. void main() {
  1307. // Fine
  1308. for (int i = 0; i < 10; i = i + 2) {}
  1309. for (int j = 0; j < 10; j = j + 2) {}
  1310. }
  1311. */
  1312. TEST_F(FusionCompatibilityTest, CompatibleNonIncrementStep) {
  1313. const std::string text = R"(
  1314. OpCapability Shader
  1315. %1 = OpExtInstImport "GLSL.std.450"
  1316. OpMemoryModel Logical GLSL450
  1317. OpEntryPoint Fragment %4 "main"
  1318. OpExecutionMode %4 OriginUpperLeft
  1319. OpSource GLSL 440
  1320. OpName %4 "main"
  1321. OpName %8 "j"
  1322. OpName %10 "i"
  1323. OpName %11 "i"
  1324. OpName %24 "j"
  1325. %2 = OpTypeVoid
  1326. %3 = OpTypeFunction %2
  1327. %6 = OpTypeInt 32 1
  1328. %7 = OpTypePointer Function %6
  1329. %9 = OpConstant %6 0
  1330. %18 = OpConstant %6 10
  1331. %19 = OpTypeBool
  1332. %22 = OpConstant %6 2
  1333. %4 = OpFunction %2 None %3
  1334. %5 = OpLabel
  1335. %8 = OpVariable %7 Function
  1336. %10 = OpVariable %7 Function
  1337. %11 = OpVariable %7 Function
  1338. %24 = OpVariable %7 Function
  1339. OpStore %8 %9
  1340. OpStore %10 %9
  1341. OpStore %11 %9
  1342. OpBranch %12
  1343. %12 = OpLabel
  1344. %34 = OpPhi %6 %9 %5 %23 %15
  1345. OpLoopMerge %14 %15 None
  1346. OpBranch %16
  1347. %16 = OpLabel
  1348. %20 = OpSLessThan %19 %34 %18
  1349. OpBranchConditional %20 %13 %14
  1350. %13 = OpLabel
  1351. OpBranch %15
  1352. %15 = OpLabel
  1353. %23 = OpIAdd %6 %34 %22
  1354. OpStore %11 %23
  1355. OpBranch %12
  1356. %14 = OpLabel
  1357. OpStore %24 %9
  1358. OpBranch %25
  1359. %25 = OpLabel
  1360. %35 = OpPhi %6 %9 %14 %33 %28
  1361. OpLoopMerge %27 %28 None
  1362. OpBranch %29
  1363. %29 = OpLabel
  1364. %31 = OpSLessThan %19 %35 %18
  1365. OpBranchConditional %31 %26 %27
  1366. %26 = OpLabel
  1367. OpBranch %28
  1368. %28 = OpLabel
  1369. %33 = OpIAdd %6 %35 %22
  1370. OpStore %24 %33
  1371. OpBranch %25
  1372. %27 = OpLabel
  1373. OpReturn
  1374. OpFunctionEnd
  1375. )";
  1376. std::unique_ptr<IRContext> context =
  1377. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1378. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1379. Module* module = context->module();
  1380. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1381. << text << std::endl;
  1382. Function& f = *module->begin();
  1383. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1384. EXPECT_EQ(ld.NumLoops(), 2u);
  1385. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1386. EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1387. }
  1388. /*
  1389. Generated from the following GLSL + --eliminate-local-multi-store
  1390. // 15
  1391. #version 440 core
  1392. int j = 0;
  1393. void main() {
  1394. // Not compatible, unknown init for second.
  1395. for (int i = 0; i < 10; i = i + 2) {}
  1396. for (; j < 10; j = j + 2) {}
  1397. }
  1398. */
  1399. TEST_F(FusionCompatibilityTest, UnknonInitForSecondLoop) {
  1400. const std::string text = R"(
  1401. OpCapability Shader
  1402. %1 = OpExtInstImport "GLSL.std.450"
  1403. OpMemoryModel Logical GLSL450
  1404. OpEntryPoint Fragment %4 "main"
  1405. OpExecutionMode %4 OriginUpperLeft
  1406. OpSource GLSL 440
  1407. OpName %4 "main"
  1408. OpName %8 "j"
  1409. OpName %11 "i"
  1410. %2 = OpTypeVoid
  1411. %3 = OpTypeFunction %2
  1412. %6 = OpTypeInt 32 1
  1413. %7 = OpTypePointer Private %6
  1414. %8 = OpVariable %7 Private
  1415. %9 = OpConstant %6 0
  1416. %10 = OpTypePointer Function %6
  1417. %18 = OpConstant %6 10
  1418. %19 = OpTypeBool
  1419. %22 = OpConstant %6 2
  1420. %4 = OpFunction %2 None %3
  1421. %5 = OpLabel
  1422. %11 = OpVariable %10 Function
  1423. OpStore %8 %9
  1424. OpStore %11 %9
  1425. OpBranch %12
  1426. %12 = OpLabel
  1427. %33 = OpPhi %6 %9 %5 %23 %15
  1428. OpLoopMerge %14 %15 None
  1429. OpBranch %16
  1430. %16 = OpLabel
  1431. %20 = OpSLessThan %19 %33 %18
  1432. OpBranchConditional %20 %13 %14
  1433. %13 = OpLabel
  1434. OpBranch %15
  1435. %15 = OpLabel
  1436. %23 = OpIAdd %6 %33 %22
  1437. OpStore %11 %23
  1438. OpBranch %12
  1439. %14 = OpLabel
  1440. OpBranch %24
  1441. %24 = OpLabel
  1442. OpLoopMerge %26 %27 None
  1443. OpBranch %28
  1444. %28 = OpLabel
  1445. %29 = OpLoad %6 %8
  1446. %30 = OpSLessThan %19 %29 %18
  1447. OpBranchConditional %30 %25 %26
  1448. %25 = OpLabel
  1449. OpBranch %27
  1450. %27 = OpLabel
  1451. %31 = OpLoad %6 %8
  1452. %32 = OpIAdd %6 %31 %22
  1453. OpStore %8 %32
  1454. OpBranch %24
  1455. %26 = OpLabel
  1456. OpReturn
  1457. OpFunctionEnd
  1458. )";
  1459. std::unique_ptr<IRContext> context =
  1460. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1461. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1462. Module* module = context->module();
  1463. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1464. << text << std::endl;
  1465. Function& f = *module->begin();
  1466. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1467. EXPECT_EQ(ld.NumLoops(), 2u);
  1468. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1469. EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1470. }
  1471. /*
  1472. Generated from the following GLSL + --eliminate-local-multi-store
  1473. // 16
  1474. #version 440 core
  1475. void main() {
  1476. // Not compatible, continue in loop 0
  1477. for (int i = 0; i < 10; ++i) {
  1478. if (i % 2 == 1) {
  1479. continue;
  1480. }
  1481. }
  1482. for (int j = 0; j < 10; ++j) {}
  1483. }
  1484. */
  1485. TEST_F(FusionCompatibilityTest, Continue) {
  1486. const std::string text = R"(
  1487. OpCapability Shader
  1488. %1 = OpExtInstImport "GLSL.std.450"
  1489. OpMemoryModel Logical GLSL450
  1490. OpEntryPoint Fragment %4 "main"
  1491. OpExecutionMode %4 OriginUpperLeft
  1492. OpSource GLSL 440
  1493. OpName %4 "main"
  1494. OpName %8 "i"
  1495. OpName %29 "j"
  1496. %2 = OpTypeVoid
  1497. %3 = OpTypeFunction %2
  1498. %6 = OpTypeInt 32 1
  1499. %7 = OpTypePointer Function %6
  1500. %9 = OpConstant %6 0
  1501. %16 = OpConstant %6 10
  1502. %17 = OpTypeBool
  1503. %20 = OpConstant %6 2
  1504. %22 = OpConstant %6 1
  1505. %4 = OpFunction %2 None %3
  1506. %5 = OpLabel
  1507. %8 = OpVariable %7 Function
  1508. %29 = OpVariable %7 Function
  1509. OpStore %8 %9
  1510. OpBranch %10
  1511. %10 = OpLabel
  1512. %39 = OpPhi %6 %9 %5 %28 %13
  1513. OpLoopMerge %12 %13 None
  1514. OpBranch %14
  1515. %14 = OpLabel
  1516. %18 = OpSLessThan %17 %39 %16
  1517. OpBranchConditional %18 %11 %12
  1518. %11 = OpLabel
  1519. %21 = OpSMod %6 %39 %20
  1520. %23 = OpIEqual %17 %21 %22
  1521. OpSelectionMerge %25 None
  1522. OpBranchConditional %23 %24 %25
  1523. %24 = OpLabel
  1524. OpBranch %13
  1525. %25 = OpLabel
  1526. OpBranch %13
  1527. %13 = OpLabel
  1528. %28 = OpIAdd %6 %39 %22
  1529. OpStore %8 %28
  1530. OpBranch %10
  1531. %12 = OpLabel
  1532. OpStore %29 %9
  1533. OpBranch %30
  1534. %30 = OpLabel
  1535. %40 = OpPhi %6 %9 %12 %38 %33
  1536. OpLoopMerge %32 %33 None
  1537. OpBranch %34
  1538. %34 = OpLabel
  1539. %36 = OpSLessThan %17 %40 %16
  1540. OpBranchConditional %36 %31 %32
  1541. %31 = OpLabel
  1542. OpBranch %33
  1543. %33 = OpLabel
  1544. %38 = OpIAdd %6 %40 %22
  1545. OpStore %29 %38
  1546. OpBranch %30
  1547. %32 = OpLabel
  1548. OpReturn
  1549. OpFunctionEnd
  1550. )";
  1551. std::unique_ptr<IRContext> context =
  1552. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1553. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1554. Module* module = context->module();
  1555. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1556. << text << std::endl;
  1557. Function& f = *module->begin();
  1558. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1559. EXPECT_EQ(ld.NumLoops(), 2u);
  1560. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1561. EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1562. }
  1563. /*
  1564. Generated from the following GLSL + --eliminate-local-multi-store
  1565. #version 440 core
  1566. void main() {
  1567. int[10] a;
  1568. // Compatible
  1569. for (int i = 0; i < 10; ++i) {
  1570. if (i % 2 == 1) {
  1571. } else {
  1572. a[i] = i;
  1573. }
  1574. }
  1575. for (int j = 0; j < 10; ++j) {}
  1576. }
  1577. */
  1578. TEST_F(FusionCompatibilityTest, IfElseInLoop) {
  1579. const std::string text = R"(
  1580. OpCapability Shader
  1581. %1 = OpExtInstImport "GLSL.std.450"
  1582. OpMemoryModel Logical GLSL450
  1583. OpEntryPoint Fragment %4 "main"
  1584. OpExecutionMode %4 OriginUpperLeft
  1585. OpSource GLSL 440
  1586. OpName %4 "main"
  1587. OpName %8 "i"
  1588. OpName %31 "a"
  1589. OpName %37 "j"
  1590. %2 = OpTypeVoid
  1591. %3 = OpTypeFunction %2
  1592. %6 = OpTypeInt 32 1
  1593. %7 = OpTypePointer Function %6
  1594. %9 = OpConstant %6 0
  1595. %16 = OpConstant %6 10
  1596. %17 = OpTypeBool
  1597. %20 = OpConstant %6 2
  1598. %22 = OpConstant %6 1
  1599. %27 = OpTypeInt 32 0
  1600. %28 = OpConstant %27 10
  1601. %29 = OpTypeArray %6 %28
  1602. %30 = OpTypePointer Function %29
  1603. %4 = OpFunction %2 None %3
  1604. %5 = OpLabel
  1605. %8 = OpVariable %7 Function
  1606. %31 = OpVariable %30 Function
  1607. %37 = OpVariable %7 Function
  1608. OpStore %8 %9
  1609. OpBranch %10
  1610. %10 = OpLabel
  1611. %47 = OpPhi %6 %9 %5 %36 %13
  1612. OpLoopMerge %12 %13 None
  1613. OpBranch %14
  1614. %14 = OpLabel
  1615. %18 = OpSLessThan %17 %47 %16
  1616. OpBranchConditional %18 %11 %12
  1617. %11 = OpLabel
  1618. %21 = OpSMod %6 %47 %20
  1619. %23 = OpIEqual %17 %21 %22
  1620. OpSelectionMerge %25 None
  1621. OpBranchConditional %23 %24 %26
  1622. %24 = OpLabel
  1623. OpBranch %25
  1624. %26 = OpLabel
  1625. %34 = OpAccessChain %7 %31 %47
  1626. OpStore %34 %47
  1627. OpBranch %25
  1628. %25 = OpLabel
  1629. OpBranch %13
  1630. %13 = OpLabel
  1631. %36 = OpIAdd %6 %47 %22
  1632. OpStore %8 %36
  1633. OpBranch %10
  1634. %12 = OpLabel
  1635. OpStore %37 %9
  1636. OpBranch %38
  1637. %38 = OpLabel
  1638. %48 = OpPhi %6 %9 %12 %46 %41
  1639. OpLoopMerge %40 %41 None
  1640. OpBranch %42
  1641. %42 = OpLabel
  1642. %44 = OpSLessThan %17 %48 %16
  1643. OpBranchConditional %44 %39 %40
  1644. %39 = OpLabel
  1645. OpBranch %41
  1646. %41 = OpLabel
  1647. %46 = OpIAdd %6 %48 %22
  1648. OpStore %37 %46
  1649. OpBranch %38
  1650. %40 = OpLabel
  1651. OpReturn
  1652. OpFunctionEnd
  1653. )";
  1654. std::unique_ptr<IRContext> context =
  1655. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  1656. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  1657. Module* module = context->module();
  1658. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  1659. << text << std::endl;
  1660. Function& f = *module->begin();
  1661. LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
  1662. EXPECT_EQ(ld.NumLoops(), 2u);
  1663. auto loops = ld.GetLoopsInBinaryLayoutOrder();
  1664. EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
  1665. }
  1666. } // namespace
  1667. } // namespace opt
  1668. } // namespace spvtools