Browse Source

Merge branch 'rtmaster' into user/texr/library-reflection

Tex Riddell 7 years ago
parent
commit
42ca602351
51 changed files with 842 additions and 418 deletions
  1. 3 1
      README.md
  2. 2 2
      appveyor.yml
  3. 31 27
      docs/SPIR-V.rst
  4. 1 1
      external/SPIRV-Headers
  5. 4 4
      include/dxc/Support/HLSLOptions.h
  6. 37 20
      lib/DxcSupport/HLSLOptions.cpp
  7. 44 1
      lib/HLSL/HLOperationLower.cpp
  8. 5 4
      tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h
  9. 1 2
      tools/clang/include/clang/SPIRV/FeatureManager.h
  10. 8 0
      tools/clang/include/clang/SPIRV/ModuleBuilder.h
  11. 9 1
      tools/clang/include/clang/SPIRV/Structure.h
  12. 58 84
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  13. 2 18
      tools/clang/lib/SPIRV/DeclResultIdMapper.h
  14. 11 17
      tools/clang/lib/SPIRV/FeatureManager.cpp
  15. 0 1
      tools/clang/lib/SPIRV/ModuleBuilder.cpp
  16. 101 35
      tools/clang/lib/SPIRV/SPIRVEmitter.cpp
  17. 9 2
      tools/clang/lib/SPIRV/Structure.cpp
  18. 52 19
      tools/clang/lib/SPIRV/TypeTranslator.cpp
  19. 4 4
      tools/clang/lib/SPIRV/TypeTranslator.h
  20. 13 0
      tools/clang/test/CodeGenHLSL/quick-test/atan.hlsl
  21. 2 1
      tools/clang/test/CodeGenHLSL/quick-test/convergent.hlsl
  22. 10 0
      tools/clang/test/CodeGenSPIRV/intrinsics.interlocked-methods.cs.hlsl
  23. 21 3
      tools/clang/test/CodeGenSPIRV/oo.struct.method.hlsl
  24. 13 0
      tools/clang/test/CodeGenSPIRV/semantic.dispatch-thread-id.int2.cs.hlsl
  25. 0 12
      tools/clang/test/CodeGenSPIRV/semantic.dispatch-thread-id.uint2.cs.hlsl
  26. 13 0
      tools/clang/test/CodeGenSPIRV/semantic.group-id.int2.cs.hlsl
  27. 0 12
      tools/clang/test/CodeGenSPIRV/semantic.group-id.uint2.cs.hlsl
  28. 13 0
      tools/clang/test/CodeGenSPIRV/semantic.group-thread-id.int2.cs.hlsl
  29. 0 12
      tools/clang/test/CodeGenSPIRV/semantic.group-thread-id.uint2.cs.hlsl
  30. 9 0
      tools/clang/test/CodeGenSPIRV/spirv.debug.opsource.hlsl
  31. 0 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.ds.hlsl
  32. 0 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.gs.hlsl
  33. 0 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.hs.hlsl
  34. 0 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.ps.hlsl
  35. 0 1
      tools/clang/test/CodeGenSPIRV/spirv.interface.vs.hlsl
  36. 53 0
      tools/clang/test/CodeGenSPIRV/spirv.stage-io.16bit.hlsl
  37. 14 1
      tools/clang/test/CodeGenSPIRV/texture.array.gather-red.hlsl
  38. 14 1
      tools/clang/test/CodeGenSPIRV/texture.gather-red.hlsl
  39. 3 3
      tools/clang/test/CodeGenSPIRV/type.struct.hlsl
  40. 53 0
      tools/clang/test/CodeGenSPIRV/vk.binding.cl.all-sets.hlsl
  41. 0 30
      tools/clang/test/CodeGenSPIRV/vk.binding.cl.error.hlsl
  42. 0 42
      tools/clang/test/CodeGenSPIRV/vk.binding.explicit.error.hlsl
  43. 0 29
      tools/clang/test/CodeGenSPIRV/vk.binding.register.error.hlsl
  44. 41 1
      tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.boolean.hlsl
  45. 56 0
      tools/clang/test/CodeGenSPIRV/vk.layout.rwstructuredbuffer.boolean.hlsl
  46. 25 0
      tools/clang/test/CodeGenSPIRV/vk.push-constant.anon-struct.hlsl
  47. 1 0
      tools/clang/tools/dxcompiler/dxcompilerobj.cpp
  48. 22 15
      tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp
  49. 1 2
      tools/clang/unittests/SPIRV/FileTestUtils.cpp
  50. 82 5
      tools/clang/unittests/SPIRV/TestMain.cpp
  51. 1 1
      utils/appveyor/appveyor_test.ps1

+ 3 - 1
README.md

@@ -1,6 +1,6 @@
 # DirectX Shader Compiler
 # DirectX Shader Compiler
 
 
