remove_block_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. // Copyright (c) 2019 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 "source/reduce/remove_block_reduction_opportunity_finder.h"
  15. #include "source/opt/build_module.h"
  16. #include "source/reduce/reduction_opportunity.h"
  17. #include "test/reduce/reduce_test_util.h"
  18. namespace spvtools {
  19. namespace reduce {
  20. namespace {
  21. TEST(RemoveBlockReductionPassTest, BasicCheck) {
  22. std::string shader = R"(
  23. OpCapability Shader
  24. %1 = OpExtInstImport "GLSL.std.450"
  25. OpMemoryModel Logical GLSL450
  26. OpEntryPoint Fragment %4 "main"
  27. OpExecutionMode %4 OriginUpperLeft
  28. OpSource ESSL 310
  29. OpName %4 "main"
  30. OpName %8 "x"
  31. %2 = OpTypeVoid
  32. %3 = OpTypeFunction %2
  33. %6 = OpTypeInt 32 1
  34. %7 = OpTypePointer Function %6
  35. %9 = OpConstant %6 1
  36. %10 = OpConstant %6 2
  37. %11 = OpConstant %6 3
  38. %12 = OpConstant %6 4
  39. %4 = OpFunction %2 None %3
  40. %5 = OpLabel
  41. %8 = OpVariable %7 Function
  42. OpBranch %14
  43. %13 = OpLabel ; unreachable
  44. OpStore %8 %9
  45. OpBranch %14
  46. %14 = OpLabel
  47. OpStore %8 %10
  48. OpBranch %16
  49. %15 = OpLabel ; unreachable
  50. OpStore %8 %11
  51. OpBranch %16
  52. %16 = OpLabel
  53. OpStore %8 %12
  54. OpBranch %17
  55. %17 = OpLabel
  56. OpReturn
  57. OpFunctionEnd
  58. )";
  59. const auto env = SPV_ENV_UNIVERSAL_1_3;
  60. const auto consumer = nullptr;
  61. const auto context =
  62. BuildModule(env, consumer, shader, kReduceAssembleOption);
  63. const auto ops =
  64. RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  65. context.get(), 0);
  66. ASSERT_EQ(2, ops.size());
  67. ASSERT_TRUE(ops[0]->PreconditionHolds());
  68. ops[0]->TryToApply();
  69. std::string after_op_0 = R"(
  70. OpCapability Shader
  71. %1 = OpExtInstImport "GLSL.std.450"
  72. OpMemoryModel Logical GLSL450
  73. OpEntryPoint Fragment %4 "main"
  74. OpExecutionMode %4 OriginUpperLeft
  75. OpSource ESSL 310
  76. OpName %4 "main"
  77. OpName %8 "x"
  78. %2 = OpTypeVoid
  79. %3 = OpTypeFunction %2
  80. %6 = OpTypeInt 32 1
  81. %7 = OpTypePointer Function %6
  82. %9 = OpConstant %6 1
  83. %10 = OpConstant %6 2
  84. %11 = OpConstant %6 3
  85. %12 = OpConstant %6 4
  86. %4 = OpFunction %2 None %3
  87. %5 = OpLabel
  88. %8 = OpVariable %7 Function
  89. OpBranch %14
  90. %14 = OpLabel
  91. OpStore %8 %10
  92. OpBranch %16
  93. %15 = OpLabel
  94. OpStore %8 %11
  95. OpBranch %16
  96. %16 = OpLabel
  97. OpStore %8 %12
  98. OpBranch %17
  99. %17 = OpLabel
  100. OpReturn
  101. OpFunctionEnd
  102. )";
  103. CheckEqual(env, after_op_0, context.get());
  104. ASSERT_TRUE(ops[1]->PreconditionHolds());
  105. ops[1]->TryToApply();
  106. std::string after_op_1 = R"(
  107. OpCapability Shader
  108. %1 = OpExtInstImport "GLSL.std.450"
  109. OpMemoryModel Logical GLSL450
  110. OpEntryPoint Fragment %4 "main"
  111. OpExecutionMode %4 OriginUpperLeft
  112. OpSource ESSL 310
  113. OpName %4 "main"
  114. OpName %8 "x"
  115. %2 = OpTypeVoid
  116. %3 = OpTypeFunction %2
  117. %6 = OpTypeInt 32 1
  118. %7 = OpTypePointer Function %6
  119. %9 = OpConstant %6 1
  120. %10 = OpConstant %6 2
  121. %11 = OpConstant %6 3
  122. %12 = OpConstant %6 4
  123. %4 = OpFunction %2 None %3
  124. %5 = OpLabel
  125. %8 = OpVariable %7 Function
  126. OpBranch %14
  127. %14 = OpLabel
  128. OpStore %8 %10
  129. OpBranch %16
  130. %16 = OpLabel
  131. OpStore %8 %12
  132. OpBranch %17
  133. %17 = OpLabel
  134. OpReturn
  135. OpFunctionEnd
  136. )";
  137. CheckEqual(env, after_op_1, context.get());
  138. }
  139. TEST(RemoveBlockReductionPassTest, UnreachableContinueAndMerge) {
  140. // Loop with unreachable merge and continue target. There should be no
  141. // opportunities.
  142. std::string shader = R"(
  143. OpCapability Shader
  144. %1 = OpExtInstImport "GLSL.std.450"
  145. OpMemoryModel Logical GLSL450
  146. OpEntryPoint Fragment %4 "main"
  147. OpExecutionMode %4 OriginUpperLeft
  148. OpSource ESSL 310
  149. OpName %4 "main"
  150. %2 = OpTypeVoid
  151. %3 = OpTypeFunction %2
  152. %4 = OpFunction %2 None %3
  153. %5 = OpLabel
  154. OpBranch %13
  155. %13 = OpLabel
  156. OpLoopMerge %16 %15 None
  157. OpBranch %14
  158. %14 = OpLabel
  159. OpReturn
  160. %15 = OpLabel
  161. OpBranch %13
  162. %16 = OpLabel
  163. OpReturn
  164. OpFunctionEnd
  165. )";
  166. const auto env = SPV_ENV_UNIVERSAL_1_3;
  167. const auto consumer = nullptr;
  168. const auto context =
  169. BuildModule(env, consumer, shader, kReduceAssembleOption);
  170. const auto ops =
  171. RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  172. context.get(), 0);
  173. ASSERT_EQ(0, ops.size());
  174. }
  175. TEST(RemoveBlockReductionPassTest, OneBlock) {
  176. // Function with just one block. There should be no opportunities.
  177. std::string shader = R"(
  178. OpCapability Shader
  179. %1 = OpExtInstImport "GLSL.std.450"
  180. OpMemoryModel Logical GLSL450
  181. OpEntryPoint Fragment %4 "main"
  182. OpExecutionMode %4 OriginUpperLeft
  183. OpSource ESSL 310
  184. OpName %4 "main"
  185. %2 = OpTypeVoid
  186. %3 = OpTypeFunction %2
  187. %4 = OpFunction %2 None %3
  188. %5 = OpLabel
  189. OpReturn
  190. OpFunctionEnd
  191. )";
  192. const auto env = SPV_ENV_UNIVERSAL_1_3;
  193. const auto consumer = nullptr;
  194. const auto context =
  195. BuildModule(env, consumer, shader, kReduceAssembleOption);
  196. const auto ops =
  197. RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  198. context.get(), 0);
  199. ASSERT_EQ(0, ops.size());
  200. }
  201. TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithOutsideIdUses) {
  202. // A function with two unreachable blocks A -> B. A defines ID %9 and B uses
  203. // %9. There are no references to A, but removing A would be invalid because
  204. // of B's use of %9, so there should be no opportunities.
  205. std::string shader = R"(
  206. OpCapability Shader
  207. %1 = OpExtInstImport "GLSL.std.450"
  208. OpMemoryModel Logical GLSL450
  209. OpEntryPoint Fragment %2 "main"
  210. OpExecutionMode %2 OriginUpperLeft
  211. OpSource ESSL 310
  212. OpName %2 "main"
  213. %3 = OpTypeVoid
  214. %4 = OpTypeInt 32 1
  215. %5 = OpTypeFunction %3
  216. %6 = OpConstant %4 1
  217. %2 = OpFunction %3 None %5
  218. %7 = OpLabel
  219. OpReturn
  220. %8 = OpLabel ; A
  221. %9 = OpUndef %4
  222. OpBranch %10
  223. %10 = OpLabel ; B
  224. %11 = OpIAdd %4 %6 %9 ; uses %9 from A, so A cannot be removed
  225. OpReturn
  226. OpFunctionEnd
  227. )";
  228. const auto env = SPV_ENV_UNIVERSAL_1_3;
  229. const auto consumer = nullptr;
  230. const auto context =
  231. BuildModule(env, consumer, shader, kReduceAssembleOption);
  232. const auto ops =
  233. RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  234. context.get(), 0);
  235. ASSERT_EQ(0, ops.size());
  236. }
  237. TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) {
  238. // Similar to the above test.
  239. // A function with two unreachable blocks A -> B. Both blocks create and use
  240. // IDs, but the uses are contained within each block, so A should be removed.
  241. std::string shader = R"(
  242. OpCapability Shader
  243. %1 = OpExtInstImport "GLSL.std.450"
  244. OpMemoryModel Logical GLSL450
  245. OpEntryPoint Fragment %2 "main"
  246. OpExecutionMode %2 OriginUpperLeft
  247. OpSource ESSL 310
  248. OpName %2 "main"
  249. %3 = OpTypeVoid
  250. %4 = OpTypeInt 32 1
  251. %5 = OpTypeFunction %3
  252. %6 = OpConstant %4 1
  253. %2 = OpFunction %3 None %5
  254. %7 = OpLabel
  255. OpReturn
  256. %8 = OpLabel ; A
  257. %9 = OpUndef %4 ; define %9
  258. %10 = OpIAdd %4 %6 %9 ; use %9
  259. OpBranch %11
  260. %11 = OpLabel ; B
  261. %12 = OpUndef %4 ; define %12
  262. %13 = OpIAdd %4 %6 %12 ; use %12
  263. OpReturn
  264. OpFunctionEnd
  265. )";
  266. const auto env = SPV_ENV_UNIVERSAL_1_3;
  267. const auto consumer = nullptr;
  268. const auto context =
  269. BuildModule(env, consumer, shader, kReduceAssembleOption);
  270. auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  271. context.get(), 0);
  272. ASSERT_EQ(1, ops.size());
  273. ASSERT_TRUE(ops[0]->PreconditionHolds());
  274. ops[0]->TryToApply();
  275. // Same as above, but block A is removed.
  276. std::string after_op_0 = R"(
  277. OpCapability Shader
  278. %1 = OpExtInstImport "GLSL.std.450"
  279. OpMemoryModel Logical GLSL450
  280. OpEntryPoint Fragment %2 "main"
  281. OpExecutionMode %2 OriginUpperLeft
  282. OpSource ESSL 310
  283. OpName %2 "main"
  284. %3 = OpTypeVoid
  285. %4 = OpTypeInt 32 1
  286. %5 = OpTypeFunction %3
  287. %6 = OpConstant %4 1
  288. %2 = OpFunction %3 None %5
  289. %7 = OpLabel
  290. OpReturn
  291. %11 = OpLabel
  292. %12 = OpUndef %4
  293. %13 = OpIAdd %4 %6 %12
  294. OpReturn
  295. OpFunctionEnd
  296. )";
  297. CheckEqual(env, after_op_0, context.get());
  298. // Find opportunities again. There are no reference to B. B should now be
  299. // removed.
  300. ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
  301. context.get(), 0);
  302. ASSERT_EQ(1, ops.size());
  303. ASSERT_TRUE(ops[0]->PreconditionHolds());
  304. ops[0]->TryToApply();
  305. // Same as above, but block B is removed.
  306. std::string after_op_0_again = R"(
  307. OpCapability Shader
  308. %1 = OpExtInstImport "GLSL.std.450"
  309. OpMemoryModel Logical GLSL450
  310. OpEntryPoint Fragment %2 "main"
  311. OpExecutionMode %2 OriginUpperLeft
  312. OpSource ESSL 310
  313. OpName %2 "main"
  314. %3 = OpTypeVoid
  315. %4 = OpTypeInt 32 1
  316. %5 = OpTypeFunction %3
  317. %6 = OpConstant %4 1
  318. %2 = OpFunction %3 None %5
  319. %7 = OpLabel
  320. OpReturn
  321. OpFunctionEnd
  322. )";
  323. CheckEqual(env, after_op_0_again, context.get());
  324. }
  325. } // namespace
  326. } // namespace reduce
  327. } // namespace spvtools