Browse Source

[spirv] Add -fspv-target-env command line option. (#1187)

* [spirv] Add -fspv-target-env command line option.

The valid values for this option currently are:
vulkan1.0
vulkan1.1

If no target environment is specified, vulkan1.0 is used as default.
Ehsan 7 years ago
parent
commit
2a0b7c49fd
40 changed files with 169 additions and 57 deletions
  1. 3 0
      docs/SPIR-V.rst
  2. 1 0
      include/dxc/Support/HLSLOptions.h
  3. 2 0
      include/dxc/Support/HLSLOptions.td
  4. 3 0
      lib/DxcSupport/HLSLOptions.cpp
  5. 1 0
      tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h
  6. 21 1
      tools/clang/include/clang/SPIRV/FeatureManager.h
  7. 0 2
      tools/clang/include/clang/SPIRV/ModuleBuilder.h
  8. 58 1
      tools/clang/lib/SPIRV/FeatureManager.cpp
  9. 8 1
      tools/clang/lib/SPIRV/ModuleBuilder.cpp
  10. 18 24
      tools/clang/lib/SPIRV/SPIRVEmitter.cpp
  11. 0 3
      tools/clang/lib/SPIRV/SPIRVEmitter.h
  12. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-diagonal.hlsl
  13. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-x.hlsl
  14. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-y.hlsl
  15. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.quad-read-lane-at.hlsl
  16. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-all-equal.hlsl
  17. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-all-true.hlsl
  18. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-any-true.hlsl
  19. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-ballot.hlsl
  20. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-and.hlsl
  21. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-or.hlsl
  22. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-xor.hlsl
  23. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-count-bits.hlsl
  24. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-max.hlsl
  25. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-min.hlsl
  26. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-product.hlsl
  27. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-active-sum.hlsl
  28. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-get-lane-count.hlsl
  29. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-get-lane-index.hlsl
  30. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-is-first-lane.hlsl
  31. 10 0
      tools/clang/test/CodeGenSPIRV/sm6.wave-op.no-target-env.error.hlsl
  32. 10 0
      tools/clang/test/CodeGenSPIRV/sm6.wave-op.target-vulkan1.error.hlsl
  33. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-count-bits.hlsl
  34. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-product.hlsl
  35. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-sum.hlsl
  36. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-read-lane-at.hlsl
  37. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave-read-lane-first.hlsl
  38. 1 1
      tools/clang/test/CodeGenSPIRV/sm6.wave.builtin.no-dup.hlsl
  39. 1 0
      tools/clang/tools/dxcompiler/dxcompilerobj.cpp
  40. 8 0
      tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

+ 3 - 0
docs/SPIR-V.rst

@@ -2652,6 +2652,9 @@ codegen for Vulkan:
 - ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
 - ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
 - ``-fspv-extension=<extension>``: Only allows using ``<extension>`` in CodeGen.
 - ``-fspv-extension=<extension>``: Only allows using ``<extension>`` in CodeGen.
   If you want to allow multiple extensions, provide more than one such option.
   If you want to allow multiple extensions, provide more than one such option.
+- ``-fspv-target-env=<env>``: Specifies the target environment for this compilation.
+  The current valid options are ``vulkan1.0`` and ``vulkan1.1``. If no target
+  environment is provided, ``vulkan1.0`` is used as default.
 
 
 Unsupported HLSL Features
 Unsupported HLSL Features
 =========================
 =========================

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -171,6 +171,7 @@ public:
   llvm::SmallVector<uint32_t, 4> VkSShift; // OPT_fvk_s_shift
   llvm::SmallVector<uint32_t, 4> VkSShift; // OPT_fvk_s_shift
   llvm::SmallVector<uint32_t, 4> VkUShift; // OPT_fvk_u_shift
   llvm::SmallVector<uint32_t, 4> VkUShift; // OPT_fvk_u_shift
   llvm::SmallVector<llvm::StringRef, 4> SpvExtensions; // OPT_fspv_extension
   llvm::SmallVector<llvm::StringRef, 4> SpvExtensions; // OPT_fspv_extension
+  llvm::StringRef SpvTargetEnv;                        // OPT_fspv_target_env
 #endif
 #endif
   // SPIRV Change Ends
   // SPIRV Change Ends
 };
 };

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -256,6 +256,8 @@ def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOp
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Specify SPIR-V extension permitted to use">;
   HelpText<"Specify SPIR-V extension permitted to use">;