-[![Build status](https://ci.appveyor.com/api/projects/status/5cwy3b8y1oi71lvl?svg=true)](https://ci.appveyor.com/project/marcelolr/directxshadercompiler)
+[![Build status](https://ci.appveyor.com/api/projects/status/oaf66n7w30xbrg38/branch/master?svg=true)](https://ci.appveyor.com/project/antiagainst/directxshadercompiler/branch/master)
 
 
 The DirectX Shader Compiler project includes a compiler and related tools used to compile High-Level Shader Language (HLSL) programs into DirectX Intermediate Language (DXIL) representation. Applications that make use of DirectX for graphics, games, and computation can use it to generate shader programs.
 The DirectX Shader Compiler project includes a compiler and related tools used to compile High-Level Shader Language (HLSL) programs into DirectX Intermediate Language (DXIL) representation. Applications that make use of DirectX for graphics, games, and computation can use it to generate shader programs.
 
 
@@ -28,6 +28,8 @@ As an example of community contribution, this project can also target the [SPIR-
 
 
 ## Building Sources
 ## Building Sources
 
 
+Note: Instead of building manually, you can download the artifacts built by Appveyor for the latest master branch at [here](https://ci.appveyor.com/project/antiagainst/directxshadercompiler/branch/master/artifacts).
+
 Before you build, you will need to have some additional software installed. This is the most straightforward path - see [Building Sources](https://github.com/Microsoft/DirectXShaderCompiler/wiki/Building-Sources) on the Wiki for more options, including Visual Studio 2015 and Ninja support.
 Before you build, you will need to have some additional software installed. This is the most straightforward path - see [Building Sources](https://github.com/Microsoft/DirectXShaderCompiler/wiki/Building-Sources) on the Wiki for more options, including Visual Studio 2015 and Ninja support.
 
 
 * [Git](http://git-scm.com/downloads).
 * [Git](http://git-scm.com/downloads).

+ 2 - 2
appveyor.yml

@@ -2,7 +2,7 @@ version: 1.0.{build}
 
 
 image: Visual Studio 2017
 image: Visual Studio 2017
 platform: x64
 platform: x64
-configuration: Debug
+configuration: Release
 
 
 clone_folder: c:\projects\DirectXShaderCompiler
 clone_folder: c:\projects\DirectXShaderCompiler
 clone_depth: 1
 clone_depth: 1
@@ -22,7 +22,7 @@ build_script:
 
 
 test_script:
 test_script:
 - ps:  utils\appveyor\appveyor_test.ps1
 - ps:  utils\appveyor\appveyor_test.ps1
-- cmd: call utils\hct\hcttest spirv_only
+- cmd: call utils\hct\hcttest -rel spirv_only
 
 
 after_test:
 after_test:
 - cmd: cd build\%CONFIGURATION%\bin
 - cmd: cd build\%CONFIGURATION%\bin

+ 31 - 27
docs/SPIR-V.rst

@@ -297,22 +297,24 @@ interface variables:
 SPIR-V version and extension
 SPIR-V version and extension
 ----------------------------
 ----------------------------
 
 
-In the **defult** mode (without ``-fspv-extension=<extension>`` command-line
-option), SPIR-V CodeGen will try its best to use the lowest SPIR-V version, and
-only require higher SPIR-V versions and extensions when they are truly needed
-for translating the input source code.
-
-For example, unless `Shader Model 6.0 wave intrinsics`_ are used, the generated
-SPIR-V will always be of version 1.0. The ``SPV_KHR_multivew`` extension will
-not be emitted unless you use ``SV_ViewID``.
-
-You can of course have fine-grained control of what extensions are permitted
-in the CodeGen using the **explicit** mode, turned on by the
-``-fspv-extension=<extension>`` command-line option. Only extensions supplied
-via ``-fspv-extension=`` will be used. If that does not suffice, errors will
-be emitted explaining what additional extensions are required to translate what
-specific feature in the source code. If you want to allow all KHR extensions,
-you can use ``-fspv-extension=KHR``.
+SPIR-V CodeGen provides two command-line options for fine-grained SPIR-V target
+environment (hence SPIR-V version) and SPIR-V extension control:
+
+- ``-fspv-target-env=``: for specifying SPIR-V target environment
+- ``-fspv-extension=``: for specifying allowed SPIR-V extensions
+
+``-fspv-target-env=`` only accepts ``vulkan1.0`` and ``vulkan1.1`` right now.
+If such an option is not given, the CodeGen defaults to ``vulkan1.0``. When
+targeting ``vulkan1.0``, trying to use features that are only available
+in Vulkan 1.1 (SPIR-V 1.3), like `Shader Model 6.0 wave intrinsics`_, will
+trigger a compiler error.
+
+If ``-fspv-extension=`` is not specified, the CodeGen will select suitable
+SPIR-V extensions to translate the source code. Otherwise, only extensions
+supplied via ``-fspv-extension=`` will be used. If that does not suffice, errors
+will be emitted explaining what additional extensions are required to translate
+what specific feature in the source code. If you want to allow all KHR
+extensions, you can use ``-fspv-extension=KHR``.
 
 
 Legalization, optimization, validation
 Legalization, optimization, validation
 --------------------------------------
 --------------------------------------
@@ -667,12 +669,12 @@ right now:
    Uniform Buffer Layout" and "Standard Storage Buffer Layout" <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-resources-layout>`_,
    Uniform Buffer Layout" and "Standard Storage Buffer Layout" <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-resources-layout>`_,
    respectively.
    respectively.
    They are the default.
    They are the default.
-2. Strict OpenGL ``std140`` for uniform buffers and strict OpenGL ``std430``
-   for storage buffers: they allow packing data on the application side that
-   can be shared with OpenGL. They can be enabled by ``-fvk-use-gl-layout``.
-3. DirectX memory layout rules for uniform buffers and storage buffers:
+2. DirectX memory layout rules for uniform buffers and storage buffers:
    they allow packing data on the application side that can be shared with
    they allow packing data on the application side that can be shared with
    DirectX. They can be enabled by ``-fvk-use-dx-layout``.
    DirectX. They can be enabled by ``-fvk-use-dx-layout``.
+3. Strict OpenGL ``std140`` for uniform buffers and strict OpenGL ``std430``
+   for storage buffers: they allow packing data on the application side that
+   can be shared with OpenGL. They can be enabled by ``-fvk-use-gl-layout``.
 
 
 In the above, "vector-relaxed OpenGL ``std140``/``std430``" rules mean OpenGL
 In the above, "vector-relaxed OpenGL ``std140``/``std430``" rules mean OpenGL
 ``std140``/``std430`` rules with the following modification for vector type
 ``std140``/``std430`` rules with the following modification for vector type
@@ -2197,7 +2199,9 @@ There are a few overloads for these functions:
 
 
 - For those overloads taking 4 offset parameters, those offset parameters will
 - For those overloads taking 4 offset parameters, those offset parameters will
   be conveyed as an additional ``ConstOffsets`` image operands to the
   be conveyed as an additional ``ConstOffsets`` image operands to the
-  instruction. So those offset parameters must all be constant values.
+  instruction if those offset parameters are all constants. Otherwise,
+  4 separate ``OpImageGather`` instructions will be emitted to get each texel
+  from each offset, using the ``Offset`` image operands.
 - For those overloads with the ``status`` parameter, ``OpImageSparseGather``
 - For those overloads with the ``status`` parameter, ``OpImageSparseGather``
   is used instead, and the resulting SPIR-V ``Residency Code`` will be
   is used instead, and the resulting SPIR-V ``Residency Code`` will be
   written to ``status``.
   written to ``status``.
@@ -2631,11 +2635,10 @@ generated. ``.RestartStrip()`` method calls will be translated into the SPIR-V
 Shader Model 6.0 Wave Intrinsics
 Shader Model 6.0 Wave Intrinsics
 ================================
 ================================
 
 
-::
 
 
-  Wave intrinsics requires SPIR-V 1.3, which is supported by Vulkan 1.1.
-  If you use wave intrinsics in your source code, the generated SPIR-V code
-  will be of version 1.3 instead of 1.0, which is supported by Vulkan 1.0.
+Note that Wave intrinsics requires SPIR-V 1.3, which is supported by Vulkan 1.1.
+If you use wave intrinsics in your source code, you will need to specify
+-fspv-target-env=vulkan1.1 via the command line to target Vulkan 1.1.
 
 
 Shader model 6.0 introduces a set of wave operations. Apart from
 Shader model 6.0 introduces a set of wave operations. Apart from
 ``WaveGetLaneCount()`` and ``WaveGetLaneIndex()``, which are translated into
 ``WaveGetLaneCount()`` and ``WaveGetLaneIndex()``, which are translated into
@@ -2683,8 +2686,9 @@ codegen for Vulkan:
   sets its Vulkan descriptor set to ``M`` and binding number to ``X + N``. If
   sets its Vulkan descriptor set to ``M`` and binding number to ``X + N``. If
   you need to shift the inferred binding numbers for more than one space,
   you need to shift the inferred binding numbers for more than one space,
   provide more than one such option. If more than one such option is provided
   provide more than one such option. If more than one such option is provided
-  for the same space, the last one takes effect. See `HLSL register and Vulkan
-  binding`_ for explanation and examples.
+  for the same space, the last one takes effect. If you need to shift the
+  inferred binding numbers for all sets, use ``all`` as ``M``.
+  See `HLSL register and Vulkan binding`_ for explanation and examples.
 - ``-fvk-t-shift N M``, similar to ``-fvk-b-shift``, but for t-type registers.
 - ``-fvk-t-shift N M``, similar to ``-fvk-b-shift``, but for t-type registers.
 - ``-fvk-s-shift N M``, similar to ``-fvk-b-shift``, but for s-type registers.
 - ``-fvk-s-shift N M``, similar to ``-fvk-b-shift``, but for s-type registers.
 - ``-fvk-u-shift N M``, similar to ``-fvk-b-shift``, but for u-type registers.
 - ``-fvk-u-shift N M``, similar to ``-fvk-b-shift``, but for u-type registers.

+ 1 - 1
external/SPIRV-Headers

@@ -1 +1 @@
-Subproject commit 12f8de9f04327336b699b1b80aa390ae7f9ddbf4
+Subproject commit 3a4dbdde9a9b2cf23736694ba70262dce27fbeaa

+ 4 - 4
include/dxc/Support/HLSLOptions.h

@@ -167,10 +167,10 @@ public:
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   llvm::StringRef VkStageIoOrder;          // OPT_fvk_stage_io_order
   llvm::StringRef VkStageIoOrder;          // OPT_fvk_stage_io_order
-  llvm::SmallVector<uint32_t, 4> VkBShift; // OPT_fvk_b_shift
-  llvm::SmallVector<uint32_t, 4> VkTShift; // OPT_fvk_t_shift
-  llvm::SmallVector<uint32_t, 4> VkSShift; // OPT_fvk_s_shift
-  llvm::SmallVector<uint32_t, 4> VkUShift; // OPT_fvk_u_shift
+  llvm::SmallVector<int32_t, 4> VkBShift;  // OPT_fvk_b_shift
+  llvm::SmallVector<int32_t, 4> VkTShift;  // OPT_fvk_t_shift
+  llvm::SmallVector<int32_t, 4> VkSShift;  // OPT_fvk_s_shift
+  llvm::SmallVector<int32_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
   llvm::StringRef SpvTargetEnv;                        // OPT_fspv_target_env
 #endif
 #endif

+ 37 - 20
lib/DxcSupport/HLSLOptions.cpp

@@ -490,26 +490,43 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
   opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
 
 
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
   // Collects the arguments for -fvk-{b|s|t|u}-shift.
-  const auto handleVkShiftArgs = [genSpirv, &Args, &errors](
-      OptSpecifier id, const char* name, llvm::SmallVectorImpl<uint32_t>* shifts) {
-    const auto values = Args.getAllArgValues(id);
-
-    if (!genSpirv && !values.empty()) {
-      errors << "-fvk-" << name << "-shift requires -spirv";
-      return false;
-    }
-
-    shifts->clear();
-    for (const auto& val : values) {
-      uint32_t number = 0;
-      if (llvm::StringRef(val).getAsInteger(10, number)) {
-        errors << "invalid -fvk-" << name << "-shift argument: " << val;
-        return false;
-      }
-      shifts->push_back(number);
-    }
-    return true;
-  };
+  const auto handleVkShiftArgs =
+      [genSpirv, &Args, &errors](OptSpecifier id, const char *name,
+                                 llvm::SmallVectorImpl<int32_t> *shifts) {
+        const auto values = Args.getAllArgValues(id);
+
+        if (!genSpirv && !values.empty()) {
+          errors << "-fvk-" << name << "-shift requires -spirv";
+          return false;
+        }
+
+        shifts->clear();
+        bool setForAll = false;
+
+        for (const auto &val : values) {
+          int32_t number = 0;
+          if (val == "all") {
+            number = -1;
+            setForAll = true;
+          } else {
+            if (llvm::StringRef(val).getAsInteger(10, number)) {
+              errors << "invalid -fvk-" << name << "-shift argument: " << val;
+              return false;
+            }
+            if (number < 0) {
+              errors << "negative -fvk-" << name << "-shift argument: " << val;
+              return false;
+            }
+          }
+          shifts->push_back(number);
+        }
+        if (setForAll && shifts->size() > 2) {
+          errors << "setting all sets via -fvk-" << name
+                 << "-shift argument should be used alone";
+          return false;
+        }
+        return true;
+      };
 
 
   if (!handleVkShiftArgs(OPT_fvk_b_shift, "b", &opts.VkBShift) ||
   if (!handleVkShiftArgs(OPT_fvk_b_shift, "b", &opts.VkBShift) ||
       !handleVkShiftArgs(OPT_fvk_t_shift, "t", &opts.VkTShift) ||
       !handleVkShiftArgs(OPT_fvk_t_shift, "t", &opts.VkTShift) ||

+ 44 - 1
lib/HLSL/HLOperationLower.cpp

@@ -1271,7 +1271,50 @@ Value *TranslateAtan2(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
 
 
   IRBuilder<> Builder(CI);
   IRBuilder<> Builder(CI);
   Value *tan = Builder.CreateFDiv(y, x);
   Value *tan = Builder.CreateFDiv(y, x);
-  return TrivialDxilUnaryOperation(OP::OpCode::Atan, tan, hlslOP, Builder);
+
+  Value *atan =
+      TrivialDxilUnaryOperation(OP::OpCode::Atan, tan, hlslOP, Builder);
+  // TODO: include M_PI from math.h.
+  const double M_PI = 3.14159265358979323846;
+  // Modify atan result based on https://en.wikipedia.org/wiki/Atan2.
+  Type *Ty = x->getType();
+  Constant *pi = ConstantFP::get(Ty->getScalarType(), M_PI);
+  Constant *halfPi = ConstantFP::get(Ty->getScalarType(), M_PI / 2);
+  Constant *negHalfPi = ConstantFP::get(Ty->getScalarType(), -M_PI / 2);
+  Constant *zero = ConstantFP::get(Ty->getScalarType(), 0);
+  if (Ty != Ty->getScalarType()) {
+    unsigned vecSize = Ty->getVectorNumElements();
+    pi = ConstantVector::getSplat(vecSize, pi);
+    halfPi = ConstantVector::getSplat(vecSize, halfPi);
+    negHalfPi = ConstantVector::getSplat(vecSize, negHalfPi);
+    zero = ConstantVector::getSplat(vecSize, zero);
+  }
+  Value *atanAddPi = Builder.CreateFAdd(atan, pi);
+  Value *atanSubPi = Builder.CreateFSub(atan, pi);
+
+  // x > 0 -> atan.
+  Value *result = atan;
+  Value *xLt0 = Builder.CreateFCmpOLT(x, zero);
+  Value *xEq0 = Builder.CreateFCmpOEQ(x, zero);
+
+  Value *yGe0 = Builder.CreateFCmpOGE(y, zero);
+  Value *yLt0 = Builder.CreateFCmpOLT(y, zero);
+  // x < 0, y >= 0 -> atan + pi.
+  Value *xLt0AndyGe0 = Builder.CreateAnd(xLt0, yGe0);
+  result = Builder.CreateSelect(xLt0AndyGe0, atanAddPi, result);
+
+  // x < 0, y < 0 -> atan - pi.
+  Value *xLt0AndYLt0 = Builder.CreateAnd(xLt0, yLt0);
+  result = Builder.CreateSelect(xLt0AndYLt0, atanSubPi, result);
+
+  // x == 0, y < 0 -> -pi/2
+  Value *xEq0AndYLt0 = Builder.CreateAnd(xEq0, yLt0);
+  result = Builder.CreateSelect(xEq0AndYLt0, negHalfPi, result);
+  // x == 0, y > 0 -> pi/2
+  Value *xEq0AndYGe0 = Builder.CreateAnd(xEq0, yGe0);
+  result = Builder.CreateSelect(xEq0AndYGe0, halfPi, result);
+
+  return result;
 }
 }
 
 
 Value *TranslateClamp(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
 Value *TranslateClamp(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,

+ 5 - 4
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -38,11 +38,12 @@ struct EmitSPIRVOptions {
   bool ignoreUnusedResources;
   bool ignoreUnusedResources;
   bool enable16BitTypes;
   bool enable16BitTypes;
   bool enableReflect;
   bool enableReflect;
+  bool enableDebugInfo;
   llvm::StringRef stageIoOrder;
   llvm::StringRef stageIoOrder;
-  llvm::SmallVector<uint32_t, 4> bShift;
-  llvm::SmallVector<uint32_t, 4> tShift;
-  llvm::SmallVector<uint32_t, 4> sShift;
-  llvm::SmallVector<uint32_t, 4> uShift;
+  llvm::SmallVector<int32_t, 4> bShift;
+  llvm::SmallVector<int32_t, 4> tShift;
+  llvm::SmallVector<int32_t, 4> sShift;
+  llvm::SmallVector<int32_t, 4> uShift;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
   llvm::StringRef targetEnv;
   llvm::StringRef targetEnv;
   spirv::LayoutRule cBufferLayoutRule;
   spirv::LayoutRule cBufferLayoutRule;

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

@@ -15,7 +15,6 @@
 
 
 #include <string>
 #include <string>
 
 
-
 #include "spirv-tools/libspirv.h"
 #include "spirv-tools/libspirv.h"
 
 
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Diagnostic.h"
@@ -31,6 +30,7 @@ namespace spirv {
 /// A list of SPIR-V extensions known to our CodeGen.
 /// A list of SPIR-V extensions known to our CodeGen.
 enum class Extension {
 enum class Extension {
   KHR = 0,
   KHR = 0,
+  KHR_16bit_storage,
   KHR_device_group,
   KHR_device_group,
   KHR_multiview,
   KHR_multiview,
   KHR_shader_draw_parameters,
   KHR_shader_draw_parameters,
@@ -38,7 +38,6 @@ enum class Extension {
   EXT_shader_stencil_export,
   EXT_shader_stencil_export,
   AMD_gpu_shader_half_float,
   AMD_gpu_shader_half_float,
   AMD_shader_explicit_vertex_parameter,
   AMD_shader_explicit_vertex_parameter,
-  GOOGLE_decorate_string,
   GOOGLE_hlsl_functionality1,
   GOOGLE_hlsl_functionality1,
   Unknown,
   Unknown,
 };
 };

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

@@ -332,6 +332,10 @@ public:
 
 
   inline void setShaderModelVersion(uint32_t major, uint32_t minor);
   inline void setShaderModelVersion(uint32_t major, uint32_t minor);
 
 
+  /// \brief Sets the source file name and the <result-id> for the OpString for
+  /// the file name.
+  inline void setSourceFileName(uint32_t id, std::string name);
+
   /// \brief Adds an execution mode to the module under construction.
   /// \brief Adds an execution mode to the module under construction.
   void addExecutionMode(uint32_t entryPointId, spv::ExecutionMode em,
   void addExecutionMode(uint32_t entryPointId, spv::ExecutionMode em,
                         llvm::ArrayRef<uint32_t> params);
                         llvm::ArrayRef<uint32_t> params);
@@ -516,6 +520,10 @@ void ModuleBuilder::setShaderModelVersion(uint32_t major, uint32_t minor) {
   theModule.setShaderModelVersion(major * 100 + minor * 10);
   theModule.setShaderModelVersion(major * 100 + minor * 10);
 }
 }
 
 
+void ModuleBuilder::setSourceFileName(uint32_t id, std::string name) {
+  theModule.setSourceFileName(id, std::move(name));
+}
+
 } // end namespace spirv
 } // end namespace spirv
 } // end namespace clang
 } // end namespace clang
 
 

+ 9 - 1
tools/clang/include/clang/SPIRV/Structure.h

@@ -307,6 +307,7 @@ public:
                             llvm::ArrayRef<uint32_t> intefaces);
                             llvm::ArrayRef<uint32_t> intefaces);
   inline void addExecutionMode(Instruction &&);
   inline void addExecutionMode(Instruction &&);
   inline void setShaderModelVersion(uint32_t);
   inline void setShaderModelVersion(uint32_t);
+  inline void setSourceFileName(uint32_t id, std::string name);
   // TODO: source code debug information
   // TODO: source code debug information
   inline void addDebugName(uint32_t targetId, llvm::StringRef name,
   inline void addDebugName(uint32_t targetId, llvm::StringRef name,
                            llvm::Optional<uint32_t> memberIndex = llvm::None);
                            llvm::Optional<uint32_t> memberIndex = llvm::None);
@@ -338,6 +339,8 @@ private:
   std::vector<EntryPoint> entryPoints;
   std::vector<EntryPoint> entryPoints;
   std::vector<Instruction> executionModes;
   std::vector<Instruction> executionModes;
   uint32_t shaderModelVersion;
   uint32_t shaderModelVersion;
+  uint32_t sourceFileNameId; // The <result-id> for the OpString for file name
+  std::string sourceFileName;
   // TODO: source code debug information
   // TODO: source code debug information
   std::set<DebugName> debugNames;
   std::set<DebugName> debugNames;
   llvm::SetVector<std::pair<uint32_t, const Decoration *>> decorations;
   llvm::SetVector<std::pair<uint32_t, const Decoration *>> decorations;
@@ -449,7 +452,7 @@ TypeIdPair::TypeIdPair(const Type &ty, uint32_t id) : type(ty), resultId(id) {}
 
 
 SPIRVModule::SPIRVModule()
 SPIRVModule::SPIRVModule()
     : addressingModel(llvm::None), memoryModel(llvm::None),
     : addressingModel(llvm::None), memoryModel(llvm::None),
-      shaderModelVersion(0) {}
+      shaderModelVersion(0), sourceFileNameId(0) {}
 
 
 void SPIRVModule::setVersion(uint32_t version) { header.version = version; }
 void SPIRVModule::setVersion(uint32_t version) { header.version = version; }
 void SPIRVModule::setBound(uint32_t newBound) { header.bound = newBound; }
 void SPIRVModule::setBound(uint32_t newBound) { header.bound = newBound; }
@@ -495,6 +498,11 @@ void SPIRVModule::setShaderModelVersion(uint32_t version) {
   shaderModelVersion = version;
   shaderModelVersion = version;
 }
 }
 
 
+void SPIRVModule::setSourceFileName(uint32_t id, std::string name) {
+  sourceFileNameId = id;
+  sourceFileName = std::move(name);
+}
+
 void SPIRVModule::addDebugName(uint32_t targetId, llvm::StringRef name,
 void SPIRVModule::addDebugName(uint32_t targetId, llvm::StringRef name,
                                llvm::Optional<uint32_t> memberIndex) {
                                llvm::Optional<uint32_t> memberIndex) {
 
 

+ 58 - 84
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -37,15 +37,6 @@ const hlsl::RegisterAssignment *getResourceBinding(const NamedDecl *decl) {
   return nullptr;
   return nullptr;
 }
 }
 
 
-/// \brief Returns the resource category for the given type.
-ResourceVar::Category getResourceCategory(QualType type) {
-  if (TypeTranslator::isTexture(type) || TypeTranslator::isRWTexture(type))
-    return ResourceVar::Category::Image;
-  if (TypeTranslator::isSampler(type))
-    return ResourceVar::Category::Sampler;
-  return ResourceVar::Category::Other;
-}
-
 /// \brief Returns true if the given declaration has a primitive type qualifier.
 /// \brief Returns true if the given declaration has a primitive type qualifier.
 /// Returns false otherwise.
 /// Returns false otherwise.
 inline bool hasGSPrimitiveTypeQualifier(const Decl *decl) {
 inline bool hasGSPrimitiveTypeQualifier(const Decl *decl) {
@@ -436,8 +427,7 @@ SpirvEvalInfo DeclResultIdMapper::createExternVar(const VarDecl *var) {
   const auto *bindingAttr = var->getAttr<VKBindingAttr>();
   const auto *bindingAttr = var->getAttr<VKBindingAttr>();
   const auto *counterBindingAttr = var->getAttr<VKCounterBindingAttr>();
   const auto *counterBindingAttr = var->getAttr<VKCounterBindingAttr>();
 
 
-  resourceVars.emplace_back(id, getResourceCategory(var->getType()), regAttr,
-                            bindingAttr, counterBindingAttr);
+  resourceVars.emplace_back(id, regAttr, bindingAttr, counterBindingAttr);
 
 
   if (const auto *inputAttachment = var->getAttr<VKInputAttachmentIndexAttr>())
   if (const auto *inputAttachment = var->getAttr<VKInputAttachmentIndexAttr>())
     theBuilder.decorateInputAttachmentIndex(id, inputAttachment->getIndex());
     theBuilder.decorateInputAttachmentIndex(id, inputAttachment->getIndex());
@@ -481,11 +471,10 @@ uint32_t DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
     llvm::StringRef varName) {
     llvm::StringRef varName) {
   // cbuffers are translated into OpTypeStruct with Block decoration.
   // cbuffers are translated into OpTypeStruct with Block decoration.
   // tbuffers are translated into OpTypeStruct with BufferBlock decoration.
   // tbuffers are translated into OpTypeStruct with BufferBlock decoration.
-  // PushConstants are translated into OpTypeStruct with Block decoration.
+  // Push constants are translated into OpTypeStruct with Block decoration.
   //
   //
-  // Both cbuffers and tbuffers have the SPIR-V Uniform storage class. cbuffers
-  // follow GLSL std140 layout rules, and tbuffers follow GLSL std430 layout
-  // rules. PushConstants follow GLSL std430 layout rules.
+  // Both cbuffers and tbuffers have the SPIR-V Uniform storage class.
+  // Push constants have the SPIR-V PushConstant storage class.
 
 
   const bool forCBuffer = usageKind == ContextUsageKind::CBuffer;
   const bool forCBuffer = usageKind == ContextUsageKind::CBuffer;
   const bool forTBuffer = usageKind == ContextUsageKind::TBuffer;
   const bool forTBuffer = usageKind == ContextUsageKind::TBuffer;
@@ -577,9 +566,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
                                              : spirvOptions.tBufferLayoutRule);
                                              : spirvOptions.tBufferLayoutRule);
     astDecls[varDecl].indexInCTBuffer = index++;
     astDecls[varDecl].indexInCTBuffer = index++;
   }
   }
-  resourceVars.emplace_back(
-      bufferVar, ResourceVar::Category::Other, getResourceBinding(decl),
-      decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
+  resourceVars.emplace_back(bufferVar, getResourceBinding(decl),
+                            decl->getAttr<VKBindingAttr>(),
+                            decl->getAttr<VKCounterBindingAttr>());
 
 
   return bufferVar;
   return bufferVar;
 }
 }
@@ -615,9 +604,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
           .setStorageClass(spv::StorageClass::Uniform)
           .setStorageClass(spv::StorageClass::Uniform)
           .setLayoutRule(context->isCBuffer() ? spirvOptions.cBufferLayoutRule
           .setLayoutRule(context->isCBuffer() ? spirvOptions.cBufferLayoutRule
                                               : spirvOptions.tBufferLayoutRule);
                                               : spirvOptions.tBufferLayoutRule);
-  resourceVars.emplace_back(
-      bufferVar, ResourceVar::Category::Other, getResourceBinding(context),
-      decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
+  resourceVars.emplace_back(bufferVar, getResourceBinding(context),
+                            decl->getAttr<VKBindingAttr>(),
+                            decl->getAttr<VKCounterBindingAttr>());
 
 
   return bufferVar;
   return bufferVar;
 }
 }
@@ -652,8 +641,7 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
       context, /*arraySize*/ 0, ContextUsageKind::Globals, "type.$Globals",
       context, /*arraySize*/ 0, ContextUsageKind::Globals, "type.$Globals",
       "$Globals");
       "$Globals");
 
 
-  resourceVars.emplace_back(globals, ResourceVar::Category::Other, nullptr,
-                            nullptr, nullptr);
+  resourceVars.emplace_back(globals, nullptr, nullptr, nullptr);
 
 
   uint32_t index = 0;
   uint32_t index = 0;
   for (const auto *decl : typeTranslator.collectDeclsInDeclContext(context))
   for (const auto *decl : typeTranslator.collectDeclsInDeclContext(context))
@@ -760,8 +748,7 @@ void DeclResultIdMapper::createCounterVar(
   if (!isAlias) {
   if (!isAlias) {
     // Non-alias counter variables should be put in to resourceVars so that
     // Non-alias counter variables should be put in to resourceVars so that
     // descriptors can be allocated for them.
     // descriptors can be allocated for them.
-    resourceVars.emplace_back(counterId, ResourceVar::Category::Other,
-                              getResourceBinding(decl),
+    resourceVars.emplace_back(counterId, getResourceBinding(decl),
                               decl->getAttr<VKBindingAttr>(),
                               decl->getAttr<VKBindingAttr>(),
                               decl->getAttr<VKCounterBindingAttr>(), true);
                               decl->getAttr<VKCounterBindingAttr>(), true);
     assert(declId);
     assert(declId);
@@ -861,39 +848,24 @@ private:
 /// set and binding number.
 /// set and binding number.
 class BindingSet {
 class BindingSet {
 public:
 public:
-  /// Tries to use the given set and binding number. Returns true if possible,
-  /// false otherwise and writes the source location of where the binding number
-  /// is used to *usedLoc.
-  bool tryToUseBinding(uint32_t binding, uint32_t set,
-                       ResourceVar::Category category, SourceLocation tryLoc,
-                       SourceLocation *usedLoc) {
-    const auto cat = static_cast<uint32_t>(category);
-    // Note that we will create the entry for binding in bindings[set] here.
-    // But that should not have bad effects since it defaults to zero.
-    if ((usedBindings[set][binding] & cat) == 0) {
-      usedBindings[set][binding] |= cat;
-      whereUsed[set][binding] = tryLoc;
-      return true;
-    }
-    *usedLoc = whereUsed[set][binding];
-    return false;
+  /// Uses the given set and binding number.
+  void useBinding(uint32_t binding, uint32_t set) {
+    usedBindings[set].insert(binding);
   }
   }
 
 
   /// Uses the next avaiable binding number in set 0.
   /// Uses the next avaiable binding number in set 0.
-  uint32_t useNextBinding(uint32_t set, ResourceVar::Category category) {
+  uint32_t useNextBinding(uint32_t set) {
     auto &binding = usedBindings[set];
     auto &binding = usedBindings[set];
     auto &next = nextBindings[set];
     auto &next = nextBindings[set];
     while (binding.count(next))
     while (binding.count(next))
       ++next;
       ++next;
-    binding[next] = static_cast<uint32_t>(category);
+    binding.insert(next);
     return next++;
     return next++;
   }
   }
 
 
 private:
 private:
-  ///< set number -> (binding number -> resource category)
-  llvm::DenseMap<uint32_t, llvm::DenseMap<uint32_t, uint32_t>> usedBindings;
-  ///< set number -> (binding number -> source location)
-  llvm::DenseMap<uint32_t, llvm::DenseMap<uint32_t, SourceLocation>> whereUsed;
+  ///< set number -> set of used binding number
+  llvm::DenseMap<uint32_t, llvm::DenseSet<uint32_t>> usedBindings;
   ///< set number -> next available binding number
   ///< set number -> next available binding number
   llvm::DenseMap<uint32_t, uint32_t> nextBindings;
   llvm::DenseMap<uint32_t, uint32_t> nextBindings;
 };
 };
@@ -1043,15 +1015,19 @@ namespace {
 /// sets.
 /// sets.
 class BindingShiftMapper {
 class BindingShiftMapper {
 public:
 public:
-  explicit BindingShiftMapper(const llvm::SmallVectorImpl<uint32_t> &shifts)
+  explicit BindingShiftMapper(const llvm::SmallVectorImpl<int32_t> &shifts)
       : masterShift(0) {
       : masterShift(0) {
     assert(shifts.size() % 2 == 0);
     assert(shifts.size() % 2 == 0);
-    for (uint32_t i = 0; i < shifts.size(); i += 2)
-      perSetShift[shifts[i + 1]] = shifts[i];
+    if (shifts.size() == 2 && shifts[1] == -1) {
+      masterShift = shifts[0];
+    } else {
+      for (uint32_t i = 0; i < shifts.size(); i += 2)
+        perSetShift[shifts[i + 1]] = shifts[i];
+    }
   }
   }
 
 
   /// Returns the shift amount for the given set.
   /// Returns the shift amount for the given set.
-  uint32_t getShiftForSet(uint32_t set) const {
+  int32_t getShiftForSet(int32_t set) const {
     const auto found = perSetShift.find(set);
     const auto found = perSetShift.find(set);
     if (found != perSetShift.end())
     if (found != perSetShift.end())
       return found->second;
       return found->second;
@@ -1060,7 +1036,7 @@ public:
 
 
 private:
 private:
   uint32_t masterShift; /// Shift amount applies to all sets.
   uint32_t masterShift; /// Shift amount applies to all sets.
-  llvm::DenseMap<uint32_t, uint32_t> perSetShift;
+  llvm::DenseMap<int32_t, int32_t> perSetShift;
 };
 };
 } // namespace
 } // namespace
 
 
@@ -1086,19 +1062,11 @@ bool DeclResultIdMapper::decorateResourceBindings() {
   BindingSet bindingSet;
   BindingSet bindingSet;
 
 
   // Decorates the given varId of the given category with set number
   // Decorates the given varId of the given category with set number
-  // setNo, binding number bindingNo. Emits warning if overlap.
-  const auto tryToDecorate = [this, &bindingSet](
-                                 const uint32_t varId, const uint32_t setNo,
-                                 const uint32_t bindingNo,
-                                 const ResourceVar::Category cat,
-                                 SourceLocation loc) {
-    SourceLocation prevUseLoc;
-    if (!bindingSet.tryToUseBinding(bindingNo, setNo, cat, loc, &prevUseLoc)) {
-      emitWarning("resource binding #%0 in descriptor set #%1 already assigned",
-                  loc)
-          << bindingNo << setNo;
-      emitNote("binding number previously assigned here", prevUseLoc);
-    }
+  // setNo, binding number bindingNo. Ignores overlaps.
+  const auto tryToDecorate = [this, &bindingSet](const uint32_t varId,
+                                                 const uint32_t setNo,
+                                                 const uint32_t bindingNo) {
+    bindingSet.useBinding(bindingNo, setNo);
     theBuilder.decorateDSetBinding(varId, setNo, bindingNo);
     theBuilder.decorateDSetBinding(varId, setNo, bindingNo);
   };
   };
 
 
@@ -1112,15 +1080,13 @@ bool DeclResultIdMapper::decorateResourceBindings() {
         if (const auto *reg = var.getRegister())
         if (const auto *reg = var.getRegister())
           set = reg->RegisterSpace;
           set = reg->RegisterSpace;
 
 
-        tryToDecorate(var.getSpirvId(), set, vkCBinding->getBinding(),
-                      var.getCategory(), vkCBinding->getLocation());
+        tryToDecorate(var.getSpirvId(), set, vkCBinding->getBinding());
       }
       }
     } else {
     } else {
       if (const auto *vkBinding = var.getBinding()) {
       if (const auto *vkBinding = var.getBinding()) {
         // Process m1
         // Process m1
         tryToDecorate(var.getSpirvId(), vkBinding->getSet(),
         tryToDecorate(var.getSpirvId(), vkBinding->getSet(),
-                      vkBinding->getBinding(), var.getCategory(),
-                      vkBinding->getLocation());
+                      vkBinding->getBinding());
       }
       }
     }
     }
   }
   }
@@ -1156,12 +1122,10 @@ bool DeclResultIdMapper::decorateResourceBindings() {
           llvm_unreachable("unknown register type found");
           llvm_unreachable("unknown register type found");
         }
         }
 
 
-        tryToDecorate(var.getSpirvId(), set, binding, var.getCategory(),
-                      reg->Loc);
+        tryToDecorate(var.getSpirvId(), set, binding);
       }
       }
 
 
   for (const auto &var : resourceVars) {
   for (const auto &var : resourceVars) {
-    const auto cat = var.getCategory();
     if (var.isCounter()) {
     if (var.isCounter()) {
       if (!var.getCounterBinding()) {
       if (!var.getCounterBinding()) {
         // Process mX * c2
         // Process mX * c2
@@ -1172,12 +1136,12 @@ bool DeclResultIdMapper::decorateResourceBindings() {
           set = reg->RegisterSpace;
           set = reg->RegisterSpace;
 
 
         theBuilder.decorateDSetBinding(var.getSpirvId(), set,
         theBuilder.decorateDSetBinding(var.getSpirvId(), set,
-                                       bindingSet.useNextBinding(set, cat));
+                                       bindingSet.useNextBinding(set));
       }
       }
     } else if (!var.getBinding() && !var.getRegister()) {
     } else if (!var.getBinding() && !var.getRegister()) {
       // Process m3
       // Process m3
       theBuilder.decorateDSetBinding(var.getSpirvId(), 0,
       theBuilder.decorateDSetBinding(var.getSpirvId(), 0,
-                                     bindingSet.useNextBinding(0, cat));
+                                     bindingSet.useNextBinding(0));
     }
     }
   }
   }
 
 
@@ -1282,11 +1246,9 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
     //   SampleMask, must be an array of integers.
     //   SampleMask, must be an array of integers.
     // * SV_InnerCoverage is an uint value, but the corresponding builtin,
     // * SV_InnerCoverage is an uint value, but the corresponding builtin,
     //   FullyCoveredEXT, must be an boolean value.
     //   FullyCoveredEXT, must be an boolean value.
-    // * SV_DispatchThreadID and SV_GroupThreadID are allowed to be uint, uint2,
-    //   or uint3, but the corresponding builtins (GlobalInvocationId and
-    //   LocalInvocationId) must be a uint3.
-    // * SV_GroupID is allowed to be uint, uint2, or uint3, but the
-    //   corresponding builtin (WorkgroupId) must be a uint3.
+    // * SV_DispatchThreadID, SV_GroupThreadID, and SV_GroupID are allowed to be
+    //   uint, uint2, or uint3, but the corresponding builtins
+    //   (GlobalInvocationId, LocalInvocationId, WorkgroupId) must be a uint3.
 
 
     if (glPerVertex.tryToAccess(sigPoint->GetKind(), semanticKind,
     if (glPerVertex.tryToAccess(sigPoint->GetKind(), semanticKind,
                                 semanticToUse->index, invocationId, value,
                                 semanticToUse->index, invocationId, value,
@@ -1294,6 +1256,7 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
       return true;
       return true;
 
 
     const uint32_t srcTypeId = typeId; // Variable type in source code
     const uint32_t srcTypeId = typeId; // Variable type in source code
+    uint32_t srcVecElemTypeId = 0;     // Variable element type if vector
 
 
     switch (semanticKind) {
     switch (semanticKind) {
     case hlsl::Semantic::Kind::DomainLocation:
     case hlsl::Semantic::Kind::DomainLocation:
@@ -1319,7 +1282,10 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
     case hlsl::Semantic::Kind::DispatchThreadID:
     case hlsl::Semantic::Kind::DispatchThreadID:
     case hlsl::Semantic::Kind::GroupThreadID:
     case hlsl::Semantic::Kind::GroupThreadID:
     case hlsl::Semantic::Kind::GroupID:
     case hlsl::Semantic::Kind::GroupID:
-      typeId = theBuilder.getVecType(theBuilder.getUint32Type(), 3);
+      // Keep the original integer signedness
+      srcVecElemTypeId = typeTranslator.translateType(
+          hlsl::IsHLSLVecType(type) ? hlsl::GetHLSLVecElementType(type) : type);
+      typeId = theBuilder.getVecType(srcVecElemTypeId, 3);
       break;
       break;
     }
     }
 
 
@@ -1356,6 +1322,13 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
     // Mark that we have used one index for this semantic
     // Mark that we have used one index for this semantic
     ++semanticToUse->index;
     ++semanticToUse->index;
 
 
+    // Require extension and capability if using 16-bit types
+    if (typeTranslator.getElementSpirvBitwidth(type) == 16) {
+      theBuilder.addExtension(Extension::KHR_16bit_storage,
+                              "16-bit stage IO variables", decl->getLocation());
+      theBuilder.requireCapability(spv::Capability::StorageInputOutput16);
+    }
+
     // TODO: the following may not be correct?
     // TODO: the following may not be correct?
     if (sigPoint->GetSignatureKind() ==
     if (sigPoint->GetSignatureKind() ==
         hlsl::DXIL::SignatureKind::PatchConstant)
         hlsl::DXIL::SignatureKind::PatchConstant)
@@ -1458,15 +1431,16 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
                 semanticKind == hlsl::Semantic::Kind::GroupID) &&
                 semanticKind == hlsl::Semantic::Kind::GroupID) &&
                (!hlsl::IsHLSLVecType(type) ||
                (!hlsl::IsHLSLVecType(type) ||
                 hlsl::GetHLSLVecSize(type) != 3)) {
                 hlsl::GetHLSLVecSize(type) != 3)) {
+        assert(srcVecElemTypeId);
         const auto vecSize =
         const auto vecSize =
             hlsl::IsHLSLVecType(type) ? hlsl::GetHLSLVecSize(type) : 1;
             hlsl::IsHLSLVecType(type) ? hlsl::GetHLSLVecSize(type) : 1;
         if (vecSize == 1)
         if (vecSize == 1)
-          *value = theBuilder.createCompositeExtract(theBuilder.getUint32Type(),
-                                                     *value, {0});
+          *value =
+              theBuilder.createCompositeExtract(srcVecElemTypeId, *value, {0});
         else if (vecSize == 2)
         else if (vecSize == 2)
           *value = theBuilder.createVectorShuffle(
           *value = theBuilder.createVectorShuffle(
-              theBuilder.getVecType(theBuilder.getUint32Type(), 2), *value,
-              *value, {0, 1});
+              theBuilder.getVecType(srcVecElemTypeId, 2), *value, *value,
+              {0, 1});
       }
       }
     } else {
     } else {
       if (noWriteBack)
       if (noWriteBack)

+ 2 - 18
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -39,7 +39,6 @@ public:
   inline StageVar(const hlsl::SigPoint *sig, llvm::StringRef semaStr,
   inline StageVar(const hlsl::SigPoint *sig, llvm::StringRef semaStr,
                   const hlsl::Semantic *sema, llvm::StringRef semaName,
                   const hlsl::Semantic *sema, llvm::StringRef semaName,
                   uint32_t semaIndex, const VKBuiltInAttr *builtin,
                   uint32_t semaIndex, const VKBuiltInAttr *builtin,
-
                   uint32_t type, uint32_t locCount)
                   uint32_t type, uint32_t locCount)
       : sigPoint(sig), semanticStr(semaStr), semantic(sema),
       : sigPoint(sig), semanticStr(semaStr), semantic(sema),
         semanticName(semaName), semanticIndex(semaIndex), builtinAttr(builtin),
         semanticName(semaName), semanticIndex(semaIndex), builtinAttr(builtin),
@@ -103,27 +102,13 @@ private:
 
 
 class ResourceVar {
 class ResourceVar {
 public:
 public:
-  /// The category of this resource.
-  ///
-  /// We only care about Vulkan image and sampler types here, since they can be
-  /// bundled together as a combined image sampler which takes the same binding
-  /// number. The compiler should allow this case.
-  ///
-  /// Numbers are assigned to make bit check easiser.
-  enum class Category : uint32_t {
-    Image = 1,
-    Sampler = 2,
-    Other = 3,
-  };
-
-  ResourceVar(uint32_t id, Category cat, const hlsl::RegisterAssignment *r,
+  ResourceVar(uint32_t id, const hlsl::RegisterAssignment *r,
               const VKBindingAttr *b, const VKCounterBindingAttr *cb,
               const VKBindingAttr *b, const VKCounterBindingAttr *cb,
               bool counter = false)
               bool counter = false)
-      : varId(id), category(cat), reg(r), binding(b), counterBinding(cb),
+      : varId(id), reg(r), binding(b), counterBinding(cb),
         isCounterVar(counter) {}
         isCounterVar(counter) {}
 
 
   uint32_t getSpirvId() const { return varId; }
   uint32_t getSpirvId() const { return varId; }
-  Category getCategory() const { return category; }
   const hlsl::RegisterAssignment *getRegister() const { return reg; }
   const hlsl::RegisterAssignment *getRegister() const { return reg; }
   const VKBindingAttr *getBinding() const { return binding; }
   const VKBindingAttr *getBinding() const { return binding; }
   bool isCounter() const { return isCounterVar; }
   bool isCounter() const { return isCounterVar; }
@@ -131,7 +116,6 @@ public:
 
 
 private:
 private:
   uint32_t varId;                             ///< <result-id>
   uint32_t varId;                             ///< <result-id>
-  Category category;                          ///< Resource category
   const hlsl::RegisterAssignment *reg;        ///< HLSL register assignment
   const hlsl::RegisterAssignment *reg;        ///< HLSL register assignment
   const VKBindingAttr *binding;               ///< Vulkan binding assignment
   const VKBindingAttr *binding;               ///< Vulkan binding assignment
   const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding
   const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding

+ 11 - 17
tools/clang/lib/SPIRV/FeatureManager.cpp

@@ -61,9 +61,6 @@ bool FeatureManager::allowExtension(llvm::StringRef name) {
   }
   }
 
 
   allowedExtensions.set(static_cast<unsigned>(symbol));
   allowedExtensions.set(static_cast<unsigned>(symbol));
-  if (symbol == Extension::GOOGLE_hlsl_functionality1)
-    allowedExtensions.set(
-        static_cast<unsigned>(Extension::GOOGLE_decorate_string));
 
 
   return true;
   return true;
 }
 }
@@ -87,7 +84,8 @@ bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
   if (targetEnv == SPV_ENV_VULKAN_1_0 && requestedEnv == SPV_ENV_VULKAN_1_1) {
   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)
     emitError("Vulkan 1.1 is required for %0 but not permitted to use", srcLoc)
         << target;
         << target;
-    emitNote("please specify your target environment via command line option -fspv-target-env=",
+    emitNote("please specify your target environment via command line option "
+             "-fspv-target-env=",
              {});
              {});
     return false;
     return false;
   }
   }
