unroll_assumptions.cpp 37 KB

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