redundancy_elimination_test.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // Copyright (c) 2017 Google Inc.
  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 "gmock/gmock.h"
  16. #include "source/opt/build_module.h"
  17. #include "source/opt/value_number_table.h"
  18. #include "test/opt/assembly_builder.h"
  19. #include "test/opt/pass_fixture.h"
  20. #include "test/opt/pass_utils.h"
  21. namespace spvtools {
  22. namespace opt {
  23. namespace {
  24. using ::testing::HasSubstr;
  25. using ::testing::MatchesRegex;
  26. using RedundancyEliminationTest = PassTest<::testing::Test>;
  27. // Test that it can get a simple case of local redundancy elimination.
  28. // The rest of the test check for extra functionality.
  29. TEST_F(RedundancyEliminationTest, RemoveRedundantLocalAdd) {
  30. const std::string text = R"(
  31. OpCapability Shader
  32. %1 = OpExtInstImport "GLSL.std.450"
  33. OpMemoryModel Logical GLSL450
  34. OpEntryPoint Fragment %2 "main"
  35. OpExecutionMode %2 OriginUpperLeft
  36. OpSource GLSL 430
  37. %3 = OpTypeVoid
  38. %4 = OpTypeFunction %3
  39. %5 = OpTypeFloat 32
  40. %6 = OpTypePointer Function %5
  41. %2 = OpFunction %3 None %4
  42. %7 = OpLabel
  43. %8 = OpVariable %6 Function
  44. %9 = OpLoad %5 %8
  45. %10 = OpFAdd %5 %9 %9
  46. ; CHECK: OpFAdd
  47. ; CHECK-NOT: OpFAdd
  48. %11 = OpFAdd %5 %9 %9
  49. OpReturn
  50. OpFunctionEnd
  51. )";
  52. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  53. }
  54. // Remove a redundant add across basic blocks.
  55. TEST_F(RedundancyEliminationTest, RemoveRedundantAdd) {
  56. const std::string text = R"(
  57. OpCapability Shader
  58. %1 = OpExtInstImport "GLSL.std.450"
  59. OpMemoryModel Logical GLSL450
  60. OpEntryPoint Fragment %2 "main"
  61. OpExecutionMode %2 OriginUpperLeft
  62. OpSource GLSL 430
  63. %3 = OpTypeVoid
  64. %4 = OpTypeFunction %3
  65. %5 = OpTypeFloat 32
  66. %6 = OpTypePointer Function %5
  67. %2 = OpFunction %3 None %4
  68. %7 = OpLabel
  69. %8 = OpVariable %6 Function
  70. %9 = OpLoad %5 %8
  71. %10 = OpFAdd %5 %9 %9
  72. OpBranch %11
  73. %11 = OpLabel
  74. ; CHECK: OpFAdd
  75. ; CHECK-NOT: OpFAdd
  76. %12 = OpFAdd %5 %9 %9
  77. OpReturn
  78. OpFunctionEnd
  79. )";
  80. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  81. }
  82. // Remove a redundant add going through a multiple basic blocks.
  83. TEST_F(RedundancyEliminationTest, RemoveRedundantAddDiamond) {
  84. const std::string text = R"(
  85. OpCapability Shader
  86. %1 = OpExtInstImport "GLSL.std.450"
  87. OpMemoryModel Logical GLSL450
  88. OpEntryPoint Fragment %2 "main"
  89. OpExecutionMode %2 OriginUpperLeft
  90. OpSource GLSL 430
  91. %3 = OpTypeVoid
  92. %4 = OpTypeFunction %3
  93. %5 = OpTypeFloat 32
  94. %6 = OpTypePointer Function %5
  95. %7 = OpTypeBool
  96. %8 = OpConstantTrue %7
  97. %2 = OpFunction %3 None %4
  98. %9 = OpLabel
  99. %10 = OpVariable %6 Function
  100. %11 = OpLoad %5 %10
  101. %12 = OpFAdd %5 %11 %11
  102. ; CHECK: OpFAdd
  103. ; CHECK-NOT: OpFAdd
  104. OpBranchConditional %8 %13 %14
  105. %13 = OpLabel
  106. OpBranch %15
  107. %14 = OpLabel
  108. OpBranch %15
  109. %15 = OpLabel
  110. %16 = OpFAdd %5 %11 %11
  111. OpReturn
  112. OpFunctionEnd
  113. )";
  114. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  115. }
  116. // Remove a redundant add in a side node.
  117. TEST_F(RedundancyEliminationTest, RemoveRedundantAddInSideNode) {
  118. const std::string text = R"(
  119. OpCapability Shader
  120. %1 = OpExtInstImport "GLSL.std.450"
  121. OpMemoryModel Logical GLSL450
  122. OpEntryPoint Fragment %2 "main"
  123. OpExecutionMode %2 OriginUpperLeft
  124. OpSource GLSL 430
  125. %3 = OpTypeVoid
  126. %4 = OpTypeFunction %3
  127. %5 = OpTypeFloat 32
  128. %6 = OpTypePointer Function %5
  129. %7 = OpTypeBool
  130. %8 = OpConstantTrue %7
  131. %2 = OpFunction %3 None %4
  132. %9 = OpLabel
  133. %10 = OpVariable %6 Function
  134. %11 = OpLoad %5 %10
  135. %12 = OpFAdd %5 %11 %11
  136. ; CHECK: OpFAdd
  137. ; CHECK-NOT: OpFAdd
  138. OpBranchConditional %8 %13 %14
  139. %13 = OpLabel
  140. OpBranch %15
  141. %14 = OpLabel
  142. %16 = OpFAdd %5 %11 %11
  143. OpBranch %15
  144. %15 = OpLabel
  145. OpReturn
  146. OpFunctionEnd
  147. )";
  148. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  149. }
  150. // Remove a redundant add whose value is in the result of a phi node.
  151. TEST_F(RedundancyEliminationTest, RemoveRedundantAddWithPhi) {
  152. const std::string text = R"(
  153. OpCapability Shader
  154. %1 = OpExtInstImport "GLSL.std.450"
  155. OpMemoryModel Logical GLSL450
  156. OpEntryPoint Fragment %2 "main"
  157. OpExecutionMode %2 OriginUpperLeft
  158. OpSource GLSL 430
  159. %3 = OpTypeVoid
  160. %4 = OpTypeFunction %3
  161. %5 = OpTypeFloat 32
  162. %6 = OpTypePointer Function %5
  163. %7 = OpTypeBool
  164. %8 = OpConstantTrue %7
  165. %2 = OpFunction %3 None %4
  166. %9 = OpLabel
  167. %10 = OpVariable %6 Function
  168. %11 = OpLoad %5 %10
  169. OpBranchConditional %8 %13 %14
  170. %13 = OpLabel
  171. %add1 = OpFAdd %5 %11 %11
  172. ; CHECK: OpFAdd
  173. OpBranch %15
  174. %14 = OpLabel
  175. %add2 = OpFAdd %5 %11 %11
  176. ; CHECK: OpFAdd
  177. OpBranch %15
  178. %15 = OpLabel
  179. ; CHECK: OpPhi
  180. %phi = OpPhi %5 %add1 %13 %add2 %14
  181. ; CHECK-NOT: OpFAdd
  182. %16 = OpFAdd %5 %11 %11
  183. OpReturn
  184. OpFunctionEnd
  185. )";
  186. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  187. }
  188. // Keep the add because it is redundant on some paths, but not all paths.
  189. TEST_F(RedundancyEliminationTest, KeepPartiallyRedundantAdd) {
  190. const std::string text = R"(
  191. OpCapability Shader
  192. %1 = OpExtInstImport "GLSL.std.450"
  193. OpMemoryModel Logical GLSL450
  194. OpEntryPoint Fragment %2 "main"
  195. OpExecutionMode %2 OriginUpperLeft
  196. OpSource GLSL 430
  197. %3 = OpTypeVoid
  198. %4 = OpTypeFunction %3
  199. %5 = OpTypeFloat 32
  200. %6 = OpTypePointer Function %5
  201. %7 = OpTypeBool
  202. %8 = OpConstantTrue %7
  203. %2 = OpFunction %3 None %4
  204. %9 = OpLabel
  205. %10 = OpVariable %6 Function
  206. %11 = OpLoad %5 %10
  207. OpBranchConditional %8 %13 %14
  208. %13 = OpLabel
  209. %add = OpFAdd %5 %11 %11
  210. OpBranch %15
  211. %14 = OpLabel
  212. OpBranch %15
  213. %15 = OpLabel
  214. %16 = OpFAdd %5 %11 %11
  215. OpReturn
  216. OpFunctionEnd
  217. )";
  218. auto result = SinglePassRunAndDisassemble<RedundancyEliminationPass>(
  219. text, /* skip_nop = */ true, /* do_validation = */ false);
  220. EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
  221. }
  222. // Keep the add. Even if it is redundant on all paths, there is no single id
  223. // whose definition dominates the add and contains the same value.
  224. TEST_F(RedundancyEliminationTest, KeepRedundantAddWithoutPhi) {
  225. const std::string text = R"(
  226. OpCapability Shader
  227. %1 = OpExtInstImport "GLSL.std.450"
  228. OpMemoryModel Logical GLSL450
  229. OpEntryPoint Fragment %2 "main"
  230. OpExecutionMode %2 OriginUpperLeft
  231. OpSource GLSL 430
  232. %3 = OpTypeVoid
  233. %4 = OpTypeFunction %3
  234. %5 = OpTypeFloat 32
  235. %6 = OpTypePointer Function %5
  236. %7 = OpTypeBool
  237. %8 = OpConstantTrue %7
  238. %2 = OpFunction %3 None %4
  239. %9 = OpLabel
  240. %10 = OpVariable %6 Function
  241. %11 = OpLoad %5 %10
  242. OpBranchConditional %8 %13 %14
  243. %13 = OpLabel
  244. %add1 = OpFAdd %5 %11 %11
  245. OpBranch %15
  246. %14 = OpLabel
  247. %add2 = OpFAdd %5 %11 %11
  248. OpBranch %15
  249. %15 = OpLabel
  250. %16 = OpFAdd %5 %11 %11
  251. OpReturn
  252. OpFunctionEnd
  253. )";
  254. auto result = SinglePassRunAndDisassemble<RedundancyEliminationPass>(
  255. text, /* skip_nop = */ true, /* do_validation = */ false);
  256. EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
  257. }
  258. // Test that it can get a simple case of local redundancy elimination
  259. // when it has OpenCL.DebugInfo.100 instructions.
  260. TEST_F(RedundancyEliminationTest, OpenCLDebugInfo100) {
  261. // When three redundant DebugValues exist, only one DebugValue must remain.
  262. const std::string text = R"(
  263. OpCapability Shader
  264. %1 = OpExtInstImport "OpenCL.DebugInfo.100"
  265. %2 = OpExtInstImport "GLSL.std.450"
  266. OpMemoryModel Logical GLSL450
  267. OpEntryPoint Fragment %3 "main"
  268. OpExecutionMode %3 OriginUpperLeft
  269. OpSource GLSL 430
  270. %4 = OpString "ps.hlsl"
  271. %5 = OpString "float"
  272. %6 = OpString "s0"
  273. %7 = OpString "main"
  274. %void = OpTypeVoid
  275. %9 = OpTypeFunction %void
  276. %float = OpTypeFloat 32
  277. %uint = OpTypeInt 32 0
  278. %uint_0 = OpConstant %uint 0
  279. %uint_32 = OpConstant %uint 32
  280. %_ptr_Function_float = OpTypePointer Function %float
  281. %15 = OpExtInst %void %1 DebugExpression
  282. %16 = OpExtInst %void %1 DebugSource %4
  283. %17 = OpExtInst %void %1 DebugCompilationUnit 1 4 %16 HLSL
  284. %18 = OpExtInst %void %1 DebugTypeBasic %5 %uint_32 Float
  285. %19 = OpExtInst %void %1 DebugTypeVector %18 4
  286. %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %19
  287. %21 = OpExtInst %void %1 DebugFunction %7 %20 %16 4 1 %17 %7 FlagIsProtected|FlagIsPrivate 4 %3
  288. ; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void {{%\w+}} DebugLocalVariable
  289. %22 = OpExtInst %void %1 DebugLocalVariable %6 %19 %16 0 0 %21 FlagIsLocal
  290. %14 = OpExtInst %void %1 DebugLocalVariable %6 %19 %16 0 0 %21 FlagIsLocal
  291. %3 = OpFunction %void None %9
  292. %23 = OpLabel
  293. %24 = OpExtInst %void %1 DebugScope %21
  294. %25 = OpVariable %_ptr_Function_float Function
  295. %26 = OpLoad %float %25
  296. OpLine %4 0 0
  297. ; Two `OpFAdd %float %26 %26` are the same. One must be removed.
  298. ; After removing one `OpFAdd %float %26 %26`, two DebugValues are the same.
  299. ; One must be removed.
  300. ;
  301. ; CHECK: OpLine {{%\w+}} 0 0
  302. ; CHECK-NEXT: [[add:%\w+]] = OpFAdd %float [[value:%\w+]]
  303. ; CHECK-NEXT: DebugValue [[dbg_local_var]] [[add]]
  304. ; CHECK-NEXT: OpLine {{%\w+}} 1 0
  305. ; CHECK-NEXT: OpFAdd %float [[add]] [[value]]
  306. ; CHECK-NEXT: OpReturn
  307. %27 = OpFAdd %float %26 %26
  308. %28 = OpExtInst %void %1 DebugValue %22 %27 %15 %uint_0
  309. OpLine %4 1 0
  310. %29 = OpFAdd %float %26 %26
  311. %30 = OpExtInst %void %1 DebugValue %14 %29 %15 %uint_0
  312. %31 = OpExtInst %void %1 DebugValue %22 %29 %15 %uint_0
  313. %32 = OpFAdd %float %29 %26
  314. %33 = OpFAdd %float %27 %26
  315. OpReturn
  316. OpFunctionEnd
  317. )";
  318. SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
  319. }
  320. TEST_F(RedundancyEliminationTest, FunctionDeclaration) {
  321. // Make sure the pass works with a function declaration that is called.
  322. const std::string text = R"(OpCapability Addresses
  323. OpCapability Linkage
  324. OpCapability Kernel
  325. OpCapability Int8
  326. %1 = OpExtInstImport "OpenCL.std"
  327. OpMemoryModel Physical64 OpenCL
  328. OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
  329. OpExecutionMode %2 ContractionOff
  330. OpSource Unknown 0
  331. OpDecorate %3 LinkageAttributes "julia_error_7712" Import
  332. %void = OpTypeVoid
  333. %5 = OpTypeFunction %void
  334. %3 = OpFunction %void None %5
  335. OpFunctionEnd
  336. %2 = OpFunction %void None %5
  337. %6 = OpLabel
  338. %7 = OpFunctionCall %void %3
  339. OpReturn
  340. OpFunctionEnd
  341. )";
  342. SinglePassRunAndCheck<RedundancyEliminationPass>(text, text, false);
  343. }
  344. } // namespace
  345. } // namespace opt
  346. } // namespace spvtools