unroll_assumptions.cpp 37 KB

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