+def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Specify the target environment: vulkan1.0 (default) or vulkan1.1">;
 // SPIRV Change Ends
 // SPIRV Change Ends
 
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////

+ 3 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -526,6 +526,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   for (const Arg *A : Args.filtered(OPT_fspv_extension_EQ)) {
   for (const Arg *A : Args.filtered(OPT_fspv_extension_EQ)) {
     opts.SpvExtensions.push_back(A->getValue());
     opts.SpvExtensions.push_back(A->getValue());
   }
   }
+
+  opts.SpvTargetEnv = Args.getLastArgValue(OPT_fspv_target_env_EQ, "vulkan1.0");
 #else
 #else
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
@@ -534,6 +536,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
+      !Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
       !Args.getLastArgValue(OPT_fvk_s_shift).empty() ||

+ 1 - 0
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -30,6 +30,7 @@ struct EmitSPIRVOptions {
   llvm::SmallVector<uint32_t, 4> sShift;
   llvm::SmallVector<uint32_t, 4> sShift;
   llvm::SmallVector<uint32_t, 4> uShift;
   llvm::SmallVector<uint32_t, 4> uShift;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
+  llvm::StringRef targetEnv;
 };
 };
 } // end namespace clang
 } // end namespace clang
 
 

+ 21 - 1
tools/clang/include/clang/SPIRV/FeatureManager.h

@@ -15,11 +15,16 @@
 
 
 #include <string>
 #include <string>
 
 
+
+#include "spirv-tools/libspirv.h"
+
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringRef.h"
 
 
+#include "EmitSPIRVOptions.h"
+
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
 
 
@@ -40,7 +45,7 @@ enum class Extension {
 /// The class for handling SPIR-V version and extension requests.
 /// The class for handling SPIR-V version and extension requests.
 class FeatureManager {
 class FeatureManager {
 public:
 public:
-  explicit FeatureManager(DiagnosticsEngine &de);
+  FeatureManager(DiagnosticsEngine &de, const EmitSPIRVOptions &);
 
 
   /// Allows the given extension to be used in CodeGen.
   /// Allows the given extension to be used in CodeGen.
   bool allowExtension(llvm::StringRef);
   bool allowExtension(llvm::StringRef);
@@ -60,6 +65,20 @@ public:
   std::string getKnownExtensions(const char *delimiter, const char *prefix = "",
   std::string getKnownExtensions(const char *delimiter, const char *prefix = "",
                                  const char *postfix = "");
                                  const char *postfix = "");
 
 
+  /// Rqeusts the given target environment for translating the given feature at
+  /// the given source location. Emits an error if the requested target
+  /// environment does not match user's target environemnt.
+  bool requestTargetEnv(spv_target_env, llvm::StringRef target, SourceLocation);
+
+  /// Returns the target environment corresponding to the target environment
+  /// that was specified as command line option. If no option is specified, the
+  /// default (Vulkan 1.0) is returned.
+  spv_target_env getTargetEnv() const { return targetEnv; }
+
+  /// Returns true if the given extension is not part of the core of the target
+  /// environment.
+  bool isExtensionRequiredForTargetEnv(Extension);
+
 private:
 private:
   /// \brief Wrapper method to create an error message and report it
   /// \brief Wrapper method to create an error message and report it
   /// in the diagnostic engine associated with this object.
   /// in the diagnostic engine associated with this object.
@@ -82,6 +101,7 @@ private:
   DiagnosticsEngine &diags;
   DiagnosticsEngine &diags;
 
 
   llvm::SmallBitVector allowedExtensions;
   llvm::SmallBitVector allowedExtensions;
+  spv_target_env targetEnv;
 };
 };
 
 
 } // end namespace spirv
 } // end namespace spirv

+ 0 - 2
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -501,8 +501,6 @@ void ModuleBuilder::setMemoryModel(spv::MemoryModel mm) {
   theModule.setMemoryModel(mm);
   theModule.setMemoryModel(mm);
 }
 }
 
 
