hoist_without_preheader.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 generate a preheader when one is not present
  25. Generated from the following GLSL fragment shader
  26. --eliminate-local-multi-store has also been run on the spv binary
  27. #version 440 core
  28. void main(){
  29. int a = 1;
  30. int b = 2;
  31. int hoist = 0;
  32. for (int i = 0; i < 10; i++) {
  33. if (i == 5) {
  34. break;
  35. }
  36. }
  37. for (int i = 0; i < 10; i++) {
  38. hoist = a + b;
  39. }
  40. }
  41. */
  42. TEST_F(PassClassTest, HoistWithoutPreheader) {
  43. const std::string text = R"(OpCapability Shader
  44. %1 = OpExtInstImport "GLSL.std.450"
  45. OpMemoryModel Logical GLSL450
  46. OpEntryPoint Fragment %main "main"
  47. OpExecutionMode %main OriginUpperLeft
  48. OpSource GLSL 440
  49. OpName %main "main"
  50. %void = OpTypeVoid
  51. %4 = OpTypeFunction %void
  52. %int = OpTypeInt 32 1
  53. %_ptr_Function_int = OpTypePointer Function %int
  54. %int_1 = OpConstant %int 1
  55. %int_2 = OpConstant %int 2
  56. %int_0 = OpConstant %int 0
  57. %int_10 = OpConstant %int 10
  58. %bool = OpTypeBool
  59. %int_5 = OpConstant %int 5
  60. %main = OpFunction %void None %4
  61. %13 = OpLabel
  62. OpBranch %14
  63. %14 = OpLabel
  64. %15 = OpPhi %int %int_0 %13 %16 %17
  65. ; CHECK: OpLoopMerge [[preheader:%\w+]]
  66. OpLoopMerge %25 %17 None
  67. OpBranch %19
  68. %19 = OpLabel
  69. %20 = OpSLessThan %bool %15 %int_10
  70. OpBranchConditional %20 %21 %25
  71. %21 = OpLabel
  72. %22 = OpIEqual %bool %15 %int_5
  73. OpSelectionMerge %23 None
  74. OpBranchConditional %22 %24 %23
  75. %24 = OpLabel
  76. OpBranch %25
  77. %23 = OpLabel
  78. OpBranch %17
  79. %17 = OpLabel
  80. %16 = OpIAdd %int %15 %int_1
  81. OpBranch %14
  82. ; Check that we hoisted the code to the preheader
  83. ; CHECK: [[preheader]] = OpLabel
  84. ; CHECK-NEXT: OpPhi
  85. ; CHECK-NEXT: OpPhi
  86. ; CHECK-NEXT: OpIAdd
  87. ; CHECK-NEXT: OpBranch [[header:%\w+]]
  88. ; CHECK: [[header]] = OpLabel
  89. ; CHECK-NEXT: OpPhi
  90. ; CHECK-NEXT: OpPhi
  91. ; CHECK: OpLoopMerge
  92. %25 = OpLabel
  93. %26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
  94. %29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
  95. OpLoopMerge %31 %28 None
  96. OpBranch %32
  97. %32 = OpLabel
  98. %33 = OpSLessThan %bool %29 %int_10
  99. OpBranchConditional %33 %34 %31
  100. %34 = OpLabel
  101. %27 = OpIAdd %int %int_1 %int_2
  102. OpBranch %28
  103. %28 = OpLabel
  104. %30 = OpIAdd %int %29 %int_1
  105. OpBranch %25
  106. %31 = OpLabel
  107. OpReturn
  108. OpFunctionEnd
  109. )";
  110. SinglePassRunAndMatch<LICMPass>(text, false);
  111. }
  112. TEST_F(PassClassTest, HoistWithoutPreheaderAtIdBound) {
  113. const std::string text = R"(OpCapability Shader
  114. %1 = OpExtInstImport "GLSL.std.450"
  115. OpMemoryModel Logical GLSL450
  116. OpEntryPoint Fragment %main "main"
  117. OpExecutionMode %main OriginUpperLeft
  118. OpSource GLSL 440
  119. OpName %main "main"
  120. %void = OpTypeVoid
  121. %4 = OpTypeFunction %void
  122. %int = OpTypeInt 32 1
  123. %_ptr_Function_int = OpTypePointer Function %int
  124. %int_1 = OpConstant %int 1
  125. %int_2 = OpConstant %int 2
  126. %int_0 = OpConstant %int 0
  127. %int_10 = OpConstant %int 10
  128. %bool = OpTypeBool
  129. %int_5 = OpConstant %int 5
  130. %main = OpFunction %void None %4
  131. %13 = OpLabel
  132. OpBranch %14
  133. %14 = OpLabel
  134. %15 = OpPhi %int %int_0 %13 %16 %17
  135. OpLoopMerge %25 %17 None
  136. OpBranch %19
  137. %19 = OpLabel
  138. %20 = OpSLessThan %bool %15 %int_10
  139. OpBranchConditional %20 %21 %25
  140. %21 = OpLabel
  141. %22 = OpIEqual %bool %15 %int_5
  142. OpSelectionMerge %23 None
  143. OpBranchConditional %22 %24 %23
  144. %24 = OpLabel
  145. OpBranch %25
  146. %23 = OpLabel
  147. OpBranch %17
  148. %17 = OpLabel
  149. %16 = OpIAdd %int %15 %int_1
  150. OpBranch %14
  151. %25 = OpLabel
  152. %26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
  153. %29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
  154. OpLoopMerge %31 %28 None
  155. OpBranch %32
  156. %32 = OpLabel
  157. %33 = OpSLessThan %bool %29 %int_10
  158. OpBranchConditional %33 %34 %31
  159. %34 = OpLabel
  160. %27 = OpIAdd %int %int_1 %int_2
  161. OpBranch %28
  162. %28 = OpLabel
  163. %30 = OpIAdd %int %29 %int_1
  164. OpBranch %25
  165. %31 = OpLabel
  166. OpReturn
  167. OpFunctionEnd
  168. )";
  169. std::unique_ptr<IRContext> context =
  170. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  171. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  172. uint32_t current_bound = context->module()->id_bound();
  173. context->set_max_id_bound(current_bound);
  174. auto pass = MakeUnique<LICMPass>();
  175. auto result = pass->Run(context.get());
  176. EXPECT_EQ(result, Pass::Status::Failure);
  177. std::vector<uint32_t> binary;
  178. context->module()->ToBinary(&binary, false);
  179. std::string optimized_asm;
  180. SpirvTools tools_(SPV_ENV_UNIVERSAL_1_1);
  181. tools_.Disassemble(binary, &optimized_asm);
  182. std::cout << optimized_asm << std::endl;
  183. }
  184. } // namespace
  185. } // namespace opt
  186. } // namespace spvtools