FeatureManager.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. //===---- FeatureManager.cpp - SPIR-V Version/Extension Manager -*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/SPIRV/FeatureManager.h"
  9. #include <sstream>
  10. #include "llvm/ADT/StringSwitch.h"
  11. namespace clang {
  12. namespace spirv {
  13. FeatureManager::FeatureManager(DiagnosticsEngine &de,
  14. const SpirvCodeGenOptions &opts)
  15. : diags(de) {
  16. allowedExtensions.resize(static_cast<unsigned>(Extension::Unknown) + 1);
  17. if (opts.allowedExtensions.empty()) {
  18. // If no explicit extension control from command line, use the default mode:
  19. // allowing all extensions.
  20. // Special case : KHR_ray_tracing and NV_ray_tracing are mutually exclusive
  21. // so enable only KHR extension by default
  22. allowAllKnownExtensions();
  23. allowedExtensions.reset(static_cast<unsigned>(Extension::NV_ray_tracing));
  24. } else {
  25. for (auto ext : opts.allowedExtensions)
  26. allowExtension(ext);
  27. }
  28. if (opts.targetEnv == "vulkan1.0")
  29. targetEnv = SPV_ENV_VULKAN_1_0;
  30. else if (opts.targetEnv == "vulkan1.1")
  31. targetEnv = SPV_ENV_VULKAN_1_1;
  32. else if (opts.targetEnv == "vulkan1.2")
  33. targetEnv = SPV_ENV_VULKAN_1_2;
  34. else {
  35. emitError("unknown SPIR-V target environment '%0'", {}) << opts.targetEnv;
  36. emitNote("allowed options are:\n vulkan1.0\n vulkan1.1\n vulkan1.2", {});
  37. }
  38. }
  39. bool FeatureManager::allowExtension(llvm::StringRef name) {
  40. // Special case: If we are asked to allow "SPV_KHR" extension, it indicates
  41. // that we should allow using *all* KHR extensions.
  42. if (getExtensionSymbol(name) == Extension::KHR) {
  43. bool result = true;
  44. for (uint32_t i = 0; i < static_cast<uint32_t>(Extension::Unknown); ++i) {
  45. llvm::StringRef extName(getExtensionName(static_cast<Extension>(i)));
  46. if (isKHRExtension(extName))
  47. result = result && allowExtension(extName);
  48. }
  49. return result;
  50. }
  51. const auto symbol = getExtensionSymbol(name);
  52. if (symbol == Extension::Unknown) {
  53. emitError("unknown SPIR-V extension '%0'", {}) << name;
  54. emitNote("known extensions are\n%0", {})
  55. << getKnownExtensions("\n* ", "* ");
  56. return false;
  57. }
  58. allowedExtensions.set(static_cast<unsigned>(symbol));
  59. return true;
  60. }
  61. void FeatureManager::allowAllKnownExtensions() { allowedExtensions.set(); }
  62. bool FeatureManager::requestExtension(Extension ext, llvm::StringRef target,
  63. SourceLocation srcLoc) {
  64. if (allowedExtensions.test(static_cast<unsigned>(ext)))
  65. return true;
  66. emitError("SPIR-V extension '%0' required for %1 but not permitted to use",
  67. srcLoc)
  68. << getExtensionName(ext) << target;
  69. return false;
  70. }
  71. bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
  72. llvm::StringRef target,
  73. SourceLocation srcLoc) {
  74. if (targetEnv < requestedEnv) {
  75. emitError("%0 is required for %1 but not permitted to use", srcLoc)
  76. << (requestedEnv == SPV_ENV_VULKAN_1_2 ? "Vulkan 1.2" : "Vulkan 1.1")
  77. << target;
  78. emitNote("please specify your target environment via command line option "
  79. "-fspv-target-env=",
  80. {});
  81. return false;
  82. }
  83. return true;
  84. }
  85. Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
  86. return llvm::StringSwitch<Extension>(name)
  87. .Case("KHR", Extension::KHR)
  88. .Case("SPV_KHR_16bit_storage", Extension::KHR_16bit_storage)
  89. .Case("SPV_KHR_device_group", Extension::KHR_device_group)
  90. .Case("SPV_KHR_multiview", Extension::KHR_multiview)
  91. .Case("SPV_KHR_non_semantic_info", Extension::KHR_non_semantic_info)
  92. .Case("SPV_KHR_shader_draw_parameters",
  93. Extension::KHR_shader_draw_parameters)
  94. .Case("SPV_KHR_ray_tracing", Extension::KHR_ray_tracing)
  95. .Case("SPV_EXT_demote_to_helper_invocation",
  96. Extension::EXT_demote_to_helper_invocation)
  97. .Case("SPV_EXT_descriptor_indexing", Extension::EXT_descriptor_indexing)
  98. .Case("SPV_EXT_fragment_fully_covered",
  99. Extension::EXT_fragment_fully_covered)
  100. .Case("SPV_EXT_fragment_invocation_density",
  101. Extension::EXT_fragment_invocation_density)
  102. .Case("SPV_EXT_shader_stencil_export",
  103. Extension::EXT_shader_stencil_export)
  104. .Case("SPV_EXT_shader_viewport_index_layer",
  105. Extension::EXT_shader_viewport_index_layer)
  106. .Case("SPV_AMD_gpu_shader_half_float",
  107. Extension::AMD_gpu_shader_half_float)
  108. .Case("SPV_AMD_shader_explicit_vertex_parameter",
  109. Extension::AMD_shader_explicit_vertex_parameter)
  110. .Case("SPV_GOOGLE_hlsl_functionality1",
  111. Extension::GOOGLE_hlsl_functionality1)
  112. .Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
  113. .Case("SPV_KHR_post_depth_coverage", Extension::KHR_post_depth_coverage)
  114. .Case("SPV_NV_ray_tracing", Extension::NV_ray_tracing)
  115. .Case("SPV_NV_mesh_shader", Extension::NV_mesh_shader)
  116. .Case("SPV_KHR_ray_query", Extension::KHR_ray_query)
  117. .Default(Extension::Unknown);
  118. }
  119. const char *FeatureManager::getExtensionName(Extension symbol) {
  120. switch (symbol) {
  121. case Extension::KHR:
  122. return "KHR";
  123. case Extension::KHR_16bit_storage:
  124. return "SPV_KHR_16bit_storage";
  125. case Extension::KHR_device_group:
  126. return "SPV_KHR_device_group";
  127. case Extension::KHR_multiview:
  128. return "SPV_KHR_multiview";
  129. case Extension::KHR_non_semantic_info:
  130. return "SPV_KHR_non_semantic_info";
  131. case Extension::KHR_shader_draw_parameters:
  132. return "SPV_KHR_shader_draw_parameters";
  133. case Extension::KHR_post_depth_coverage:
  134. return "SPV_KHR_post_depth_coverage";
  135. case Extension::KHR_ray_tracing:
  136. return "SPV_KHR_ray_tracing";
  137. case Extension::EXT_demote_to_helper_invocation:
  138. return "SPV_EXT_demote_to_helper_invocation";
  139. case Extension::EXT_descriptor_indexing:
  140. return "SPV_EXT_descriptor_indexing";
  141. case Extension::EXT_fragment_fully_covered:
  142. return "SPV_EXT_fragment_fully_covered";
  143. case Extension::EXT_fragment_invocation_density:
  144. return "SPV_EXT_fragment_invocation_density";
  145. case Extension::EXT_shader_stencil_export:
  146. return "SPV_EXT_shader_stencil_export";
  147. case Extension::EXT_shader_viewport_index_layer:
  148. return "SPV_EXT_shader_viewport_index_layer";
  149. case Extension::AMD_gpu_shader_half_float:
  150. return "SPV_AMD_gpu_shader_half_float";
  151. case Extension::AMD_shader_explicit_vertex_parameter:
  152. return "SPV_AMD_shader_explicit_vertex_parameter";
  153. case Extension::GOOGLE_hlsl_functionality1:
  154. return "SPV_GOOGLE_hlsl_functionality1";
  155. case Extension::GOOGLE_user_type:
  156. return "SPV_GOOGLE_user_type";
  157. case Extension::NV_ray_tracing:
  158. return "SPV_NV_ray_tracing";
  159. case Extension::NV_mesh_shader:
  160. return "SPV_NV_mesh_shader";
  161. case Extension::KHR_ray_query:
  162. return "SPV_KHR_ray_query";
  163. default:
  164. break;
  165. }
  166. return "<unknown extension>";
  167. }
  168. bool FeatureManager::isKHRExtension(llvm::StringRef name) {
  169. return name.startswith_lower("spv_khr_");
  170. }
  171. std::string FeatureManager::getKnownExtensions(const char *delimiter,
  172. const char *prefix,
  173. const char *postfix) {
  174. std::ostringstream oss;
  175. oss << prefix;
  176. const auto numExtensions = static_cast<uint32_t>(Extension::Unknown);
  177. for (uint32_t i = 0; i < numExtensions; ++i) {
  178. oss << getExtensionName(static_cast<Extension>(i));
  179. if (i + 1 < numExtensions)
  180. oss << delimiter;
  181. }
  182. oss << postfix;
  183. return oss.str();
  184. }
  185. bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
  186. bool required = true;
  187. if (targetEnv >= SPV_ENV_VULKAN_1_1) {
  188. // The following extensions are incorporated into Vulkan 1.1 or above, and
  189. // are therefore not required to be emitted for that target environment.
  190. // TODO: Also add the following extensions if we start to support them.
  191. // * SPV_KHR_storage_buffer_storage_class
  192. // * SPV_KHR_variable_pointers
  193. switch (ext) {
  194. case Extension::KHR_16bit_storage:
  195. case Extension::KHR_device_group:
  196. case Extension::KHR_multiview:
  197. case Extension::KHR_shader_draw_parameters:
  198. required = false;
  199. break;
  200. default:
  201. // Only 1.1 or above extensions can be suppressed.
  202. required = true;
  203. }
  204. }
  205. return required;
  206. }
  207. bool FeatureManager::isExtensionEnabled(llvm::StringRef name) {
  208. bool allowed = false;
  209. Extension ext = getExtensionSymbol(name);
  210. if (ext != Extension::Unknown &&
  211. allowedExtensions.test(static_cast<unsigned>(ext)))
  212. allowed = true;
  213. return allowed;
  214. }
  215. } // end namespace spirv
  216. } // end namespace clang