-void ModuleBuilder::useSpirv1p3() { theModule.setVersion(0x00010300); }
-
 void ModuleBuilder::requireCapability(spv::Capability cap) {
 void ModuleBuilder::requireCapability(spv::Capability cap) {
   if (cap != spv::Capability::Max)
   if (cap != spv::Capability::Max)
     theModule.addCapability(cap);
     theModule.addCapability(cap);

+ 58 - 1
tools/clang/lib/SPIRV/FeatureManager.cpp

@@ -15,8 +15,28 @@
 namespace clang {
 namespace clang {
 namespace spirv {
 namespace spirv {
 
 
-FeatureManager::FeatureManager(DiagnosticsEngine &de) : diags(de) {
+FeatureManager::FeatureManager(DiagnosticsEngine &de,
+                               const EmitSPIRVOptions &opts)
+    : diags(de) {
   allowedExtensions.resize(static_cast<unsigned>(Extension::Unknown) + 1);
   allowedExtensions.resize(static_cast<unsigned>(Extension::Unknown) + 1);
+
+  if (opts.allowedExtensions.empty()) {
+    // If no explicit extension control from command line, use the default mode:
+    // allowing all extensions.
+    allowAllKnownExtensions();
+  } else {
+    for (auto ext : opts.allowedExtensions)
+      allowExtension(ext);
+  }
+
+  if (opts.targetEnv == "vulkan1.0")
+    targetEnv = SPV_ENV_VULKAN_1_0;
+  else if (opts.targetEnv == "vulkan1.1")
+    targetEnv = SPV_ENV_VULKAN_1_1;
+  else {
+    emitError("unknown SPIR-V target environment '%0'", {}) << opts.targetEnv;
+    emitNote("allowed options are:\n vulkan1.0\n vulkan1.1", {});
+  }
 }
 }
 
 
 bool FeatureManager::allowExtension(llvm::StringRef name) {
 bool FeatureManager::allowExtension(llvm::StringRef name) {
@@ -49,6 +69,19 @@ bool FeatureManager::requestExtension(Extension ext, llvm::StringRef target,
   return false;
   return false;
 }
 }
 
 
+bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
+                                      llvm::StringRef target,
+                                      SourceLocation srcLoc) {
+  if (targetEnv == SPV_ENV_VULKAN_1_0 && requestedEnv == SPV_ENV_VULKAN_1_1) {
+    emitError("Vulkan 1.1 is required for %0 but not permitted to use", srcLoc)
+        << target;
+    emitNote("please specify your target environment via command line option -fspv-target-env=",
+             {});
+    return false;
+  }
+  return true;
+}
+
 Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
 Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
   return llvm::StringSwitch<Extension>(name)
   return llvm::StringSwitch<Extension>(name)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
@@ -114,5 +147,29 @@ std::string FeatureManager::getKnownExtensions(const char *delimiter,
   return oss.str();
   return oss.str();
 }
 }
 
 
+bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
+  bool required = true;
+  if (targetEnv == SPV_ENV_VULKAN_1_1) {
+    // The following extensions are incorporated into Vulkan 1.1, and are
+    // therefore not required to be emitted for that target environment. The
+    // last 3 are currently not supported by the FeatureManager.
+    // TODO: Add the last 3 extensions to the list if we start to support them.
+    // SPV_KHR_shader_draw_parameters
+    // SPV_KHR_device_group
+    // SPV_KHR_multiview
+    // SPV_KHR_16bit_storage
+    // SPV_KHR_storage_buffer_storage_class
+    // SPV_KHR_variable_pointers
+    switch (ext) {
+    case Extension::KHR_shader_draw_parameters:
+    case Extension::KHR_device_group:
+    case Extension::KHR_multiview:
+      required = false;
+    }
+  }
+
+  return required;
+}
+
 } // end namespace spirv
 } // end namespace spirv
 } // end namespace clang
 } // end namespace clang

+ 8 - 1
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -26,6 +26,10 @@ ModuleBuilder::ModuleBuilder(SPIRVContext *C, FeatureManager *features,
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
     this->constructSite = std::move(words);
     this->constructSite = std::move(words);
   });
   });
