val_extensions_test.cpp 15 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. // Tests for OpExtension validator rules.
  15. #include <string>
  16. #include <vector>
  17. #include "gmock/gmock.h"
  18. #include "source/enum_string_mapping.h"
  19. #include "source/extensions.h"
  20. #include "source/spirv_target_env.h"
  21. #include "test/test_fixture.h"
  22. #include "test/unit_spirv.h"
  23. #include "test/val/val_fixtures.h"
  24. namespace spvtools {
  25. namespace val {
  26. namespace {
  27. using ::testing::HasSubstr;
  28. using ::testing::Not;
  29. using ::testing::Values;
  30. using ::testing::ValuesIn;
  31. using ValidateKnownExtensions = spvtest::ValidateBase<std::string>;
  32. using ValidateUnknownExtensions = spvtest::ValidateBase<std::string>;
  33. using ValidateExtensionCapabilities = spvtest::ValidateBase<bool>;
  34. // Returns expected error string if |extension| is not recognized.
  35. std::string GetErrorString(const std::string& extension) {
  36. return "Found unrecognized extension " + extension;
  37. }
  38. INSTANTIATE_TEST_SUITE_P(
  39. ExpectSuccess, ValidateKnownExtensions,
  40. Values(
  41. // Match the order as published on the SPIR-V Registry.
  42. "SPV_AMD_shader_explicit_vertex_parameter",
  43. "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
  44. "SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
  45. "SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
  46. "SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage",
  47. "SPV_KHR_device_group", "SPV_KHR_multiview",
  48. "SPV_NVX_multiview_per_view_attributes", "SPV_NV_viewport_array2",
  49. "SPV_NV_stereo_view_rendering", "SPV_NV_sample_mask_override_coverage",
  50. "SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
  51. "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_variable_pointers",
  52. "SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
  53. "SPV_KHR_shader_atomic_counter_ops", "SPV_EXT_shader_stencil_export",
  54. "SPV_EXT_shader_viewport_index_layer",
  55. "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_fragment_mask",
  56. "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1",
  57. "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_descriptor_indexing",
  58. "SPV_KHR_terminate_invocation"));
  59. INSTANTIATE_TEST_SUITE_P(FailSilently, ValidateUnknownExtensions,
  60. Values("ERROR_unknown_extension", "SPV_KHR_",
  61. "SPV_KHR_shader_ballot_ERROR"));
  62. TEST_P(ValidateKnownExtensions, ExpectSuccess) {
  63. const std::string extension = GetParam();
  64. const std::string str =
  65. "OpCapability Shader\nOpCapability Linkage\nOpExtension \"" + extension +
  66. "\"\nOpMemoryModel Logical GLSL450";
  67. CompileSuccessfully(str.c_str());
  68. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  69. EXPECT_THAT(getDiagnosticString(), Not(HasSubstr(GetErrorString(extension))));
  70. }
  71. TEST_P(ValidateUnknownExtensions, FailSilently) {
  72. const std::string extension = GetParam();
  73. const std::string str =
  74. "OpCapability Shader\nOpCapability Linkage\nOpExtension \"" + extension +
  75. "\"\nOpMemoryModel Logical GLSL450";
  76. CompileSuccessfully(str.c_str());
  77. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  78. EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(extension)));
  79. }
  80. TEST_F(ValidateUnknownExtensions, HitMaxNumOfWarnings) {
  81. const std::string str =
  82. std::string("OpCapability Shader\n") + "OpCapability Linkage\n" +
  83. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  84. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  85. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  86. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  87. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  88. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  89. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  90. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  91. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  92. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  93. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  94. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  95. "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" +
  96. "OpMemoryModel Logical GLSL450";
  97. CompileSuccessfully(str.c_str());
  98. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  99. EXPECT_THAT(getDiagnosticString(),
  100. HasSubstr("Other warnings have been suppressed."));
  101. }
  102. TEST_F(ValidateExtensionCapabilities, DeclCapabilitySuccess) {
  103. const std::string str =
  104. "OpCapability Shader\nOpCapability Linkage\nOpCapability DeviceGroup\n"
  105. "OpExtension \"SPV_KHR_device_group\""
  106. "\nOpMemoryModel Logical GLSL450";
  107. CompileSuccessfully(str.c_str());
  108. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  109. }
  110. TEST_F(ValidateExtensionCapabilities, DeclCapabilityFailure) {
  111. const std::string str =
  112. "OpCapability Shader\nOpCapability Linkage\nOpCapability DeviceGroup\n"
  113. "\nOpMemoryModel Logical GLSL450";
  114. CompileSuccessfully(str.c_str());
  115. ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
  116. EXPECT_THAT(getDiagnosticString(), HasSubstr("1st operand of Capability"));
  117. EXPECT_THAT(getDiagnosticString(),
  118. HasSubstr("requires one of these extensions"));
  119. EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_KHR_device_group"));
  120. }
  121. using ValidateAMDShaderBallotCapabilities = spvtest::ValidateBase<std::string>;
  122. // Returns a vector of strings for the prefix of a SPIR-V assembly shader
  123. // that can use the group instructions introduced by SPV_AMD_shader_ballot.
  124. std::vector<std::string> ShaderPartsForAMDShaderBallot() {
  125. return std::vector<std::string>{R"(
  126. OpCapability Shader
  127. OpCapability Linkage
  128. )",
  129. R"(
  130. OpMemoryModel Logical GLSL450
  131. %float = OpTypeFloat 32
  132. %uint = OpTypeInt 32 0
  133. %int = OpTypeInt 32 1
  134. %scope = OpConstant %uint 3
  135. %uint_const = OpConstant %uint 42
  136. %int_const = OpConstant %uint 45
  137. %float_const = OpConstant %float 3.5
  138. %void = OpTypeVoid
  139. %fn_ty = OpTypeFunction %void
  140. %fn = OpFunction %void None %fn_ty
  141. %entry = OpLabel
  142. )"};
  143. }
  144. // Returns a list of SPIR-V assembly strings, where each uses only types
  145. // and IDs that can fit with a shader made from parts from the result
  146. // of ShaderPartsForAMDShaderBallot.
  147. std::vector<std::string> AMDShaderBallotGroupInstructions() {
  148. return std::vector<std::string>{
  149. "%iadd_reduce = OpGroupIAddNonUniformAMD %uint %scope Reduce %uint_const",
  150. "%iadd_iscan = OpGroupIAddNonUniformAMD %uint %scope InclusiveScan "
  151. "%uint_const",
  152. "%iadd_escan = OpGroupIAddNonUniformAMD %uint %scope ExclusiveScan "
  153. "%uint_const",
  154. "%fadd_reduce = OpGroupFAddNonUniformAMD %float %scope Reduce "
  155. "%float_const",
  156. "%fadd_iscan = OpGroupFAddNonUniformAMD %float %scope InclusiveScan "
  157. "%float_const",
  158. "%fadd_escan = OpGroupFAddNonUniformAMD %float %scope ExclusiveScan "
  159. "%float_const",
  160. "%fmin_reduce = OpGroupFMinNonUniformAMD %float %scope Reduce "
  161. "%float_const",
  162. "%fmin_iscan = OpGroupFMinNonUniformAMD %float %scope InclusiveScan "
  163. "%float_const",
  164. "%fmin_escan = OpGroupFMinNonUniformAMD %float %scope ExclusiveScan "
  165. "%float_const",
  166. "%umin_reduce = OpGroupUMinNonUniformAMD %uint %scope Reduce %uint_const",
  167. "%umin_iscan = OpGroupUMinNonUniformAMD %uint %scope InclusiveScan "
  168. "%uint_const",
  169. "%umin_escan = OpGroupUMinNonUniformAMD %uint %scope ExclusiveScan "
  170. "%uint_const",
  171. "%smin_reduce = OpGroupUMinNonUniformAMD %int %scope Reduce %int_const",
  172. "%smin_iscan = OpGroupUMinNonUniformAMD %int %scope InclusiveScan "
  173. "%int_const",
  174. "%smin_escan = OpGroupUMinNonUniformAMD %int %scope ExclusiveScan "
  175. "%int_const",
  176. "%fmax_reduce = OpGroupFMaxNonUniformAMD %float %scope Reduce "
  177. "%float_const",
  178. "%fmax_iscan = OpGroupFMaxNonUniformAMD %float %scope InclusiveScan "
  179. "%float_const",
  180. "%fmax_escan = OpGroupFMaxNonUniformAMD %float %scope ExclusiveScan "
  181. "%float_const",
  182. "%umax_reduce = OpGroupUMaxNonUniformAMD %uint %scope Reduce %uint_const",
  183. "%umax_iscan = OpGroupUMaxNonUniformAMD %uint %scope InclusiveScan "
  184. "%uint_const",
  185. "%umax_escan = OpGroupUMaxNonUniformAMD %uint %scope ExclusiveScan "
  186. "%uint_const",
  187. "%smax_reduce = OpGroupUMaxNonUniformAMD %int %scope Reduce %int_const",
  188. "%smax_iscan = OpGroupUMaxNonUniformAMD %int %scope InclusiveScan "
  189. "%int_const",
  190. "%smax_escan = OpGroupUMaxNonUniformAMD %int %scope ExclusiveScan "
  191. "%int_const"};
  192. }
  193. TEST_P(ValidateAMDShaderBallotCapabilities, ExpectSuccess) {
  194. // Succeed because the module specifies the SPV_AMD_shader_ballot extension.
  195. auto parts = ShaderPartsForAMDShaderBallot();
  196. const std::string assembly =
  197. parts[0] + "OpExtension \"SPV_AMD_shader_ballot\"\n" + parts[1] +
  198. GetParam() + "\nOpReturn OpFunctionEnd";
  199. CompileSuccessfully(assembly.c_str());
  200. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
  201. }
  202. INSTANTIATE_TEST_SUITE_P(ExpectSuccess, ValidateAMDShaderBallotCapabilities,
  203. ValuesIn(AMDShaderBallotGroupInstructions()));
  204. TEST_P(ValidateAMDShaderBallotCapabilities, ExpectFailure) {
  205. // Fail because the module does not specify the SPV_AMD_shader_ballot
  206. // extension.
  207. auto parts = ShaderPartsForAMDShaderBallot();
  208. const std::string assembly =
  209. parts[0] + parts[1] + GetParam() + "\nOpReturn OpFunctionEnd";
  210. CompileSuccessfully(assembly.c_str());
  211. EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
  212. // Make sure we get an appropriate error message.
  213. // Find just the opcode name, skipping over the "Op" part.
  214. auto prefix_with_opcode = GetParam().substr(GetParam().find("Group"));
  215. auto opcode = prefix_with_opcode.substr(0, prefix_with_opcode.find(' '));
  216. EXPECT_THAT(
  217. getDiagnosticString(),
  218. HasSubstr(std::string("Opcode " + opcode +
  219. " requires one of these capabilities: Groups")));
  220. }
  221. INSTANTIATE_TEST_SUITE_P(ExpectFailure, ValidateAMDShaderBallotCapabilities,
  222. ValuesIn(AMDShaderBallotGroupInstructions()));
  223. struct ExtIntoCoreCase {
  224. const char* ext;
  225. const char* cap;
  226. const char* builtin;
  227. spv_target_env env;
  228. bool success;
  229. };
  230. using ValidateExtIntoCore = spvtest::ValidateBase<ExtIntoCoreCase>;
  231. // Make sure that we don't panic about missing extensions for using
  232. // functionalities that introduced in extensions but became core SPIR-V later.
  233. TEST_P(ValidateExtIntoCore, DoNotAskForExtensionInLaterVersion) {
  234. const std::string code = std::string(R"(
  235. OpCapability Shader
  236. OpCapability )") +
  237. GetParam().cap + R"(
  238. OpMemoryModel Logical GLSL450
  239. OpEntryPoint Vertex %main "main" %builtin
  240. OpDecorate %builtin BuiltIn )" + GetParam().builtin + R"(
  241. %void = OpTypeVoid
  242. %3 = OpTypeFunction %void
  243. %int = OpTypeInt 32 1
  244. %_ptr_Input_int = OpTypePointer Input %int
  245. %builtin = OpVariable %_ptr_Input_int Input
  246. %main = OpFunction %void None %3
  247. %5 = OpLabel
  248. %18 = OpLoad %int %builtin
  249. OpReturn
  250. OpFunctionEnd)";
  251. CompileSuccessfully(code.c_str(), GetParam().env);
  252. if (GetParam().success) {
  253. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(GetParam().env))
  254. << getDiagnosticString();
  255. } else {
  256. ASSERT_NE(SPV_SUCCESS, ValidateInstructions(GetParam().env))
  257. << " in " << spvTargetEnvDescription(GetParam().env) << ":\n"
  258. << code;
  259. const std::string message = getDiagnosticString();
  260. if (spvIsVulkanEnv(GetParam().env)) {
  261. EXPECT_THAT(message, HasSubstr(std::string(GetParam().cap) +
  262. " is not allowed by Vulkan"));
  263. EXPECT_THAT(message, HasSubstr(std::string("or requires extension")));
  264. } else {
  265. EXPECT_THAT(message,
  266. HasSubstr(std::string("requires one of these extensions: ") +
  267. GetParam().ext));
  268. }
  269. }
  270. }
  271. // clang-format off
  272. INSTANTIATE_TEST_SUITE_P(
  273. KHR_extensions, ValidateExtIntoCore,
  274. ValuesIn(std::vector<ExtIntoCoreCase>{
  275. // SPV_KHR_shader_draw_parameters became core SPIR-V 1.3
  276. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_UNIVERSAL_1_3, true},
  277. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_UNIVERSAL_1_2, false},
  278. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_UNIVERSAL_1_1, false},
  279. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_UNIVERSAL_1_0, false},
  280. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_VULKAN_1_1, true},
  281. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseVertex", SPV_ENV_VULKAN_1_0, false},
  282. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseInstance", SPV_ENV_UNIVERSAL_1_3, true},
  283. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "BaseInstance", SPV_ENV_VULKAN_1_0, false},
  284. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "DrawIndex", SPV_ENV_UNIVERSAL_1_3, true},
  285. {"SPV_KHR_shader_draw_parameters", "DrawParameters", "DrawIndex", SPV_ENV_UNIVERSAL_1_1, false},
  286. // SPV_KHR_multiview became core SPIR-V 1.3
  287. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_UNIVERSAL_1_3, true},
  288. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_UNIVERSAL_1_2, false},
  289. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_UNIVERSAL_1_1, false},
  290. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_UNIVERSAL_1_0, false},
  291. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_VULKAN_1_1, true},
  292. {"SPV_KHR_multiview", "MultiView", "ViewIndex", SPV_ENV_VULKAN_1_0, false},
  293. // SPV_KHR_device_group became core SPIR-V 1.3
  294. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_UNIVERSAL_1_3, true},
  295. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_UNIVERSAL_1_2, false},
  296. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_UNIVERSAL_1_1, false},
  297. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_UNIVERSAL_1_0, false},
  298. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_VULKAN_1_1, true},
  299. {"SPV_KHR_device_group", "DeviceGroup", "DeviceIndex", SPV_ENV_VULKAN_1_0, false},
  300. }));
  301. // clang-format on
  302. } // namespace
  303. } // namespace val
  304. } // namespace spvtools