cfg_test.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 <string>
  15. #include "gmock/gmock.h"
  16. #include "gtest/gtest.h"
  17. #include "source/opt/ir_context.h"
  18. #include "test/opt/pass_fixture.h"
  19. #include "test/opt/pass_utils.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. using ::testing::ContainerEq;
  24. using CFGTest = PassTest<::testing::Test>;
  25. TEST_F(CFGTest, ForEachBlockInPostOrderIf) {
  26. const std::string test = R"(
  27. OpCapability Shader
  28. %1 = OpExtInstImport "GLSL.std.450"
  29. OpMemoryModel Logical GLSL450
  30. OpEntryPoint Vertex %main "main"
  31. OpName %main "main"
  32. %bool = OpTypeBool
  33. %true = OpConstantTrue %bool
  34. %void = OpTypeVoid
  35. %4 = OpTypeFunction %void
  36. %uint = OpTypeInt 32 0
  37. %5 = OpConstant %uint 5
  38. %main = OpFunction %void None %4
  39. %8 = OpLabel
  40. OpSelectionMerge %10 None
  41. OpBranchConditional %true %9 %10
  42. %9 = OpLabel
  43. OpBranch %10
  44. %10 = OpLabel
  45. OpReturn
  46. OpFunctionEnd
  47. )";
  48. std::unique_ptr<IRContext> context =
  49. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  50. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  51. ASSERT_NE(nullptr, context);
  52. CFG* cfg = context->cfg();
  53. Module* module = context->module();
  54. Function* function = &*module->begin();
  55. std::vector<uint32_t> order;
  56. cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) {
  57. order.push_back(bb->id());
  58. });
  59. std::vector<uint32_t> expected_result = {10, 9, 8};
  60. EXPECT_THAT(order, ContainerEq(expected_result));
  61. }
  62. TEST_F(CFGTest, ForEachBlockInPostOrderLoop) {
  63. const std::string test = R"(
  64. OpCapability Shader
  65. %1 = OpExtInstImport "GLSL.std.450"
  66. OpMemoryModel Logical GLSL450
  67. OpEntryPoint Vertex %main "main"
  68. OpName %main "main"
  69. %bool = OpTypeBool
  70. %true = OpConstantTrue %bool
  71. %void = OpTypeVoid
  72. %4 = OpTypeFunction %void
  73. %uint = OpTypeInt 32 0
  74. %5 = OpConstant %uint 5
  75. %main = OpFunction %void None %4
  76. %8 = OpLabel
  77. OpBranch %9
  78. %9 = OpLabel
  79. OpLoopMerge %11 %10 None
  80. OpBranchConditional %true %11 %10
  81. %10 = OpLabel
  82. OpBranch %9
  83. %11 = OpLabel
  84. OpReturn
  85. OpFunctionEnd
  86. )";
  87. std::unique_ptr<IRContext> context =
  88. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  89. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  90. ASSERT_NE(nullptr, context);
  91. CFG* cfg = context->cfg();
  92. Module* module = context->module();
  93. Function* function = &*module->begin();
  94. std::vector<uint32_t> order;
  95. cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) {
  96. order.push_back(bb->id());
  97. });
  98. std::vector<uint32_t> expected_result1 = {10, 11, 9, 8};
  99. std::vector<uint32_t> expected_result2 = {11, 10, 9, 8};
  100. EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1),
  101. ContainerEq(expected_result2)));
  102. }
  103. TEST_F(CFGTest, ForEachBlockInReversePostOrderIf) {
  104. const std::string test = R"(
  105. OpCapability Shader
  106. %1 = OpExtInstImport "GLSL.std.450"
  107. OpMemoryModel Logical GLSL450
  108. OpEntryPoint Vertex %main "main"
  109. OpName %main "main"
  110. %bool = OpTypeBool
  111. %true = OpConstantTrue %bool
  112. %void = OpTypeVoid
  113. %4 = OpTypeFunction %void
  114. %uint = OpTypeInt 32 0
  115. %5 = OpConstant %uint 5
  116. %main = OpFunction %void None %4
  117. %8 = OpLabel
  118. OpSelectionMerge %10 None
  119. OpBranchConditional %true %9 %10
  120. %9 = OpLabel
  121. OpBranch %10
  122. %10 = OpLabel
  123. OpReturn
  124. OpFunctionEnd
  125. )";
  126. std::unique_ptr<IRContext> context =
  127. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  128. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  129. ASSERT_NE(nullptr, context);
  130. CFG* cfg = context->cfg();
  131. Module* module = context->module();
  132. Function* function = &*module->begin();
  133. std::vector<uint32_t> order;
  134. cfg->ForEachBlockInReversePostOrder(
  135. &*function->begin(),
  136. [&order](BasicBlock* bb) { order.push_back(bb->id()); });
  137. std::vector<uint32_t> expected_result = {8, 9, 10};
  138. EXPECT_THAT(order, ContainerEq(expected_result));
  139. }
  140. TEST_F(CFGTest, ForEachBlockInReversePostOrderLoop) {
  141. const std::string test = R"(
  142. OpCapability Shader
  143. %1 = OpExtInstImport "GLSL.std.450"
  144. OpMemoryModel Logical GLSL450
  145. OpEntryPoint Vertex %main "main"
  146. OpName %main "main"
  147. %bool = OpTypeBool
  148. %true = OpConstantTrue %bool
  149. %void = OpTypeVoid
  150. %4 = OpTypeFunction %void
  151. %uint = OpTypeInt 32 0
  152. %5 = OpConstant %uint 5
  153. %main = OpFunction %void None %4
  154. %8 = OpLabel
  155. OpBranch %9
  156. %9 = OpLabel
  157. OpLoopMerge %11 %10 None
  158. OpBranchConditional %true %11 %10
  159. %10 = OpLabel
  160. OpBranch %9
  161. %11 = OpLabel
  162. OpReturn
  163. OpFunctionEnd
  164. )";
  165. std::unique_ptr<IRContext> context =
  166. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  167. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  168. ASSERT_NE(nullptr, context);
  169. CFG* cfg = context->cfg();
  170. Module* module = context->module();
  171. Function* function = &*module->begin();
  172. std::vector<uint32_t> order;
  173. cfg->ForEachBlockInReversePostOrder(
  174. &*function->begin(),
  175. [&order](BasicBlock* bb) { order.push_back(bb->id()); });
  176. std::vector<uint32_t> expected_result1 = {8, 9, 10, 11};
  177. std::vector<uint32_t> expected_result2 = {8, 9, 11, 10};
  178. EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1),
  179. ContainerEq(expected_result2)));
  180. }
  181. TEST_F(CFGTest, SplitLoopHeaderForSingleBlockLoop) {
  182. const std::string test = R"(
  183. OpCapability Shader
  184. %1 = OpExtInstImport "GLSL.std.450"
  185. OpMemoryModel Logical GLSL450
  186. OpEntryPoint Fragment %2 "main"
  187. OpExecutionMode %2 OriginUpperLeft
  188. %void = OpTypeVoid
  189. %uint = OpTypeInt 32 0
  190. %uint_0 = OpConstant %uint 0
  191. %6 = OpTypeFunction %void
  192. %2 = OpFunction %void None %6
  193. %7 = OpLabel
  194. OpBranch %8
  195. %8 = OpLabel
  196. %9 = OpPhi %uint %uint_0 %7 %9 %8
  197. OpLoopMerge %10 %8 None
  198. OpBranch %8
  199. %10 = OpLabel
  200. OpUnreachable
  201. OpFunctionEnd
  202. )";
  203. const std::string expected_result = R"(OpCapability Shader
  204. %1 = OpExtInstImport "GLSL.std.450"
  205. OpMemoryModel Logical GLSL450
  206. OpEntryPoint Fragment %2 "main"
  207. OpExecutionMode %2 OriginUpperLeft
  208. %void = OpTypeVoid
  209. %uint = OpTypeInt 32 0
  210. %uint_0 = OpConstant %uint 0
  211. %6 = OpTypeFunction %void
  212. %2 = OpFunction %void None %6
  213. %7 = OpLabel
  214. OpBranch %8
  215. %8 = OpLabel
  216. OpBranch %11
  217. %11 = OpLabel
  218. %9 = OpPhi %uint %9 %11 %uint_0 %8
  219. OpLoopMerge %10 %11 None
  220. OpBranch %11
  221. %10 = OpLabel
  222. OpUnreachable
  223. OpFunctionEnd
  224. )";
  225. std::unique_ptr<IRContext> context =
  226. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  227. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  228. ASSERT_NE(nullptr, context);
  229. BasicBlock* loop_header = context->get_instr_block(8);
  230. ASSERT_TRUE(loop_header->GetLoopMergeInst() != nullptr);
  231. CFG* cfg = context->cfg();
  232. cfg->SplitLoopHeader(loop_header);
  233. std::vector<uint32_t> binary;
  234. bool skip_nop = false;
  235. context->module()->ToBinary(&binary, skip_nop);
  236. std::string optimized_asm;
  237. SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
  238. EXPECT_TRUE(tools.Disassemble(binary, &optimized_asm,
  239. SpirvTools::kDefaultDisassembleOption))
  240. << "Disassembling failed for shader\n"
  241. << std::endl;
  242. EXPECT_EQ(optimized_asm, expected_result);
  243. }
  244. TEST_F(CFGTest, ComputeStructedOrderForLoop) {
  245. const std::string test = R"(
  246. OpCapability Shader
  247. %1 = OpExtInstImport "GLSL.std.450"
  248. OpMemoryModel Logical GLSL450
  249. OpEntryPoint Vertex %main "main"
  250. OpName %main "main"
  251. %bool = OpTypeBool
  252. %true = OpConstantTrue %bool
  253. %void = OpTypeVoid
  254. %4 = OpTypeFunction %void
  255. %uint = OpTypeInt 32 0
  256. %5 = OpConstant %uint 5
  257. %main = OpFunction %void None %4
  258. %8 = OpLabel
  259. OpBranch %9
  260. %9 = OpLabel
  261. OpLoopMerge %11 %10 None
  262. OpBranchConditional %true %11 %10
  263. %10 = OpLabel
  264. OpBranch %9
  265. %11 = OpLabel
  266. OpBranch %12
  267. %12 = OpLabel
  268. OpReturn
  269. OpFunctionEnd
  270. )";
  271. std::unique_ptr<IRContext> context =
  272. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
  273. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  274. ASSERT_NE(nullptr, context);
  275. CFG* cfg = context->cfg();
  276. Module* module = context->module();
  277. Function* function = &*module->begin();
  278. std::list<BasicBlock*> order;
  279. cfg->ComputeStructuredOrder(function, context->get_instr_block(9),
  280. context->get_instr_block(11), &order);
  281. // Order should contain the loop header, the continue target, and the merge
  282. // node.
  283. std::list<BasicBlock*> expected_result = {context->get_instr_block(9),
  284. context->get_instr_block(10),
  285. context->get_instr_block(11)};
  286. EXPECT_THAT(order, ContainerEq(expected_result));
  287. }
  288. } // namespace
  289. } // namespace opt
  290. } // namespace spvtools