@@ -97,6 +95,7 @@ bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
 Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
 Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
   return llvm::StringSwitch<Extension>(name)
   return llvm::StringSwitch<Extension>(name)
       .Case("KHR", Extension::KHR)
       .Case("KHR", Extension::KHR)
+      .Case("SPV_KHR_16bit_storage", Extension::KHR_16bit_storage)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
       .Case("SPV_KHR_device_group", Extension::KHR_device_group)
       .Case("SPV_KHR_multiview", Extension::KHR_multiview)
       .Case("SPV_KHR_multiview", Extension::KHR_multiview)
       .Case("SPV_KHR_shader_draw_parameters",
       .Case("SPV_KHR_shader_draw_parameters",
@@ -109,7 +108,6 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
             Extension::AMD_gpu_shader_half_float)
             Extension::AMD_gpu_shader_half_float)
       .Case("SPV_AMD_shader_explicit_vertex_parameter",
       .Case("SPV_AMD_shader_explicit_vertex_parameter",
             Extension::AMD_shader_explicit_vertex_parameter)
             Extension::AMD_shader_explicit_vertex_parameter)
-      .Case("SPV_GOOGLE_decorate_string", Extension::GOOGLE_decorate_string)
       .Case("SPV_GOOGLE_hlsl_functionality1",
       .Case("SPV_GOOGLE_hlsl_functionality1",
             Extension::GOOGLE_hlsl_functionality1)
             Extension::GOOGLE_hlsl_functionality1)
       .Default(Extension::Unknown);
       .Default(Extension::Unknown);
