FeatureManager.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 EmitSPIRVOptions &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. allowAllKnownExtensions();
  21. } else {
  22. for (auto ext : opts.allowedExtensions)
  23. allowExtension(ext);
  24. }
  25. if (opts.targetEnv == "vulkan1.0")
  26. targetEnv = SPV_ENV_VULKAN_1_0;
  27. else if (opts.targetEnv == "vulkan1.1")
  28. targetEnv = SPV_ENV_VULKAN_1_1;
  29. else {
  30. emitError("unknown SPIR-V target environment '%0'", {}) << opts.targetEnv;
  31. emitNote("allowed options are:\n vulkan1.0\n vulkan1.1", {});
  32. }
  33. }
  34. bool FeatureManager::allowExtension(llvm::StringRef name) {
  35. // Special case: If we are asked to allow "SPV_KHR" extension, it indicates
  36. // that we should allow using *all* KHR extensions.
  37. if (getExtensionSymbol(name) == Extension::KHR) {
  38. bool result = true;
  39. for (uint32_t i = 0; i < static_cast<uint32_t>(Extension::Unknown); ++i) {
  40. llvm::StringRef extName(getExtensionName(static_cast<Extension>(i)));
  41. if (isKHRExtension(extName))
  42. result = result && allowExtension(extName);
  43. }
  44. return result;
  45. }
  46. const auto symbol = getExtensionSymbol(name);
  47. if (symbol == Extension::Unknown) {
  48. emitError("unknown SPIR-V extension '%0'", {}) << name;
  49. emitNote("known extensions are\n%0", {})
  50. << getKnownExtensions("\n* ", "* ");
  51. return false;
  52. }
  53. allowedExtensions.set(static_cast<unsigned>(symbol));
  54. if (symbol == Extension::GOOGLE_hlsl_functionality1)
  55. allowedExtensions.set(
  56. static_cast<unsigned>(Extension::GOOGLE_decorate_string));
  57. return true;
  58. }
  59. void FeatureManager::allowAllKnownExtensions() { allowedExtensions.set(); }
  60. bool FeatureManager::requestExtension(Extension ext, llvm::StringRef target,
  61. SourceLocation srcLoc) {
  62. if (allowedExtensions.test(static_cast<unsigned>(ext)))
  63. return true;
  64. emitError("SPIR-V extension '%0' required for %1 but not permitted to use",
  65. srcLoc)
  66. << getExtensionName(ext) << target;
  67. return false;
  68. }
  69. bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
  70. llvm::StringRef target,
  71. SourceLocation srcLoc) {
  72. if (targetEnv == SPV_ENV_VULKAN_1_0 && requestedEnv == SPV_ENV_VULKAN_1_1) {
  73. emitError("Vulkan 1.1 is required for %0 but not permitted to use", srcLoc)
  74. << target;
  75. emitNote("please specify your target environment via command line option -fspv-target-env=",
  76. {});
  77. return false;
  78. }
  79. return true;
  80. }
  81. Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
  82. return llvm::StringSwitch<Extension>(name)
  83. .Case("KHR", Extension::KHR)
  84. .Case("SPV_KHR_device_group", Extension::KHR_device_group)
  85. .Case("SPV_KHR_multiview", Extension::KHR_multiview)
  86. .Case("SPV_KHR_shader_draw_parameters",
  87. Extension::KHR_shader_draw_parameters)
  88. .Case("SPV_EXT_fragment_fully_covered",
  89. Extension::EXT_fragment_fully_covered)
  90. .Case("SPV_EXT_shader_stencil_export",
  91. Extension::EXT_shader_stencil_export)
  92. .Case("SPV_AMD_gpu_shader_half_float",
  93. Extension::AMD_gpu_shader_half_float)
  94. .Case("SPV_AMD_shader_explicit_vertex_parameter",
  95. Extension::AMD_shader_explicit_vertex_parameter)
  96. .Case("SPV_GOOGLE_decorate_string", Extension::GOOGLE_decorate_string)
  97. .Case("SPV_GOOGLE_hlsl_functionality1",
  98. Extension::GOOGLE_hlsl_functionality1)
  99. .Default(Extension::Unknown);
  100. }
  101. const char *FeatureManager::getExtensionName(Extension symbol) {
  102. switch (symbol) {
  103. case Extension::KHR:
  104. return "KHR";
  105. case Extension::KHR_device_group:
  106. return "SPV_KHR_device_group";
  107. case Extension::KHR_multiview:
  108. return "SPV_KHR_multiview";
  109. case Extension::KHR_shader_draw_parameters:
  110. return "SPV_KHR_shader_draw_parameters";
  111. case Extension::EXT_fragment_fully_covered:
  112. return "SPV_EXT_fragment_fully_covered";
  113. case Extension::EXT_shader_stencil_export:
  114. return "SPV_EXT_shader_stencil_export";
  115. case Extension::AMD_gpu_shader_half_float:
  116. return "SPV_AMD_gpu_shader_half_float";
  117. case Extension::AMD_shader_explicit_vertex_parameter:
  118. return "SPV_AMD_shader_explicit_vertex_parameter";
  119. case Extension::GOOGLE_decorate_string:
  120. return "SPV_GOOGLE_decorate_string";
  121. case Extension::GOOGLE_hlsl_functionality1:
  122. return "SPV_GOOGLE_hlsl_functionality1";
  123. default:
  124. break;
  125. }
  126. return "<unknown extension>";
  127. }
  128. bool FeatureManager::isKHRExtension(llvm::StringRef name) {
  129. return name.startswith_lower("spv_khr_");
  130. }
  131. std::string FeatureManager::getKnownExtensions(const char *delimiter,
  132. const char *prefix,
  133. const char *postfix) {
  134. std::ostringstream oss;
  135. oss << prefix;
  136. const auto numExtensions = static_cast<uint32_t>(Extension::Unknown);
  137. for (uint32_t i = 0; i < numExtensions; ++i) {
  138. oss << getExtensionName(static_cast<Extension>(i));
  139. if (i + 1 < numExtensions)
  140. oss << delimiter;
  141. }
  142. oss << postfix;
  143. return oss.str();
  144. }
  145. bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
  146. bool required = true;
  147. if (targetEnv == SPV_ENV_VULKAN_1_1) {
  148. // The following extensions are incorporated into Vulkan 1.1, and are
  149. // therefore not required to be emitted for that target environment. The
  150. // last 3 are currently not supported by the FeatureManager.
  151. // TODO: Add the last 3 extensions to the list if we start to support them.
  152. // SPV_KHR_shader_draw_parameters
  153. // SPV_KHR_device_group
  154. // SPV_KHR_multiview
  155. // SPV_KHR_16bit_storage
  156. // SPV_KHR_storage_buffer_storage_class
  157. // SPV_KHR_variable_pointers
  158. switch (ext) {
  159. case Extension::KHR_shader_draw_parameters:
  160. case Extension::KHR_device_group:
  161. case Extension::KHR_multiview:
  162. required = false;
  163. }
  164. }
  165. return required;
  166. }
  167. } // end namespace spirv
  168. } // end namespace clang