+
+  // Set the SPIR-V version if needed.
+  if (featureManager && featureManager->getTargetEnv() == SPV_ENV_VULKAN_1_1)
+    theModule.setVersion(0x00010300);
 }
 }
 
 
 std::vector<uint32_t> ModuleBuilder::takeModule() {
 std::vector<uint32_t> ModuleBuilder::takeModule() {
@@ -758,7 +762,10 @@ void ModuleBuilder::addExtension(Extension ext, llvm::StringRef target,
                                  SourceLocation srcLoc) {
                                  SourceLocation srcLoc) {
   assert(featureManager);
   assert(featureManager);
   featureManager->requestExtension(ext, target, srcLoc);
   featureManager->requestExtension(ext, target, srcLoc);
-  theModule.addExtension(featureManager->getExtensionName(ext));
+  // Do not emit OpExtension if the given extension is natively supported in the
+  // target environment.
+  if (featureManager->isExtensionRequiredForTargetEnv(ext))
+    theModule.addExtension(featureManager->getExtensionName(ext));
 }
 }
 
 
 uint32_t ModuleBuilder::getGLSLExtInstSet() {
 uint32_t ModuleBuilder::getGLSLExtInstSet() {

+ 18 - 24
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -519,29 +519,20 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       shaderModel(*hlsl::ShaderModel::GetByName(
       shaderModel(*hlsl::ShaderModel::GetByName(
           ci.getCodeGenOpts().HLSLProfile.c_str())),
           ci.getCodeGenOpts().HLSLProfile.c_str())),
-      theContext(), featureManager(diags),
+      theContext(), featureManager(diags, options),
       theBuilder(&theContext, &featureManager, options.enableReflect),
       theBuilder(&theContext, &featureManager, options.enableReflect),
       typeTranslator(astContext, theBuilder, diags, options),
       typeTranslator(astContext, theBuilder, diags, options),
       declIdMapper(shaderModel, astContext, theBuilder, typeTranslator,
       declIdMapper(shaderModel, astContext, theBuilder, typeTranslator,
                    featureManager, spirvOptions),
                    featureManager, spirvOptions),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
-      seenPushConstantAt(), isSpecConstantMode(false), needsLegalization(false),
-      needsSpirv1p3(false) {
+      seenPushConstantAt(), isSpecConstantMode(false),
+      needsLegalization(false) {
   if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)
   if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)
     emitError("unknown shader module: %0", {}) << shaderModel.GetName();
     emitError("unknown shader module: %0", {}) << shaderModel.GetName();
 
 
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
       !shaderModel.IsGS())
       !shaderModel.IsGS())
     emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
     emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
-
-  if (options.allowedExtensions.empty()) {
-    // If no explicit extension control from command line, use the default mode:
-    // allowing all extensions.
-    featureManager.allowAllKnownExtensions();
-  } else {
-    for (auto ext : options.allowedExtensions)
-      featureManager.allowExtension(ext);
-  }
 }
 }
 
 
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -579,11 +570,7 @@ void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
   if (context.getDiagnostics().hasErrorOccurred())
   if (context.getDiagnostics().hasErrorOccurred())
     return;
     return;
 
 
-  spv_target_env targetEnv = SPV_ENV_VULKAN_1_0;
-  if (needsSpirv1p3) {
-    theBuilder.useSpirv1p3();
-    targetEnv = SPV_ENV_VULKAN_1_1;
-  }
+  const spv_target_env targetEnv = featureManager.getTargetEnv();
 
 
   AddRequiredCapabilitiesForShaderModel();
   AddRequiredCapabilitiesForShaderModel();
 
 
