function_test.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 <memory>
  15. #include <vector>
  16. #include "function_utils.h"
  17. #include "gmock/gmock.h"
  18. #include "gtest/gtest.h"
  19. #include "source/opt/build_module.h"
  20. #include "source/opt/ir_context.h"
  21. namespace spvtools {
  22. namespace opt {
  23. namespace {
  24. using ::testing::Eq;
  25. TEST(FunctionTest, HasEarlyReturn) {
  26. std::string shader = R"(
  27. OpCapability Shader
  28. %1 = OpExtInstImport "GLSL.std.450"
  29. OpMemoryModel Logical GLSL450
  30. OpEntryPoint Vertex %6 "main"
  31. ; Types
  32. %2 = OpTypeBool
  33. %3 = OpTypeVoid
  34. %4 = OpTypeFunction %3
  35. ; Constants
  36. %5 = OpConstantTrue %2
  37. ; main function without early return
  38. %6 = OpFunction %3 None %4
  39. %7 = OpLabel
  40. OpBranch %8
  41. %8 = OpLabel
  42. OpBranch %9
  43. %9 = OpLabel
  44. OpBranch %10
  45. %10 = OpLabel
  46. OpReturn
  47. OpFunctionEnd
  48. ; function with early return
  49. %11 = OpFunction %3 None %4
  50. %12 = OpLabel
  51. OpSelectionMerge %15 None
  52. OpBranchConditional %5 %13 %14
  53. %13 = OpLabel
  54. OpReturn
  55. %14 = OpLabel
  56. OpBranch %15
  57. %15 = OpLabel
  58. OpReturn
  59. OpFunctionEnd
  60. )";
  61. const auto context =
  62. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, shader,
  63. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  64. // Tests |function| without early return.
  65. auto* function = spvtest::GetFunction(context->module(), 6);
  66. ASSERT_FALSE(function->HasEarlyReturn());
  67. // Tests |function| with early return.
  68. function = spvtest::GetFunction(context->module(), 11);
  69. ASSERT_TRUE(function->HasEarlyReturn());
  70. }
  71. TEST(FunctionTest, IsNotRecursive) {
  72. const std::string text = R"(
  73. OpCapability Shader
  74. OpMemoryModel Logical GLSL450
  75. OpEntryPoint Fragment %1 "main"
  76. OpExecutionMode %1 OriginUpperLeft
  77. OpDecorate %2 DescriptorSet 439418829
  78. %void = OpTypeVoid
  79. %4 = OpTypeFunction %void
  80. %float = OpTypeFloat 32
  81. %_struct_6 = OpTypeStruct %float %float
  82. %7 = OpTypeFunction %_struct_6
  83. %1 = OpFunction %void Pure|Const %4
  84. %8 = OpLabel
  85. %2 = OpFunctionCall %_struct_6 %9
  86. OpKill
  87. OpFunctionEnd
  88. %9 = OpFunction %_struct_6 None %7
  89. %10 = OpLabel
  90. %11 = OpFunctionCall %_struct_6 %12
  91. OpUnreachable
  92. OpFunctionEnd
  93. %12 = OpFunction %_struct_6 None %7
  94. %13 = OpLabel
  95. OpUnreachable
  96. OpFunctionEnd
  97. )";
  98. std::unique_ptr<IRContext> ctx =
  99. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  100. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  101. auto* func = spvtest::GetFunction(ctx->module(), 9);
  102. EXPECT_FALSE(func->IsRecursive());
  103. func = spvtest::GetFunction(ctx->module(), 12);
  104. EXPECT_FALSE(func->IsRecursive());
  105. }
  106. TEST(FunctionTest, IsDirectlyRecursive) {
  107. const std::string text = R"(
  108. OpCapability Shader
  109. OpMemoryModel Logical GLSL450
  110. OpEntryPoint Fragment %1 "main"
  111. OpExecutionMode %1 OriginUpperLeft
  112. OpDecorate %2 DescriptorSet 439418829
  113. %void = OpTypeVoid
  114. %4 = OpTypeFunction %void
  115. %float = OpTypeFloat 32
  116. %_struct_6 = OpTypeStruct %float %float
  117. %7 = OpTypeFunction %_struct_6
  118. %1 = OpFunction %void Pure|Const %4
  119. %8 = OpLabel
  120. %2 = OpFunctionCall %_struct_6 %9
  121. OpKill
  122. OpFunctionEnd
  123. %9 = OpFunction %_struct_6 None %7
  124. %10 = OpLabel
  125. %11 = OpFunctionCall %_struct_6 %9
  126. OpUnreachable
  127. OpFunctionEnd
  128. )";
  129. std::unique_ptr<IRContext> ctx =
  130. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  131. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  132. auto* func = spvtest::GetFunction(ctx->module(), 9);
  133. EXPECT_TRUE(func->IsRecursive());
  134. }
  135. TEST(FunctionTest, IsIndirectlyRecursive) {
  136. const std::string text = R"(
  137. OpCapability Shader
  138. OpMemoryModel Logical GLSL450
  139. OpEntryPoint Fragment %1 "main"
  140. OpExecutionMode %1 OriginUpperLeft
  141. OpDecorate %2 DescriptorSet 439418829
  142. %void = OpTypeVoid
  143. %4 = OpTypeFunction %void
  144. %float = OpTypeFloat 32
  145. %_struct_6 = OpTypeStruct %float %float
  146. %7 = OpTypeFunction %_struct_6
  147. %1 = OpFunction %void Pure|Const %4
  148. %8 = OpLabel
  149. %2 = OpFunctionCall %_struct_6 %9
  150. OpKill
  151. OpFunctionEnd
  152. %9 = OpFunction %_struct_6 None %7
  153. %10 = OpLabel
  154. %11 = OpFunctionCall %_struct_6 %12
  155. OpUnreachable
  156. OpFunctionEnd
  157. %12 = OpFunction %_struct_6 None %7
  158. %13 = OpLabel
  159. %14 = OpFunctionCall %_struct_6 %9
  160. OpUnreachable
  161. OpFunctionEnd
  162. )";
  163. std::unique_ptr<IRContext> ctx =
  164. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  165. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  166. auto* func = spvtest::GetFunction(ctx->module(), 9);
  167. EXPECT_TRUE(func->IsRecursive());
  168. func = spvtest::GetFunction(ctx->module(), 12);
  169. EXPECT_TRUE(func->IsRecursive());
  170. }
  171. TEST(FunctionTest, IsNotRecuriseCallingRecursive) {
  172. const std::string text = R"(
  173. OpCapability Shader
  174. OpMemoryModel Logical GLSL450
  175. OpEntryPoint Fragment %1 "main"
  176. OpExecutionMode %1 OriginUpperLeft
  177. OpDecorate %2 DescriptorSet 439418829
  178. %void = OpTypeVoid
  179. %4 = OpTypeFunction %void
  180. %float = OpTypeFloat 32
  181. %_struct_6 = OpTypeStruct %float %float
  182. %7 = OpTypeFunction %_struct_6
  183. %1 = OpFunction %void Pure|Const %4
  184. %8 = OpLabel
  185. %2 = OpFunctionCall %_struct_6 %9
  186. OpKill
  187. OpFunctionEnd
  188. %9 = OpFunction %_struct_6 None %7
  189. %10 = OpLabel
  190. %11 = OpFunctionCall %_struct_6 %9
  191. OpUnreachable
  192. OpFunctionEnd
  193. )";
  194. std::unique_ptr<IRContext> ctx =
  195. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  196. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  197. auto* func = spvtest::GetFunction(ctx->module(), 1);
  198. EXPECT_FALSE(func->IsRecursive());
  199. }
  200. TEST(FunctionTest, NonSemanticInfoSkipIteration) {
  201. const std::string text = R"(
  202. OpCapability Shader
  203. OpCapability Linkage
  204. OpExtension "SPV_KHR_non_semantic_info"
  205. %1 = OpExtInstImport "NonSemantic.Test"
  206. OpMemoryModel Logical GLSL450
  207. %2 = OpTypeVoid
  208. %3 = OpTypeFunction %2
  209. %4 = OpFunction %2 None %3
  210. %5 = OpLabel
  211. %6 = OpExtInst %2 %1 1
  212. OpReturn
  213. OpFunctionEnd
  214. %7 = OpExtInst %2 %1 2
  215. %8 = OpExtInst %2 %1 3
  216. )";
  217. std::unique_ptr<IRContext> ctx =
  218. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  219. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  220. auto* func = spvtest::GetFunction(ctx->module(), 4);
  221. ASSERT_TRUE(func != nullptr);
  222. std::unordered_set<uint32_t> non_semantic_ids;
  223. func->ForEachInst(
  224. [&non_semantic_ids](const Instruction* inst) {
  225. if (inst->opcode() == spv::Op::OpExtInst) {
  226. non_semantic_ids.insert(inst->result_id());
  227. }
  228. },
  229. true, false);
  230. EXPECT_EQ(1, non_semantic_ids.count(6));
  231. EXPECT_EQ(0, non_semantic_ids.count(7));
  232. EXPECT_EQ(0, non_semantic_ids.count(8));
  233. }
  234. TEST(FunctionTest, NonSemanticInfoIncludeIteration) {
  235. const std::string text = R"(
  236. OpCapability Shader
  237. OpCapability Linkage
  238. OpExtension "SPV_KHR_non_semantic_info"
  239. %1 = OpExtInstImport "NonSemantic.Test"
  240. OpMemoryModel Logical GLSL450
  241. %2 = OpTypeVoid
  242. %3 = OpTypeFunction %2
  243. %4 = OpFunction %2 None %3
  244. %5 = OpLabel
  245. %6 = OpExtInst %2 %1 1
  246. OpReturn
  247. OpFunctionEnd
  248. %7 = OpExtInst %2 %1 2
  249. %8 = OpExtInst %2 %1 3
  250. )";
  251. std::unique_ptr<IRContext> ctx =
  252. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  253. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  254. auto* func = spvtest::GetFunction(ctx->module(), 4);
  255. ASSERT_TRUE(func != nullptr);
  256. std::unordered_set<uint32_t> non_semantic_ids;
  257. func->ForEachInst(
  258. [&non_semantic_ids](const Instruction* inst) {
  259. if (inst->opcode() == spv::Op::OpExtInst) {
  260. non_semantic_ids.insert(inst->result_id());
  261. }
  262. },
  263. true, true);
  264. EXPECT_EQ(1, non_semantic_ids.count(6));
  265. EXPECT_EQ(1, non_semantic_ids.count(7));
  266. EXPECT_EQ(1, non_semantic_ids.count(8));
  267. }
  268. TEST(FunctionTest, ReorderBlocksinStructuredOrder) {
  269. // The spir-v has the basic block in a random order. We want to reorder them
  270. // in structured order.
  271. const std::string text = R"(
  272. OpCapability Shader
  273. OpMemoryModel Logical GLSL450
  274. OpEntryPoint Fragment %100 "PSMain"
  275. OpExecutionMode %PSMain OriginUpperLeft
  276. OpSource HLSL 600
  277. %int = OpTypeInt 32 1
  278. %void = OpTypeVoid
  279. %19 = OpTypeFunction %void
  280. %bool = OpTypeBool
  281. %undef_bool = OpUndef %bool
  282. %undef_int = OpUndef %int
  283. %100 = OpFunction %void None %19
  284. %11 = OpLabel
  285. OpSelectionMerge %10 None
  286. OpSwitch %undef_int %3 0 %2 10 %1
  287. %2 = OpLabel
  288. OpReturn
  289. %7 = OpLabel
  290. OpBranch %8
  291. %3 = OpLabel
  292. OpBranch %4
  293. %10 = OpLabel
  294. OpReturn
  295. %9 = OpLabel
  296. OpBranch %10
  297. %8 = OpLabel
  298. OpBranch %4
  299. %4 = OpLabel
  300. OpLoopMerge %9 %8 None
  301. OpBranchConditional %undef_bool %5 %9
  302. %1 = OpLabel
  303. OpReturn
  304. %6 = OpLabel
  305. OpBranch %7
  306. %5 = OpLabel
  307. OpSelectionMerge %7 None
  308. OpBranchConditional %undef_bool %6 %7
  309. OpFunctionEnd
  310. )";
  311. std::unique_ptr<IRContext> ctx =
  312. spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  313. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  314. ASSERT_TRUE(ctx);
  315. auto* func = spvtest::GetFunction(ctx->module(), 100);
  316. ASSERT_TRUE(func);
  317. func->ReorderBasicBlocksInStructuredOrder();
  318. auto first_block = func->begin();
  319. auto bb = first_block;
  320. for (++bb; bb != func->end(); ++bb) {
  321. EXPECT_EQ(bb->id(), (bb - first_block));
  322. }
  323. }
  324. } // namespace
  325. } // namespace opt
  326. } // namespace spvtools