unswitch.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  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 <string>
  15. #include "effcee/effcee.h"
  16. #include "gmock/gmock.h"
  17. #include "test/opt/pass_fixture.h"
  18. namespace spvtools {
  19. namespace opt {
  20. namespace {
  21. using UnswitchTest = PassTest<::testing::Test>;
  22. /*
  23. Generated from the following GLSL + --eliminate-local-multi-store
  24. #version 450 core
  25. uniform vec4 c;
  26. void main() {
  27. int i = 0;
  28. int j = 0;
  29. bool cond = c[0] == 0;
  30. for (; i < 10; i++, j++) {
  31. if (cond) {
  32. i++;
  33. }
  34. else {
  35. j++;
  36. }
  37. }
  38. }
  39. */
  40. TEST_F(UnswitchTest, SimpleUnswitch) {
  41. const std::string text = R"(
  42. ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
  43. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  44. ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
  45. ; Loop specialized for false.
  46. ; CHECK: [[loop_f]] = OpLabel
  47. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  48. ; CHECK: [[loop]] = OpLabel
  49. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
  50. ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_j:%\w+]] [[continue]]
  51. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  52. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  53. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  54. ; [[loop_body]] = OpLabel
  55. ; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
  56. ; CHECK: OpBranchConditional %false [[bb1:%\w+]] [[bb2:%\w+]]
  57. ; CHECK: [[bb2]] = OpLabel
  58. ; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
  59. ; CHECK-NEXT: OpBranch [[sel_merge]]
  60. ; CHECK: [[bb1]] = OpLabel
  61. ; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
  62. ; CHECK-NEXT: OpBranch [[sel_merge]]
  63. ; CHECK: [[sel_merge]] = OpLabel
  64. ; CHECK: OpBranch [[if_merge]]
  65. ; Loop specialized for true.
  66. ; CHECK: [[loop_t]] = OpLabel
  67. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  68. ; CHECK: [[loop]] = OpLabel
  69. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
  70. ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_j:%\w+]] [[continue]]
  71. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  72. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  73. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  74. ; [[loop_body]] = OpLabel
  75. ; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
  76. ; CHECK: OpBranchConditional %true [[bb1:%\w+]] [[bb2:%\w+]]
  77. ; CHECK: [[bb1]] = OpLabel
  78. ; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
  79. ; CHECK-NEXT: OpBranch [[sel_merge]]
  80. ; CHECK: [[bb2]] = OpLabel
  81. ; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
  82. ; CHECK-NEXT: OpBranch [[sel_merge]]
  83. ; CHECK: [[sel_merge]] = OpLabel
  84. ; CHECK: OpBranch [[if_merge]]
  85. ; CHECK: [[if_merge]] = OpLabel
  86. ; CHECK-NEXT: OpReturn
  87. OpCapability Shader
  88. %1 = OpExtInstImport "GLSL.std.450"
  89. OpMemoryModel Logical GLSL450
  90. OpEntryPoint Fragment %main "main"
  91. OpExecutionMode %main OriginLowerLeft
  92. OpSource GLSL 450
  93. OpName %main "main"
  94. OpName %c "c"
  95. OpDecorate %c Location 0
  96. OpDecorate %c DescriptorSet 0
  97. %void = OpTypeVoid
  98. %3 = OpTypeFunction %void
  99. %int = OpTypeInt 32 1
  100. %_ptr_Function_int = OpTypePointer Function %int
  101. %int_0 = OpConstant %int 0
  102. %bool = OpTypeBool
  103. %_ptr_Function_bool = OpTypePointer Function %bool
  104. %float = OpTypeFloat 32
  105. %v4float = OpTypeVector %float 4
  106. %_ptr_UniformConstant_v4float = OpTypePointer UniformConstant %v4float
  107. %c = OpVariable %_ptr_UniformConstant_v4float UniformConstant
  108. %uint = OpTypeInt 32 0
  109. %uint_0 = OpConstant %uint 0
  110. %_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
  111. %float_0 = OpConstant %float 0
  112. %int_10 = OpConstant %int 10
  113. %int_1 = OpConstant %int 1
  114. %main = OpFunction %void None %3
  115. %5 = OpLabel
  116. %21 = OpAccessChain %_ptr_UniformConstant_float %c %uint_0
  117. %22 = OpLoad %float %21
  118. %24 = OpFOrdEqual %bool %22 %float_0
  119. OpBranch %25
  120. %25 = OpLabel
  121. %46 = OpPhi %int %int_0 %5 %43 %28
  122. %47 = OpPhi %int %int_0 %5 %45 %28
  123. OpLoopMerge %27 %28 None
  124. OpBranch %29
  125. %29 = OpLabel
  126. %32 = OpSLessThan %bool %46 %int_10
  127. OpBranchConditional %32 %26 %27
  128. %26 = OpLabel
  129. OpSelectionMerge %35 None
  130. OpBranchConditional %24 %34 %39
  131. %34 = OpLabel
  132. %38 = OpIAdd %int %46 %int_1
  133. OpBranch %35
  134. %39 = OpLabel
  135. %41 = OpIAdd %int %47 %int_1
  136. OpBranch %35
  137. %35 = OpLabel
  138. %48 = OpPhi %int %38 %34 %46 %39
  139. %49 = OpPhi %int %47 %34 %41 %39
  140. OpBranch %28
  141. %28 = OpLabel
  142. %43 = OpIAdd %int %48 %int_1
  143. %45 = OpIAdd %int %49 %int_1
  144. OpBranch %25
  145. %27 = OpLabel
  146. OpReturn
  147. OpFunctionEnd
  148. )";
  149. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  150. }
  151. /*
  152. Generated from the following GLSL + --eliminate-local-multi-store
  153. #version 330 core
  154. in vec4 c;
  155. void main() {
  156. int i = 0;
  157. bool cond = c[0] == 0;
  158. for (; i < 10; i++) {
  159. if (cond) {
  160. i++;
  161. }
  162. else {
  163. return;
  164. }
  165. }
  166. }
  167. */
  168. TEST_F(UnswitchTest, UnswitchExit) {
  169. const std::string text = R"(
  170. ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
  171. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  172. ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
  173. ; Loop specialized for false.
  174. ; CHECK: [[loop_f]] = OpLabel
  175. ; CHECK: OpReturn
  176. ; Loop specialized for true.
  177. ; CHECK: [[loop_t]] = OpLabel
  178. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  179. ; CHECK: [[loop]] = OpLabel
  180. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
  181. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  182. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  183. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
  184. ; Check that we have i+=2.
  185. ; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
  186. ; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
  187. ; CHECK: [[merge]] = OpLabel
  188. ; CHECK-NEXT: OpBranch [[if_merge]]
  189. ; CHECK: [[if_merge]] = OpLabel
  190. ; CHECK-NEXT: OpReturn
  191. OpCapability Shader
  192. %1 = OpExtInstImport "GLSL.std.450"
  193. OpMemoryModel Logical GLSL450
  194. OpEntryPoint Fragment %main "main" %c
  195. OpExecutionMode %main OriginUpperLeft
  196. OpSource GLSL 330
  197. OpName %main "main"
  198. OpName %c "c"
  199. OpDecorate %c Location 0
  200. OpDecorate %23 Uniform
  201. %void = OpTypeVoid
  202. %3 = OpTypeFunction %void
  203. %int = OpTypeInt 32 1
  204. %_ptr_Function_int = OpTypePointer Function %int
  205. %int_0 = OpConstant %int 0
  206. %bool = OpTypeBool
  207. %_ptr_Function_bool = OpTypePointer Function %bool
  208. %float = OpTypeFloat 32
  209. %v4float = OpTypeVector %float 4
  210. %_ptr_Input_v4float = OpTypePointer Input %v4float
  211. %c = OpVariable %_ptr_Input_v4float Input
  212. %uint = OpTypeInt 32 0
  213. %uint_0 = OpConstant %uint 0
  214. %_ptr_Input_float = OpTypePointer Input %float
  215. %float_0 = OpConstant %float 0
  216. %int_10 = OpConstant %int 10
  217. %int_1 = OpConstant %int 1
  218. %main = OpFunction %void None %3
  219. %5 = OpLabel
  220. %20 = OpAccessChain %_ptr_Input_float %c %uint_0
  221. %21 = OpLoad %float %20
  222. %23 = OpFOrdEqual %bool %21 %float_0
  223. OpBranch %24
  224. %24 = OpLabel
  225. %42 = OpPhi %int %int_0 %5 %41 %27
  226. OpLoopMerge %26 %27 None
  227. OpBranch %28
  228. %28 = OpLabel
  229. %31 = OpSLessThan %bool %42 %int_10
  230. OpBranchConditional %31 %25 %26
  231. %25 = OpLabel
  232. OpSelectionMerge %34 None
  233. OpBranchConditional %23 %33 %38
  234. %33 = OpLabel
  235. %37 = OpIAdd %int %42 %int_1
  236. OpBranch %34
  237. %38 = OpLabel
  238. OpReturn
  239. %34 = OpLabel
  240. OpBranch %27
  241. %27 = OpLabel
  242. %41 = OpIAdd %int %37 %int_1
  243. OpBranch %24
  244. %26 = OpLabel
  245. OpReturn
  246. OpFunctionEnd
  247. )";
  248. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  249. }
  250. /*
  251. Generated from the following GLSL + --eliminate-local-multi-store
  252. #version 330 core
  253. in vec4 c;
  254. void main() {
  255. int i = 0;
  256. bool cond = c[0] == 0;
  257. for (; i < 10; i++) {
  258. if (cond) {
  259. continue;
  260. }
  261. else {
  262. i++;
  263. }
  264. }
  265. }
  266. */
  267. TEST_F(UnswitchTest, UnswitchContinue) {
  268. const std::string text = R"(
  269. ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
  270. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  271. ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
  272. ; Loop specialized for false.
  273. ; CHECK: [[loop_f]] = OpLabel
  274. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  275. ; CHECK: [[loop]] = OpLabel
  276. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
  277. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  278. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  279. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  280. ; CHECK: [[loop_body:%\w+]] = OpLabel
  281. ; CHECK-NEXT: OpSelectionMerge
  282. ; CHECK-NEXT: OpBranchConditional %false
  283. ; CHECK: [[merge]] = OpLabel
  284. ; CHECK-NEXT: OpBranch [[if_merge]]
  285. ; Loop specialized for true.
  286. ; CHECK: [[loop_t]] = OpLabel
  287. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  288. ; CHECK: [[loop]] = OpLabel
  289. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
  290. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  291. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  292. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  293. ; CHECK: [[loop_body:%\w+]] = OpLabel
  294. ; CHECK-NEXT: OpSelectionMerge
  295. ; CHECK-NEXT: OpBranchConditional %true
  296. ; CHECK: [[merge]] = OpLabel
  297. ; CHECK-NEXT: OpBranch [[if_merge]]
  298. ; CHECK: [[if_merge]] = OpLabel
  299. ; CHECK-NEXT: OpReturn
  300. OpCapability Shader
  301. %1 = OpExtInstImport "GLSL.std.450"
  302. OpMemoryModel Logical GLSL450
  303. OpEntryPoint Fragment %main "main" %c
  304. OpExecutionMode %main OriginUpperLeft
  305. OpSource GLSL 330
  306. OpName %main "main"
  307. OpName %c "c"
  308. OpDecorate %c Location 0
  309. OpDecorate %23 Uniform
  310. %void = OpTypeVoid
  311. %3 = OpTypeFunction %void
  312. %int = OpTypeInt 32 1
  313. %_ptr_Function_int = OpTypePointer Function %int
  314. %int_0 = OpConstant %int 0
  315. %bool = OpTypeBool
  316. %_ptr_Function_bool = OpTypePointer Function %bool
  317. %float = OpTypeFloat 32
  318. %v4float = OpTypeVector %float 4
  319. %_ptr_Input_v4float = OpTypePointer Input %v4float
  320. %c = OpVariable %_ptr_Input_v4float Input
  321. %uint = OpTypeInt 32 0
  322. %uint_0 = OpConstant %uint 0
  323. %_ptr_Input_float = OpTypePointer Input %float
  324. %float_0 = OpConstant %float 0
  325. %int_10 = OpConstant %int 10
  326. %int_1 = OpConstant %int 1
  327. %main = OpFunction %void None %3
  328. %5 = OpLabel
  329. %20 = OpAccessChain %_ptr_Input_float %c %uint_0
  330. %21 = OpLoad %float %20
  331. %23 = OpFOrdEqual %bool %21 %float_0
  332. OpBranch %24
  333. %24 = OpLabel
  334. %42 = OpPhi %int %int_0 %5 %41 %27
  335. OpLoopMerge %26 %27 None
  336. OpBranch %28
  337. %28 = OpLabel
  338. %31 = OpSLessThan %bool %42 %int_10
  339. OpBranchConditional %31 %25 %26
  340. %25 = OpLabel
  341. OpSelectionMerge %34 None
  342. OpBranchConditional %23 %33 %36
  343. %33 = OpLabel
  344. OpBranch %27
  345. %36 = OpLabel
  346. %39 = OpIAdd %int %42 %int_1
  347. OpBranch %34
  348. %34 = OpLabel
  349. OpBranch %27
  350. %27 = OpLabel
  351. %43 = OpPhi %int %42 %33 %39 %34
  352. %41 = OpIAdd %int %43 %int_1
  353. OpBranch %24
  354. %26 = OpLabel
  355. OpReturn
  356. OpFunctionEnd
  357. )";
  358. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  359. }
  360. /*
  361. Generated from the following GLSL + --eliminate-local-multi-store
  362. #version 330 core
  363. in vec4 c;
  364. void main() {
  365. int i = 0;
  366. bool cond = c[0] == 0;
  367. for (; i < 10; i++) {
  368. if (cond) {
  369. i++;
  370. }
  371. else {
  372. break;
  373. }
  374. }
  375. }
  376. */
  377. TEST_F(UnswitchTest, UnswitchKillLoop) {
  378. const std::string text = R"(
  379. ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
  380. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  381. ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
  382. ; Loop specialized for false.
  383. ; CHECK: [[loop_f]] = OpLabel
  384. ; CHECK: OpBranch [[if_merge]]
  385. ; Loop specialized for true.
  386. ; CHECK: [[loop_t]] = OpLabel
  387. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  388. ; CHECK: [[loop]] = OpLabel
  389. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
  390. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  391. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  392. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
  393. ; Check that we have i+=2.
  394. ; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
  395. ; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
  396. ; CHECK: [[merge]] = OpLabel
  397. ; CHECK-NEXT: OpBranch [[if_merge]]
  398. ; CHECK: [[if_merge]] = OpLabel
  399. ; CHECK-NEXT: OpReturn
  400. OpCapability Shader
  401. %1 = OpExtInstImport "GLSL.std.450"
  402. OpMemoryModel Logical GLSL450
  403. OpEntryPoint Fragment %main "main" %c
  404. OpExecutionMode %main OriginUpperLeft
  405. OpSource GLSL 330
  406. OpName %main "main"
  407. OpName %c "c"
  408. OpDecorate %c Location 0
  409. OpDecorate %23 Uniform
  410. %void = OpTypeVoid
  411. %3 = OpTypeFunction %void
  412. %int = OpTypeInt 32 1
  413. %_ptr_Function_int = OpTypePointer Function %int
  414. %int_0 = OpConstant %int 0
  415. %bool = OpTypeBool
  416. %_ptr_Function_bool = OpTypePointer Function %bool
  417. %float = OpTypeFloat 32
  418. %v4float = OpTypeVector %float 4
  419. %_ptr_Input_v4float = OpTypePointer Input %v4float
  420. %c = OpVariable %_ptr_Input_v4float Input
  421. %uint = OpTypeInt 32 0
  422. %uint_0 = OpConstant %uint 0
  423. %_ptr_Input_float = OpTypePointer Input %float
  424. %float_0 = OpConstant %float 0
  425. %int_10 = OpConstant %int 10
  426. %int_1 = OpConstant %int 1
  427. %main = OpFunction %void None %3
  428. %5 = OpLabel
  429. %20 = OpAccessChain %_ptr_Input_float %c %uint_0
  430. %21 = OpLoad %float %20
  431. %23 = OpFOrdEqual %bool %21 %float_0
  432. OpBranch %24
  433. %24 = OpLabel
  434. %42 = OpPhi %int %int_0 %5 %41 %27
  435. OpLoopMerge %26 %27 None
  436. OpBranch %28
  437. %28 = OpLabel
  438. %31 = OpSLessThan %bool %42 %int_10
  439. OpBranchConditional %31 %25 %26
  440. %25 = OpLabel
  441. OpSelectionMerge %34 None
  442. OpBranchConditional %23 %33 %38
  443. %33 = OpLabel
  444. %37 = OpIAdd %int %42 %int_1
  445. OpBranch %34
  446. %38 = OpLabel
  447. OpBranch %26
  448. %34 = OpLabel
  449. OpBranch %27
  450. %27 = OpLabel
  451. %41 = OpIAdd %int %37 %int_1
  452. OpBranch %24
  453. %26 = OpLabel
  454. OpReturn
  455. OpFunctionEnd
  456. )";
  457. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  458. }
  459. /*
  460. Generated from the following GLSL + --eliminate-local-multi-store
  461. #version 330 core
  462. in vec4 c;
  463. void main() {
  464. int i = 0;
  465. int cond = int(c[0]);
  466. for (; i < 10; i++) {
  467. switch (cond) {
  468. case 0:
  469. return;
  470. case 1:
  471. discard;
  472. case 2:
  473. break;
  474. default:
  475. break;
  476. }
  477. }
  478. bool cond2 = i == 9;
  479. }
  480. */
  481. TEST_F(UnswitchTest, UnswitchSwitch) {
  482. const std::string text = R"(
  483. ; CHECK: [[cst_cond:%\w+]] = OpConvertFToS
  484. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  485. ; CHECK-NEXT: OpSwitch [[cst_cond]] [[default:%\w+]] 0 [[loop_0:%\w+]] 1 [[loop_1:%\w+]] 2 [[loop_2:%\w+]]
  486. ; Loop specialized for 2.
  487. ; CHECK: [[loop_2]] = OpLabel
  488. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  489. ; CHECK: [[loop]] = OpLabel
  490. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_2]] [[iv_i:%\w+]] [[continue:%\w+]]
  491. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  492. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  493. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  494. ; CHECK: [[loop_body]] = OpLabel
  495. ; CHECK-NEXT: OpSelectionMerge
  496. ; CHECK-NEXT: OpSwitch %int_2
  497. ; CHECK: [[merge]] = OpLabel
  498. ; CHECK-NEXT: OpBranch [[if_merge]]
  499. ; Loop specialized for 1.
  500. ; CHECK: [[loop_1]] = OpLabel
  501. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  502. ; CHECK: [[loop]] = OpLabel
  503. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_1]] [[iv_i:%\w+]] [[continue:%\w+]]
  504. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  505. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  506. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  507. ; CHECK: [[loop_body]] = OpLabel
  508. ; CHECK-NEXT: OpSelectionMerge
  509. ; CHECK-NEXT: OpSwitch %int_1
  510. ; CHECK: [[merge]] = OpLabel
  511. ; CHECK-NEXT: OpBranch [[if_merge]]
  512. ; Loop specialized for 0.
  513. ; CHECK: [[loop_0]] = OpLabel
  514. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  515. ; CHECK: [[loop]] = OpLabel
  516. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_0]] [[iv_i:%\w+]] [[continue:%\w+]]
  517. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  518. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  519. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  520. ; CHECK: [[loop_body]] = OpLabel
  521. ; CHECK-NEXT: OpSelectionMerge
  522. ; CHECK-NEXT: OpSwitch %int_0
  523. ; CHECK: [[merge]] = OpLabel
  524. ; CHECK-NEXT: OpBranch [[if_merge]]
  525. ; Loop specialized for the default case.
  526. ; CHECK: [[default]] = OpLabel
  527. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  528. ; CHECK: [[loop]] = OpLabel
  529. ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[default]] [[iv_i:%\w+]] [[continue:%\w+]]
  530. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  531. ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
  532. ; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
  533. ; CHECK: [[loop_body]] = OpLabel
  534. ; CHECK-NEXT: OpSelectionMerge
  535. ; CHECK-NEXT: OpSwitch %uint_3
  536. ; CHECK: [[merge]] = OpLabel
  537. ; CHECK-NEXT: OpBranch [[if_merge]]
  538. ; CHECK: [[if_merge]] = OpLabel
  539. ; CHECK-NEXT: OpReturn
  540. OpCapability Shader
  541. %1 = OpExtInstImport "GLSL.std.450"
  542. OpMemoryModel Logical GLSL450
  543. OpEntryPoint Fragment %main "main" %c
  544. OpExecutionMode %main OriginUpperLeft
  545. OpSource GLSL 330
  546. OpName %main "main"
  547. OpName %c "c"
  548. OpDecorate %c Location 0
  549. OpDecorate %20 Uniform
  550. %void = OpTypeVoid
  551. %3 = OpTypeFunction %void
  552. %int = OpTypeInt 32 1
  553. %_ptr_Function_int = OpTypePointer Function %int
  554. %int_0 = OpConstant %int 0
  555. %float = OpTypeFloat 32
  556. %v4float = OpTypeVector %float 4
  557. %_ptr_Input_v4float = OpTypePointer Input %v4float
  558. %c = OpVariable %_ptr_Input_v4float Input
  559. %uint = OpTypeInt 32 0
  560. %uint_0 = OpConstant %uint 0
  561. %_ptr_Input_float = OpTypePointer Input %float
  562. %int_10 = OpConstant %int 10
  563. %bool = OpTypeBool
  564. %int_1 = OpConstant %int 1
  565. %_ptr_Function_bool = OpTypePointer Function %bool
  566. %main = OpFunction %void None %3
  567. %5 = OpLabel
  568. %18 = OpAccessChain %_ptr_Input_float %c %uint_0
  569. %19 = OpLoad %float %18
  570. %20 = OpConvertFToS %int %19
  571. OpBranch %21
  572. %21 = OpLabel
  573. %49 = OpPhi %int %int_0 %5 %43 %24
  574. OpLoopMerge %23 %24 None
  575. OpBranch %25
  576. %25 = OpLabel
  577. %29 = OpSLessThan %bool %49 %int_10
  578. OpBranchConditional %29 %22 %23
  579. %22 = OpLabel
  580. OpSelectionMerge %35 None
  581. OpSwitch %20 %34 0 %31 1 %32 2 %33
  582. %34 = OpLabel
  583. OpBranch %35
  584. %31 = OpLabel
  585. OpReturn
  586. %32 = OpLabel
  587. OpKill
  588. %33 = OpLabel
  589. OpBranch %35
  590. %35 = OpLabel
  591. OpBranch %24
  592. %24 = OpLabel
  593. %43 = OpIAdd %int %49 %int_1
  594. OpBranch %21
  595. %23 = OpLabel
  596. OpReturn
  597. OpFunctionEnd
  598. )";
  599. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  600. }
  601. /*
  602. Generated from the following GLSL + --eliminate-local-multi-store
  603. #version 440 core
  604. layout(location = 0)in vec4 c;
  605. void main() {
  606. int i = 0;
  607. int j = 0;
  608. int k = 0;
  609. bool cond = c[0] == 0;
  610. for (; i < 10; i++) {
  611. for (; j < 10; j++) {
  612. if (cond) {
  613. i++;
  614. } else {
  615. j++;
  616. }
  617. }
  618. }
  619. }
  620. */
  621. TEST_F(UnswitchTest, UnSwitchNested) {
  622. // Test that an branch can be unswitched out of two nested loops.
  623. const std::string text = R"(
  624. ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
  625. ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
  626. ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
  627. ; Loop specialized for false
  628. ; CHECK: [[loop_f]] = OpLabel
  629. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  630. ; CHECK: [[loop]] = OpLabel
  631. ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue:%\w+]]
  632. ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue]]
  633. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  634. ; CHECK-NOT: [[merge]] = OpLabel
  635. ; CHECK: OpLoopMerge
  636. ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
  637. ; CHECK: [[bb1]] = OpLabel
  638. ; CHECK-NEXT: OpSLessThan
  639. ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
  640. ; CHECK: [[bb2]] = OpLabel
  641. ; CHECK-NEXT: OpSelectionMerge
  642. ; CHECK-NEXT: OpBranchConditional %false
  643. ; CHECK: [[merge]] = OpLabel
  644. ; Loop specialized for true. Same as first loop except the branch condition is true.
  645. ; CHECK: [[loop_t]] = OpLabel
  646. ; CHECK-NEXT: OpBranch [[loop:%\w+]]
  647. ; CHECK: [[loop]] = OpLabel
  648. ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue:%\w+]]
  649. ; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue]]
  650. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  651. ; CHECK-NOT: [[merge]] = OpLabel
  652. ; CHECK: OpLoopMerge
  653. ; CHECK-NEXT: OpBranch [[bb1:%\w+]]
  654. ; CHECK: [[bb1]] = OpLabel
  655. ; CHECK-NEXT: OpSLessThan
  656. ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
  657. ; CHECK: [[bb2]] = OpLabel
  658. ; CHECK-NEXT: OpSelectionMerge
  659. ; CHECK-NEXT: OpBranchConditional %true
  660. ; CHECK: [[merge]] = OpLabel
  661. OpCapability Shader
  662. %1 = OpExtInstImport "GLSL.std.450"
  663. OpMemoryModel Logical GLSL450
  664. OpEntryPoint Fragment %main "main" %c
  665. OpExecutionMode %main OriginUpperLeft
  666. OpSource GLSL 440
  667. OpName %main "main"
  668. OpName %c "c"
  669. OpDecorate %c Location 0
  670. OpDecorate %25 Uniform
  671. %void = OpTypeVoid
  672. %3 = OpTypeFunction %void
  673. %int = OpTypeInt 32 1
  674. %_ptr_Function_int = OpTypePointer Function %int
  675. %int_0 = OpConstant %int 0
  676. %bool = OpTypeBool
  677. %_ptr_Function_bool = OpTypePointer Function %bool
  678. %float = OpTypeFloat 32
  679. %v4float = OpTypeVector %float 4
  680. %_ptr_Input_v4float = OpTypePointer Input %v4float
  681. %c = OpVariable %_ptr_Input_v4float Input
  682. %uint = OpTypeInt 32 0
  683. %uint_0 = OpConstant %uint 0
  684. %_ptr_Input_float = OpTypePointer Input %float
  685. %float_0 = OpConstant %float 0
  686. %int_10 = OpConstant %int 10
  687. %int_1 = OpConstant %int 1
  688. %main = OpFunction %void None %3
  689. %5 = OpLabel
  690. %22 = OpAccessChain %_ptr_Input_float %c %uint_0
  691. %23 = OpLoad %float %22
  692. %25 = OpFOrdEqual %bool %23 %float_0
  693. OpBranch %26
  694. %26 = OpLabel
  695. %67 = OpPhi %int %int_0 %5 %52 %29
  696. %68 = OpPhi %int %int_0 %5 %70 %29
  697. OpLoopMerge %28 %29 None
  698. OpBranch %30
  699. %30 = OpLabel
  700. %33 = OpSLessThan %bool %67 %int_10
  701. OpBranchConditional %33 %27 %28
  702. %27 = OpLabel
  703. OpBranch %34
  704. %34 = OpLabel
  705. %69 = OpPhi %int %67 %27 %46 %37
  706. %70 = OpPhi %int %68 %27 %50 %37
  707. OpLoopMerge %36 %37 None
  708. OpBranch %38
  709. %38 = OpLabel
  710. %40 = OpSLessThan %bool %70 %int_10
  711. OpBranchConditional %40 %35 %36
  712. %35 = OpLabel
  713. OpSelectionMerge %43 None
  714. OpBranchConditional %25 %42 %47
  715. %42 = OpLabel
  716. %46 = OpIAdd %int %69 %int_1
  717. OpBranch %43
  718. %47 = OpLabel
  719. OpReturn
  720. %43 = OpLabel
  721. OpBranch %37
  722. %37 = OpLabel
  723. %50 = OpIAdd %int %70 %int_1
  724. OpBranch %34
  725. %36 = OpLabel
  726. OpBranch %29
  727. %29 = OpLabel
  728. %52 = OpIAdd %int %69 %int_1
  729. OpBranch %26
  730. %28 = OpLabel
  731. OpReturn
  732. OpFunctionEnd
  733. )";
  734. SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
  735. }
  736. /*
  737. Generated from the following GLSL + --eliminate-local-multi-store
  738. #version 330 core
  739. in vec4 c;
  740. void main() {
  741. bool cond = false;
  742. if (c[0] == 0) {
  743. cond = c[1] == 0;
  744. } else {
  745. cond = c[2] == 0;
  746. }
  747. for (int i = 0; i < 10; i++) {
  748. if (cond) {
  749. i++;
  750. }
  751. }
  752. }
  753. */
  754. TEST_F(UnswitchTest, UnswitchNotUniform) {
  755. // Check that the unswitch is not triggered (condition loop invariant but not
  756. // uniform)
  757. const std::string text = R"(
  758. OpCapability Shader
  759. %1 = OpExtInstImport "GLSL.std.450"
  760. OpMemoryModel Logical GLSL450
  761. OpEntryPoint Fragment %main "main" %c
  762. OpExecutionMode %main OriginUpperLeft
  763. OpSource GLSL 330
  764. OpName %main "main"
  765. OpName %c "c"
  766. OpDecorate %c Location 0
  767. %void = OpTypeVoid
  768. %3 = OpTypeFunction %void
  769. %bool = OpTypeBool
  770. %_ptr_Function_bool = OpTypePointer Function %bool
  771. %float = OpTypeFloat 32
  772. %v4float = OpTypeVector %float 4
  773. %_ptr_Input_v4float = OpTypePointer Input %v4float
  774. %c = OpVariable %_ptr_Input_v4float Input
  775. %uint = OpTypeInt 32 0
  776. %uint_0 = OpConstant %uint 0
  777. %_ptr_Input_float = OpTypePointer Input %float
  778. %float_0 = OpConstant %float 0
  779. %uint_1 = OpConstant %uint 1
  780. %uint_2 = OpConstant %uint 2
  781. %int = OpTypeInt 32 1
  782. %_ptr_Function_int = OpTypePointer Function %int
  783. %int_0 = OpConstant %int 0
  784. %int_10 = OpConstant %int 10
  785. %int_1 = OpConstant %int 1
  786. %main = OpFunction %void None %3
  787. %5 = OpLabel
  788. %17 = OpAccessChain %_ptr_Input_float %c %uint_0
  789. %18 = OpLoad %float %17
  790. %20 = OpFOrdEqual %bool %18 %float_0
  791. OpSelectionMerge %22 None
  792. OpBranchConditional %20 %21 %27
  793. %21 = OpLabel
  794. %24 = OpAccessChain %_ptr_Input_float %c %uint_1
  795. %25 = OpLoad %float %24
  796. %26 = OpFOrdEqual %bool %25 %float_0
  797. OpBranch %22
  798. %27 = OpLabel
  799. %29 = OpAccessChain %_ptr_Input_float %c %uint_2
  800. %30 = OpLoad %float %29
  801. %31 = OpFOrdEqual %bool %30 %float_0
  802. OpBranch %22
  803. %22 = OpLabel
  804. %52 = OpPhi %bool %26 %21 %31 %27
  805. OpBranch %36
  806. %36 = OpLabel
  807. %53 = OpPhi %int %int_0 %22 %51 %39
  808. OpLoopMerge %38 %39 None
  809. OpBranch %40
  810. %40 = OpLabel
  811. %43 = OpSLessThan %bool %53 %int_10
  812. OpBranchConditional %43 %37 %38
  813. %37 = OpLabel
  814. OpSelectionMerge %46 None
  815. OpBranchConditional %52 %45 %46
  816. %45 = OpLabel
  817. %49 = OpIAdd %int %53 %int_1
  818. OpBranch %46
  819. %46 = OpLabel
  820. %54 = OpPhi %int %53 %37 %49 %45
  821. OpBranch %39
  822. %39 = OpLabel
  823. %51 = OpIAdd %int %54 %int_1
  824. OpBranch %36
  825. %38 = OpLabel
  826. OpReturn
  827. OpFunctionEnd
  828. )";
  829. auto result =
  830. SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
  831. EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
  832. }
  833. TEST_F(UnswitchTest, DontUnswitchLatch) {
  834. // Check that the unswitch is not triggered for the latch branch.
  835. const std::string text = R"(
  836. OpCapability Shader
  837. %1 = OpExtInstImport "GLSL.std.450"
  838. OpMemoryModel Logical GLSL450
  839. OpEntryPoint Fragment %4 "main"
  840. OpExecutionMode %4 OriginUpperLeft
  841. OpSource ESSL 310
  842. %void = OpTypeVoid
  843. %3 = OpTypeFunction %void
  844. %bool = OpTypeBool
  845. %false = OpConstantFalse %bool
  846. %4 = OpFunction %void None %3
  847. %5 = OpLabel
  848. OpBranch %6
  849. %6 = OpLabel
  850. OpLoopMerge %8 %9 None
  851. OpBranch %7
  852. %7 = OpLabel
  853. OpBranch %9
  854. %9 = OpLabel
  855. OpBranchConditional %false %6 %8
  856. %8 = OpLabel
  857. OpReturn
  858. OpFunctionEnd
  859. )";
  860. auto result =
  861. SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
  862. EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
  863. }
  864. TEST_F(UnswitchTest, DontUnswitchConstantCondition) {
  865. const std::string text = R"(
  866. OpCapability Shader
  867. %1 = OpExtInstImport "GLSL.std.450"
  868. OpMemoryModel Logical GLSL450
  869. OpEntryPoint Fragment %main "main"
  870. OpExecutionMode %main OriginLowerLeft
  871. OpSource GLSL 450
  872. OpName %main "main"
  873. %void = OpTypeVoid
  874. %4 = OpTypeFunction %void
  875. %int = OpTypeInt 32 1
  876. %int_0 = OpConstant %int 0
  877. %bool = OpTypeBool
  878. %true = OpConstantTrue %bool
  879. %int_1 = OpConstant %int 1
  880. %main = OpFunction %void None %4
  881. %10 = OpLabel
  882. OpBranch %11
  883. %11 = OpLabel
  884. %12 = OpPhi %int %int_0 %10 %13 %14
  885. OpLoopMerge %15 %14 None
  886. OpBranch %16
  887. %16 = OpLabel
  888. %17 = OpSLessThan %bool %12 %int_1
  889. OpBranchConditional %17 %18 %15
  890. %18 = OpLabel
  891. OpSelectionMerge %19 None
  892. OpBranchConditional %true %20 %19
  893. %20 = OpLabel
  894. %21 = OpIAdd %int %12 %int_1
  895. OpBranch %19
  896. %19 = OpLabel
  897. %22 = OpPhi %int %21 %20 %12 %18
  898. OpBranch %14
  899. %14 = OpLabel
  900. %13 = OpIAdd %int %22 %int_1
  901. OpBranch %11
  902. %15 = OpLabel
  903. OpReturn
  904. OpFunctionEnd
  905. )";
  906. auto result =
  907. SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
  908. EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
  909. }
  910. } // namespace
  911. } // namespace opt
  912. } // namespace spvtools