@@ -6202,7 +6189,8 @@ SpirvEvalInfo SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     retVal = processIntrinsicF32ToF16(callExpr);
     retVal = processIntrinsicF32ToF16(callExpr);
     break;
     break;
   case hlsl::IntrinsicOp::IOP_WaveGetLaneCount: {
   case hlsl::IntrinsicOp::IOP_WaveGetLaneCount: {
-    needsSpirv1p3 = true;
+    featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "WaveGetLaneCount",
+                                    callExpr->getExprLoc());
     const uint32_t retType =
     const uint32_t retType =
         typeTranslator.translateType(callExpr->getCallReturnType(astContext));
         typeTranslator.translateType(callExpr->getCallReturnType(astContext));
     const uint32_t varId =
     const uint32_t varId =
@@ -6210,7 +6198,8 @@ SpirvEvalInfo SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     retVal = theBuilder.createLoad(retType, varId);
     retVal = theBuilder.createLoad(retType, varId);
   } break;
   } break;
   case hlsl::IntrinsicOp::IOP_WaveGetLaneIndex: {
   case hlsl::IntrinsicOp::IOP_WaveGetLaneIndex: {
-    needsSpirv1p3 = true;
+    featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "WaveGetLaneIndex",
+                                    callExpr->getExprLoc());
     const uint32_t retType =
     const uint32_t retType =
         typeTranslator.translateType(callExpr->getCallReturnType(astContext));
         typeTranslator.translateType(callExpr->getCallReturnType(astContext));
     const uint32_t varId =
     const uint32_t varId =
@@ -6654,7 +6643,8 @@ uint32_t SPIRVEmitter::processWaveQuery(const CallExpr *callExpr,
   // uint WaveGetLaneCount()
   // uint WaveGetLaneCount()
   // uint WaveGetLaneIndex()
   // uint WaveGetLaneIndex()
   assert(callExpr->getNumArgs() == 0);
   assert(callExpr->getNumArgs() == 0);
-  needsSpirv1p3 = true;
+  featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "Wave Operation",
+                                  callExpr->getExprLoc());
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
   const uint32_t retType =
   const uint32_t retType =
@@ -6669,7 +6659,8 @@ uint32_t SPIRVEmitter::processWaveVote(const CallExpr *callExpr,
   // bool WaveActiveAllTrue( bool expr )
   // bool WaveActiveAllTrue( bool expr )
   // bool uint4 WaveActiveBallot( bool expr )
   // bool uint4 WaveActiveBallot( bool expr )
   assert(callExpr->getNumArgs() == 1);
   assert(callExpr->getNumArgs() == 1);
-  needsSpirv1p3 = true;
+  featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "Wave Operation",
+                                  callExpr->getExprLoc());
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   const uint32_t predicate = doExpr(callExpr->getArg(0));
   const uint32_t predicate = doExpr(callExpr->getArg(0));
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
@@ -6762,7 +6753,8 @@ uint32_t SPIRVEmitter::processWaveReductionOrPrefix(
   // <type> WavePrefixProduct(<type> value)
   // <type> WavePrefixProduct(<type> value)
   // <type> WavePrefixSum(<type> value)
   // <type> WavePrefixSum(<type> value)
   assert(callExpr->getNumArgs() == 1);
   assert(callExpr->getNumArgs() == 1);
-  needsSpirv1p3 = true;
+  featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "Wave Operation",
+                                  callExpr->getExprLoc());
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   theBuilder.requireCapability(getCapabilityForGroupNonUniform(opcode));
   const uint32_t predicate = doExpr(callExpr->getArg(0));
   const uint32_t predicate = doExpr(callExpr->getArg(0));
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
@@ -6779,7 +6771,8 @@ uint32_t SPIRVEmitter::processWaveBroadcast(const CallExpr *callExpr) {
   // <type> WaveReadLaneAt(<type> expr, uint laneIndex)
   // <type> WaveReadLaneAt(<type> expr, uint laneIndex)
   const auto numArgs = callExpr->getNumArgs();
   const auto numArgs = callExpr->getNumArgs();
   assert(numArgs == 1 || numArgs == 2);
   assert(numArgs == 1 || numArgs == 2);
-  needsSpirv1p3 = true;
+  featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "Wave Operation",
+                                  callExpr->getExprLoc());
   theBuilder.requireCapability(spv::Capability::GroupNonUniformBallot);
   theBuilder.requireCapability(spv::Capability::GroupNonUniformBallot);
   const uint32_t value = doExpr(callExpr->getArg(0));
   const uint32_t value = doExpr(callExpr->getArg(0));
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
   const uint32_t subgroupScope = theBuilder.getConstantInt32(3);
@@ -6803,7 +6796,8 @@ uint32_t SPIRVEmitter::processWaveQuadWideShuffle(const CallExpr *callExpr,
   // <type> QuadReadAcrossDiagonal(<type> localValue)
   // <type> QuadReadAcrossDiagonal(<type> localValue)
   // <type> QuadReadLaneAt(<type> sourceValue, uint quadLaneID)
   // <type> QuadReadLaneAt(<type> sourceValue, uint quadLaneID)
   assert(callExpr->getNumArgs() == 1 || callExpr->getNumArgs() == 2);
   assert(callExpr->getNumArgs() == 1 || callExpr->getNumArgs() == 2);
-  needsSpirv1p3 = true;
+  featureManager.requestTargetEnv(SPV_ENV_VULKAN_1_1, "Wave Operation",
+                                  callExpr->getExprLoc());
   theBuilder.requireCapability(spv::Capability::GroupNonUniformQuad);
   theBuilder.requireCapability(spv::Capability::GroupNonUniformQuad);
 
 
   const uint32_t value = doExpr(callExpr->getArg(0));
   const uint32_t value = doExpr(callExpr->getArg(0));

+ 0 - 3
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -955,9 +955,6 @@ private:
   /// Note: legalization specific code
   /// Note: legalization specific code
   bool needsLegalization;
   bool needsLegalization;
 
 
-  /// Indicates whether we should generate SPIR-V 1.3 instead of 1.0.
-  bool needsSpirv1p3;
-
   /// Mapping from methods to the decls to represent their implicit object
   /// Mapping from methods to the decls to represent their implicit object
   /// parameters
   /// parameters
   ///
   ///

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-diagonal.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-x.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.quad-read-across-y.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.quad-read-lane-at.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-all-equal.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-all-true.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-any-true.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-ballot.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-and.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // Note: WaveActiveBitAnd() only accepts unsigned interger scalars/vectors.
 // Note: WaveActiveBitAnd() only accepts unsigned interger scalars/vectors.
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-or.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // Note: WaveActiveBitOr() only accepts unsigned interger scalars/vectors.
 // Note: WaveActiveBitOr() only accepts unsigned interger scalars/vectors.
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-bit-xor.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // Note: WaveActiveBitXor() only accepts unsigned interger scalars/vectors.
 // Note: WaveActiveBitXor() only accepts unsigned interger scalars/vectors.
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-count-bits.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-max.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-min.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-product.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-active-sum.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-get-lane-count.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-get-lane-index.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-is-first-lane.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 10 - 0
tools/clang/test/CodeGenSPIRV/sm6.wave-op.no-target-env.error.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T cs_6_0 -E main
+
+RWStructuredBuffer<uint> values;
+[numthreads(32, 1, 1)]
+void main(uint3 id: SV_DispatchThreadID) {
+    values[id.x] = WaveIsFirstLane();
+}
+
+// CHECK: 6:20: error: Vulkan 1.1 is required for Wave Operation but not permitted to use
+// CHECK: note: please specify your target environment via command line option

+ 10 - 0
tools/clang/test/CodeGenSPIRV/sm6.wave-op.target-vulkan1.error.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.0
+
+RWStructuredBuffer<uint> values;
+[numthreads(32, 1, 1)]
+void main(uint3 id: SV_DispatchThreadID) {
+    values[id.x] = WaveIsFirstLane();
+}
+
+// CHECK: 6:20: error: Vulkan 1.1 is required for Wave Operation but not permitted to use
+// CHECK: note: please specify your target environment via command line option

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-count-bits.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-product.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-prefix-sum.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-read-lane-at.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave-read-lane-first.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // CHECK: ; Version: 1.3
 // CHECK: ; Version: 1.3
 
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/sm6.wave.builtin.no-dup.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T cs_6_0 -E main
+// Run: %dxc -T cs_6_0 -E main -fspv-target-env=vulkan1.1
 
 
 // Some wave ops translates into SPIR-V builtin variables.
 // Some wave ops translates into SPIR-V builtin variables.
 // Test that we are not generating duplicated builtins for multiple calls of
 // Test that we are not generating duplicated builtins for multiple calls of

+ 1 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -479,6 +479,7 @@ public:
           spirvOpts.sShift = opts.VkSShift;
           spirvOpts.sShift = opts.VkSShift;
           spirvOpts.uShift = opts.VkUShift;
           spirvOpts.uShift = opts.VkUShift;
           spirvOpts.allowedExtensions = opts.SpvExtensions;
           spirvOpts.allowedExtensions = opts.SpvExtensions;
+          spirvOpts.targetEnv = opts.SpvTargetEnv;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
           clang::EmitSPIRVAction action(spirvOpts);
           clang::EmitSPIRVAction action(spirvOpts);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);

+ 8 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1131,6 +1131,14 @@ TEST_F(FileTest, SM6QuadReadLaneAt) {
   runFileTest("sm6.quad-read-lane-at.hlsl");
   runFileTest("sm6.quad-read-lane-at.hlsl");
 }
 }
 
 
+// Test error on using wave ops on Vulkan 1.0 target environment.
+TEST_F(FileTest, WaveOpVulkan1Error) {
+  runFileTest("sm6.wave-op.target-vulkan1.error.hlsl", Expect::Failure);
+}
+TEST_F(FileTest, WaveOpNoTargetEnvError) {
+  runFileTest("sm6.wave-op.no-target-env.error.hlsl", Expect::Failure);
+}
+
 // SPIR-V specific
 // SPIR-V specific
 TEST_F(FileTest, SpirvStorageClass) { runFileTest("spirv.storage-class.hlsl"); }
 TEST_F(FileTest, SpirvStorageClass) { runFileTest("spirv.storage-class.hlsl"); }