remove_block_test.cpp 11 KB

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