hoist_single_nested_loops.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 "gmock/gmock.h"
  16. #include "source/opt/licm_pass.h"
  17. #include "test/opt/pass_fixture.h"
  18. namespace spvtools {
  19. namespace opt {
  20. namespace {
  21. using ::testing::UnorderedElementsAre;
  22. using PassClassTest = PassTest<::testing::Test>;
  23. /*
  24. Tests that the LICM pass will detect an move an invariant from a nested loop,
  25. but not it's parent loop
  26. Generated from the following GLSL fragment shader
  27. --eliminate-local-multi-store has also been run on the spv binary
  28. #version 440 core
  29. void main(){
  30. int a = 2;
  31. int hoist = 0;
  32. for (int i = 0; i < 10; i++) {
  33. for (int j = 0; j < 10; j++) {
  34. // hoist 'hoist = a - i' out of j loop, but not i loop
  35. hoist = a - i;
  36. }
  37. }
  38. }
  39. */
  40. TEST_F(PassClassTest, NestedSingleHoist) {
  41. const std::string before_hoist = R"(OpCapability Shader
  42. %1 = OpExtInstImport "GLSL.std.450"
  43. OpMemoryModel Logical GLSL450
  44. OpEntryPoint Fragment %main "main"
  45. OpExecutionMode %main OriginUpperLeft
  46. OpSource GLSL 440
  47. OpName %main "main"
  48. %void = OpTypeVoid
  49. %4 = OpTypeFunction %void
  50. %int = OpTypeInt 32 1
  51. %_ptr_Function_int = OpTypePointer Function %int
  52. %int_2 = OpConstant %int 2
  53. %int_0 = OpConstant %int 0
  54. %int_10 = OpConstant %int 10
  55. %bool = OpTypeBool
  56. %int_1 = OpConstant %int 1
  57. %12 = OpUndef %int
  58. %main = OpFunction %void None %4
  59. %13 = OpLabel
  60. OpBranch %14
  61. %14 = OpLabel
  62. %15 = OpPhi %int %int_0 %13 %16 %17
  63. %18 = OpPhi %int %int_0 %13 %19 %17
  64. %20 = OpPhi %int %12 %13 %21 %17
  65. OpLoopMerge %22 %17 None
  66. OpBranch %23
  67. %23 = OpLabel
  68. %24 = OpSLessThan %bool %18 %int_10
  69. OpBranchConditional %24 %25 %22
  70. %25 = OpLabel
  71. OpBranch %26
  72. %26 = OpLabel
  73. %16 = OpPhi %int %15 %25 %27 %28
  74. %21 = OpPhi %int %int_0 %25 %29 %28
  75. OpLoopMerge %30 %28 None
  76. OpBranch %31
  77. %31 = OpLabel
  78. %32 = OpSLessThan %bool %21 %int_10
  79. OpBranchConditional %32 %33 %30
  80. %33 = OpLabel
  81. %27 = OpISub %int %int_2 %18
  82. OpBranch %28
  83. %28 = OpLabel
  84. %29 = OpIAdd %int %21 %int_1
  85. OpBranch %26
  86. %30 = OpLabel
  87. OpBranch %17
  88. %17 = OpLabel
  89. %19 = OpIAdd %int %18 %int_1
  90. OpBranch %14
  91. %22 = OpLabel
  92. OpReturn
  93. OpFunctionEnd
  94. )";
  95. const std::string after_hoist = R"(OpCapability Shader
  96. %1 = OpExtInstImport "GLSL.std.450"
  97. OpMemoryModel Logical GLSL450
  98. OpEntryPoint Fragment %main "main"
  99. OpExecutionMode %main OriginUpperLeft
  100. OpSource GLSL 440
  101. OpName %main "main"
  102. %void = OpTypeVoid
  103. %4 = OpTypeFunction %void
  104. %int = OpTypeInt 32 1
  105. %_ptr_Function_int = OpTypePointer Function %int
  106. %int_2 = OpConstant %int 2
  107. %int_0 = OpConstant %int 0
  108. %int_10 = OpConstant %int 10
  109. %bool = OpTypeBool
  110. %int_1 = OpConstant %int 1
  111. %12 = OpUndef %int
  112. %main = OpFunction %void None %4
  113. %13 = OpLabel
  114. OpBranch %14
  115. %14 = OpLabel
  116. %15 = OpPhi %int %int_0 %13 %16 %17
  117. %18 = OpPhi %int %int_0 %13 %19 %17
  118. %20 = OpPhi %int %12 %13 %21 %17
  119. OpLoopMerge %22 %17 None
  120. OpBranch %23
  121. %23 = OpLabel
  122. %24 = OpSLessThan %bool %18 %int_10
  123. OpBranchConditional %24 %25 %22
  124. %25 = OpLabel
  125. %27 = OpISub %int %int_2 %18
  126. OpBranch %26
  127. %26 = OpLabel
  128. %16 = OpPhi %int %15 %25 %27 %28
  129. %21 = OpPhi %int %int_0 %25 %29 %28
  130. OpLoopMerge %30 %28 None
  131. OpBranch %31
  132. %31 = OpLabel
  133. %32 = OpSLessThan %bool %21 %int_10
  134. OpBranchConditional %32 %33 %30
  135. %33 = OpLabel
  136. OpBranch %28
  137. %28 = OpLabel
  138. %29 = OpIAdd %int %21 %int_1
  139. OpBranch %26
  140. %30 = OpLabel
  141. OpBranch %17
  142. %17 = OpLabel
  143. %19 = OpIAdd %int %18 %int_1
  144. OpBranch %14
  145. %22 = OpLabel
  146. OpReturn
  147. OpFunctionEnd
  148. )";
  149. SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
  150. }
  151. TEST_F(PassClassTest, PreHeaderIsAlsoHeader) {
  152. // Move OpSLessThan out of the inner loop. The preheader for the inner loop
  153. // is the header of the outer loop. The loop merge should not be separated
  154. // from the branch in that block.
  155. const std::string text = R"(
  156. ; CHECK: OpFunction
  157. ; CHECK-NEXT: OpLabel
  158. ; CHECK-NEXT: OpBranch [[header:%\w+]]
  159. ; CHECK: [[header]] = OpLabel
  160. ; CHECK-NEXT: OpSLessThan %bool %int_1 %int_1
  161. ; CHECK-NEXT: OpLoopMerge
  162. OpCapability Shader
  163. %1 = OpExtInstImport "GLSL.std.450"
  164. OpMemoryModel Logical GLSL450
  165. OpEntryPoint Fragment %2 "main"
  166. OpExecutionMode %2 OriginUpperLeft
  167. OpSource ESSL 310
  168. %void = OpTypeVoid
  169. %4 = OpTypeFunction %void
  170. %int = OpTypeInt 32 1
  171. %int_1 = OpConstant %int 1
  172. %bool = OpTypeBool
  173. %2 = OpFunction %void None %4
  174. %18 = OpLabel
  175. OpBranch %21
  176. %21 = OpLabel
  177. OpLoopMerge %22 %23 None
  178. OpBranch %24
  179. %24 = OpLabel
  180. %25 = OpSLessThan %bool %int_1 %int_1
  181. OpLoopMerge %26 %27 None
  182. OpBranchConditional %25 %27 %26
  183. %27 = OpLabel
  184. OpBranch %24
  185. %26 = OpLabel
  186. OpBranch %22
  187. %23 = OpLabel
  188. OpBranch %21
  189. %22 = OpLabel
  190. OpReturn
  191. OpFunctionEnd
  192. )";
  193. SinglePassRunAndMatch<LICMPass>(text, true);
  194. }
  195. } // namespace
  196. } // namespace opt
  197. } // namespace spvtools