fusion_compatibility.cpp 54 KB

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