compact_ids_test.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 <memory>
  15. #include <vector>
  16. #include "gmock/gmock.h"
  17. #include "spirv-tools/libspirv.hpp"
  18. #include "spirv-tools/optimizer.hpp"
  19. #include "test/opt/pass_fixture.h"
  20. #include "test/opt/pass_utils.h"
  21. namespace spvtools {
  22. namespace opt {
  23. namespace {
  24. using CompactIdsTest = PassTest<::testing::Test>;
  25. TEST_F(CompactIdsTest, PassOff) {
  26. const std::string before =
  27. R"(OpCapability Addresses
  28. OpCapability Kernel
  29. OpCapability GenericPointer
  30. OpCapability Linkage
  31. OpMemoryModel Physical32 OpenCL
  32. %99 = OpTypeInt 32 0
  33. %10 = OpTypeVector %99 2
  34. %20 = OpConstant %99 2
  35. %30 = OpTypeArray %99 %20
  36. )";
  37. const std::string after = before;
  38. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  39. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  40. SinglePassRunAndCheck<NullPass>(before, after, false, false);
  41. }
  42. TEST_F(CompactIdsTest, PassOn) {
  43. const std::string before =
  44. R"(OpCapability Addresses
  45. OpCapability Kernel
  46. OpCapability GenericPointer
  47. OpCapability Linkage
  48. OpMemoryModel Physical32 OpenCL
  49. OpEntryPoint Kernel %3 "simple_kernel"
  50. %99 = OpTypeInt 32 0
  51. %10 = OpTypeVector %99 2
  52. %20 = OpConstant %99 2
  53. %30 = OpTypeArray %99 %20
  54. %40 = OpTypeVoid
  55. %50 = OpTypeFunction %40
  56. %3 = OpFunction %40 None %50
  57. %70 = OpLabel
  58. OpReturn
  59. OpFunctionEnd
  60. )";
  61. const std::string after =
  62. R"(OpCapability Addresses
  63. OpCapability Kernel
  64. OpCapability GenericPointer
  65. OpCapability Linkage
  66. OpMemoryModel Physical32 OpenCL
  67. OpEntryPoint Kernel %1 "simple_kernel"
  68. %2 = OpTypeInt 32 0
  69. %3 = OpTypeVector %2 2
  70. %4 = OpConstant %2 2
  71. %5 = OpTypeArray %2 %4
  72. %6 = OpTypeVoid
  73. %7 = OpTypeFunction %6
  74. %1 = OpFunction %6 None %7
  75. %8 = OpLabel
  76. OpReturn
  77. OpFunctionEnd
  78. )";
  79. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  80. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  81. SinglePassRunAndCheck<CompactIdsPass>(before, after, false, false);
  82. }
  83. TEST_F(CompactIdsTest, DebugScope) {
  84. const std::string text =
  85. R"(OpCapability Addresses
  86. OpCapability Kernel
  87. OpCapability GenericPointer
  88. OpCapability Linkage
  89. %5 = OpExtInstImport "OpenCL.DebugInfo.100"
  90. OpMemoryModel Physical32 OpenCL
  91. OpEntryPoint Kernel %3 "simple_kernel"
  92. %2 = OpString "test"
  93. %99 = OpTypeInt 32 0
  94. %10 = OpTypeVector %99 2
  95. %20 = OpConstant %99 2
  96. %30 = OpTypeArray %99 %20
  97. %40 = OpTypeVoid
  98. %50 = OpTypeFunction %40
  99. %11 = OpExtInst %40 %5 DebugSource %2
  100. %12 = OpExtInst %40 %5 DebugCompilationUnit 1 4 %11 HLSL
  101. %13 = OpExtInst %40 %5 DebugTypeFunction FlagIsProtected|FlagIsPrivate %40
  102. ; CHECK: [[fn:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugFunction
  103. %14 = OpExtInst %40 %5 DebugFunction %2 %13 %11 0 0 %12 %2 FlagIsProtected|FlagIsPrivate 0 %3
  104. %3 = OpFunction %40 None %50
  105. %70 = OpLabel
  106. ; CHECK: DebugScope [[fn]]
  107. %19 = OpExtInst %40 %5 DebugScope %14
  108. OpReturn
  109. OpFunctionEnd
  110. )";
  111. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  112. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  113. SinglePassRunAndMatch<CompactIdsPass>(text, true);
  114. }
  115. TEST(CompactIds, InstructionResultIsUpdated) {
  116. // For https://github.com/KhronosGroup/SPIRV-Tools/issues/827
  117. // In that bug, the compact Ids pass was directly updating the result Id
  118. // word for an OpFunction instruction, but not updating the cached
  119. // result_id_ in that Instruction object.
  120. //
  121. // This test is a bit cheesy. We don't expose internal interfaces enough
  122. // to see the inconsistency. So reproduce the original scenario, with
  123. // compact ids followed by a pass that trips up on the inconsistency.
  124. const std::string input(R"(OpCapability Shader
  125. OpMemoryModel Logical Simple
  126. OpEntryPoint GLCompute %100 "main"
  127. %200 = OpTypeVoid
  128. %300 = OpTypeFunction %200
  129. %100 = OpFunction %200 None %300
  130. %400 = OpLabel
  131. OpReturn
  132. OpFunctionEnd
  133. )");
  134. std::vector<uint32_t> binary;
  135. const spv_target_env env = SPV_ENV_UNIVERSAL_1_0;
  136. spvtools::SpirvTools tools(env);
  137. auto assembled = tools.Assemble(
  138. input, &binary, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  139. EXPECT_TRUE(assembled);
  140. spvtools::Optimizer optimizer(env);
  141. optimizer.RegisterPass(CreateCompactIdsPass());
  142. // The exhaustive inliner will use the result_id
  143. optimizer.RegisterPass(CreateInlineExhaustivePass());
  144. // This should not crash!
  145. optimizer.Run(binary.data(), binary.size(), &binary);
  146. std::string disassembly;
  147. tools.Disassemble(binary, &disassembly, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  148. const std::string expected(R"(OpCapability Shader
  149. OpMemoryModel Logical Simple
  150. OpEntryPoint GLCompute %1 "main"
  151. %2 = OpTypeVoid
  152. %3 = OpTypeFunction %2
  153. %1 = OpFunction %2 None %3
  154. %4 = OpLabel
  155. OpReturn
  156. OpFunctionEnd
  157. )");
  158. EXPECT_THAT(disassembly, ::testing::Eq(expected));
  159. }
  160. TEST(CompactIds, HeaderIsUpdated) {
  161. const std::string input(R"(OpCapability Shader
  162. OpMemoryModel Logical Simple
  163. OpEntryPoint GLCompute %100 "main"
  164. %200 = OpTypeVoid
  165. %300 = OpTypeFunction %200
  166. %100 = OpFunction %200 None %300
  167. %400 = OpLabel
  168. OpReturn
  169. OpFunctionEnd
  170. )");
  171. std::vector<uint32_t> binary;
  172. const spv_target_env env = SPV_ENV_UNIVERSAL_1_0;
  173. spvtools::SpirvTools tools(env);
  174. auto assembled = tools.Assemble(
  175. input, &binary, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  176. EXPECT_TRUE(assembled);
  177. spvtools::Optimizer optimizer(env);
  178. optimizer.RegisterPass(CreateCompactIdsPass());
  179. // The exhaustive inliner will use the result_id
  180. optimizer.RegisterPass(CreateInlineExhaustivePass());
  181. // This should not crash!
  182. optimizer.Run(binary.data(), binary.size(), &binary);
  183. std::string disassembly;
  184. tools.Disassemble(binary, &disassembly, SPV_BINARY_TO_TEXT_OPTION_NONE);
  185. const std::string expected(R"(; SPIR-V
  186. ; Version: 1.0
  187. ; Generator: Khronos SPIR-V Tools Assembler; 0
  188. ; Bound: 5
  189. ; Schema: 0
  190. OpCapability Shader
  191. OpMemoryModel Logical Simple
  192. OpEntryPoint GLCompute %1 "main"
  193. %2 = OpTypeVoid
  194. %3 = OpTypeFunction %2
  195. %1 = OpFunction %2 None %3
  196. %4 = OpLabel
  197. OpReturn
  198. OpFunctionEnd
  199. )");
  200. EXPECT_THAT(disassembly, ::testing::Eq(expected));
  201. }
  202. // Test context consistency check after invalidating
  203. // CFG and others by compact IDs Pass.
  204. // Uses a GLSL shader with named labels for variety
  205. TEST(CompactIds, ConsistentCheck) {
  206. const std::string input(R"(OpCapability Shader
  207. OpMemoryModel Logical GLSL450
  208. OpEntryPoint Fragment %main "main" %in_var_A %out_var_SV_TARGET
  209. OpExecutionMode %main OriginUpperLeft
  210. OpSource HLSL 600
  211. OpName %main "main"
  212. OpName %in_var_A "in.var.A"
  213. OpName %out_var_SV_TARGET "out.var.SV_TARGET"
  214. OpDecorate %in_var_A Location 0
  215. OpDecorate %out_var_SV_TARGET Location 0
  216. %void = OpTypeVoid
  217. %3 = OpTypeFunction %void
  218. %float = OpTypeFloat 32
  219. %v4float = OpTypeVector %float 4
  220. %_ptr_Input_v4float = OpTypePointer Input %v4float
  221. %_ptr_Output_v4float = OpTypePointer Output %v4float
  222. %in_var_A = OpVariable %_ptr_Input_v4float Input
  223. %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
  224. %main = OpFunction %void None %3
  225. %5 = OpLabel
  226. %12 = OpLoad %v4float %in_var_A
  227. %23 = OpVectorShuffle %v4float %12 %12 0 0 0 1
  228. OpStore %out_var_SV_TARGET %23
  229. OpReturn
  230. OpFunctionEnd
  231. )");
  232. spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
  233. std::unique_ptr<IRContext> context =
  234. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input,
  235. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  236. ASSERT_NE(context, nullptr);
  237. CompactIdsPass compact_id_pass;
  238. context->BuildInvalidAnalyses(compact_id_pass.GetPreservedAnalyses());
  239. const auto status = compact_id_pass.Run(context.get());
  240. ASSERT_NE(status, Pass::Status::Failure);
  241. EXPECT_TRUE(context->IsConsistent());
  242. // Test output just in case
  243. std::vector<uint32_t> binary;
  244. context->module()->ToBinary(&binary, false);
  245. std::string disassembly;
  246. tools.Disassemble(binary, &disassembly,
  247. SpirvTools::kDefaultDisassembleOption);
  248. const std::string expected(R"(OpCapability Shader
  249. OpMemoryModel Logical GLSL450
  250. OpEntryPoint Fragment %main "main" %in_var_A %out_var_SV_TARGET
  251. OpExecutionMode %main OriginUpperLeft
  252. OpSource HLSL 600
  253. OpName %main "main"
  254. OpName %in_var_A "in.var.A"
  255. OpName %out_var_SV_TARGET "out.var.SV_TARGET"
  256. OpDecorate %in_var_A Location 0
  257. OpDecorate %out_var_SV_TARGET Location 0
  258. %void = OpTypeVoid
  259. %5 = OpTypeFunction %void
  260. %float = OpTypeFloat 32
  261. %v4float = OpTypeVector %float 4
  262. %_ptr_Input_v4float = OpTypePointer Input %v4float
  263. %_ptr_Output_v4float = OpTypePointer Output %v4float
  264. %in_var_A = OpVariable %_ptr_Input_v4float Input
  265. %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
  266. %main = OpFunction %void None %5
  267. %10 = OpLabel
  268. %11 = OpLoad %v4float %in_var_A
  269. %12 = OpVectorShuffle %v4float %11 %11 0 0 0 1
  270. OpStore %out_var_SV_TARGET %12
  271. OpReturn
  272. OpFunctionEnd
  273. )");
  274. EXPECT_THAT(disassembly, ::testing::Eq(expected));
  275. }
  276. TEST(CompactIds, ResetIdBound) {
  277. const std::string input(R"(OpCapability Shader
  278. OpMemoryModel Logical GLSL450
  279. OpEntryPoint Fragment %1 "main"
  280. OpExecutionMode %1 OriginUpperLeft
  281. %void = OpTypeVoid
  282. %3 = OpTypeFunction %void
  283. %1 = OpFunction %void None %3
  284. %4 = OpLabel
  285. OpReturn
  286. OpFunctionEnd
  287. )");
  288. spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
  289. std::unique_ptr<IRContext> context =
  290. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input,
  291. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  292. ASSERT_NE(context, nullptr);
  293. CompactIdsPass compact_id_pass;
  294. context->module()->SetIdBound(20000);
  295. const auto status = compact_id_pass.Run(context.get());
  296. EXPECT_EQ(status, Pass::Status::SuccessWithChange);
  297. EXPECT_EQ(context->module()->id_bound(), 5);
  298. // Test output just in case
  299. std::vector<uint32_t> binary;
  300. context->module()->ToBinary(&binary, false);
  301. std::string disassembly;
  302. tools.Disassemble(binary, &disassembly,
  303. SpirvTools::kDefaultDisassembleOption);
  304. EXPECT_THAT(disassembly, ::testing::Eq(input));
  305. }
  306. } // namespace
  307. } // namespace opt
  308. } // namespace spvtools