unroll_assumptions.cpp 36 KB

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