compact_ids_test.cpp 9.1 KB

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