FeatureManager.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 that are enabled by default.
  20. allowAllKnownExtensions();
  21. } else {
  22. for (auto ext : opts.allowedExtensions)
  23. allowExtension(ext);
  24. }
  25. targetEnvStr = opts.targetEnv;
  26. if (opts.targetEnv == "vulkan1.0")
  27. targetEnv = SPV_ENV_VULKAN_1_0;
  28. else if (opts.targetEnv == "vulkan1.1")
  29. targetEnv = SPV_ENV_VULKAN_1_1;
  30. else if (opts.targetEnv == "vulkan1.2")
  31. targetEnv = SPV_ENV_VULKAN_1_2;
  32. else if(opts.targetEnv == "universal1.5")
  33. targetEnv = SPV_ENV_UNIVERSAL_1_5;
  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\n "
  37. "universal1.5",
  38. {});
  39. }
  40. }
  41. bool FeatureManager::allowExtension(llvm::StringRef name) {
  42. // Special case: If we are asked to allow "SPV_KHR" extension, it indicates
  43. // that we should allow using *all* KHR extensions.
  44. if (getExtensionSymbol(name) == Extension::KHR) {
  45. bool result = true;
  46. for (uint32_t i = 0; i < static_cast<uint32_t>(Extension::Unknown); ++i) {
  47. llvm::StringRef extName(getExtensionName(static_cast<Extension>(i)));
  48. if (isKHRExtension(extName))
  49. result = result && allowExtension(extName);
  50. }
  51. return result;
  52. }
  53. const auto symbol = getExtensionSymbol(name);
  54. if (symbol == Extension::Unknown) {
  55. emitError("unknown SPIR-V extension '%0'", {}) << name;
  56. emitNote("known extensions are\n%0", {})
  57. << getKnownExtensions("\n* ", "* ");
  58. return false;
  59. }
  60. allowedExtensions.set(static_cast<unsigned>(symbol));
  61. return true;
  62. }
  63. void FeatureManager::allowAllKnownExtensions() {
  64. allowedExtensions.set();
  65. const auto numExtensions = static_cast<uint32_t>(Extension::Unknown);
  66. for (uint32_t ext = 0; ext < numExtensions; ++ext)
  67. if (!enabledByDefault(static_cast<Extension>(ext)))
  68. allowedExtensions.reset(ext);
  69. }
  70. bool FeatureManager::requestExtension(Extension ext, llvm::StringRef target,
  71. SourceLocation srcLoc) {
  72. if (allowedExtensions.test(static_cast<unsigned>(ext)))
  73. return true;
  74. emitError("SPIR-V extension '%0' required for %1 but not permitted to use",
  75. srcLoc)
  76. << getExtensionName(ext) << target;
  77. return false;
  78. }
  79. bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
  80. llvm::StringRef target,
  81. SourceLocation srcLoc) {
  82. if (targetEnv < requestedEnv) {
  83. emitError("%0 is required for %1 but not permitted to use", srcLoc)
  84. << (requestedEnv > SPV_ENV_VULKAN_1_1 ? "Vulkan 1.2" : "Vulkan 1.1")
  85. << target;
  86. emitNote("please specify your target environment via command line option "
  87. "-fspv-target-env=",
  88. {});
  89. return false;
  90. }
  91. return true;
  92. }
  93. Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
  94. return llvm::StringSwitch<Extension>(name)
  95. .Case("KHR", Extension::KHR)
  96. .Case("SPV_KHR_16bit_storage", Extension::KHR_16bit_storage)
  97. .Case("SPV_KHR_device_group", Extension::KHR_device_group)
  98. .Case("SPV_KHR_multiview", Extension::KHR_multiview)
  99. .Case("SPV_KHR_non_semantic_info", Extension::KHR_non_semantic_info)
  100. .Case("SPV_KHR_shader_draw_parameters",
  101. Extension::KHR_shader_draw_parameters)
  102. .Case("SPV_KHR_ray_tracing", Extension::KHR_ray_tracing)
  103. .Case("SPV_EXT_demote_to_helper_invocation",
  104. Extension::EXT_demote_to_helper_invocation)
  105. .Case("SPV_EXT_descriptor_indexing", Extension::EXT_descriptor_indexing)
  106. .Case("SPV_EXT_fragment_fully_covered",
  107. Extension::EXT_fragment_fully_covered)
  108. .Case("SPV_EXT_fragment_invocation_density",
  109. Extension::EXT_fragment_invocation_density)
  110. .Case("SPV_EXT_shader_stencil_export",
  111. Extension::EXT_shader_stencil_export)
  112. .Case("SPV_EXT_shader_viewport_index_layer",
  113. Extension::EXT_shader_viewport_index_layer)
  114. .Case("SPV_AMD_gpu_shader_half_float",
  115. Extension::AMD_gpu_shader_half_float)
  116. .Case("SPV_AMD_shader_explicit_vertex_parameter",
  117. Extension::AMD_shader_explicit_vertex_parameter)
  118. .Case("SPV_GOOGLE_hlsl_functionality1",
  119. Extension::GOOGLE_hlsl_functionality1)
  120. .Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
  121. .Case("SPV_KHR_post_depth_coverage", Extension::KHR_post_depth_coverage)
  122. .Case("SPV_KHR_shader_clock", Extension::KHR_shader_clock)
  123. .Case("SPV_NV_ray_tracing", Extension::NV_ray_tracing)
  124. .Case("SPV_NV_mesh_shader", Extension::NV_mesh_shader)
  125. .Case("SPV_KHR_ray_query", Extension::KHR_ray_query)
  126. .Case("SPV_KHR_fragment_shading_rate",
  127. Extension::KHR_fragment_shading_rate)
  128. .Default(Extension::Unknown);
  129. }
  130. const char *FeatureManager::getExtensionName(Extension symbol) {
  131. switch (symbol) {
  132. case Extension::KHR:
  133. return "KHR";
  134. case Extension::KHR_16bit_storage:
  135. return "SPV_KHR_16bit_storage";
  136. case Extension::KHR_device_group:
  137. return "SPV_KHR_device_group";
  138. case Extension::KHR_multiview:
  139. return "SPV_KHR_multiview";
  140. case Extension::KHR_non_semantic_info:
  141. return "SPV_KHR_non_semantic_info";
  142. case Extension::KHR_shader_draw_parameters:
  143. return "SPV_KHR_shader_draw_parameters";
  144. case Extension::KHR_post_depth_coverage:
  145. return "SPV_KHR_post_depth_coverage";
  146. case Extension::KHR_ray_tracing:
  147. return "SPV_KHR_ray_tracing";
  148. case Extension::KHR_shader_clock:
  149. return "SPV_KHR_shader_clock";
  150. case Extension::EXT_demote_to_helper_invocation:
  151. return "SPV_EXT_demote_to_helper_invocation";
  152. case Extension::EXT_descriptor_indexing:
  153. return "SPV_EXT_descriptor_indexing";
  154. case Extension::EXT_fragment_fully_covered:
  155. return "SPV_EXT_fragment_fully_covered";
  156. case Extension::EXT_fragment_invocation_density:
  157. return "SPV_EXT_fragment_invocation_density";
  158. case Extension::EXT_shader_stencil_export:
  159. return "SPV_EXT_shader_stencil_export";
  160. case Extension::EXT_shader_viewport_index_layer:
  161. return "SPV_EXT_shader_viewport_index_layer";
  162. case Extension::AMD_gpu_shader_half_float:
  163. return "SPV_AMD_gpu_shader_half_float";
  164. case Extension::AMD_shader_explicit_vertex_parameter:
  165. return "SPV_AMD_shader_explicit_vertex_parameter";
  166. case Extension::GOOGLE_hlsl_functionality1:
  167. return "SPV_GOOGLE_hlsl_functionality1";
  168. case Extension::GOOGLE_user_type:
  169. return "SPV_GOOGLE_user_type";
  170. case Extension::NV_ray_tracing:
  171. return "SPV_NV_ray_tracing";
  172. case Extension::NV_mesh_shader:
  173. return "SPV_NV_mesh_shader";
  174. case Extension::KHR_ray_query:
  175. return "SPV_KHR_ray_query";
  176. case Extension::KHR_fragment_shading_rate:
  177. return "SPV_KHR_fragment_shading_rate";
  178. default:
  179. break;
  180. }
  181. return "<unknown extension>";
  182. }
  183. bool FeatureManager::isKHRExtension(llvm::StringRef name) {
  184. return name.startswith_lower("spv_khr_");
  185. }
  186. std::string FeatureManager::getKnownExtensions(const char *delimiter,
  187. const char *prefix,
  188. const char *postfix) {
  189. std::ostringstream oss;
  190. oss << prefix;
  191. const auto numExtensions = static_cast<uint32_t>(Extension::Unknown);
  192. for (uint32_t i = 0; i < numExtensions; ++i) {
  193. oss << getExtensionName(static_cast<Extension>(i));
  194. if (i + 1 < numExtensions)
  195. oss << delimiter;
  196. }
  197. oss << postfix;
  198. return oss.str();
  199. }
  200. bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
  201. bool required = true;
  202. if (targetEnv >= SPV_ENV_VULKAN_1_1) {
  203. // The following extensions are incorporated into Vulkan 1.1 or above, and
  204. // are therefore not required to be emitted for that target environment.
  205. // TODO: Also add the following extensions if we start to support them.
  206. // * SPV_KHR_storage_buffer_storage_class
  207. // * SPV_KHR_variable_pointers
  208. switch (ext) {
  209. case Extension::KHR_16bit_storage:
  210. case Extension::KHR_device_group:
  211. case Extension::KHR_multiview:
  212. case Extension::KHR_shader_draw_parameters:
  213. required = false;
  214. break;
  215. default:
  216. // Only 1.1 or above extensions can be suppressed.
  217. required = true;
  218. }
  219. }
  220. return required;
  221. }
  222. bool FeatureManager::isExtensionEnabled(Extension ext) {
  223. bool allowed = false;
  224. if (ext != Extension::Unknown &&
  225. allowedExtensions.test(static_cast<unsigned>(ext)))
  226. allowed = true;
  227. return allowed;
  228. }
  229. bool FeatureManager::enabledByDefault(Extension ext) {
  230. switch (ext) {
  231. // KHR_ray_tracing and NV_ray_tracing are mutually exclusive so enable only
  232. // KHR extension by default
  233. case Extension::NV_ray_tracing:
  234. return false;
  235. // Enabling EXT_demote_to_helper_invocation changes the code generation
  236. // behavior for the 'discard' statement. Therefore we will only enable it if
  237. // the user explicitly asks for it.
  238. case Extension::EXT_demote_to_helper_invocation:
  239. return false;
  240. default:
  241. return true;
  242. }
  243. }
  244. bool FeatureManager::isTargetEnvVulkan1p1OrAbove() {
  245. std::string vulkanStr = "vulkan";
  246. return targetEnvStr.substr(0, vulkanStr.size()) == vulkanStr &&
  247. targetEnvStr.compare("vulkan1.1") >= 0;
  248. }
  249. bool FeatureManager::isTargetEnvVulkan1p2OrAbove() {
  250. std::string vulkanStr = "vulkan";
  251. return targetEnvStr.substr(0, vulkanStr.size()) == vulkanStr &&
  252. targetEnvStr.compare("vulkan1.2") >= 0;
  253. }
  254. } // end namespace spirv
  255. } // end namespace clang