validate_capability.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. // Validates OpCapability instruction.
  15. #include "validate.h"
  16. #include <cassert>
  17. #include <unordered_set>
  18. #include "diagnostic.h"
  19. #include "opcode.h"
  20. #include "val/instruction.h"
  21. #include "val/validation_state.h"
  22. namespace libspirv {
  23. namespace {
  24. bool IsSupportGuaranteedVulkan_1_0(uint32_t capability) {
  25. switch (capability) {
  26. case SpvCapabilityMatrix:
  27. case SpvCapabilityShader:
  28. case SpvCapabilityInputAttachment:
  29. case SpvCapabilitySampled1D:
  30. case SpvCapabilityImage1D:
  31. case SpvCapabilitySampledBuffer:
  32. case SpvCapabilityImageBuffer:
  33. case SpvCapabilityImageQuery:
  34. case SpvCapabilityDerivativeControl:
  35. return true;
  36. }
  37. return false;
  38. }
  39. bool IsSupportOptionalVulkan_1_0(uint32_t capability) {
  40. switch (capability) {
  41. case SpvCapabilityGeometry:
  42. case SpvCapabilityTessellation:
  43. case SpvCapabilityFloat64:
  44. case SpvCapabilityInt64:
  45. case SpvCapabilityInt16:
  46. case SpvCapabilityTessellationPointSize:
  47. case SpvCapabilityGeometryPointSize:
  48. case SpvCapabilityImageGatherExtended:
  49. case SpvCapabilityStorageImageMultisample:
  50. case SpvCapabilityUniformBufferArrayDynamicIndexing:
  51. case SpvCapabilitySampledImageArrayDynamicIndexing:
  52. case SpvCapabilityStorageBufferArrayDynamicIndexing:
  53. case SpvCapabilityStorageImageArrayDynamicIndexing:
  54. case SpvCapabilityClipDistance:
  55. case SpvCapabilityCullDistance:
  56. case SpvCapabilityImageCubeArray:
  57. case SpvCapabilitySampleRateShading:
  58. case SpvCapabilitySparseResidency:
  59. case SpvCapabilityMinLod:
  60. case SpvCapabilitySampledCubeArray:
  61. case SpvCapabilityImageMSArray:
  62. case SpvCapabilityStorageImageExtendedFormats:
  63. case SpvCapabilityInterpolationFunction:
  64. case SpvCapabilityStorageImageReadWithoutFormat:
  65. case SpvCapabilityStorageImageWriteWithoutFormat:
  66. case SpvCapabilityMultiViewport:
  67. return true;
  68. }
  69. return false;
  70. }
  71. bool IsSupportGuaranteedOpenCL_1_2(uint32_t capability, bool embedded_profile) {
  72. switch (capability) {
  73. case SpvCapabilityAddresses:
  74. case SpvCapabilityFloat16Buffer:
  75. case SpvCapabilityGroups:
  76. case SpvCapabilityInt16:
  77. case SpvCapabilityInt8:
  78. case SpvCapabilityKernel:
  79. case SpvCapabilityLinkage:
  80. case SpvCapabilityVector16:
  81. return true;
  82. case SpvCapabilityInt64:
  83. return !embedded_profile;
  84. case SpvCapabilityPipes:
  85. return embedded_profile;
  86. }
  87. return false;
  88. }
  89. bool IsSupportGuaranteedOpenCL_2_0(uint32_t capability, bool embedded_profile) {
  90. if (IsSupportGuaranteedOpenCL_1_2(capability, embedded_profile)) return true;
  91. switch (capability) {
  92. case SpvCapabilityDeviceEnqueue:
  93. case SpvCapabilityGenericPointer:
  94. case SpvCapabilityPipes:
  95. return true;
  96. }
  97. return false;
  98. }
  99. bool IsSupportGuaranteedOpenCL_2_2(uint32_t capability, bool embedded_profile) {
  100. if (IsSupportGuaranteedOpenCL_2_0(capability, embedded_profile)) return true;
  101. switch (capability) {
  102. case SpvCapabilitySubgroupDispatch:
  103. case SpvCapabilityPipeStorage:
  104. return true;
  105. }
  106. return false;
  107. }
  108. bool IsSupportOptionalOpenCL_1_2(uint32_t capability) {
  109. switch (capability) {
  110. case SpvCapabilityImageBasic:
  111. case SpvCapabilityFloat64:
  112. return true;
  113. }
  114. return false;
  115. }
  116. // Checks if |capability| was enabled by extension.
  117. bool IsEnabledByExtension(ValidationState_t& _, uint32_t capability) {
  118. spv_operand_desc operand_desc = nullptr;
  119. _.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  120. &operand_desc);
  121. // operand_desc is expected to be not null, otherwise validator would have
  122. // failed at an earlier stage. This 'assert' is 'just in case'.
  123. assert(operand_desc);
  124. ExtensionSet operand_exts(operand_desc->numExtensions,
  125. operand_desc->extensions);
  126. if (operand_exts.IsEmpty()) return false;
  127. return _.HasAnyOfExtensions(operand_exts);
  128. }
  129. bool IsEnabledByCapabilityOpenCL_1_2(ValidationState_t& _,
  130. uint32_t capability) {
  131. if (_.HasCapability(SpvCapabilityImageBasic)) {
  132. switch (capability) {
  133. case SpvCapabilityLiteralSampler:
  134. case SpvCapabilitySampled1D:
  135. case SpvCapabilityImage1D:
  136. case SpvCapabilitySampledBuffer:
  137. case SpvCapabilityImageBuffer:
  138. return true;
  139. }
  140. return false;
  141. }
  142. return false;
  143. }
  144. bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _,
  145. uint32_t capability) {
  146. if (_.HasCapability(SpvCapabilityImageBasic)) {
  147. switch (capability) {
  148. case SpvCapabilityImageReadWrite:
  149. case SpvCapabilityLiteralSampler:
  150. case SpvCapabilitySampled1D:
  151. case SpvCapabilityImage1D:
  152. case SpvCapabilitySampledBuffer:
  153. case SpvCapabilityImageBuffer:
  154. return true;
  155. }
  156. return false;
  157. }
  158. return false;
  159. }
  160. } // namespace
  161. // Validates that capability declarations use operands allowed in the current
  162. // context.
  163. spv_result_t CapabilityPass(ValidationState_t& _,
  164. const spv_parsed_instruction_t* inst) {
  165. const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  166. if (opcode != SpvOpCapability) return SPV_SUCCESS;
  167. assert(inst->num_operands == 1);
  168. const spv_parsed_operand_t& operand = inst->operands[0];
  169. assert(operand.num_words == 1);
  170. assert(operand.offset < inst->num_words);
  171. const uint32_t capability = inst->words[operand.offset];
  172. const auto capability_str = [&_, capability]() {
  173. spv_operand_desc desc = nullptr;
  174. if (_.grammar().lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability,
  175. &desc) != SPV_SUCCESS ||
  176. !desc) {
  177. return std::string("Unknown");
  178. }
  179. return std::string(desc->name);
  180. };
  181. const auto env = _.context()->target_env;
  182. const bool opencl_embedded = env == SPV_ENV_OPENCL_EMBEDDED_1_2 ||
  183. env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  184. env == SPV_ENV_OPENCL_EMBEDDED_2_1 ||
  185. env == SPV_ENV_OPENCL_EMBEDDED_2_2;
  186. const std::string opencl_profile = opencl_embedded ? "Embedded" : "Full";
  187. if (env == SPV_ENV_VULKAN_1_0) {
  188. if (!IsSupportGuaranteedVulkan_1_0(capability) &&
  189. !IsSupportOptionalVulkan_1_0(capability) &&
  190. !IsEnabledByExtension(_, capability)) {
  191. return _.diag(SPV_ERROR_INVALID_CAPABILITY)
  192. << "Capability " << capability_str()
  193. << " is not allowed by Vulkan 1.0 specification"
  194. << " (or requires extension)";
  195. }
  196. } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) {
  197. if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) &&
  198. !IsSupportOptionalOpenCL_1_2(capability) &&
  199. !IsEnabledByExtension(_, capability) &&
  200. !IsEnabledByCapabilityOpenCL_1_2(_, capability)) {
  201. return _.diag(SPV_ERROR_INVALID_CAPABILITY)
  202. << "Capability " << capability_str()
  203. << " is not allowed by OpenCL 1.2 " << opencl_profile
  204. << " Profile specification"
  205. << " (or requires extension or capability)";
  206. }
  207. } else if (env == SPV_ENV_OPENCL_2_0 || env == SPV_ENV_OPENCL_EMBEDDED_2_0 ||
  208. env == SPV_ENV_OPENCL_2_1 || env == SPV_ENV_OPENCL_EMBEDDED_2_1) {
  209. if (!IsSupportGuaranteedOpenCL_2_0(capability, opencl_embedded) &&
  210. !IsSupportOptionalOpenCL_1_2(capability) &&
  211. !IsEnabledByExtension(_, capability) &&
  212. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  213. return _.diag(SPV_ERROR_INVALID_CAPABILITY)
  214. << "Capability " << capability_str()
  215. << " is not allowed by OpenCL 2.0/2.1 " << opencl_profile
  216. << " Profile specification"
  217. << " (or requires extension or capability)";
  218. }
  219. } else if (env == SPV_ENV_OPENCL_2_2 || env == SPV_ENV_OPENCL_EMBEDDED_2_2) {
  220. if (!IsSupportGuaranteedOpenCL_2_2(capability, opencl_embedded) &&
  221. !IsSupportOptionalOpenCL_1_2(capability) &&
  222. !IsEnabledByExtension(_, capability) &&
  223. !IsEnabledByCapabilityOpenCL_2_0(_, capability)) {
  224. return _.diag(SPV_ERROR_INVALID_CAPABILITY)
  225. << "Capability " << capability_str()
  226. << " is not allowed by OpenCL 2.2 " << opencl_profile
  227. << " Profile specification"
  228. << " (or requires extension or capability)";
  229. }
  230. }
  231. return SPV_SUCCESS;
  232. }
  233. } // namespace libspirv