redundancy_elimination_test.cpp 12 KB

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