@@ -119,6 +117,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
   switch (symbol) {
   switch (symbol) {
   case Extension::KHR:
   case Extension::KHR:
     return "KHR";
     return "KHR";
+  case Extension::KHR_16bit_storage:
+    return "SPV_KHR_16bit_storage";
   case Extension::KHR_device_group:
   case Extension::KHR_device_group:
     return "SPV_KHR_device_group";
     return "SPV_KHR_device_group";
   case Extension::KHR_multiview:
   case Extension::KHR_multiview:
@@ -133,8 +133,6 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
     return "SPV_AMD_gpu_shader_half_float";
     return "SPV_AMD_gpu_shader_half_float";
   case Extension::AMD_shader_explicit_vertex_parameter:
   case Extension::AMD_shader_explicit_vertex_parameter:
     return "SPV_AMD_shader_explicit_vertex_parameter";
     return "SPV_AMD_shader_explicit_vertex_parameter";
-  case Extension::GOOGLE_decorate_string:
-    return "SPV_GOOGLE_decorate_string";
   case Extension::GOOGLE_hlsl_functionality1:
   case Extension::GOOGLE_hlsl_functionality1:
     return "SPV_GOOGLE_hlsl_functionality1";
     return "SPV_GOOGLE_hlsl_functionality1";
   default:
   default:
@@ -170,19 +168,15 @@ bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
   bool required = true;
   bool required = true;
   if (targetEnv == SPV_ENV_VULKAN_1_1) {
   if (targetEnv == SPV_ENV_VULKAN_1_1) {
     // The following extensions are incorporated into Vulkan 1.1, and are
     // 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
+    // therefore not required to be emitted for that target environment.
+    // TODO: Also add the following extensions  if we start to support them.
+    // * SPV_KHR_storage_buffer_storage_class
+    // * SPV_KHR_variable_pointers
     switch (ext) {
     switch (ext) {
-    case Extension::KHR_shader_draw_parameters:
+    case Extension::KHR_16bit_storage:
     case Extension::KHR_device_group:
     case Extension::KHR_device_group:
     case Extension::KHR_multiview:
     case Extension::KHR_multiview:
+    case Extension::KHR_shader_draw_parameters:
       required = false;
       required = false;
     }
     }
   }
   }

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

@@ -845,7 +845,6 @@ void ModuleBuilder::decorateHlslSemantic(uint32_t targetId,
                                          llvm::StringRef semantic,
                                          llvm::StringRef semantic,
                                          llvm::Optional<uint32_t> memberIdx) {
                                          llvm::Optional<uint32_t> memberIdx) {
   if (allowReflect) {
   if (allowReflect) {
-    addExtension(Extension::GOOGLE_decorate_string, "SPIR-V reflection", {});
     addExtension(Extension::GOOGLE_hlsl_functionality1, "SPIR-V reflection",
     addExtension(Extension::GOOGLE_hlsl_functionality1, "SPIR-V reflection",
                  {});
                  {});
     theModule.addDecoration(
     theModule.addDecoration(

+ 101 - 35
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -510,7 +510,7 @@ spv::Capability getCapabilityForGroupNonUniform(spv::Op opcode) {
   return spv::Capability::Max;
   return spv::Capability::Max;
 }
 }
 
 
-std::string getNamespacePrefix(const Decl* decl) {
+std::string getNamespacePrefix(const Decl *decl) {
   std::string nsPrefix = "";
   std::string nsPrefix = "";
   const DeclContext *dc = decl->getDeclContext();
   const DeclContext *dc = decl->getDeclContext();
   while (dc && !dc->isTranslationUnit()) {
   while (dc && !dc->isTranslationUnit()) {
@@ -561,6 +561,16 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
               {});
               {});
 
 
   options.Initialize();
   options.Initialize();
+
+  // Set shader module version
+  theBuilder.setShaderModelVersion(shaderModel.GetMajor(),
+                                   shaderModel.GetMinor());
+
+  // Set debug info
+  const auto &inputFiles = ci.getFrontendOpts().Inputs;
+  if (options.enableDebugInfo && !inputFiles.empty())
+    theBuilder.setSourceFileName(theContext.takeNextId(),
+                                 inputFiles.front().getFile().str());
 }
 }
 
 
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -568,9 +578,6 @@ void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
   if (context.getDiagnostics().hasErrorOccurred())
   if (context.getDiagnostics().hasErrorOccurred())
     return;
     return;
 
 
-  theBuilder.setShaderModelVersion(shaderModel.GetMajor(),
-                                   shaderModel.GetMinor());
-
   TranslationUnitDecl *tu = context.getTranslationUnitDecl();
   TranslationUnitDecl *tu = context.getTranslationUnitDecl();
 
 
   // The entry function is the seed of the queue.
   // The entry function is the seed of the queue.
@@ -1950,7 +1957,7 @@ SpirvEvalInfo SPIRVEmitter::processCall(const CallExpr *callExpr) {
   bool isNonStaticMemberCall = false;
   bool isNonStaticMemberCall = false;
   QualType objectType = {};         // Type of the object (if exists)
   QualType objectType = {};         // Type of the object (if exists)
   SpirvEvalInfo objectEvalInfo = 0; // EvalInfo for the object (if exists)
   SpirvEvalInfo objectEvalInfo = 0; // EvalInfo for the object (if exists)
-  bool objectNeedsTempVar = false;  // Temporary variable for lvalue object
+  bool needsTempVar = false;        // Whether we need temporary variable.
 
 
   llvm::SmallVector<uint32_t, 4> params;    // Temporary variables
   llvm::SmallVector<uint32_t, 4> params;    // Temporary variables
   llvm::SmallVector<SpirvEvalInfo, 4> args; // Evaluated arguments
   llvm::SmallVector<SpirvEvalInfo, 4> args; // Evaluated arguments
@@ -1975,17 +1982,11 @@ SpirvEvalInfo SPIRVEmitter::processCall(const CallExpr *callExpr) {
       // If not already a variable, we need to create a temporary variable and
       // If not already a variable, we need to create a temporary variable and
       // pass the object pointer to the function. Example:
       // pass the object pointer to the function. Example:
       // getObject().objectMethod();
       // getObject().objectMethod();
-      bool needsTempVar = objectEvalInfo.isRValue();
-
-      // Try to see if we are calling methods on a global variable, which is put
-      // in the Private storage class. We also need to create temporary variable
-      // for it since the function signature expects all arguments in the
-      // Function storage class.
-      if (!needsTempVar)
-        if (const auto *declRefExpr = dyn_cast<DeclRefExpr>(object))
-          if (const auto *refDecl = declRefExpr->getFoundDecl())
-            if (const auto *varDecl = dyn_cast<VarDecl>(refDecl))
-              needsTempVar = objectNeedsTempVar = varDecl->hasGlobalStorage();
+      // Also, any parameter passed to the member function must be of Function
+      // storage class.
+      needsTempVar =
+          objectEvalInfo.isRValue() ||
+          objectEvalInfo.getStorageClass() != spv::StorageClass::Function;
 
 
       if (needsTempVar) {
       if (needsTempVar) {
         objectId =
         objectId =
@@ -2041,10 +2042,10 @@ SpirvEvalInfo SPIRVEmitter::processCall(const CallExpr *callExpr) {
   const uint32_t retVal =
   const uint32_t retVal =
       theBuilder.createFunctionCall(retType, funcId, params);
       theBuilder.createFunctionCall(retType, funcId, params);
 
 
-  // If we created a temporary variable for the object this method is invoked
-  // upon, we need to copy the contents in the temporary variable back to the
-  // original object's variable in case there are side effects.
-  if (objectNeedsTempVar) {
+  // If we created a temporary variable for the lvalue object this method is
+  // invoked upon, we need to copy the contents in the temporary variable back
+  // to the original object's variable in case there are side effects.
+  if (needsTempVar && !objectEvalInfo.isRValue()) {
     const uint32_t typeId = typeTranslator.translateType(objectType);
     const uint32_t typeId = typeTranslator.translateType(objectType);
     const uint32_t value = theBuilder.createLoad(typeId, params.front());
     const uint32_t value = theBuilder.createLoad(typeId, params.front());
     storeValue(objectEvalInfo, value, objectType);
     storeValue(objectEvalInfo, value, objectType);
@@ -2938,6 +2939,7 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
   const uint32_t compareVal = isCmp ? doExpr(expr->getArg(2)) : 0;
   const uint32_t compareVal = isCmp ? doExpr(expr->getArg(2)) : 0;
 
 
   // Handle offsets (if any).
   // Handle offsets (if any).
+  bool needsEmulation = false;
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
   if (numOffsetArgs == 1) {
   if (numOffsetArgs == 1) {
     // The offset arg is not optional.
     // The offset arg is not optional.
@@ -2948,21 +2950,40 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
     const auto offset2 = tryToEvaluateAsConst(expr->getArg(4 + isCmp));
     const auto offset2 = tryToEvaluateAsConst(expr->getArg(4 + isCmp));
     const auto offset3 = tryToEvaluateAsConst(expr->getArg(5 + isCmp));
     const auto offset3 = tryToEvaluateAsConst(expr->getArg(5 + isCmp));
 
 
-    // Make sure we can generate the ConstOffsets image operands in SPIR-V.
-    if (!offset0 || !offset1 || !offset2 || !offset3) {
-      emitError("all offset parameters to '%0' method call must be constants",
-                expr->getExprLoc())
-          << callee->getName() << expr->getSourceRange();
-      return 0;
+    // If any of the offsets is not constant, we then need to emulate the call
+    // using 4 OpImageGather instructions. Otherwise, we can leverage the
+    // ConstOffsets image operand.
+    if (offset0 && offset1 && offset2 && offset3) {
+      const uint32_t v2i32 =
+          theBuilder.getVecType(theBuilder.getInt32Type(), 2);
+      const uint32_t offsetType =
+          theBuilder.getArrayType(v2i32, theBuilder.getConstantUint32(4));
+      constOffsets = theBuilder.getConstantComposite(
+          offsetType, {offset0, offset1, offset2, offset3});
+    } else {
+      needsEmulation = true;
     }
     }
-    const uint32_t v2i32 = theBuilder.getVecType(theBuilder.getInt32Type(), 2);
-    const uint32_t offsetType =
-        theBuilder.getArrayType(v2i32, theBuilder.getConstantUint32(4));
-    constOffsets = theBuilder.getConstantComposite(
-        offsetType, {offset0, offset1, offset2, offset3});
   }
   }
 
 
   const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
   const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
+
+  if (needsEmulation) {
+    const auto elemType = typeTranslator.translateType(
+        hlsl::GetHLSLVecElementType(callee->getReturnType()));
+
+    uint32_t texels[4];
+    for (uint32_t i = 0; i < 4; ++i) {
+      varOffset = doExpr(expr->getArg(2 + isCmp + i));
+      const uint32_t gatherRet = theBuilder.createImageGather(
+          retTypeId, imageTypeId, image, sampler, coordinate,
+          theBuilder.getConstantInt32(component), compareVal, /*constOffset*/ 0,
+          varOffset, /*constOffsets*/ 0, /*sampleNumber*/ 0, status);
+      texels[i] = theBuilder.createCompositeExtract(elemType, gatherRet, {i});
+    }
+    return theBuilder.createCompositeConstruct(
+        retTypeId, {texels[0], texels[1], texels[2], texels[3]});
+  }
+
   return theBuilder.createImageGather(
   return theBuilder.createImageGather(
       retTypeId, imageTypeId, image, sampler, coordinate,
       retTypeId, imageTypeId, image, sampler, coordinate,
       theBuilder.getConstantInt32(component), compareVal, constOffset,
       theBuilder.getConstantInt32(component), compareVal, constOffset,
@@ -4824,6 +4845,45 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
 uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
 uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
                                         const QualType valType,
                                         const QualType valType,
                                         LayoutRule dstLR) {
                                         LayoutRule dstLR) {
+  // Lambda for casting scalar or vector of bool<-->uint in cases where one side
+  // of the reconstruction (lhs or rhs) has a layout rule.
+  const auto handleBooleanLayout = [this, &srcVal, dstLR](uint32_t val,
+                                                          QualType valType) {
+    // We only need to cast if we have a scalar or vector of booleans.
+    if (!isBoolOrVecOfBoolType(valType))
+      return val;
+
+    LayoutRule srcLR = srcVal.getLayoutRule();
+    // Source value has a layout rule, and has therefore been represented
+    // as a uint. Cast it to boolean before using.
+    bool shouldCastToBool =
+        srcLR != LayoutRule::Void && dstLR == LayoutRule::Void;
+    // Destination has a layout rule, and should therefore be represented
+    // as a uint. Cast to uint before using.
+    bool shouldCastToUint =
+        srcLR == LayoutRule::Void && dstLR != LayoutRule::Void;
+    // No boolean layout issues to take care of.
+    if (!shouldCastToBool && !shouldCastToUint)
+      return val;
+
+    uint32_t vecSize = 1;
+    TypeTranslator::isVectorType(valType, nullptr, &vecSize);
+    QualType boolType =
+        vecSize == 1 ? astContext.BoolTy
+                     : astContext.getExtVectorType(astContext.BoolTy, vecSize);
+    QualType uintType =
+        vecSize == 1
+            ? astContext.UnsignedIntTy
+            : astContext.getExtVectorType(astContext.UnsignedIntTy, vecSize);
+
+    if (shouldCastToBool)
+      return castToBool(val, uintType, boolType);
+    if (shouldCastToUint)
+      return castToInt(val, boolType, uintType, {});
+
+    return val;
+  };
+
   // Lambda for cases where we want to reconstruct an array
   // Lambda for cases where we want to reconstruct an array
   const auto reconstructArray = [this, &srcVal, valType,
   const auto reconstructArray = [this, &srcVal, valType,
                                  dstLR](uint32_t arraySize,
                                  dstLR](uint32_t arraySize,
@@ -4834,7 +4894,6 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
           typeTranslator.translateType(arrayElemType, srcVal.getLayoutRule());
           typeTranslator.translateType(arrayElemType, srcVal.getLayoutRule());
       const auto subSrcVal =
       const auto subSrcVal =
           theBuilder.createCompositeExtract(subSrcValType, srcVal, {i});
           theBuilder.createCompositeExtract(subSrcValType, srcVal, {i});
-
       elements.push_back(reconstructValue(srcVal.substResultId(subSrcVal),
       elements.push_back(reconstructValue(srcVal.substResultId(subSrcVal),
                                           arrayElemType, dstLR));
                                           arrayElemType, dstLR));
     }
     }
@@ -4868,7 +4927,7 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
   // Note: This check should happen before the RecordType check since
   // Note: This check should happen before the RecordType check since
   // vector/matrix/resource types are represented as RecordType in the AST.
   // vector/matrix/resource types are represented as RecordType in the AST.
   if (hlsl::IsHLSLVecMatType(valType) || hlsl::IsHLSLResourceType(valType))
   if (hlsl::IsHLSLVecMatType(valType) || hlsl::IsHLSLResourceType(valType))
-    return srcVal;
+    return handleBooleanLayout(srcVal, valType);
 
 
   // Structs
   // Structs
   if (const auto *recordType = valType->getAs<RecordType>()) {
   if (const auto *recordType = valType->getAs<RecordType>()) {
@@ -4888,7 +4947,7 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
     return theBuilder.createCompositeConstruct(dstValType, elements);
     return theBuilder.createCompositeConstruct(dstValType, elements);
   }
   }
 
 
-  return srcVal;
+  return handleBooleanLayout(srcVal, valType);
 }
 }
 
 
 SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
 SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
@@ -6509,7 +6568,14 @@ SPIRVEmitter::processIntrinsicInterlockedMethod(const CallExpr *expr,
     if (isBufferTextureIndexing(callExpr, &base, &index)) {
     if (isBufferTextureIndexing(callExpr, &base, &index)) {
       const auto ptrType =
       const auto ptrType =
           theBuilder.getPointerType(baseTypeId, spv::StorageClass::Image);
           theBuilder.getPointerType(baseTypeId, spv::StorageClass::Image);
-      const auto baseId = doExpr(base);
+      auto baseId = doExpr(base);
+      if (baseId.isRValue()) {
+        // OpImageTexelPointer's Image argument must have a type of
+        // OpTypePointer with Type OpTypeImage. Need to create a temporary
+        // variable if the baseId is an rvalue.
+        baseId = createTemporaryVar(
+            base->getType(), TypeTranslator::getName(base->getType()), baseId);
+      }
       const auto coordId = doExpr(index);
       const auto coordId = doExpr(index);
       ptr = theBuilder.createImageTexelPointer(ptrType, baseId, coordId, zero);
       ptr = theBuilder.createImageTexelPointer(ptrType, baseId, coordId, zero);
     }
     }

+ 9 - 2
tools/clang/lib/SPIRV/Structure.cpp

@@ -282,11 +282,18 @@ void SPIRVModule::take(InstBuilder *builder) {
     consumer(inst.take());
     consumer(inst.take());
   }
   }
 
 
-  if (shaderModelVersion != 0)
+  if (shaderModelVersion != 0) {
+    llvm::Optional<uint32_t> fileName = llvm::None;
+    if (!sourceFileName.empty() && sourceFileNameId) {
+      builder->opString(sourceFileNameId, sourceFileName).x();
+      fileName = sourceFileNameId;
+    }
+
     builder
     builder
-        ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, llvm::None,
+        ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, fileName,
                    llvm::None)
                    llvm::None)
         .x();
         .x();
+  }
 
 
   // BasicBlock debug names should be emitted only for blocks that are
   // BasicBlock debug names should be emitted only for blocks that are
   // reachable.
   // reachable.

+ 52 - 19
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -395,12 +395,34 @@ uint32_t TypeTranslator::getElementSpirvBitwidth(QualType type) {
       return getElementSpirvBitwidth(elemType);
       return getElementSpirvBitwidth(elemType);
   }
   }
 
 
+  // Matrix types
+  if (hlsl::IsHLSLMatType(type))
+    return getElementSpirvBitwidth(hlsl::GetHLSLMatElementType(type));
+
+  // Array types
+  if (const auto *arrayType = type->getAsArrayTypeUnsafe()) {
+    return getElementSpirvBitwidth(arrayType->getElementType());
+  }
+
+  // Typedefs
+  if (const auto *typedefType = type->getAs<TypedefType>())
+    return getLocationCount(typedefType->desugar());
+
+  // Reference types
+  if (const auto *refType = type->getAs<ReferenceType>())
+    return getLocationCount(refType->getPointeeType());
+
+  // Pointer types
+  if (const auto *ptrType = type->getAs<PointerType>())
+    return getLocationCount(ptrType->getPointeeType());
+
   // Scalar types
   // Scalar types
   QualType ty = {};
   QualType ty = {};
   const bool isScalar = isScalarType(type, &ty);
   const bool isScalar = isScalarType(type, &ty);
   assert(isScalar);
   assert(isScalar);
   if (const auto *builtinType = ty->getAs<BuiltinType>()) {
   if (const auto *builtinType = ty->getAs<BuiltinType>()) {
     switch (builtinType->getKind()) {
     switch (builtinType->getKind()) {
+    case BuiltinType::Bool:
     case BuiltinType::Int:
     case BuiltinType::Int:
     case BuiltinType::UInt:
     case BuiltinType::UInt:
     case BuiltinType::Float:
     case BuiltinType::Float:
@@ -1133,41 +1155,52 @@ TypeTranslator::getCapabilityForStorageImageReadWrite(QualType type) {
 
 
 bool TypeTranslator::shouldSkipInStructLayout(const Decl *decl) {
 bool TypeTranslator::shouldSkipInStructLayout(const Decl *decl) {
   // Ignore implicit generated struct declarations/constructors/destructors
   // Ignore implicit generated struct declarations/constructors/destructors
+  if (decl->isImplicit())
+    return true;
   // Ignore embedded type decls
   // Ignore embedded type decls
+  if (isa<TypeDecl>(decl))
+    return true;
   // Ignore embeded function decls
   // Ignore embeded function decls
+  if (isa<FunctionDecl>(decl))
+    return true;
   // Ignore empty decls
   // Ignore empty decls
-  if (decl->isImplicit() || isa<TypeDecl>(decl) || isa<FunctionDecl>(decl) ||
-      isa<EmptyDecl>(decl))
+  if (isa<EmptyDecl>(decl))
     return true;
     return true;
 
 
-  // For $Globals (whose "struct" is the TranslationUnit)
-  // Ignore resources in the TranslationUnit "struct"
-
   // For the $Globals cbuffer, we only care about externally-visiable
   // For the $Globals cbuffer, we only care about externally-visiable
   // non-resource-type variables. The rest should be filtered out.
   // non-resource-type variables. The rest should be filtered out.
 
 
+  const auto *declContext = decl->getDeclContext();
+
   // Special check for ConstantBuffer/TextureBuffer, whose DeclContext is a
   // Special check for ConstantBuffer/TextureBuffer, whose DeclContext is a
   // HLSLBufferDecl. So that we need to check the HLSLBufferDecl's parent decl
   // HLSLBufferDecl. So that we need to check the HLSLBufferDecl's parent decl
   // to check whether this is a ConstantBuffer/TextureBuffer defined in the
   // to check whether this is a ConstantBuffer/TextureBuffer defined in the
   // global namespace.
   // global namespace.
+  // Note that we should not be seeing ConstantBuffer/TextureBuffer for normal
+  // cbuffer/tbuffer or push constant blocks. So this case should only happen
+  // for $Globals cbuffer.
   if (isConstantTextureBuffer(decl) &&
   if (isConstantTextureBuffer(decl) &&
-      decl->getDeclContext()->getLexicalParent()->isTranslationUnit())
+      declContext->getLexicalParent()->isTranslationUnit())
     return true;
     return true;
 
 
-  // External visibility
-  if (const auto *declDecl = dyn_cast<DeclaratorDecl>(decl))
-    if (!declDecl->hasExternalFormalLinkage())
-      return true;
-
-  // cbuffer/tbuffer
-  if (isa<HLSLBufferDecl>(decl))
-    return true;
+  // $Globals' "struct" is the TranslationUnit, so we should ignore resources
+  // in the TranslationUnit "struct" and its child namespaces.
+  if (declContext->isTranslationUnit() || declContext->isNamespace()) {
+    // External visibility
+    if (const auto *declDecl = dyn_cast<DeclaratorDecl>(decl))
+      if (!declDecl->hasExternalFormalLinkage())
+        return true;
 
 
-  // Other resource types
-  if (const auto *valueDecl = dyn_cast<ValueDecl>(decl))
-    if (isResourceType(valueDecl))
+    // cbuffer/tbuffer
+    if (isa<HLSLBufferDecl>(decl))
       return true;
       return true;
 
 
+    // Other resource types
+    if (const auto *valueDecl = dyn_cast<ValueDecl>(decl))
+      if (isResourceType(valueDecl))
+        return true;
+  }
+
   return false;
   return false;
 }
 }
 
 
@@ -1281,10 +1314,10 @@ void TypeTranslator::collectDeclsInField(
     return;
     return;
   }
   }
 
 
-  (*decls).push_back(field);
+  decls->push_back(field);
 }
 }
 
 
-const llvm::SmallVector<const Decl *, 4>
+llvm::SmallVector<const Decl *, 4>
 TypeTranslator::collectDeclsInDeclContext(const DeclContext *declContext) {
 TypeTranslator::collectDeclsInDeclContext(const DeclContext *declContext) {
   llvm::SmallVector<const Decl *, 4> decls;
   llvm::SmallVector<const Decl *, 4> decls;
   for (const auto *field : declContext->decls()) {
   for (const auto *field : declContext->decls()) {

+ 4 - 4
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -140,9 +140,9 @@ public:
   uint32_t getTypeWithCustomBitwidth(QualType type, uint32_t bitwidth);
   uint32_t getTypeWithCustomBitwidth(QualType type, uint32_t bitwidth);
 
 
   /// \brief Returns the realized bitwidth of the given type when represented in
   /// \brief Returns the realized bitwidth of the given type when represented in
-  /// SPIR-V. Panics if the given type is not a scalar or vector of float or
-  /// integer. In case of vectors, it returns the realized SPIR-V bitwidth of
-  /// the vector elements.
+  /// SPIR-V. Panics if the given type is not a scalar, a vector/matrix of float
+  /// or integer, or an array of them. In case of vectors, it returns the
+  /// realized SPIR-V bitwidth of the vector elements.
   uint32_t getElementSpirvBitwidth(QualType type);
   uint32_t getElementSpirvBitwidth(QualType type);
 
 
   /// \brief Returns true if the given type will be translated into a SPIR-V
   /// \brief Returns true if the given type will be translated into a SPIR-V
@@ -274,7 +274,7 @@ public:
   /// DeclContext. If it sees a NamespaceDecl, it recursively dives in and
   /// DeclContext. If it sees a NamespaceDecl, it recursively dives in and
   /// collects decls in the correct order.
   /// collects decls in the correct order.
   /// Utilizes collectDeclsInNamespace and collectDeclsInField private methods.
   /// Utilizes collectDeclsInNamespace and collectDeclsInField private methods.
-  const llvm::SmallVector<const Decl *, 4>
+  llvm::SmallVector<const Decl *, 4>
   collectDeclsInDeclContext(const DeclContext *declContext);
   collectDeclsInDeclContext(const DeclContext *declContext);
 
 
 private:
 private:

+ 13 - 0
tools/clang/test/CodeGenHLSL/quick-test/atan.hlsl

@@ -0,0 +1,13 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+
+// Make sure there're select for atan2.
+// CHECK: Atan
+// CHECK: select
+// CHECK: select
+// CHECK: select
+// CHECK: select
+
+float main(float2 a : A) : SV_Target {
+  return atan2(a.y, a.x);
+}

+ 2 - 1
tools/clang/test/CodeGenHLSL/quick-test/convergent.hlsl

@@ -3,7 +3,8 @@
 // Make sure add is not sink into if.
 // Make sure add is not sink into if.
 // CHECK: fadd
 // CHECK: fadd
 // CHECK: fadd
 // CHECK: fadd
-// CHECK: if.then
+// CHECK: fcmp
+// CHECK-NEXT: br
 
 
 Texture2D<float4> tex;
 Texture2D<float4> tex;
 SamplerState s;
 SamplerState s;

+ 10 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.interlocked-methods.cs.hlsl

@@ -3,6 +3,11 @@
 groupshared int dest_i;
 groupshared int dest_i;
 groupshared uint dest_u;
 groupshared uint dest_u;
 
 
+RWBuffer<uint> buff;
+RWBuffer<uint> getDest() {
+  return buff;
+}
+
 void main()
 void main()
 {
 {
   uint original_u_val;
   uint original_u_val;
@@ -21,6 +26,11 @@ void main()
 // CHECK-NEXT:                   OpStore %original_i_val [[iadd27]]
 // CHECK-NEXT:                   OpStore %original_i_val [[iadd27]]
   InterlockedAdd(dest_i, val1, original_i_val);
   InterlockedAdd(dest_i, val1, original_i_val);
 
 
+// CHECK:      [[buff:%\d+]] = OpFunctionCall %type_buffer_image %getDest
+// CHECK-NEXT: OpStore %temp_var_RWBuffer [[buff]]
+// CHECK-NEXT: OpImageTexelPointer %_ptr_Image_uint %temp_var_RWBuffer %uint_0 %uint_0
+  InterlockedAdd(getDest()[0], val1, original_i_val);
+
 // CHECK:      [[and28:%\d+]] = OpAtomicAnd %uint %dest_u %uint_1 %uint_0 %uint_10
 // CHECK:      [[and28:%\d+]] = OpAtomicAnd %uint %dest_u %uint_1 %uint_0 %uint_10
 // CHECK-NEXT:                  OpStore %original_u_val [[and28]]
 // CHECK-NEXT:                  OpStore %original_u_val [[and28]]
   InterlockedAnd(dest_u, 10,  original_u_val);
   InterlockedAnd(dest_u, 10,  original_u_val);

+ 21 - 3
tools/clang/test/CodeGenSPIRV/oo.struct.method.hlsl

@@ -59,6 +59,12 @@ T foo() {
   return t;
   return t;
 }
 }
 
 
+struct R {
+  int a;
+  void incr() { ++a; }
+};
+RWStructuredBuffer<R> rwsb;
+
 // CHECK:     [[ft_f32:%\d+]] = OpTypeFunction %float
 // CHECK:     [[ft_f32:%\d+]] = OpTypeFunction %float
 // CHECK:       [[ft_S:%\d+]] = OpTypeFunction %float %_ptr_Function_S
 // CHECK:       [[ft_S:%\d+]] = OpTypeFunction %float %_ptr_Function_S
 // CHECK:   [[ft_S_f32:%\d+]] = OpTypeFunction %float %_ptr_Function_S %_ptr_Function_float
 // CHECK:   [[ft_S_f32:%\d+]] = OpTypeFunction %float %_ptr_Function_S %_ptr_Function_float
@@ -98,6 +104,18 @@ float main() : A {
 // CHECK-NEXT:        {{%\d+}} = OpFunctionCall %float %S_fn_ref %temp_var_S
 // CHECK-NEXT:        {{%\d+}} = OpFunctionCall %float %S_fn_ref %temp_var_S
   float f2 = foo().get_S().fn_ref();
   float f2 = foo().get_S().fn_ref();
 
 
+// CHECK:         [[uniformPtr:%\d+]] = OpAccessChain %_ptr_Uniform_R %rwsb %int_0 %uint_0
+// CHECK-NEXT:   [[originalObj:%\d+]] = OpLoad %R [[uniformPtr]]
+// CHECK-NEXT:        [[member:%\d+]] = OpCompositeExtract %int [[originalObj]] 0
+// CHECK-NEXT:       [[tempVar:%\d+]] = OpCompositeConstruct %R_0 [[member]]
+// CHECK-NEXT:                          OpStore %temp_var_R [[tempVar]]
+// CHECK-NEXT:                          OpFunctionCall %void %R_incr %temp_var_R
+// CHECK-NEXT:       [[tempVar:%\d+]] = OpLoad %R_0 %temp_var_R
+// CHECK-NEXT: [[tempVarMember:%\d+]] = OpCompositeExtract %int [[tempVar]] 0
+// CHECK-NEXT:          [[newR:%\d+]] = OpCompositeConstruct %R [[tempVarMember]]
+// CHECK-NEXT:                          OpStore [[uniformPtr]] [[newR]]
+  rwsb[0].incr();
+
   return f1;
   return f1;
 // CHECK:                     OpFunctionEnd
 // CHECK:                     OpFunctionEnd
 }
 }
@@ -151,8 +169,8 @@ float main() : A {
 // CHECK:                      OpFunctionEnd
 // CHECK:                      OpFunctionEnd
 
 
 // CHECK:        %S_fn_param = OpFunction %float None [[ft_S_f32]]
 // CHECK:        %S_fn_param = OpFunction %float None [[ft_S_f32]]
-// CHECK-NEXT: %param_this_4 = OpFunctionParameter %_ptr_Function_S
+// CHECK-NEXT: %param_this_5 = OpFunctionParameter %_ptr_Function_S
 // CHECK-NEXT:          %c_0 = OpFunctionParameter %_ptr_Function_float
 // CHECK-NEXT:          %c_0 = OpFunctionParameter %_ptr_Function_float
-// CHECK-NEXT:   %bb_entry_8 = OpLabel
-// CHECK:           {{%\d+}} = OpAccessChain %_ptr_Function_float %param_this_4 %int_0
+// CHECK-NEXT:                 OpLabel
+// CHECK:                      OpAccessChain %_ptr_Function_float %param_this_5 %int_0
 // CHECK:                      OpFunctionEnd
 // CHECK:                      OpFunctionEnd

+ 13 - 0
tools/clang/test/CodeGenSPIRV/semantic.dispatch-thread-id.int2.cs.hlsl

@@ -0,0 +1,13 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+// CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+// CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3int Input
+
+// CHECK:                  %param_var_tid = OpVariable %_ptr_Function_v2int Function
+// CHECK:  [[gl_GlobalInvocationID:%\d+]] = OpLoad %v3int %gl_GlobalInvocationID
+// CHECK:  [[int2_DispatchThreadID:%\d+]] = OpVectorShuffle %v2int [[gl_GlobalInvocationID]] [[gl_GlobalInvocationID]] 0 1
+// CHECK:                                   OpStore %param_var_tid [[int2_DispatchThreadID]]
+
+[numthreads(8, 8, 8)]
+void main(int2 tid : SV_DispatchThreadId) {}

+ 0 - 12
tools/clang/test/CodeGenSPIRV/semantic.dispatch-thread-id.uint2.cs.hlsl

@@ -1,12 +0,0 @@
-// Run: %dxc -T cs_6_0 -E main
-
-// CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
-// CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
-// CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
-
-// CHECK:  [[gl_GlobalInvocationID:%\d+]] = OpLoad %v3uint %gl_GlobalInvocationID
-// CHECK: [[uint2_DispatchThreadID:%\d+]] = OpVectorShuffle %v2uint [[gl_GlobalInvocationID]] [[gl_GlobalInvocationID]] 0 1
-// CHECK:                                   OpStore %param_var_tid [[uint2_DispatchThreadID]]
-
-[numthreads(8, 8, 8)]
-void main(uint2 tid : SV_DispatchThreadId) {}

+ 13 - 0
tools/clang/test/CodeGenSPIRV/semantic.group-id.int2.cs.hlsl

@@ -0,0 +1,13 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK: OpEntryPoint GLCompute %main "main" %gl_WorkGroupID
+// CHECK: OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
+// CHECK: %gl_WorkGroupID = OpVariable %_ptr_Input_v3int Input
+
+// CHECK:         %param_var_tid = OpVariable %_ptr_Function_v2int Function
+// CHECK: [[gl_WorkGrouID:%\d+]] = OpLoad %v3int %gl_WorkGroupID
+// CHECK:  [[int2_GroupID:%\d+]] = OpVectorShuffle %v2int [[gl_WorkGrouID]] [[gl_WorkGrouID]] 0 1
+// CHECK:                          OpStore %param_var_tid [[int2_GroupID]]
+
+[numthreads(8, 8, 8)]
+void main(int2 tid : SV_GroupID) {}

+ 0 - 12
tools/clang/test/CodeGenSPIRV/semantic.group-id.uint2.cs.hlsl

@@ -1,12 +0,0 @@
-// Run: %dxc -T cs_6_0 -E main
-
-// CHECK: OpEntryPoint GLCompute %main "main" %gl_WorkGroupID
-// CHECK: OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
-// CHECK: %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
-
-// CHECK: [[gl_WorkGrouID:%\d+]] = OpLoad %v3uint %gl_WorkGroupID
-// CHECK: [[uint2_GroupID:%\d+]] = OpVectorShuffle %v2uint [[gl_WorkGrouID]] [[gl_WorkGrouID]] 0 1
-// CHECK:                          OpStore %param_var_tid [[uint2_GroupID]]
-
-[numthreads(8, 8, 8)]
-void main(uint2 tid : SV_GroupID) {}

+ 13 - 0
tools/clang/test/CodeGenSPIRV/semantic.group-thread-id.int2.cs.hlsl

@@ -0,0 +1,13 @@
+// Run: %dxc -T cs_6_0 -E main
+
+// CHECK: OpEntryPoint GLCompute %main "main" %gl_LocalInvocationID
+// CHECK: OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
+// CHECK: %gl_LocalInvocationID = OpVariable %_ptr_Input_v3int Input
+
+// CHECK:               %param_var_gtid = OpVariable %_ptr_Function_v2int Function
+// CHECK: [[gl_LocalInvocationID:%\d+]] = OpLoad %v3int %gl_LocalInvocationID
+// CHECK:   [[int2_GroupThreadID:%\d+]] = OpVectorShuffle %v2int [[gl_LocalInvocationID]] [[gl_LocalInvocationID]] 0 1
+// CHECK:                                 OpStore %param_var_gtid [[int2_GroupThreadID]]
+
+[numthreads(8, 8, 8)]
+void main(int2 gtid : SV_GroupThreadID) {}

+ 0 - 12
tools/clang/test/CodeGenSPIRV/semantic.group-thread-id.uint2.cs.hlsl

@@ -1,12 +0,0 @@
-// Run: %dxc -T cs_6_0 -E main
-
-// CHECK: OpEntryPoint GLCompute %main "main" %gl_LocalInvocationID
-// CHECK: OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
-// CHECK: %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
-
-// CHECK: [[gl_LocalInvocationID:%\d+]] = OpLoad %v3uint %gl_LocalInvocationID
-// CHECK:  [[uint2_GroupThreadID:%\d+]] = OpVectorShuffle %v2uint [[gl_LocalInvocationID]] [[gl_LocalInvocationID]] 0 1
-// CHECK:                                 OpStore %param_var_gtid [[uint2_GroupThreadID]]
-
-[numthreads(8, 8, 8)]
-void main(uint2 gtid : SV_GroupThreadID) {}

+ 9 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opsource.hlsl

@@ -0,0 +1,9 @@
+// Run: %dxc -T cs_6_1 -E main -Zi
+
+// CHECK:      [[str:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opsource.hlsl
+// CHECK:      OpSource HLSL 610 [[str]]
+
+[numthreads(8, 1, 1)]
+void main() {
+}

+ 0 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.ds.hlsl

@@ -4,7 +4,6 @@
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Tessellation
 // CHECK: OpCapability Tessellation
 
 
-// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // HS PCF output
 // HS PCF output

+ 0 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.gs.hlsl

@@ -4,7 +4,6 @@
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Geometry
 // CHECK: OpCapability Geometry
 
 
-// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 struct GsPerVertexIn {
 struct GsPerVertexIn {

+ 0 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.hs.hlsl

@@ -6,7 +6,6 @@
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability Tessellation
 // CHECK: OpCapability Tessellation
 
 
-// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // Input control point
 // Input control point

+ 0 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.ps.hlsl

@@ -3,7 +3,6 @@
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 
 
-// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 struct Inner {
 struct Inner {

+ 0 - 1
tools/clang/test/CodeGenSPIRV/spirv.interface.vs.hlsl

@@ -3,7 +3,6 @@
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability ClipDistance
 // CHECK: OpCapability CullDistance
 // CHECK: OpCapability CullDistance
 
 
-// CHECK: OpExtension "SPV_GOOGLE_decorate_string"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 // CHECK: OpExtension "SPV_GOOGLE_hlsl_functionality1"
 
 
 // CHECK: OpEntryPoint Vertex %main "main" %gl_PerVertexOut %in_var_TEXCOORD %in_var_SV_Position %in_var_SV_ClipDistance %in_var_SV_CullDistance0 %out_var_COLOR %out_var_TEXCOORD
 // CHECK: OpEntryPoint Vertex %main "main" %gl_PerVertexOut %in_var_TEXCOORD %in_var_SV_Position %in_var_SV_ClipDistance %in_var_SV_CullDistance0 %out_var_COLOR %out_var_TEXCOORD

+ 53 - 0
tools/clang/test/CodeGenSPIRV/spirv.stage-io.16bit.hlsl

@@ -0,0 +1,53 @@
+// Run: %dxc -T vs_6_2 -E main -enable-16bit-types
+
+// CHECK: OpCapability StorageInputOutput16
+
+// CHECK: OpExtension "SPV_KHR_16bit_storage"
+
+// CHECK: OpDecorate %in_var_A Location 0
+// CHECK: OpDecorate %in_var_B Location 4
+// CHECK: OpDecorate %in_var_C Location 6
+// CHECK: OpDecorate %in_var_D Location 7
+// CHECK: OpDecorate %in_var_E Location 8
+
+// CHECK: OpDecorate %out_var_A Location 0
+// CHECK: OpDecorate %out_var_B Location 2
+// CHECK: OpDecorate %out_var_C Location 6
+// CHECK: OpDecorate %out_var_D Location 7
+// CHECK: OpDecorate %out_var_E Location 8
+
+// CHECK:  %in_var_A = OpVariable %_ptr_Input__arr_v2half_uint_4 Input
+// CHECK:  %in_var_B = OpVariable %_ptr_Input__arr_v3ushort_uint_2 Input
+// CHECK:  %in_var_C = OpVariable %_ptr_Input_short Input
+// CHECK:  %in_var_D = OpVariable %_ptr_Input_v2ushort Input
+// CHECK:  %in_var_E = OpVariable %_ptr_Input_mat3v2half Input
+
+// CHECK: %out_var_A = OpVariable %_ptr_Output_mat2v3half Output
+// CHECK: %out_var_B = OpVariable %_ptr_Output__arr_v2short_uint_4 Output
+// CHECK: %out_var_C = OpVariable %_ptr_Output_half Output
+// CHECK: %out_var_D = OpVariable %_ptr_Output_v2short Output
+// CHECK: %out_var_E = OpVariable %_ptr_Output_v3ushort Output
+
+struct VSOut {
+    half2x3   outA    : A; // 2 locations: 0, 1
+    int16_t2  outB[4] : B; // 4 locations: 2, 3, 4, 5
+    half      outC    : C; // 1 location : 6
+    int16_t2  outD    : D; // 1 location : 7
+    uint16_t3 outE    : E; // 1 location : 8
+};
+
+VSOut main(
+    half2        inA[4] : A, // 4 locations: 0, 1, 2, 3
+    uint16_t2x3  inB    : B, // 2 locations: 4, 5
+    int16_t      inC    : C, // 1 location : 6
+    uint16_t2    inD    : D, // 1 location : 7
+    float16_t3x2 inE    : E  // 3 location : 8, 9, 10
+) {
+    VSOut o;
+    o.outA    = inA[0].x;
+    o.outB[0] = inB[0][0];
+    o.outC    = inC.x;
+    o.outD    = inD[0];
+    o.outE    = inE[0][0];
+    return o;
+}

+ 14 - 1
tools/clang/test/CodeGenSPIRV/texture.array.gather-red.hlsl

@@ -21,7 +21,7 @@ TextureCubeArray<int4> tCubeArray : register(t3);
 
 
 // CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
 // CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
 
 
-float4 main(float3 location: A) : SV_Target {
+float4 main(float3 location: A, int2 offset : B) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
 // CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
 // CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
 // CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v3float %location
 // CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v3float %location
@@ -85,5 +85,18 @@ float4 main(float3 location: A) : SV_Target {
 // CHECK-NEXT:                         OpStore %g [[result]]
 // CHECK-NEXT:                         OpStore %g [[result]]
     int4 g = tCubeArray.GatherRed(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
     int4 g = tCubeArray.GatherRed(gSampler, /*location*/ float4(1.5, 1.5, 1.5, 1.5), status);
 
 
+// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
+// CHECK: [[texel0:%\d+]] = OpCompositeExtract %float [[gather]] 0
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c34]]
+// CHECK: [[texel1:%\d+]] = OpCompositeExtract %float [[gather]] 1
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c56]]
+// CHECK: [[texel2:%\d+]] = OpCompositeExtract %float [[gather]] 2
+// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
+// CHECK: [[texel3:%\d+]] = OpCompositeExtract %float [[gather]] 3
+// CHECK:                   OpCompositeConstruct %v4float [[texel0]] [[texel1]] [[texel2]] [[texel3]]
+    float4 h = t2f4.GatherRed(gSampler, location, offset, int2(3, 4), int2(5, 6), offset);
+
     return 1.0;
     return 1.0;
 }
 }

+ 14 - 1
tools/clang/test/CodeGenSPIRV/texture.gather-red.hlsl

@@ -22,7 +22,7 @@ TextureCube<int4> tCube : register(t3);
 
 
 // CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
 // CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
 
 
-float4 main(float2 location: A) : SV_Target {
+float4 main(float2 location: A, int2 offset : B) : SV_Target {
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
 // CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
 // CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
 // CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
 // CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v2float %location
 // CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v2float %location
@@ -86,5 +86,18 @@ float4 main(float2 location: A) : SV_Target {
 // CHECK-NEXT:                        OpStore %g [[result]]
 // CHECK-NEXT:                        OpStore %g [[result]]
     int4 g = tCube.GatherRed(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
     int4 g = tCube.GatherRed(gSampler, /*location*/ float3(1.5, 1.5, 1.5), status);
 
 
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c12]]
+// CHECK: [[texel0:%\d+]] = OpCompositeExtract %float [[gather]] 0
+// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
+// CHECK: [[texel1:%\d+]] = OpCompositeExtract %float [[gather]] 1
+// CHECK: [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[offset]]
+// CHECK: [[texel2:%\d+]] = OpCompositeExtract %float [[gather]] 2
+// CHECK: [[gather:%\d+]] = OpImageGather %v4float {{%\d+}} {{%\d+}} %int_0 Offset [[c78]]
+// CHECK: [[texel3:%\d+]] = OpCompositeExtract %float [[gather]] 3
+// CHECK:                   OpCompositeConstruct %v4float [[texel0]] [[texel1]] [[texel2]] [[texel3]]
+    float4 h = t2f4.GatherRed(gSampler, location, int2(1, 2), offset, offset, int2(7, 8));
+
     return 1.0;
     return 1.0;
 }
 }

+ 3 - 3
tools/clang/test/CodeGenSPIRV/type.struct.hlsl

@@ -57,13 +57,13 @@ void main() {
   S s;
   S s;
   T t;
   T t;
 
 
-// CHECK: %_ptr_Function__struct_[[num]] = OpTypePointer Function %_struct_[[num]]
+// CHECK: %R = OpTypeStruct %v2float
 
 
-// CHECK: %r0 = OpVariable %_ptr_Function__struct_[[num]] Function
+// CHECK: %r0 = OpVariable %_ptr_Function_R Function
   struct R {
   struct R {
     float2 rVal;
     float2 rVal;
   } r0;
   } r0;
 
 
-// CHECK: %r1 = OpVariable %_ptr_Function__struct_[[num]] Function
+// CHECK: %r1 = OpVariable %_ptr_Function_R Function
   R r1;
   R r1;
 }
 }

+ 53 - 0
tools/clang/test/CodeGenSPIRV/vk.binding.cl.all-sets.hlsl

@@ -0,0 +1,53 @@
+// Run: %dxc -T ps_6_0 -E main -fvk-b-shift 1000 all -fvk-t-shift 2000 all -fvk-s-shift 3000 all -fvk-u-shift 4000 all
+
+struct S {
+    float4 f;
+};
+
+// Explicit binding assignment is unaffected.
+
+// CHECK: OpDecorate %cbuffer3 DescriptorSet 0
+// CHECK: OpDecorate %cbuffer3 Binding 42
+[[vk::binding(42)]]
+ConstantBuffer<S> cbuffer3 : register(b10, space2);
+
+// CHECK: OpDecorate %cbuffer1 DescriptorSet 0
+// CHECK: OpDecorate %cbuffer1 Binding 1000
+ConstantBuffer<S> cbuffer1 : register(b0);
+// CHECK: OpDecorate %cbuffer2 DescriptorSet 2
+// CHECK: OpDecorate %cbuffer2 Binding 1000
+ConstantBuffer<S> cbuffer2 : register(b0, space2);
+
+// CHECK: OpDecorate %texture1 DescriptorSet 1
+// CHECK: OpDecorate %texture1 Binding 2001
+Texture2D<float4> texture1: register(t1, space1);
+// CHECK: OpDecorate %texture2 DescriptorSet 0
+// CHECK: OpDecorate %texture2 Binding 2001
+Texture2D<float4> texture2: register(t1);
+
+// CHECK: OpDecorate %sampler1 DescriptorSet 0
+// CHECK: OpDecorate %sampler1 Binding 3000
+// CHECK: OpDecorate %sampler2 DescriptorSet 2
+// CHECK: OpDecorate %sampler2 Binding 3000
+SamplerState sampler1: register(s0);
+SamplerState sampler2: register(s0, space2);
+
+// CHECK: OpDecorate %rwbuffer1 DescriptorSet 3
+// CHECK: OpDecorate %rwbuffer1 Binding 4003
+RWBuffer<float4> rwbuffer1 : register(u3, space3);
+// CHECK: OpDecorate %rwbuffer2 DescriptorSet 0
+// CHECK: OpDecorate %rwbuffer2 Binding 4003
+RWBuffer<float4> rwbuffer2 : register(u3);
+
+// Lacking binding assignment is unaffacted.
+
+// CHECK: OpDecorate %cbuffer4 DescriptorSet 0
+// CHECK: OpDecorate %cbuffer4 Binding 0
+ConstantBuffer<S> cbuffer4;
+// CHECK: OpDecorate %cbuffer5 DescriptorSet 0
+// CHECK: OpDecorate %cbuffer5 Binding 1
+ConstantBuffer<S> cbuffer5;
+
+float4 main() : SV_Target {
+    return cbuffer1.f;
+}

+ 0 - 30
tools/clang/test/CodeGenSPIRV/vk.binding.cl.error.hlsl

@@ -1,30 +0,0 @@
-// Run: %dxc -T ps_6_0 -E main -fvk-b-shift 2 0 -fvk-t-shift 2 0 -fvk-s-shift 3 0 -fvk-u-shift 3 0
-
-struct S {
-    float4 f;
-};
-
-[[vk::binding(2)]]
-ConstantBuffer<S> cbuffer3;
-
-ConstantBuffer<S> cbuffer1 : register(b0); // Collision with cbuffer3 after shift
-
-Texture2D<float4> texture1: register(t0, space1);
-Texture2D<float4> texture2: register(t0); // Collision with cbuffer3 after shift
-
-SamplerState sampler1: register(s0);
-SamplerState sampler2: register(s0, space2);
-
-RWBuffer<float4> rwbuffer1 : register(u0, space3);
-RWBuffer<float4> rwbuffer2 : register(u0); // Collision with sampler1 after shift
-
-float4 main() : SV_Target {
-    return cbuffer1.f;
-}
-
-//CHECK: :10:30: warning: resource binding #2 in descriptor set #0 already assigned
-//CHECK:   :7:3: note: binding number previously assigned here
-
-//CHECK: :13:29: warning: resource binding #2 in descriptor set #0 already assigned
-
-//CHECK: :19:30: warning: resource binding #3 in descriptor set #0 already assigned

+ 0 - 42
tools/clang/test/CodeGenSPIRV/vk.binding.explicit.error.hlsl

@@ -1,42 +0,0 @@
-// Run: %dxc -T ps_6_0 -E main
-
-[[vk::binding(1)]]
-SamplerState sampler1      : register(s1, space1);
-
-[[vk::binding(3, 1)]]
-SamplerState sampler2      : register(s2);
-
-[[vk::binding(1)]] // reuse - allowed for combined image sampler
-Texture2D<float4> texture1;
-
-[[vk::binding(3, 1)]] // reuse - allowed for combined image sampler
-Texture3D<float4> texture2 : register(t0, space0);
-
-[[vk::binding(3, 1)]] // reuse - disallowed
-Texture3D<float4> texture3 : register(t0, space0);
-
-[[vk::binding(1)]] // reuse - disallowed
-SamplerState sampler3      : register(s1, space1);
-
-struct S { float f; };
-
-[[vk::binding(5)]]
-StructuredBuffer<S> buf1;
-
-[[vk::binding(5)]] // reuse - disallowed
-SamplerState sampler4;
-
-[[vk::binding(5)]] // reuse - disallowed
-Texture2D<float4> texture4;
-
-float4 main() : SV_Target {
-    return 1.0;
-}
-
-// CHECK-NOT:  :9:{{%\d+}}: warning: resource binding #1 in descriptor set #0 already assigned
-// CHECK-NOT: :12:{{%\d+}}: warning: resource binding #3 in descriptor set #1 already assigned
-// CHECK: :15:3: warning: resource binding #3 in descriptor set #1 already assigned
-// CHECK: :12:3: note: binding number previously assigned here
-// CHECK: :18:3: warning: resource binding #1 in descriptor set #0 already assigned
-// CHECK: :26:3: warning: resource binding #5 in descriptor set #0 already assigned
-// CHECK: :29:3: warning: resource binding #5 in descriptor set #0 already assigned

+ 0 - 29
tools/clang/test/CodeGenSPIRV/vk.binding.register.error.hlsl

@@ -1,29 +0,0 @@
-// Run: %dxc -T ps_6_0 -E main
-
-struct S {
-    float4 f;
-};
-
-ConstantBuffer<S>     myCbuffer1 : register(b0);
-ConstantBuffer<S>     myCbuffer2 : register(b0, space1);
-
-RWStructuredBuffer<S> mySBuffer1 : register(u0);         // reuse - disallowed
-RWStructuredBuffer<S> mySBuffer2 : register(u0, space1); // reuse - disallowed
-RWStructuredBuffer<S> mySBuffer3 : register(u0, space2);
-
-SamplerState mySampler1 : register(s5, space1);
-Texture2D    myTexture1 : register(t5, space1); // reuse - allowed
-
-Texture2D    myTexture2 : register(t6, space6);
-[[vk::binding(6, 6)]] // reuse - allowed
-SamplerState mySampler2;
-
-float4 main() : SV_Target {
-    return 1.0;
-}
-
-// CHECK: :10:36: warning: resource binding #0 in descriptor set #0 already assigned
-// CHECK:  :7:36: note: binding number previously assigned here
-// CHECK: :11:36: warning: resource binding #0 in descriptor set #1 already assigned
-// CHECK-NOT: :15:{{%\d+}}: warning: resource binding #5 in descriptor set #1 already assigned
-// CHECK-NOT: :18:{{%\d+}}: warning: resource binding #6 in descriptor set #6 already assigned

+ 41 - 1
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.boolean.hlsl

@@ -7,12 +7,18 @@
 // CHECK: OpMemberDecorate %type_CONSTANTS 0 Offset 0
 // CHECK: OpMemberDecorate %type_CONSTANTS 0 Offset 0
 // CHECK: OpDecorate %type_CONSTANTS Block
 // CHECK: OpDecorate %type_CONSTANTS Block
 
 
-// CHECK: %FrameConstants = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2
+// CHECK: %T = OpTypeStruct %_arr_uint_uint_1
+struct T {
+  bool boolArray[1];
+};
+
+// CHECK: %FrameConstants = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2 %T
 struct FrameConstants
 struct FrameConstants
 {
 {
   bool  boolScalar;
   bool  boolScalar;
   bool3 boolVec;
   bool3 boolVec;
   row_major bool2x3 boolMat;
   row_major bool2x3 boolMat;
+  T t;
 };
 };
 
 
 [[vk::binding(0, 0)]]
 [[vk::binding(0, 0)]]
@@ -23,6 +29,11 @@ cbuffer CONSTANTS
 
 
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
 // CHECK: [[v2uint0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
 // CHECK: [[v2uint0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
+
+// These are the types that hold SPIR-V booleans, rather than Uints.
+// CHECK:              %T_0 = OpTypeStruct %_arr_bool_uint_1
+// CHECK: %FrameConstants_0 = OpTypeStruct %bool %v3bool %_arr_v3bool_uint_2 %T_0
+
 float4 main(in float4 texcoords : TEXCOORD0) : SV_TARGET
 float4 main(in float4 texcoords : TEXCOORD0) : SV_TARGET
 {
 {
 // CHECK:      [[FrameConstants:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
 // CHECK:      [[FrameConstants:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
@@ -118,5 +129,34 @@ float4 main(in float4 texcoords : TEXCOORD0) : SV_TARGET
 // CHECK-NEXT:                           OpStore %k [[boolVec]]
 // CHECK-NEXT:                           OpStore %k [[boolVec]]
     bool2   k = frameConstants.boolMat._m12_m01;
     bool2   k = frameConstants.boolMat._m12_m01;
 
 
+// CHECK:      [[FrameConstants:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
+// CHECK-NEXT:            [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[FrameConstants]] %int_3 %int_0 %int_2
+// CHECK-NEXT:           [[uint:%\d+]] = OpLoad %uint [[ptr]]
+// CHECK-NEXT:           [[bool:%\d+]] = OpINotEqual %bool [[uint]] %uint_0
+// CHECK-NEXT:                           OpStore %l [[bool]]
+    bool    l = frameConstants.t.boolArray[2];
+
+// CHECK:           [[FrameConstantsPtr:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
+// CHECK-NEXT:         [[FrameConstants:%\d+]] = OpLoad %FrameConstants [[FrameConstantsPtr]]
+// CHECK-NEXT:              [[fc_0_uint:%\d+]] = OpCompositeExtract %uint [[FrameConstants]] 0
+// CHECK-NEXT:              [[fc_0_bool:%\d+]] = OpINotEqual %bool [[fc_0_uint]] %uint_0
+// CHECK-NEXT:             [[fc_1_uint3:%\d+]] = OpCompositeExtract %v3uint [[FrameConstants]] 1
+// CHECK-NEXT:             [[fc_1_bool3:%\d+]] = OpINotEqual %v3bool [[fc_1_uint3]] [[v3uint0]]
+// CHECK-NEXT:           [[fc_2_uintMat:%\d+]] = OpCompositeExtract %_arr_v3uint_uint_2 [[FrameConstants]] 2
+// CHECK-NEXT: [[fc_2_uintMat_row0_uint:%\d+]] = OpCompositeExtract %v3uint [[fc_2_uintMat]] 0
+// CHECK-NEXT: [[fc_2_uintMat_row0_bool:%\d+]] = OpINotEqual %v3bool [[fc_2_uintMat_row0_uint]] [[v3uint0]]
+// CHECK-NEXT: [[fc_2_uintMat_row1_uint:%\d+]] = OpCompositeExtract %v3uint [[fc_2_uintMat]] 1
+// CHECK-NEXT: [[fc_2_uintMat_row1_bool:%\d+]] = OpINotEqual %v3bool [[fc_2_uintMat_row1_uint]] [[v3uint0]]
+// CHECK-NEXT:           [[fc_2_boolMat:%\d+]] = OpCompositeConstruct %_arr_v3bool_uint_2 [[fc_2_uintMat_row0_bool]] [[fc_2_uintMat_row1_bool]]
+// CHECK-NEXT:                 [[fc_3_T:%\d+]] = OpCompositeExtract %T [[FrameConstants]] 3
+// CHECK-NEXT:      [[fc_3_T_0_uint_arr:%\d+]] = OpCompositeExtract %_arr_uint_uint_1 [[fc_3_T]] 0
+// CHECK-NEXT:        [[fc_3_T_0_0_uint:%\d+]] = OpCompositeExtract %uint [[fc_3_T_0_uint_arr]] 0
+// CHECK-NEXT:        [[fc_3_T_0_0_bool:%\d+]] = OpINotEqual %bool [[fc_3_T_0_0_uint]] %uint_0
+// CHECK-NEXT:      [[fc_3_T_0_bool_arr:%\d+]] = OpCompositeConstruct %_arr_bool_uint_1 [[fc_3_T_0_0_bool]]
+// CHECK-NEXT:            [[fc_3_T_bool:%\d+]] = OpCompositeConstruct %T_0 [[fc_3_T_0_bool_arr]]
+// CHECK-NEXT:                     [[fc:%\d+]] = OpCompositeConstruct %FrameConstants_0 [[fc_0_bool]] [[fc_1_bool3]] [[fc_2_boolMat]] [[fc_3_T_bool]]
+// CHECK-NEXT:                                   OpStore %fc [[fc]]
+    FrameConstants fc = frameConstants;
+
     return (1.0).xxxx;
     return (1.0).xxxx;
 }
 }

+ 56 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.rwstructuredbuffer.boolean.hlsl

@@ -1,16 +1,28 @@
 // Run: %dxc -T vs_6_0 -E main
 // Run: %dxc -T vs_6_0 -E main
 
 
+// CHECK: %T = OpTypeStruct %_arr_uint_uint_1
+struct T {
+  bool boolArray[1];
+};
+
+// CHECK: %S = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2 %T
 struct S
 struct S
 {
 {
   bool  boolScalar;
   bool  boolScalar;
   bool3 boolVec;
   bool3 boolVec;
   row_major bool2x3 boolMat;
   row_major bool2x3 boolMat;
+  T t;
 };
 };
 
 
 RWStructuredBuffer<S> values;
 RWStructuredBuffer<S> values;
 
 
 // CHECK: [[v3uint1:%\d+]] = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 // CHECK: [[v3uint1:%\d+]] = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
+
+// These are the types that hold SPIR-V booleans, rather than Uints.
+// CHECK: %T_0 = OpTypeStruct %_arr_bool_uint_1
+// CHECK: %S_0 = OpTypeStruct %bool %v3bool %_arr_v3bool_uint_2 %T_0
+
 void main()
 void main()
 {
 {
   bool3 boolVecVar;
   bool3 boolVecVar;
@@ -32,4 +44,48 @@ void main()
   // values[2].boolMat = boolMatVar;
   // values[2].boolMat = boolMatVar;
   // values[0].boolVec.yzx = boolVecVar;
   // values[0].boolVec.yzx = boolVecVar;
   // values[0].boolMat._m12_m11 = boolVecVar2;
   // values[0].boolMat._m12_m11 = boolVecVar2;
+
+// CHECK:              [[sPtr:%\d+]] = OpAccessChain %_ptr_Uniform_S %values %int_0 %uint_0
+// CHECK-NEXT:            [[s:%\d+]] = OpLoad %S [[sPtr]]
+// CHECK-NEXT:           [[s0:%\d+]] = OpCompositeExtract %uint [[s]] 0
+// CHECK-NEXT:      [[s0_bool:%\d+]] = OpINotEqual %bool [[s0]] %uint_0
+// CHECK-NEXT:           [[s1:%\d+]] = OpCompositeExtract %v3uint [[s]] 1
+// CHECK-NEXT:      [[s1_bool:%\d+]] = OpINotEqual %v3bool [[s1]] [[v3uint0]]
+// CHECK-NEXT:           [[s2:%\d+]] = OpCompositeExtract %_arr_v3uint_uint_2 [[s]] 2
+// CHECK-NEXT:      [[s2_row0:%\d+]] = OpCompositeExtract %v3uint [[s2]] 0
+// CHECK-NEXT: [[s2_row0_bool:%\d+]] = OpINotEqual %v3bool [[s2_row0]] [[v3uint0]]
+// CHECK-NEXT:      [[s2_row1:%\d+]] = OpCompositeExtract %v3uint [[s2]] 1
+// CHECK-NEXT: [[s2_row1_bool:%\d+]] = OpINotEqual %v3bool [[s2_row1]] [[v3uint0]]
+// CHECK-NEXT:      [[s2_bool:%\d+]] = OpCompositeConstruct %_arr_v3bool_uint_2 [[s2_row0_bool]] [[s2_row1_bool]]
+// CHECK-NEXT:            [[t:%\d+]] = OpCompositeExtract %T [[s]] 3
+// CHECK-NEXT:  [[t0_uint_arr:%\d+]] = OpCompositeExtract %_arr_uint_uint_1 [[t]] 0
+// CHECK-NEXT:    [[t0_0_uint:%\d+]] = OpCompositeExtract %uint [[t0_uint_arr]] 0
+// CHECK-NEXT:    [[t0_0_bool:%\d+]] = OpINotEqual %bool [[t0_0_uint]] %uint_0
+// CHECK-NEXT:      [[t0_bool:%\d+]] = OpCompositeConstruct %_arr_bool_uint_1 [[t0_0_bool]]
+// CHECK-NEXT:       [[t_bool:%\d+]] = OpCompositeConstruct %T_0 [[t0_bool]]
+// CHECK-NEXT:       [[s_bool:%\d+]] = OpCompositeConstruct %S_0 [[s0_bool]] [[s1_bool]] [[s2_bool]] [[t_bool]]
+// CHECK-NEXT:                         OpStore %s [[s_bool]]
+  S s = values[0];
+
+// CHECK:                         [[s:%\d+]] = OpLoad %S_0 %s
+// CHECK-NEXT:            [[resultPtr:%\d+]] = OpAccessChain %_ptr_Uniform_S %values %int_0 %uint_1
+// CHECK-NEXT:              [[s0_bool:%\d+]] = OpCompositeExtract %bool [[s]] 0
+// CHECK-NEXT:              [[s0_uint:%\d+]] = OpSelect %uint [[s0_bool]] %uint_1 %uint_0
+// CHECK-NEXT:           [[s1_boolVec:%\d+]] = OpCompositeExtract %v3bool [[s]] 1
+// CHECK-NEXT:           [[s1_uintVec:%\d+]] = OpSelect %v3uint [[s1_boolVec]]
+// CHECK-NEXT:           [[s2_boolMat:%\d+]] = OpCompositeExtract %_arr_v3bool_uint_2 [[s]] 2
+// CHECK-NEXT:      [[s2_boolMat_row0:%\d+]] = OpCompositeExtract %v3bool [[s2_boolMat]] 0
+// CHECK-NEXT: [[s2_boolMat_row0_uint:%\d+]] = OpSelect %v3uint [[s2_boolMat_row0]]
+// CHECK-NEXT:      [[s2_boolMat_row1:%\d+]] = OpCompositeExtract %v3bool [[s2_boolMat]] 1
+// CHECK-NEXT: [[s2_boolMat_row1_uint:%\d+]] = OpSelect %v3uint [[s2_boolMat_row1]]
+// CHECK-NEXT:           [[s2_uintMat:%\d+]] = OpCompositeConstruct %_arr_v3uint_uint_2 [[s2_boolMat_row0_uint]] [[s2_boolMat_row1_uint]]
+// CHECK-NEXT:                    [[t:%\d+]] = OpCompositeExtract %T_0 [[s]] 3
+// CHECK-NEXT:          [[t0_bool_arr:%\d+]] = OpCompositeExtract %_arr_bool_uint_1 [[t]] 0
+// CHECK-NEXT:        [[t0_bool_arr_0:%\d+]] = OpCompositeExtract %bool [[t0_bool_arr]] 0
+// CHECK-NEXT:   [[t0_bool_arr_0_uint:%\d+]] = OpSelect %uint [[t0_bool_arr_0]] %uint_1 %uint_0
+// CHECK-NEXT:          [[t0_uint_arr:%\d+]] = OpCompositeConstruct %_arr_uint_uint_1 [[t0_bool_arr_0_uint]]
+// CHECK-NEXT:               [[t_uint:%\d+]] = OpCompositeConstruct %T [[t0_uint_arr]]
+// CHECK-NEXT:               [[s_uint:%\d+]] = OpCompositeConstruct %S [[s0_uint]] [[s1_uintVec]] [[s2_uintMat]] [[t_uint]]
+// CHECK-NEXT:                                 OpStore [[resultPtr:%\d+]] [[s_uint]]
+  values[1] = s;
 }
 }

+ 25 - 0
tools/clang/test/CodeGenSPIRV/vk.push-constant.anon-struct.hlsl

@@ -0,0 +1,25 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// CHECK: OpName %type_PushConstant_ "type.PushConstant."
+// CHECK: OpMemberName %type_PushConstant_ 0 "a"
+// CHECK: OpMemberName %type_PushConstant_ 1 "b"
+// CHECK: OpMemberName %type_PushConstant_ 2 "c"
+
+// CHECK: %type_PushConstant_ = OpTypeStruct %int %float %v3float
+// CHECK: %_ptr_PushConstant_type_PushConstant_ = OpTypePointer PushConstant %type_PushConstant_
+[[vk::push_constant]]
+struct {
+    int    a;
+    float  b;
+    float3 c;
+}
+// CHECK: %PushConstants = OpVariable %_ptr_PushConstant_type_PushConstant_ PushConstant
+PushConstants;
+
+RWBuffer<int> Output;
+
+[numthreads(1, 1, 1)]
+void main() {
+// CHECK: OpAccessChain %_ptr_PushConstant_int %PushConstants %int_0
+    Output[0] = PushConstants.a;
+}

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

@@ -460,6 +460,7 @@ public:
           spirvOpts.allowedExtensions = opts.SpvExtensions;
           spirvOpts.allowedExtensions = opts.SpvExtensions;
           spirvOpts.targetEnv = opts.SpvTargetEnv;
           spirvOpts.targetEnv = opts.SpvTargetEnv;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
+          spirvOpts.enableDebugInfo = opts.DebugInfo;
           clang::EmitSPIRVAction action(spirvOpts);
           clang::EmitSPIRVAction action(spirvOpts);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
           action.BeginSourceFile(compiler, file);
           action.BeginSourceFile(compiler, file);

+ 22 - 15
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -501,15 +501,15 @@ TEST_F(FileTest, SemanticDispatchThreadId) {
 TEST_F(FileTest, SemanticDispatchThreadIdUint) {
 TEST_F(FileTest, SemanticDispatchThreadIdUint) {
   runFileTest("semantic.dispatch-thread-id.uint.cs.hlsl");
   runFileTest("semantic.dispatch-thread-id.uint.cs.hlsl");
 }
 }
-TEST_F(FileTest, SemanticDispatchThreadIdUint2) {
-  runFileTest("semantic.dispatch-thread-id.uint2.cs.hlsl");
+TEST_F(FileTest, SemanticDispatchThreadIdInt2) {
+  runFileTest("semantic.dispatch-thread-id.int2.cs.hlsl");
 }
 }
 TEST_F(FileTest, SemanticGroupID) { runFileTest("semantic.group-id.cs.hlsl"); }
 TEST_F(FileTest, SemanticGroupID) { runFileTest("semantic.group-id.cs.hlsl"); }
 TEST_F(FileTest, SemanticGroupIDUint) {
 TEST_F(FileTest, SemanticGroupIDUint) {
   runFileTest("semantic.group-id.uint.cs.hlsl");
   runFileTest("semantic.group-id.uint.cs.hlsl");
 }
 }
-TEST_F(FileTest, SemanticGroupIDUint2) {
-  runFileTest("semantic.group-id.uint2.cs.hlsl");
+TEST_F(FileTest, SemanticGroupIDInt2) {
+  runFileTest("semantic.group-id.int2.cs.hlsl");
 }
 }
 TEST_F(FileTest, SemanticGroupThreadID) {
 TEST_F(FileTest, SemanticGroupThreadID) {
   runFileTest("semantic.group-thread-id.cs.hlsl");
   runFileTest("semantic.group-thread-id.cs.hlsl");
@@ -517,8 +517,8 @@ TEST_F(FileTest, SemanticGroupThreadID) {
 TEST_F(FileTest, SemanticGroupThreadIDUint) {
 TEST_F(FileTest, SemanticGroupThreadIDUint) {
   runFileTest("semantic.group-thread-id.uint.cs.hlsl");
   runFileTest("semantic.group-thread-id.uint.cs.hlsl");
 }
 }
-TEST_F(FileTest, SemanticGroupThreadIDUint2) {
-  runFileTest("semantic.group-thread-id.uint2.cs.hlsl");
+TEST_F(FileTest, SemanticGroupThreadIDInt2) {
+  runFileTest("semantic.group-thread-id.int2.cs.hlsl");
 }
 }
 TEST_F(FileTest, SemanticGroupIndex) {
 TEST_F(FileTest, SemanticGroupIndex) {
   runFileTest("semantic.group-index.cs.hlsl");
   runFileTest("semantic.group-index.cs.hlsl");
@@ -1216,6 +1216,10 @@ TEST_F(FileTest, SpirvStageIOInterfacePS) {
   runFileTest("spirv.interface.ps.hlsl");
   runFileTest("spirv.interface.ps.hlsl");
 }
 }
 
 
+TEST_F(FileTest, SpirvStageIO16bitTypes) {
+  runFileTest("spirv.stage-io.16bit.hlsl");
+}
+
 TEST_F(FileTest, SpirvInterpolation) {
 TEST_F(FileTest, SpirvInterpolation) {
   runFileTest("spirv.interpolation.hlsl");
   runFileTest("spirv.interpolation.hlsl");
 }
 }
@@ -1262,6 +1266,10 @@ TEST_F(FileTest, SpirvLegalizationTextureBuffer) {
               /*runValidation=*/false);
               /*runValidation=*/false);
 }
 }
 
 
+TEST_F(FileTest, SpirvDebugOpSource) {
+  runFileTest("spirv.debug.opsource.hlsl");
+}
+
 TEST_F(FileTest, VulkanAttributeErrors) {
 TEST_F(FileTest, VulkanAttributeErrors) {
   runFileTest("vk.attribute.error.hlsl", Expect::Failure);
   runFileTest("vk.attribute.error.hlsl", Expect::Failure);
 }
 }
@@ -1317,18 +1325,14 @@ TEST_F(FileTest, VulkanRegisterBinding) {
   runFileTest("vk.binding.register.hlsl");
   runFileTest("vk.binding.register.hlsl");
 }
 }
 TEST_F(FileTest, VulkanRegisterBindingShift) {
 TEST_F(FileTest, VulkanRegisterBindingShift) {
-  // Resource binding from :register() and with shift specified via
+  // Resource binding from :register() with shift specified via
   // command line option
   // command line option
   runFileTest("vk.binding.cl.hlsl");
   runFileTest("vk.binding.cl.hlsl");
 }
 }
-TEST_F(FileTest, VulkanExplicitBindingReassigned) {
-  runFileTest("vk.binding.explicit.error.hlsl", Expect::Warning);
-}
-TEST_F(FileTest, VulkanRegisterBindingReassigned) {
-  runFileTest("vk.binding.register.error.hlsl", Expect::Warning);
-}
-TEST_F(FileTest, VulkanRegisterBindingShiftReassigned) {
-  runFileTest("vk.binding.cl.error.hlsl", Expect::Warning);
+TEST_F(FileTest, VulkanRegisterBindingShiftAllSets) {
+  // Resource binding from :register() with shift specified for all sets via
+  // command line option
+  runFileTest("vk.binding.cl.all-sets.hlsl");
 }
 }
 TEST_F(FileTest, VulkanStructuredBufferCounter) {
 TEST_F(FileTest, VulkanStructuredBufferCounter) {
   // [[vk::counter_binding()]] for RWStructuredBuffer, AppendStructuredBuffer,
   // [[vk::counter_binding()]] for RWStructuredBuffer, AppendStructuredBuffer,
@@ -1340,6 +1344,9 @@ TEST_F(FileTest, VulkanPushConstant) { runFileTest("vk.push-constant.hlsl"); }
 TEST_F(FileTest, VulkanPushConstantOffset) {
 TEST_F(FileTest, VulkanPushConstantOffset) {
   runFileTest("vk.push-constant.offset.hlsl");
   runFileTest("vk.push-constant.offset.hlsl");
 }
 }
+TEST_F(FileTest, VulkanPushConstantAnonymousStruct) {
+  runFileTest("vk.push-constant.anon-struct.hlsl");
+}
 TEST_F(FileTest, VulkanMultiplePushConstant) {
 TEST_F(FileTest, VulkanMultiplePushConstant) {
   runFileTest("vk.push-constant.multiple.hlsl", Expect::Failure);
   runFileTest("vk.push-constant.multiple.hlsl", Expect::Failure);
 }
 }

+ 1 - 2
tools/clang/unittests/SPIRV/FileTestUtils.cpp

@@ -157,11 +157,10 @@ bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
     // Get compilation results.
     // Get compilation results.
     IFT(pResult->GetStatus(&resultStatus));
     IFT(pResult->GetStatus(&resultStatus));
 
 
-    // Get diagnostics string and print warnings and errors to stderr.
+    // Get diagnostics string.
     IFT(pResult->GetErrorBuffer(&pErrorBuffer));
     IFT(pResult->GetErrorBuffer(&pErrorBuffer));
     const std::string diagnostics((char *)pErrorBuffer->GetBufferPointer(),
     const std::string diagnostics((char *)pErrorBuffer->GetBufferPointer(),
                                   pErrorBuffer->GetBufferSize());
                                   pErrorBuffer->GetBufferSize());
-    fprintf(stderr, "%s\n", diagnostics.c_str());
     *errorMessages = diagnostics;
     *errorMessages = diagnostics;
 
 
     if (SUCCEEDED(resultStatus)) {
     if (SUCCEEDED(resultStatus)) {

+ 82 - 5
tools/clang/unittests/SPIRV/TestMain.cpp

@@ -21,20 +21,87 @@
 #endif
 #endif
 #endif
 #endif
 
 
+namespace {
+using namespace ::testing;
+
+/// A GoogleTest event printer that only prints test failures.
+class FailurePrinter : public TestEventListener {
+public:
+  explicit FailurePrinter(TestEventListener *listener)
+      : defaultListener(listener) {}
+
+  ~FailurePrinter() override { delete defaultListener; }
+
+  void OnTestProgramStart(const UnitTest &ut) override {
+    defaultListener->OnTestProgramStart(ut);
+  }
+
+  void OnTestIterationStart(const UnitTest &ut, int iteration) override {
+    defaultListener->OnTestIterationStart(ut, iteration);
+  }
+
+  void OnEnvironmentsSetUpStart(const UnitTest &ut) override {
+    defaultListener->OnEnvironmentsSetUpStart(ut);
+  }
+
+  void OnEnvironmentsSetUpEnd(const UnitTest &ut) override {
+    defaultListener->OnEnvironmentsSetUpEnd(ut);
+  }
+
+  void OnTestCaseStart(const TestCase &tc) override {
+    defaultListener->OnTestCaseStart(tc);
+  }
+
+  void OnTestStart(const TestInfo &ti) override {
+    // Do not output on test start
+    // defaultListener->OnTestStart(ti);
+  }
+
+  void OnTestPartResult(const TestPartResult &result) override {
+    defaultListener->OnTestPartResult(result);
+  }
+
+  void OnTestEnd(const TestInfo &ti) override {
+    // Only output if failure on test end
+    if (ti.result()->Failed())
+      defaultListener->OnTestEnd(ti);
+  }
+
+  void OnTestCaseEnd(const TestCase &tc) override {
+    defaultListener->OnTestCaseEnd(tc);
+  }
+
+  void OnEnvironmentsTearDownStart(const UnitTest &ut) override {
+    defaultListener->OnEnvironmentsTearDownStart(ut);
+  }
+
+  void OnEnvironmentsTearDownEnd(const UnitTest &ut) override {
+    defaultListener->OnEnvironmentsTearDownEnd(ut);
+  }
+
+  void OnTestIterationEnd(const UnitTest &ut, int iteration) override {
+    defaultListener->OnTestIterationEnd(ut, iteration);
+  }
+
+  void OnTestProgramEnd(const UnitTest &ut) override {
+    defaultListener->OnTestProgramEnd(ut);
+  }
+
+private:
+  TestEventListener *defaultListener;
+};
+} // namespace
+
 const char *TestMainArgv0;
 const char *TestMainArgv0;
 
 
 int main(int argc, char **argv) {
 int main(int argc, char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(true /* Disable crash reporting */);
   llvm::sys::PrintStackTraceOnErrorSignal(true /* Disable crash reporting */);
 
 
-  // Initialize both gmock and gtest.
-  testing::InitGoogleMock(&argc, argv);
-
   for (int i = 1; i < argc; ++i) {
   for (int i = 1; i < argc; ++i) {
     if (std::string("--spirv-test-root") == argv[i]) {
     if (std::string("--spirv-test-root") == argv[i]) {
       // Allow the user set the root directory for test input files.
       // Allow the user set the root directory for test input files.
       if (i + 1 < argc) {
       if (i + 1 < argc) {
-        clang::spirv::testOptions::inputDataDir = argv[i + 1];
-        i++;
+        clang::spirv::testOptions::inputDataDir = argv[++i];
       } else {
       } else {
         fprintf(stderr, "Error: --spirv-test-root requires an argument\n");
         fprintf(stderr, "Error: --spirv-test-root requires an argument\n");
         return 1;
         return 1;
@@ -42,6 +109,16 @@ int main(int argc, char **argv) {
     }
     }
   }
   }
 
 
+  // Initialize both gmock and gtest.
+  testing::InitGoogleMock(&argc, argv);
+
+  // Switch event listener to one that only prints failures.
+  testing::TestEventListeners &listeners =
+      ::testing::UnitTest::GetInstance()->listeners();
+  auto *defaultPrinter = listeners.Release(listeners.default_result_printer());
+  // Google Test takes the ownership.
+  listeners.Append(new FailurePrinter(defaultPrinter));
+
   // Make it easy for a test to re-execute itself by saving argv[0].
   // Make it easy for a test to re-execute itself by saving argv[0].
   TestMainArgv0 = argv[0];
   TestMainArgv0 = argv[0];
 
 

+ 1 - 1
utils/appveyor/appveyor_test.ps1

@@ -39,7 +39,7 @@ function Invoke-AppveyorTestsRestMethod($appveyorTests) {
 }
 }
 
 
 function Invoke-TE($logfile) {
 function Invoke-TE($logfile) {
-    $testdll = "$env:HLSL_BLD_DIR\Debug\bin\clang-hlsl-tests.dll"
+    $testdll = "$env:HLSL_BLD_DIR\Release\bin\clang-hlsl-tests.dll"
     $p = Start-Process "te.exe" -Args "$testdll /logOutput:Low /logFile:$logfile /enableWttLogging /p:HlslDataDir=%HLSL_SRC_DIR%\tools\clang\test\HLSL /labMode /miniDumpOnCrash" -Wait -NoNewWindow -PassThru
     $p = Start-Process "te.exe" -Args "$testdll /logOutput:Low /logFile:$logfile /enableWttLogging /p:HlslDataDir=%HLSL_SRC_DIR%\tools\clang\test\HLSL /labMode /miniDumpOnCrash" -Wait -NoNewWindow -PassThru
     return $p.ExitCode
     return $p.ExitCode
 }
 }