Kaynağa Gözat

Merged PR 111: Integrate master

Merge master to rtmaster, fix missing module shader flags for lib target.
Tex Riddell 7 yıl önce
ebeveyn
işleme
8b4bc1c7c7
100 değiştirilmiş dosya ile 3104 ekleme ve 1182 silme
  1. 78 0
      .travis.yml
  2. 1 1
      CMakeLists.txt
  3. 3 0
      README.md
  4. 148 0
      docs/DxcOnUnix.rst
  5. 29 9
      docs/SPIR-V.rst
  6. 1 1
      external/SPIRV-Headers
  7. 1 1
      external/SPIRV-Tools
  8. 0 2
      include/dxc/Support/Global.h
  9. 2 0
      include/dxc/Support/HLSLOptions.h
  10. 3 1
      include/dxc/Support/HLSLOptions.td
  11. 19 0
      include/dxc/Support/Unicode.h
  12. 472 6
      include/dxc/Support/WinAdapter.h
  13. 70 0
      include/dxc/Support/WinFunctions.h
  14. 56 0
      include/dxc/Support/WinIncludes.h
  15. 25 20
      include/dxc/Support/dxcapi.use.h
  16. 62 10
      include/dxc/dxcapi.h
  17. 13 3
      include/dxc/dxcisense.h
  18. 8 1
      include/dxc/dxctools.h
  19. 8 0
      include/llvm/Analysis/TargetLibraryInfo.def
  20. 4 1
      include/llvm/PassRegistry.h
  21. 8 0
      include/llvm/Support/MSFileSystem.h
  22. 3 3
      include/llvm/Support/Mutex.h
  23. 4 4
      lib/Analysis/TargetLibraryInfo.cpp
  24. 2 0
      lib/DxcSupport/CMakeLists.txt
  25. 14 16
      lib/DxcSupport/FileIOHelper.cpp
  26. 21 0
      lib/DxcSupport/HLSLOptions.cpp
  27. 82 0
      lib/DxcSupport/Unicode.cpp
  28. 59 0
      lib/DxcSupport/WinAdapter.cpp
  29. 337 0
      lib/DxcSupport/WinFunctions.cpp
  30. 8 1
      lib/DxcSupport/dxcapi.use.cpp
  31. 8 13
      lib/DxcSupport/dxcmem.cpp
  32. 4 4
      lib/HLSL/DxilContainerAssembler.cpp
  33. 10 0
      lib/HLSL/DxilContainerReflection.cpp
  34. 2 0
      lib/HLSL/DxilLegalizeSampleOffsetPass.cpp
  35. 1 0
      lib/HLSL/DxilMetadataHelper.cpp
  36. 5 6
      lib/HLSL/DxilPreparePasses.cpp
  37. 1 0
      lib/HLSL/DxilRootSignature.cpp
  38. 31 7
      lib/IR/PassRegistry.cpp
  39. 197 0
      lib/MSSupport/MSFileSystemImpl.cpp
  40. 2 1
      lib/Support/CMakeLists.txt
  41. 3 3
      lib/Support/ErrorHandling.cpp
  42. 34 0
      lib/Support/MSFileSystemBasic.cpp
  43. 1 0
      lib/Support/MemoryBuffer.cpp
  44. 93 4
      lib/Support/Unix/Path.inc
  45. 1 1
      lib/Support/Unix/Process.inc
  46. 13 0
      lib/Support/assert.cpp
  47. 4 1
      lib/Support/regerror.c
  48. 3 3
      lib/Support/regex_impl.h
  49. 2 0
      lib/Transforms/IPO/FunctionAttrs.cpp
  50. 7 1
      tools/CMakeLists.txt
  51. 1 0
      tools/clang/include/clang/AST/HlslTypes.h
  52. 6 0
      tools/clang/include/clang/Basic/Attr.td
  53. 1 0
      tools/clang/include/clang/Basic/TokenKinds.def
  54. 12 0
      tools/clang/include/clang/Basic/TokenKinds.h
  55. 2 0
      tools/clang/include/clang/Frontend/FrontendActions.h
  56. 2 1
      tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h
  57. 7 552
      tools/clang/include/clang/SPIRV/InstBuilder.h
  58. 6 0
      tools/clang/include/clang/SPIRV/ModuleBuilder.h
  59. 6 0
      tools/clang/include/clang/SPIRV/Structure.h
  60. 5 2
      tools/clang/include/clang/SPIRV/Type.h
  61. 1 1
      tools/clang/lib/AST/ItaniumMangle.cpp
  62. 8 1
      tools/clang/lib/Frontend/CompilerInvocation.cpp
  63. 1 2
      tools/clang/lib/Frontend/FrontendActions.cpp
  64. 4 0
      tools/clang/lib/Parse/HLSLRootSignature.cpp
  65. 43 6
      tools/clang/lib/Parse/ParseDecl.cpp
  66. 23 5
      tools/clang/lib/Parse/ParseExpr.cpp
  67. 19 0
      tools/clang/lib/Parse/ParseStmt.cpp
  68. 16 3
      tools/clang/lib/Parse/ParseTentative.cpp
  69. 27 6
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  70. 7 3
      tools/clang/lib/SPIRV/DeclResultIdMapper.h
  71. 266 342
      tools/clang/lib/SPIRV/InstBuilderAuto.cpp
  72. 30 1
      tools/clang/lib/SPIRV/InstBuilderManual.cpp
  73. 9 48
      tools/clang/lib/SPIRV/ModuleBuilder.cpp
  74. 138 37
      tools/clang/lib/SPIRV/SPIRVEmitter.cpp
  75. 14 3
      tools/clang/lib/SPIRV/SPIRVEmitter.h
  76. 38 1
      tools/clang/lib/SPIRV/Structure.cpp
  77. 7 5
      tools/clang/lib/SPIRV/Type.cpp
  78. 102 20
      tools/clang/lib/SPIRV/TypeTranslator.cpp
  79. 8 1
      tools/clang/lib/SPIRV/TypeTranslator.h
  80. 28 0
      tools/clang/lib/Sema/SemaHLSL.cpp
  81. 11 0
      tools/clang/test/CodeGenHLSL/quick-test/center_kwd.hlsl
  82. 13 0
      tools/clang/test/CodeGenHLSL/quick-test/matrix_return_sub2.hlsl
  83. 11 0
      tools/clang/test/CodeGenHLSL/quick-test/min10float.hlsl
  84. 21 0
      tools/clang/test/CodeGenHLSL/quick-test/min10float_to_float.hlsl
  85. 11 0
      tools/clang/test/CodeGenHLSL/quick-test/min12int.hlsl
  86. 21 0
      tools/clang/test/CodeGenHLSL/quick-test/min12int_to_int.hlsl
  87. 12 0
      tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test01.hlsl
  88. 14 0
      tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test02.hlsl
  89. 18 0
      tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test03.hlsl
  90. 12 0
      tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test04.hlsl
  91. 49 0
      tools/clang/test/CodeGenHLSL/quick-test/sample_kwd.hlsl
  92. 0 3
      tools/clang/test/CodeGenSPIRV/bezier.domain.hlsl2spv
  93. 0 3
      tools/clang/test/CodeGenSPIRV/bezier.hull.hlsl2spv
  94. 9 7
      tools/clang/test/CodeGenSPIRV/empty-struct-interface.vs.hlsl2spv
  95. 1 1
      tools/clang/test/CodeGenSPIRV/hs.pcf.primitive-id.1.hlsl
  96. 1 1
      tools/clang/test/CodeGenSPIRV/hs.pcf.view-id.1.hlsl
  97. 19 0
      tools/clang/test/CodeGenSPIRV/intrinsics.interlocked-methods.error.hlsl
  98. 33 0
      tools/clang/test/CodeGenSPIRV/op.buffer.access.hlsl
  99. 29 3
      tools/clang/test/CodeGenSPIRV/op.struct.access.hlsl
  100. 19 0
      tools/clang/test/CodeGenSPIRV/op.texture.access.hlsl

+ 78 - 0
.travis.yml

@@ -0,0 +1,78 @@
+# Linux Build Configuration for Travis
+
+language: cpp
+
+os:
+  - linux
+  - osx
+
+# Use Ubuntu 14.04 LTS (Trusty) as the Linux testing environment.
+sudo: required
+dist: trusty
+
+env:
+  - DXC_BUILD_TYPE=Release
+  - DXC_BUILD_TYPE=Debug
+
+compiler:
+  - clang
+
+matrix:
+  include:
+    - os: linux
+      compiler: gcc
+      addons:
+        apt:
+          sources: ubuntu-toolchain-r-test
+          packages: ninja-build g++-5
+      env: DXC_BUILD_TYPE=Debug
+    - os: linux
+      compiler: gcc
+      addons:
+        apt:
+          sources: ubuntu-toolchain-r-test
+          packages: ninja-build g++-5
+      env: DXC_BUILD_TYPE=Release
+  allow_failures:
+    - os: linux
+    - os: osx
+
+cache:
+  apt: true
+
+git:
+  depth: 1
+
+branches:
+  only:
+    - master
+
+addons:
+  apt:
+    packages:
+      - ninja-build
+
+before_install:
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja; fi
+
+before_script:
+  - git submodule update --init
+  - if [ ${CC} = gcc ]; then CC=gcc-5; CXX=g++-5; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ulimit -Sn 1024; fi
+
+script:
+  - mkdir build && cd build
+  - cmake .. -GNinja
+      $(cat ../utils/cmake-predefined-config-params)
+      -DSPIRV_BUILD_TESTS=ON
+      -DCMAKE_BUILD_TYPE=${DXC_BUILD_TYPE}
+      -DCMAKE_C_COMPILER=${CC} -DCMAKE_CXX_COMPILER=${CXX}
+  - ninja
+  - ./bin/dxc --help
+  - ./bin/dxc -T ps_6_0 ../tools/clang/test/CodeGenSPIRV/passthru-ps.hlsl2spv
+  - ./bin/dxc -T ps_6_0 -Fo passthru-ps.dxil ../tools/clang/test/CodeGenSPIRV/passthru-ps.hlsl2spv
+  - cmp passthru-ps.dxil ../tools/clang/test/CodeGenSPIRV/passthru-ps.${DXC_BUILD_TYPE}.dxil
+  - ./bin/dxc -T ps_6_0 -Fo passthru-ps.spv ../tools/clang/test/CodeGenSPIRV/passthru-ps.hlsl2spv -spirv
+  - cmp passthru-ps.spv ../tools/clang/test/CodeGenSPIRV/passthru-ps.spv
+  - ./bin/clang-spirv-tests --spirv-test-root ../tools/clang/test/CodeGenSPIRV/
+  - ./bin/clang-hlsl-tests --HlslDataDir $PWD/../tools/clang/test/HLSL/

+ 1 - 1
CMakeLists.txt

@@ -103,10 +103,10 @@ option(SPIRV_BUILD_TESTS "Build targets for the SPIR-V unit tests." OFF)
 # Enable SPIR-V CodeGen for Linux by default.
 if(NOT WIN32)
   set(ENABLE_SPIRV_CODEGEN ON)
-  set(SPIRV_BUILD_TESTS ON)
 endif()
 
 if (${SPIRV_BUILD_TESTS})
+  enable_testing()
   set(ENABLE_SPIRV_CODEGEN ON)
 endif()
 if (${ENABLE_SPIRV_CODEGEN})

+ 3 - 0
README.md

@@ -1,6 +1,7 @@
 # DirectX Shader Compiler
 
 [![Build status](https://ci.appveyor.com/api/projects/status/oaf66n7w30xbrg38/branch/master?svg=true)](https://ci.appveyor.com/project/antiagainst/directxshadercompiler/branch/master)
+[![Build Status](https://travis-ci.org/Microsoft/DirectXShaderCompiler.svg?branch=master)](https://travis-ci.org/Microsoft/DirectXShaderCompiler)
 
 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.
 
@@ -30,6 +31,8 @@ As an example of community contribution, this project can also target the [SPIR-
 
 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).
 
+Note: If you intend to build from sources on Linux/macOS, follow [these instructions](docs/DxcOnUnix.rst).
+
 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).

+ 148 - 0
docs/DxcOnUnix.rst

@@ -0,0 +1,148 @@
+======================================
+DirectXShaderCompiler on Linux & macOS
+======================================
+
+.. contents::
+   :local:
+   :depth: 3
+
+Introduction
+============
+
+DirectXShaderCompiler (DXC) is based on LLVM/Clang, which is originally
+cross-platform. However, to support HLSL, certain Windows specific techniques
+(like COM, SAL, etc.) are introduced to solve technical issues on the Windows
+platform, which also makes DXC not compilable/runnable on non-Windows platforms.
+
+Upon `several <https://github.com/Microsoft/DirectXShaderCompiler/issues/1082>`_
+`requests <https://github.com/Microsoft/DirectXShaderCompiler/issues/1236>`_
+from the community, we have started the effort to enable compilation and running
+of DXC on non-Windows platforms (Linux and macOS).
+
+Current Status
+==============
+
+Up and Running
+--------------
+We have currently reached the point where we can successfully build and run DXC
+on Linux and macOS. Code generation works for both DXIL and SPIR-V, and we are
+also able to fully run the SPIR-V CodeGen test suite on these platforms.
+
+*Note: This work is currently in experimental phase. How we implement certain
+things for Unix platforms may change without considering backward portability.*
+
+Known Limitations
+-----------------
+
+The following targets are currently disabled for non-Windows platforms and this
+is an area where further contributions can be made:
+
+* d3dcomp
+* dxa
+* dxopt
+* dxl
+* dxr
+* dxv
+* dxlib-sample
+
+Moreover, since the HLSL CodeGen tests were originally written with Windows in
+mind, they require the Windows-specific `TAEF Framework <https://docs.microsoft.com/en-us/windows-hardware/drivers/taef/>`_
+to run. Therefore we are not able to compile/run these tests on non-Windows
+platforms. Note that it is only the testing infrastructure that has this
+limitation, and DXIL CodeGen works as expected by running the DXC executable.
+
+Known Issues
+------------
+- Running the SPIR-V CodeGen tests results in opening a large number of file
+  descriptors, and if the OS limitation on the number of FDs allowed to be opened
+  by a process is low, it will cause test failures. We have not seen this as an
+  issue on Windows and Linux. On macOS we currently increase the allowed limit to
+  get around the problem for the time being.
+
+- The version number of the shared library is currently stuck at 3.7. We need to
+  fix this once a certain versioning scheme is in place.
+
+Building and Using
+==================
+
+Build Requirements
+------------------
+Please make sure you have the following resources before building:
+
+- `Git <https://git-scm.com/downloads>`_
+- `Python <https://www.python.org/downloads/>`_. Version 2.7.x is required, 3.x might work but it's not officially supported. 
+- `Ninja <https://github.com/ninja-build/ninja/releases>`_ (*Optional* CMake generator)
+- Either of gcc/g++ or clang/clang++ compilers. Minimum supported version:
+
+  - `GCC <https://gcc.gnu.org/releases.html>`_ version 5.5 or higher.
+  - `Clang <http://releases.llvm.org/>`_ version 3.8 or higher.
+
+
+Building DXC
+------------
+You can follow these steps to build DXC on Linux/macOS:
+
+.. code:: sh
+
+  cd <dxc-build-dir>
+  cmake <dxc-src-dir> -GNinja -DCMAKE_BUILD_TYPE=Release $(cat <dxc-src-dir>/utils/cmake-predefined-config-params)
+  ninja
+
+Note that ``cmake-predefined-config-params`` file contains several cmake
+configurations that are needed for successful compilation. You can further
+customize your build by adding configurations at the end of the cmake command
+above.
+
+For instance, you can use
+
+``-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++``
+
+or
+
+``-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++``
+
+to choose your desired C/C++ compiler.
+
+You should now have the dxc executable located at ``<dxc-build-dir>/bin/dxc``.
+And you should be able to successfully run commands as you would on Windows, e.g:
+
+.. code:: sh
+
+  ./bin/dxc -help
+  ./bin/dxc -T <target> -E <entry-point-name> <input-hlsl-file>
+
+Note that you cannot use slashes (``/``) for specifying command line options as
+you would on Windows. You should use dashes as per usual Unix style.
+
+Building and Running HLSL CodeGen Tests
+---------------------------------------
+As described in the `Known Limitations`_ section, we can not run these tests on
+non-Windows platforms due to their dependency on TAEF.
+
+Building and Running SPIR-V CodeGen Tests
+-----------------------------------------
+The SPIR-V CodeGen tests were written within the googletest framework, and can
+therefore be built and run on non-Windows platforms.
+
+You can follow these steps to build and run the SPIR-V CodeGen tests:
+
+.. code:: sh
+
+  cd <dxc-build-dir>
+  # Use SPIRV_BUILD_TESTS flag to enable building these tests.
+  cmake <dxc-src-dir> \
+    $(cat <dxc-src-dir>/utils/cmake-predefined-config-params) \
+    -DCMAKE_BUILD_TYPE=Release -DSPIRV_BUILD_TESTS=ON \
+    -GNinja
+  # Build all targets. Includes 'dxc' and tests.
+  ninja
+  # Run all tests
+  ctest
+
+
+As described in the `Known Issues`_ section above, you currently need to
+increase the maximum per-process open files on macOS using
+``ulimit -Sn 1024`` before running the tests on that platform.
+
+TODO: Add more information about Linux implementation details.
+

+ 29 - 9
docs/SPIR-V.rst

@@ -248,6 +248,9 @@ The namespace ``vk`` will be used for all Vulkan attributes:
 - ``push_constant``: For marking a variable as the push constant block. Allowed
   on global variables of struct type. At most one variable can be marked as
   ``push_constant`` in a shader.
+- ``offset(X)``: For manually layout struct members. Annotating a struct member
+  with this attribute will force the compiler to put the member at offset ``X``
+  w.r.t. the beginning of the struct. Only allowed on struct members.
 - ``constant_id(X)``: For marking a global constant as a specialization constant.
   Allowed on global variables of boolean/integer/float types.
 - ``input_attachment_index(X)``: To associate the Xth entry in the input pass
@@ -713,6 +716,21 @@ We will have the following offsets for each member:
 ``g_float2_2``   160    160    176    112    88    128
 ============== ====== ====== ====== ====== ====== ======
 
+If the above layout rules do not satisfy your needs and you want to manually
+control the layout of struct members, you can use either
+
+* The native HLSL ``:packoffset()`` attribute: only available for cbuffers; or
+* The Vulkan-specific ``[[vk::offset()]]`` attribute: applies to all resources.
+
+``[[vk::offset]]`` overrules ``:packoffset``. Attaching ``[[vk::offset]]``
+to a struct memeber affects all variables of the struct type in question. So
+sharing the same struct definition having ``[[vk::offset]]`` annotations means
+also sharing the layout.
+
+These attributes give great flexibility but also responsibility to the
+developer; the compiler will just take in what is specified in the source code
+and emit it to SPIR-V with no error checking.
+
 ``cbuffer`` and ``ConstantBuffer``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2262,8 +2280,8 @@ parameter is attached to the instruction as the parameter to the ``Lod`` SPIR-V
 image operands. The ``position`` parameter are used as the coordinate to the
 instruction directly.
 
-``.CalculateLevelOfDetail()``
-+++++++++++++++++++++++++++++
+``.CalculateLevelOfDetail()`` and ``.CalculateLevelOfDetailUnclamped()``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
 
@@ -2272,7 +2290,7 @@ instruction is used for translation. An ``OpSampledImage`` is created based on
 the ``SamplerState`` passed to the function. The resulting sampled image and
 the coordinate passed to the function are used to invoke ``OpImageQueryLod``.
 The result of ``OpImageQueryLod`` is a ``float2``. The first element contains
-the mipmap array layer.
+the mipmap array layer. The second element contains the unclamped level of detail.
 
 ``Texture1D``
 ~~~~~~~~~~~~~
@@ -2698,9 +2716,14 @@ codegen for Vulkan:
 - ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
   layout rules for resources.
 - ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
-- ``-fvk-invert-y``: Inverts SV_Position.y before writing to stage output.
-  Used to accommodate the difference between Vulkan's coordinate system and
-  DirectX's. Only allowed in VS/DS/GS.
+- ``-fvk-invert-y``: Negates (additively inverts) SV_Position.y before writing
+  to stage output. Used to accommodate the difference between Vulkan's
+  coordinate system and DirectX's. Only allowed in VS/DS/GS.
+- ``-fvk-use-dx-position-w``: Reciprocates (multiplicatively inverts)
+  SV_Position.w after reading from stage input. Used to accommodate the
+  difference between Vulkan DirectX: the w component of SV_Position in PS is
+  stored as 1/w in Vulkan. Only recognized in PS; applying to other stages
+  is no-op.
 - ``-fvk-stage-io-order={alpha|decl}``: Assigns the stage input/output variable
   location number according to alphabetical order or declaration order. See
   `HLSL semantic and Vulkan Location`_ for more details.
@@ -2735,9 +2758,6 @@ either because of no Vulkan equivalents at the moment, or because of deprecation
 * ``.GatherCmpGreen()``, ``.GatherCmpBlue()``, ``.GatherCmpAlpha()`` intrinsic
   method: no Vulkan equivalent. (SPIR-V ``OpImageDrefGather`` instruction does
   not take component as input.) The compiler will emit an error.
-* ``.CalculateLevelOfDetailUnclamped()`` intrinsic method: no Vulkan equivalent.
-  (SPIR-V ``OpImageQueryLod`` returns the clamped LOD in Vulkan.) The compiler
-  will emit an error.
 * Since ``StructuredBuffer``, ``RWStructuredBuffer``, ``ByteAddressBuffer``, and
   ``RWByteAddressBuffer`` are not represented as image types in SPIR-V, using the
   output unsigned integer ``status`` argument in their ``Load*`` methods is not

+ 1 - 1
external/SPIRV-Headers

@@ -1 +1 @@
-Subproject commit 87a720a5a7ba8fb2ede50fef57e5d936e5e45e97
+Subproject commit ff684ffc6a35d2a58f0f63108877d0064ea33feb

+ 1 - 1
external/SPIRV-Tools

@@ -1 +1 @@
-Subproject commit f80696eaf64298ab60e545086a6a5ab8be2c5ac1
+Subproject commit 208921efe813b457ee909693a270233fbb012987

+ 0 - 2
include/dxc/Support/Global.h

@@ -60,8 +60,6 @@ IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMalloc, IMalloc **ppPrior) throw
 
 // Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
 IMalloc *DxcGetThreadMallocNoRef() throw();
-_Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw();
-void DxcThreadFree(void *) throw();
 
 struct DxcThreadMalloc {
   DxcThreadMalloc(IMalloc *pMallocOrNull) throw() {

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

@@ -165,6 +165,7 @@ public:
 #ifdef ENABLE_SPIRV_CODEGEN
   bool GenSPIRV;                           // OPT_spirv
   bool VkInvertY;                          // OPT_fvk_invert_y
+  bool VkInvertW;                          // OPT_fvk_use_dx_position_w
   bool VkUseGlLayout;                      // OPT_fvk_use_gl_layout
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect
@@ -189,6 +190,7 @@ public:
 
   MainArgs() = default;
   MainArgs(int argc, const wchar_t **argv, int skipArgCount = 1);
+  MainArgs(int argc, const char **argv, int skipArgCount = 1);
   MainArgs(llvm::ArrayRef<llvm::StringRef> args);
   MainArgs& operator=(const MainArgs &other);
   llvm::ArrayRef<const char *> getArrayRef() const {

+ 3 - 1
include/dxc/Support/HLSLOptions.td

@@ -253,7 +253,9 @@ def fvk_s_shift : MultiArg<["-"], "fvk-s-shift", 2>, MetaVarName<"<shift> <space
 def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Specify Vulkan binding number shift for u-type register">;
 def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
-  HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
+  HelpText<"Negate SV_Position.y before writing to stage output in VS/DS/GS to accommodate Vulkan's coordinate system">;
+def fvk_use_dx_position_w: Flag<["-"], "fvk-use-dx-position-w">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Reciprocate SV_Position.w after reading from stage input in PS to accommodate the difference between Vulkan and DirectX">;
 def fvk_use_gl_layout: Flag<["-"], "fvk-use-gl-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Use strict OpenGL std140/std430 memory layout for Vulkan resources">;
 def fvk_use_dx_layout: Flag<["-"], "fvk-use-dx-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,

+ 19 - 0
include/dxc/Support/Unicode.h

@@ -12,7 +12,26 @@
 #pragma once
 
 #include <string>
+
+#ifdef _WIN32
 #include <specstrings.h>
+#else
+// MultiByteToWideChar which is a Windows-specific method.
+// This is a very simplistic implementation for non-Windows platforms. This
+// implementation completely ignores CodePage and dwFlags.
+int MultiByteToWideChar(uint32_t CodePage, uint32_t dwFlags,
+                        const char *lpMultiByteStr, int cbMultiByte,
+                        wchar_t *lpWideCharStr, int cchWideChar);
+
+// WideCharToMultiByte is a Windows-specific method.
+// This is a very simplistic implementation for non-Windows platforms. This
+// implementation completely ignores CodePage and dwFlags.
+int WideCharToMultiByte(uint32_t CodePage, uint32_t dwFlags,
+                        const wchar_t *lpWideCharStr, int cchWideChar,
+                        char *lpMultiByteStr, int cbMultiByte,
+                        const char *lpDefaultChar = nullptr,
+                        bool *lpUsedDefaultChar = nullptr);
+#endif // _WIN32
 
 namespace Unicode
 {

+ 472 - 6
include/dxc/Support/WinAdapter.h

@@ -32,6 +32,7 @@
 #include <typeinfo>
 #include <vector>
 #endif // __cplusplus
+#include <execinfo.h>
 
 //===----------------------------------------------------------------------===//
 //
@@ -41,11 +42,18 @@
 #define C_ASSERT(expr) static_assert((expr), "")
 #define ATLASSERT assert
 
+#define CoTaskMemAlloc malloc
+#define CoTaskMemFree free
+
+#define SysFreeString free
+#define SysAllocStringLen(ptr, size) (wchar_t*)realloc(ptr, (size + 1)*sizeof(wchar_t))
+
 #define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0]))
 
 #define _countof(a) (sizeof(a) / sizeof(*(a)))
 
 #define __declspec(x)
+#define DECLSPEC_SELECTANY
 
 #define uuid(id)
 
@@ -94,13 +102,17 @@
 
 // Map these errors to equivalent errnos.
 #define ERROR_SUCCESS 0L
-#define ERROR_OUT_OF_STRUCTURES ENOMEM
-#define ERROR_UNHANDLED_EXCEPTION EINTR
-#define ERROR_NOT_FOUND ENOTSUP
-#define ERROR_NOT_CAPABLE EPERM
+#define ERROR_ARITHMETIC_OVERFLOW EOVERFLOW
 #define ERROR_FILE_NOT_FOUND ENOENT
+#define ERROR_FUNCTION_NOT_CALLED ENOSYS
 #define ERROR_IO_DEVICE EIO
+#define ERROR_INSUFFICIENT_BUFFER ENOBUFS
 #define ERROR_INVALID_HANDLE EBADF
+#define ERROR_INVALID_PARAMETER EINVAL
+#define ERROR_OUT_OF_STRUCTURES ENOMEM
+#define ERROR_NOT_CAPABLE EPERM
+#define ERROR_NOT_FOUND ENOTSUP
+#define ERROR_UNHANDLED_EXCEPTION EINTR
 
 // Used by HRESULT <--> WIN32 error code conversion
 #define SEVERITY_ERROR 1
@@ -137,21 +149,47 @@
 #define STREAM_SEEK_CUR 1
 #define STREAM_SEEK_END 2
 
-#define HEAP_NO_SERIALIZE 1
+#define HEAP_NO_SERIALIZE 0x1
+#define HEAP_ZERO_MEMORY 0x8
 
 #define MB_ERR_INVALID_CHARS 0x00000008 // error for invalid chars
 
+// File IO
+
+#define CREATE_ALWAYS 2
+#define CREATE_NEW 1
+#define OPEN_ALWAYS 4
+#define OPEN_EXISTING 3
+#define TRUNCATE_EXISTING 5
+
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+
+#define GENERIC_READ 0x80000000
+#define GENERIC_WRITE 0x40000000
+
 #define _atoi64 atoll
 #define sprintf_s snprintf
 #define _strdup strdup
+
 #define vsprintf_s vsprintf
 #define strcat_s strcat
+#define strcpy_s(dst, n, src) strncpy(dst, src, n)
+#define _vscwprintf vwprintf
+#define vswprintf_s vswprintf
+#define swprintf_s swprintf
+
+#define StringCchCopyW(dst, n, src) wcsncpy(dst, src, n)
 
 #define OutputDebugStringW(msg) fputws(msg, stderr)
 
 #define OutputDebugStringA(msg) fputs(msg, stderr)
 #define OutputDebugFormatA(...) fprintf(stderr, __VA_ARGS__)
 
+#define CaptureStackBackTrace(FramesToSkip, FramesToCapture, BackTrace, BackTraceHash)\
+  backtrace(BackTrace, FramesToCapture)
+
 // Event Tracing for Windows (ETW) provides application programmers the ability
 // to start and stop event tracing sessions, instrument an application to
 // provide trace events, and consume trace events.
@@ -216,6 +254,7 @@
 
 #define _Out_
 #define _Out_bytecap_(nbytes)
+#define _Out_writes_to_(a, b)
 #define _Out_writes_to_opt_(a, b)
 #define _Outptr_
 #define _Outptr_opt_
@@ -370,6 +409,22 @@ typedef void *HMODULE;
 #define STD_OUTPUT_HANDLE ((DWORD)-11)
 #define STD_ERROR_HANDLE ((DWORD)-12)
 
+//===--------------------- ID Types and Macros for COM --------------------===//
+
+struct GUID {
+  uint32_t Data1;
+  uint16_t Data2;
+  uint16_t Data3;
+  uint8_t Data4[8];
+};
+typedef GUID CLSID;
+typedef const GUID &REFGUID;
+typedef const void *REFIID;
+typedef const GUID &REFCLSID;
+
+#define IsEqualIID(a, b) a == b
+#define IsEqualCLSID(a, b) !memcmp(&a, &b, sizeof(GUID))
+
 //===--------------------- Struct Types -----------------------------------===//
 
 typedef struct _FILETIME {
@@ -444,7 +499,418 @@ enum tagSTATFLAG {
   STATFLAG_NOOPEN = 2
 };
 
-// TODO: More definitions will be added here.
+//===--------------------- UUID Related Macros ----------------------------===//
+
+// The following macros are defined to facilitate the lack of 'uuid' on Linux.
+#define DECLARE_CROSS_PLATFORM_UUIDOF(T)                                       \
+public:                                                                        \
+  static REFIID uuidof() { return static_cast<REFIID>(&T##_ID); }              \
+                                                                               \
+private:                                                                       \
+  static const char T##_ID;
+
+#define DEFINE_CROSS_PLATFORM_UUIDOF(T) const char T::T##_ID = '\0';
+#define __uuidof(T) T::uuidof()
+#define IID_PPV_ARGS(ppType)                                                   \
+  (**(ppType)).uuidof(), reinterpret_cast<void **>(ppType)
+
+//===--------------------- COM Interfaces ---------------------------------===//
+
+struct IUnknown {
+  virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
+  virtual ULONG AddRef();
+  virtual ULONG Release();
+  virtual ~IUnknown();
+  template <class Q> HRESULT QueryInterface(Q **pp) {
+    return QueryInterface(__uuidof(Q), (void **)pp);
+  }
+
+private:
+  std::atomic<unsigned long> m_count;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IUnknown)
+};
+
+struct INoMarshal : public IUnknown {
+  DECLARE_CROSS_PLATFORM_UUIDOF(INoMarshal)
+};
+
+struct IMalloc : public IUnknown {
+  virtual void *Alloc(size_t size);
+  virtual void *Realloc(void *ptr, size_t size);
+  virtual void Free(void *ptr);
+  virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
+};
+
+struct ISequentialStream : public IUnknown {
+  virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
+  virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
+};
+
+struct IStream : public ISequentialStream {
+  virtual HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
+                       ULARGE_INTEGER *plibNewPosition) = 0;
+  virtual HRESULT SetSize(ULARGE_INTEGER libNewSize) = 0;
+  virtual HRESULT CopyTo(IStream *pstm, ULARGE_INTEGER cb,
+                         ULARGE_INTEGER *pcbRead,
+                         ULARGE_INTEGER *pcbWritten) = 0;
+
+  virtual HRESULT Commit(DWORD grfCommitFlags) = 0;
+
+  virtual HRESULT Revert(void) = 0;
+
+  virtual HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+                             DWORD dwLockType) = 0;
+
+  virtual HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+                               DWORD dwLockType) = 0;
+
+  virtual HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag) = 0;
+
+  virtual HRESULT Clone(IStream **ppstm) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IStream)
+};
+
+//===--------------------- COM Pointer Types ------------------------------===//
+
+class CAllocator {
+public:
+  static void *Reallocate(void *p, size_t nBytes) throw();
+  static void *Allocate(size_t nBytes) throw();
+  static void Free(void *p) throw();
+};
+
+template <class T> class CComPtrBase {
+protected:
+  CComPtrBase() throw() { p = nullptr; }
+  CComPtrBase(T *lp) throw() {
+    p = lp;
+    if (p != nullptr)
+      p->AddRef();
+  }
+  void Swap(CComPtrBase &other) {
+    T *pTemp = p;
+    p = other.p;
+    other.p = pTemp;
+  }
+
+public:
+  ~CComPtrBase() throw() {
+    if (p) {
+      p->Release();
+      p = nullptr;
+    }
+  }
+  operator T *() const throw() { return p; }
+  T &operator*() const { return *p; }
+  T *operator->() const { return p; }
+  T **operator&() throw() {
+    assert(p == nullptr);
+    return &p;
+  }
+  bool operator!() const throw() { return (p == nullptr); }
+  bool operator<(T *pT) const throw() { return p < pT; }
+  bool operator!=(T *pT) const { return !operator==(pT); }
+  bool operator==(T *pT) const throw() { return p == pT; }
+
+  // Release the interface and set to nullptr
+  void Release() throw() {
+    T *pTemp = p;
+    if (pTemp) {
+      p = nullptr;
+      pTemp->Release();
+    }
+  }
+
+  // Attach to an existing interface (does not AddRef)
+  void Attach(T *p2) throw() {
+    if (p) {
+      ULONG ref = p->Release();
+      (void)(ref);
+      // Attaching to the same object only works if duplicate references are
+      // being coalesced.  Otherwise re-attaching will cause the pointer to be
+      // released and may cause a crash on a subsequent dereference.
+      assert(ref != 0 || p2 != p);
+    }
+    p = p2;
+  }
+
+  // Detach the interface (does not Release)
+  T *Detach() throw() {
+    T *pt = p;
+    p = nullptr;
+    return pt;
+  }
+
+  HRESULT CopyTo(T **ppT) throw() {
+    assert(ppT != nullptr);
+    if (ppT == nullptr)
+      return E_POINTER;
+    *ppT = p;
+    if (p)
+      p->AddRef();
+    return S_OK;
+  }
+
+  template <class Q> HRESULT QueryInterface(Q **pp) const throw() {
+    assert(pp != nullptr);
+    return p->QueryInterface(__uuidof(Q), (void **)pp);
+  }
+
+  T *p;
+};
+
+template <class T> class CComPtr : public CComPtrBase<T> {
+public:
+  CComPtr() throw() {}
+  CComPtr(T *lp) throw() : CComPtrBase<T>(lp) {}
+  CComPtr(const CComPtr<T> &lp) throw() : CComPtrBase<T>(lp.p) {}
+  T *operator=(T *lp) throw() {
+    if (*this != lp) {
+      CComPtr(lp).Swap(*this);
+    }
+    return *this;
+  }
+
+  inline bool IsEqualObject(IUnknown *pOther) throw() {
+    if (this->p == nullptr && pOther == nullptr)
+      return true; // They are both NULL objects
+
+    if (this->p == nullptr || pOther == nullptr)
+      return false; // One is NULL the other is not
+
+    CComPtr<IUnknown> punk1;
+    CComPtr<IUnknown> punk2;
+    this->p->QueryInterface(__uuidof(IUnknown), (void **)&punk1);
+    pOther->QueryInterface(__uuidof(IUnknown), (void **)&punk2);
+    return punk1 == punk2;
+  }
+
+  void ComPtrAssign(IUnknown **pp, IUnknown *lp, REFIID riid) {
+    IUnknown *pTemp = *pp; // takes ownership
+    if (lp == nullptr || FAILED(lp->QueryInterface(riid, (void **)pp)))
+      *pp = nullptr;
+    if (pTemp)
+      pTemp->Release();
+  }
+
+  template <typename Q> T *operator=(const CComPtr<Q> &lp) throw() {
+    if (!this->IsEqualObject(lp)) {
+      ComPtrAssign((IUnknown **)&this->p, lp, __uuidof(T));
+    }
+    return *this;
+  }
+
+  T *operator=(const CComPtr<T> &lp) throw() {
+    if (*this != lp) {
+      CComPtr(lp).Swap(*this);
+    }
+    return *this;
+  }
+
+  CComPtr(CComPtr<T> &&lp) throw() : CComPtrBase<T>() { lp.Swap(*this); }
+
+  T *operator=(CComPtr<T> &&lp) throw() {
+    if (*this != lp) {
+      CComPtr(static_cast<CComPtr &&>(lp)).Swap(*this);
+    }
+    return *this;
+  }
+};
+
+template <class T> class CSimpleArray : public std::vector<T> {
+public:
+  bool Add(const T &t) {
+    this->push_back(t);
+    return true;
+  }
+  int GetSize() { return this->size(); }
+  T *GetData() { return this->data(); }
+  void RemoveAll() { this->clear(); }
+};
+
+template <class T, class Allocator = CAllocator> class CHeapPtrBase {
+protected:
+  CHeapPtrBase() throw() : m_pData(NULL) {}
+  CHeapPtrBase(CHeapPtrBase<T, Allocator> &p) throw() {
+    m_pData = p.Detach(); // Transfer ownership
+  }
+  explicit CHeapPtrBase(T *pData) throw() : m_pData(pData) {}
+
+public:
+  ~CHeapPtrBase() throw() { Free(); }
+
+protected:
+  CHeapPtrBase<T, Allocator> &operator=(CHeapPtrBase<T, Allocator> &p) throw() {
+    if (m_pData != p.m_pData)
+      Attach(p.Detach()); // Transfer ownership
+    return *this;
+  }
+
+public:
+  operator T *() const throw() { return m_pData; }
+  T *operator->() const throw() {
+    assert(m_pData != NULL);
+    return m_pData;
+  }
+
+  T **operator&() throw() {
+    assert(m_pData == NULL);
+    return &m_pData;
+  }
+
+  // Allocate a buffer with the given number of bytes
+  bool AllocateBytes(size_t nBytes) throw() {
+    assert(m_pData == NULL);
+    m_pData = static_cast<T *>(Allocator::Allocate(nBytes * sizeof(char)));
+    if (m_pData == NULL)
+      return false;
+
+    return true;
+  }
+
+  // Attach to an existing pointer (takes ownership)
+  void Attach(T *pData) throw() {
+    Allocator::Free(m_pData);
+    m_pData = pData;
+  }
+
+  // Detach the pointer (releases ownership)
+  T *Detach() throw() {
+    T *pTemp = m_pData;
+    m_pData = NULL;
+    return pTemp;
+  }
+
+  // Free the memory pointed to, and set the pointer to NULL
+  void Free() throw() {
+    Allocator::Free(m_pData);
+    m_pData = NULL;
+  }
+
+  // Reallocate the buffer to hold a given number of bytes
+  bool ReallocateBytes(size_t nBytes) throw() {
+    T *pNew;
+    pNew =
+        static_cast<T *>(Allocator::Reallocate(m_pData, nBytes * sizeof(char)));
+    if (pNew == NULL)
+      return false;
+    m_pData = pNew;
+
+    return true;
+  }
+
+public:
+  T *m_pData;
+};
+
+template <typename T, class Allocator = CAllocator>
+class CHeapPtr : public CHeapPtrBase<T, Allocator> {
+public:
+  CHeapPtr() throw() {}
+  CHeapPtr(CHeapPtr<T, Allocator> &p) throw() : CHeapPtrBase<T, Allocator>(p) {}
+  explicit CHeapPtr(T *p) throw() : CHeapPtrBase<T, Allocator>(p) {}
+  CHeapPtr<T> &operator=(CHeapPtr<T, Allocator> &p) throw() {
+    CHeapPtrBase<T, Allocator>::operator=(p);
+    return *this;
+  }
+
+  // Allocate a buffer with the given number of elements
+  bool Allocate(size_t nElements = 1) throw() {
+    size_t nBytes = nElements * sizeof(T);
+    return this->AllocateBytes(nBytes);
+  }
+
+  // Reallocate the buffer to hold a given number of elements
+  bool Reallocate(size_t nElements) throw() {
+    size_t nBytes = nElements * sizeof(T);
+    return this->ReallocateBytes(nBytes);
+  }
+};
+
+#define CComHeapPtr CHeapPtr
+
+//===--------------------- UTF-8 Related Types ----------------------------===//
+
+// Code Page
+#define CP_ACP 0
+#define CP_UTF8 65001 // UTF-8 translation.
+
+// The t_nBufferLength parameter is part of the published interface, but not
+// used here.
+template <int t_nBufferLength = 128> class CW2AEX {
+public:
+  CW2AEX(LPCWSTR psz, UINT nCodePage = CP_UTF8) {
+    if (nCodePage != CP_UTF8) {
+      // Current Implementation only supports CP_UTF8
+      assert(false && "CW2AEX implementation for Linux does not handle "
+                      "non-UTF8 code pages");
+      return;
+    }
+
+    if (!psz) {
+      m_psz = NULL;
+      return;
+    }
+
+    int len = (wcslen(psz) + 1) * 4;
+    m_psz = new char[len];
+    std::wcstombs(m_psz, psz, len);
+  }
+
+  ~CW2AEX() { delete[] m_psz; }
+
+  operator LPSTR() const { return m_psz; }
+
+  char *m_psz;
+};
+typedef CW2AEX<> CW2A;
+
+// The t_nBufferLength parameter is part of the published interface, but not
+// used here.
+template <int t_nBufferLength = 128> class CA2WEX {
+public:
+  CA2WEX(LPCSTR psz, UINT nCodePage = CP_UTF8) {
+    if (nCodePage != CP_UTF8) {
+      // Current Implementation only supports CP_UTF8
+      assert(false && "CA2WEX implementation for Linux does not handle "
+                      "non-UTF8 code pages");
+      return;
+    }
+
+    if (!psz) {
+      m_psz = NULL;
+      return;
+    }
+
+    int len = strlen(psz) + 1;
+    m_psz = new wchar_t[len];
+    std::mbstowcs(m_psz, psz, len);
+  }
+
+  ~CA2WEX() { delete[] m_psz; }
+
+  operator LPWSTR() const { return m_psz; }
+
+  wchar_t *m_psz;
+};
+
+typedef CA2WEX<> CA2W;
+
+//===--------- File IO Related Types ----------------===//
+
+class CHandle {
+public:
+  CHandle(HANDLE h);
+  ~CHandle();
+  operator HANDLE() const throw();
+
+private:
+  HANDLE m_h;
+};
 
 #endif // __cplusplus
 

+ 70 - 0
include/dxc/Support/WinFunctions.h

@@ -0,0 +1,70 @@
+//===-- WinFunctions.h - Windows Functions for other platforms --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Windows-specific functions used in the codebase for
+// non-Windows platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WINFUNCTIONS_H
+#define LLVM_SUPPORT_WINFUNCTIONS_H
+
+#ifndef _WIN32
+
+#include "dxc/Support/WinAdapter.h"
+
+HRESULT StringCchCopyEx(LPSTR pszDest, size_t cchDest, LPCSTR pszSrc,
+                        LPSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags);
+HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...);
+HRESULT UIntAdd(UINT uAugend, UINT uAddend, UINT *puResult);
+HRESULT IntToUInt(int in, UINT *out);
+HRESULT SizeTToInt(size_t in, INT *out);
+HRESULT UInt32Mult(UINT a, UINT b, UINT *out);
+int _stricmp(const char *str1, const char *str2);
+int _wcsicmp(const wchar_t *str1, const wchar_t *str2);
+int _wcsnicmp(const wchar_t *str1, const wchar_t *str2, size_t n);
+int wsprintf(wchar_t *wcs, const wchar_t *fmt, ...);
+unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
+HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc);
+
+HANDLE CreateFile2(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition,
+                   _In_opt_ void *pCreateExParams);
+
+HANDLE CreateFileW(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_opt_ void *lpSecurityAttributes,
+                   _In_ DWORD dwCreationDisposition,
+                   _In_ DWORD dwFlagsAndAttributes,
+                   _In_opt_ HANDLE hTemplateFile);
+
+BOOL GetFileSizeEx(_In_ HANDLE hFile, _Out_ PLARGE_INTEGER lpFileSize);
+
+BOOL ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer,
+              _In_ DWORD nNumberOfBytesToRead,
+              _Out_opt_ LPDWORD lpNumberOfBytesRead,
+              _Inout_opt_ void *lpOverlapped);
+BOOL WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer,
+               _In_ DWORD nNumberOfBytesToWrite,
+               _Out_opt_ LPDWORD lpNumberOfBytesWritten,
+               _Inout_opt_ void *lpOverlapped);
+
+BOOL CloseHandle(_In_ HANDLE hObject);
+
+// Windows-specific heap functions
+HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize , SIZE_T dwMaximumSize);
+BOOL HeapDestroy(HANDLE heap);
+LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T nBytes);
+LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
+BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
+SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
+HANDLE GetProcessHeap();
+
+#endif // _WIN32
+
+#endif // LLVM_SUPPORT_WINFUNCTIONS_H

+ 56 - 0
include/dxc/Support/WinIncludes.h

@@ -10,6 +10,8 @@
 
 #pragma once
 
+#ifdef _MSC_VER
+
 #define NOATOM 1
 #define NOGDICAPMASKS 1
 #define NOMETAFILE 1
@@ -46,3 +48,57 @@ template <class T> void swap(CComHeapPtr<T> &a, CComHeapPtr<T> &b) {
   a.m_pData = b.m_pData;
   b.m_pData = c;
 }
+
+#else // _MSC_VER
+
+#include "dxc/Support/WinAdapter.h"
+
+#ifdef __cplusplus
+// Define operator overloads to enable bit operations on enum values that are
+// used to define flags. Use DEFINE_ENUM_FLAG_OPERATORS(YOUR_TYPE) to enable these
+// operators on YOUR_TYPE.
+extern "C++" {
+    template <size_t S>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE;
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<1>
+    {
+        typedef int8_t type;
+    };
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<2>
+    {
+        typedef int16_t type;
+    };
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<4>
+    {
+        typedef int32_t type;
+    };
+
+    // used as an approximation of std::underlying_type<T>
+    template <class T>
+    struct _ENUM_FLAG_SIZED_INTEGER
+    {
+        typedef typename _ENUM_FLAG_INTEGER_FOR_SIZE<sizeof(T)>::type type;
+    };
+
+}
+#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
+extern "C++" { \
+inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) | ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) |= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) & ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) &= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE operator ~ (ENUMTYPE a) { return ENUMTYPE(~((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a)); } \
+inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) ^ ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) ^= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+}
+#else
+#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) // NOP, C allows these operators.
+#endif
+
+#endif // _MSC_VER

+ 25 - 20
include/dxc/Support/dxcapi.use.h

@@ -13,27 +13,27 @@
 #define __DXCAPI_USE_H__
 
 #include "dxc/dxcapi.h"
+#include "llvm/Support/DynamicLibrary.h"
 
 namespace dxc {
 
 // Helper class to dynamically load the dxcompiler or a compatible libraries.
 class DxcDllSupport {
 protected:
-  HMODULE m_dll;
+  using DynamicLibrary = llvm::sys::DynamicLibrary;
+  DynamicLibrary m_dll;
   DxcCreateInstanceProc m_createFn;
   DxcCreateInstance2Proc m_createFn2;
 
   HRESULT InitializeInternal(LPCWSTR dllName, LPCSTR fnName) {
-    if (m_dll != nullptr) return S_OK;
-    m_dll = LoadLibraryW(dllName);
-
-    if (m_dll == nullptr) return HRESULT_FROM_WIN32(GetLastError());
-    m_createFn = (DxcCreateInstanceProc)GetProcAddress(m_dll, fnName);
+    if (m_dll.isValid()) return S_OK;
+    m_dll = DynamicLibrary::getPermanentLibrary(CW2A(dllName));
+    if (!m_dll.isValid()) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    m_createFn = (DxcCreateInstanceProc)m_dll.getAddressOfSymbol(fnName);
 
     if (m_createFn == nullptr) {
       HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
-      FreeLibrary(m_dll);
-      m_dll = nullptr;
+      m_dll = DynamicLibrary();
       return hr;
     }
 
@@ -45,18 +45,18 @@ protected:
       memcpy(fnName2, fnName, s);
       fnName2[s] = '2';
       fnName2[s + 1] = '\0';
-      m_createFn2 = (DxcCreateInstance2Proc)GetProcAddress(m_dll, fnName2);
+      m_createFn2 = (DxcCreateInstance2Proc)m_dll.getAddressOfSymbol(fnName2);
     }
 
     return S_OK;
   }
 
 public:
-  DxcDllSupport() : m_dll(nullptr), m_createFn(nullptr), m_createFn2(nullptr) {
+  DxcDllSupport() : m_dll(), m_createFn(nullptr), m_createFn2(nullptr) {
   }
 
   DxcDllSupport(DxcDllSupport&& other) {
-    m_dll = other.m_dll; other.m_dll = nullptr;
+    m_dll = other.m_dll; other.m_dll = DynamicLibrary();
     m_createFn = other.m_createFn; other.m_createFn = nullptr;
     m_createFn2 = other.m_createFn2; other.m_createFn2 = nullptr;
   }
@@ -66,7 +66,13 @@ public:
   }
 
   HRESULT Initialize() {
+    #ifdef _WIN32
     return InitializeInternal(L"dxcompiler.dll", "DxcCreateInstance");
+    #elif __APPLE__
+    return InitializeInternal(L"libdxcompiler.dylib", "DxcCreateInstance");
+    #else
+    return InitializeInternal(L"libdxcompiler.so", "DxcCreateInstance");
+    #endif
   }
 
   HRESULT InitializeForDll(_In_z_ const wchar_t* dll, _In_z_ const char* entryPoint) {
@@ -80,7 +86,7 @@ public:
 
   HRESULT CreateInstance(REFCLSID clsid, REFIID riid, _Outptr_ IUnknown **pResult) {
     if (pResult == nullptr) return E_POINTER;
-    if (m_dll == nullptr) return E_FAIL;
+    if (!m_dll.isValid()) return E_FAIL;
     HRESULT hr = m_createFn(clsid, riid, (LPVOID*)pResult);
     return hr;
   }
@@ -92,7 +98,7 @@ public:
 
   HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid, REFIID riid, _Outptr_ IUnknown **pResult) {
     if (pResult == nullptr) return E_POINTER;
-    if (m_dll == nullptr) return E_FAIL;
+    if (!m_dll.isValid()) return E_FAIL;
     if (m_createFn2 == nullptr) return E_FAIL;
     HRESULT hr = m_createFn2(pMalloc, clsid, riid, (LPVOID*)pResult);
     return hr;
@@ -103,21 +109,20 @@ public:
   }
 
   bool IsEnabled() const {
-    return m_dll != nullptr;
+    return m_dll.isValid();
   }
 
   void Cleanup() {
-    if (m_dll != nullptr) {
+    if (m_dll.isValid()) {
       m_createFn = nullptr;
       m_createFn2 = nullptr;
-      FreeLibrary(m_dll);
-      m_dll = nullptr;
+      m_dll = DynamicLibrary();
     }
   }
 
-  HMODULE Detach() {
-    HMODULE module = m_dll;
-    m_dll = nullptr;
+  DynamicLibrary Detach() {
+    DynamicLibrary module = m_dll;
+    m_dll = DynamicLibrary();
     return module;
   }
 };

+ 62 - 10
include/dxc/dxcapi.h

@@ -17,11 +17,16 @@
 #define DXC_API_IMPORT __declspec(dllimport)
 #endif
 
-#ifndef _WIN32
+#ifdef _WIN32
+#define DECLARE_CROSS_PLATFORM_UUIDOF(T)
+#define DEFINE_CROSS_PLATFORM_UUIDOF(T)
+#else
+#include <dlfcn.h>
 #include "dxc/Support/WinAdapter.h"
 #endif
 
 struct IMalloc;
+
 struct IDxcIncludeHandler;
 
 /// <summary>
@@ -71,12 +76,19 @@ typedef HRESULT(__stdcall *DxcCreateInstance2Proc)(
 /// <remarks>
 /// While this function is similar to CoCreateInstance, there is no COM involvement.
 /// </remarks>
+
+#ifndef _MSC_VER
+extern "C"
+#endif
 DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance(
   _In_ REFCLSID   rclsid,
   _In_ REFIID     riid,
   _Out_ LPVOID*   ppv
   );
 
+#ifndef _MSC_VER
+extern "C"
+#endif
 DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance2(
   _In_ IMalloc    *pMalloc,
   _In_ REFCLSID   rclsid,
@@ -91,6 +103,8 @@ IDxcBlob : public IUnknown {
 public:
   virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) = 0;
   virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcBlob)
 };
 
 struct __declspec(uuid("7241d424-2646-4191-97c0-98e96e42fc68"))
@@ -98,6 +112,8 @@ IDxcBlobEncoding : public IDxcBlob {
 public:
   virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown,
                                                 _Out_ UINT32 *pCodePage) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcBlobEncoding)
 };
 
 struct __declspec(uuid("e5204dc7-d18c-4c3c-bdfb-851673980fe7"))
@@ -125,6 +141,8 @@ IDxcLibrary : public IUnknown {
       _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf16(
       _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcLibrary)
 };
 
 struct __declspec(uuid("CEDB484A-D4E9-445A-B991-CA21CA157DC2"))
@@ -132,6 +150,8 @@ IDxcOperationResult : public IUnknown {
   virtual HRESULT STDMETHODCALLTYPE GetStatus(_Out_ HRESULT *pStatus) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetResult(_COM_Outptr_result_maybenull_ IDxcBlob **pResult) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetErrorBuffer(_COM_Outptr_result_maybenull_ IDxcBlobEncoding **pErrors) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcOperationResult)
 };
 
 struct __declspec(uuid("7f61fc7d-950d-467f-b3e3-3c02fb49187c"))
@@ -140,6 +160,8 @@ IDxcIncludeHandler : public IUnknown {
     _In_ LPCWSTR pFilename,                                   // Candidate filename.
     _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource  // Resultant source object for included file, nullptr if not found.
     ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcIncludeHandler)
 };
 
 struct DxcDefine {
@@ -180,6 +202,8 @@ IDxcCompiler : public IUnknown {
     _In_ IDxcBlob *pSource,                         // Program to disassemble.
     _COM_Outptr_ IDxcBlobEncoding **ppDisassembly   // Disassembly text.
     ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcCompiler)
 };
 
 struct __declspec(uuid("A005A9D9-B8BB-4594-B5C9-0E633BEC4D37"))
@@ -199,6 +223,8 @@ IDxcCompiler2 : public IDxcCompiler {
     _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
     _COM_Outptr_opt_ IDxcBlob **ppDebugBlob       // Debug blob
   ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcCompiler2)
 };
 
 struct __declspec(uuid("F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6"))
@@ -224,6 +250,8 @@ public:
       _COM_Outptr_ IDxcOperationResult *
           *ppResult // Linker output status, buffer, and errors
   ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcLinker)
 };
 
 static const UINT32 DxcValidatorFlags_Default = 0;
@@ -240,6 +268,8 @@ IDxcValidator : public IUnknown {
     _In_ UINT32 Flags,                            // Validation flags.
     _COM_Outptr_ IDxcOperationResult **ppResult   // Validation output status, buffer, and errors
     ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcValidator)
 };
 
 struct __declspec(uuid("334b1f50-2292-4b35-99a1-25588d8c17fe"))
@@ -248,6 +278,8 @@ IDxcContainerBuilder : public IUnknown {
   virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) = 0;      // Part to add to the container
   virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0;                           // Remove the part with fourCC
   virtual HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; // Builds a container of the given container builder state
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcContainerBuilder)
 };
 
 struct __declspec(uuid("091f7a26-1c1f-4948-904b-e6e3a8a771d5"))
@@ -257,6 +289,8 @@ IDxcAssembler : public IUnknown {
     _In_ IDxcBlob *pShader,                       // Shader to assemble.
     _COM_Outptr_ IDxcOperationResult **ppResult   // Assembly output status, buffer, and errors
     ) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcAssembler)
 };
 
 // D3D_SIT_RTACCELERATIONSTRUCTURE is an additional value for D3D_SHADER_INPUT_TYPE,
@@ -271,6 +305,8 @@ IDxcContainerReflection : public IUnknown {
   virtual HRESULT STDMETHODCALLTYPE GetPartContent(UINT32 idx, _COM_Outptr_ IDxcBlob **ppResult) = 0;
   virtual HRESULT STDMETHODCALLTYPE FindFirstPartKind(UINT32 kind, _Out_ UINT32 *pResult) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid, void **ppvObject) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcContainerReflection)
 };
 
 struct __declspec(uuid("AE2CD79F-CC22-453F-9B6B-B124E7A5204C"))
@@ -280,6 +316,8 @@ IDxcOptimizerPass : public IUnknown {
   virtual HRESULT STDMETHODCALLTYPE GetOptionArgCount(_Out_ UINT32 *pCount) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetOptionArgName(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetOptionArgDescription(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcOptimizerPass)
 };
 
 struct __declspec(uuid("25740E2E-9CBA-401B-9119-4FB42F39F270"))
@@ -290,6 +328,8 @@ IDxcOptimizer : public IUnknown {
     _In_count_(optionCount) LPCWSTR *ppOptions, UINT32 optionCount,
     _COM_Outptr_ IDxcBlob **pOutputModule,
     _COM_Outptr_opt_ IDxcBlobEncoding **ppOutputText) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcOptimizer)
 };
 
 static const UINT32 DxcVersionInfoFlags_None = 0;
@@ -300,15 +340,27 @@ struct __declspec(uuid("b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e"))
 IDxcVersionInfo : public IUnknown {
   virtual HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcVersionInfo)
 };
 
 struct __declspec(uuid("fb6904c4-42f0-4b62-9c46-983af7da7c83"))
 IDxcVersionInfo2 : public IDxcVersionInfo {
   virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount, _Out_ char **pCommitHash) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcVersionInfo2)
 };
 
+// Note: __declspec(selectany) requires 'extern'
+// On Linux __declspec(selectany) is removed and using 'extern' results in link error.
+#ifdef _MSC_VER
+#define EXTERN extern
+#else
+#define EXTERN
+#endif
+
 // {73e22d93-e6ce-47f3-b5bf-f0664f39c1b0}
-__declspec(selectany) extern const CLSID CLSID_DxcCompiler = {
+__declspec(selectany) EXTERN const CLSID CLSID_DxcCompiler = {
   0x73e22d93,
   0xe6ce,
   0x47f3,
@@ -316,7 +368,7 @@ __declspec(selectany) extern const CLSID CLSID_DxcCompiler = {
 };
 
 // {EF6A8087-B0EA-4D56-9E45-D07E1A8B7806}
-__declspec(selectany) extern const GUID CLSID_DxcLinker = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcLinker = {
     0xef6a8087,
     0xb0ea,
     0x4d56,
@@ -324,7 +376,7 @@ __declspec(selectany) extern const GUID CLSID_DxcLinker = {
 };
 
 // {CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F}
-__declspec(selectany) extern const CLSID CLSID_DxcDiaDataSource = {
+__declspec(selectany) EXTERN const CLSID CLSID_DxcDiaDataSource = {
   0xcd1f6b73,
   0x2ab0,
   0x484d,
@@ -332,7 +384,7 @@ __declspec(selectany) extern const CLSID CLSID_DxcDiaDataSource = {
 };
 
 // {6245D6AF-66E0-48FD-80B4-4D271796748C}
-__declspec(selectany) extern const GUID CLSID_DxcLibrary = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcLibrary = {
   0x6245d6af,
   0x66e0,
   0x48fd,
@@ -340,7 +392,7 @@ __declspec(selectany) extern const GUID CLSID_DxcLibrary = {
 };
 
 // {8CA3E215-F728-4CF3-8CDD-88AF917587A1}
-__declspec(selectany) extern const GUID CLSID_DxcValidator = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcValidator = {
   0x8ca3e215,
   0xf728,
   0x4cf3,
@@ -348,7 +400,7 @@ __declspec(selectany) extern const GUID CLSID_DxcValidator = {
 };
 
 // {D728DB68-F903-4F80-94CD-DCCF76EC7151}
-__declspec(selectany) extern const GUID CLSID_DxcAssembler = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcAssembler = {
   0xd728db68,
   0xf903,
   0x4f80,
@@ -356,7 +408,7 @@ __declspec(selectany) extern const GUID CLSID_DxcAssembler = {
 };
 
 // {b9f54489-55b8-400c-ba3a-1675e4728b91}
-__declspec(selectany) extern const GUID CLSID_DxcContainerReflection = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcContainerReflection = {
   0xb9f54489,
   0x55b8,
   0x400c,
@@ -364,7 +416,7 @@ __declspec(selectany) extern const GUID CLSID_DxcContainerReflection = {
 };
 
 // {AE2CD79F-CC22-453F-9B6B-B124E7A5204C}
-__declspec(selectany) extern const GUID CLSID_DxcOptimizer = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcOptimizer = {
     0xae2cd79f,
     0xcc22,
     0x453f,
@@ -372,7 +424,7 @@ __declspec(selectany) extern const GUID CLSID_DxcOptimizer = {
 };
 
 // {94134294-411f-4574-b4d0-8741e25240d2}
-__declspec(selectany) extern const GUID CLSID_DxcContainerBuilder = {
+__declspec(selectany) EXTERN const GUID CLSID_DxcContainerBuilder = {
   0x94134294,
   0x411f,
   0x4574,  

+ 13 - 3
include/dxc/dxcisense.h

@@ -12,6 +12,7 @@
 #ifndef __DXC_ISENSE__
 #define __DXC_ISENSE__
 
+#include "dxc/dxcapi.h"
 #include "dxc/Support/WinAdapter.h"
 
 typedef enum DxcGlobalOptions
@@ -134,8 +135,8 @@ typedef enum DxcDiagnosticDisplayOptions
   // Display the category name associated with this diagnostic, if any.
   DxcDiagnostic_DisplayCategoryName = 0x20,
 
-	// Display the severity of the diagnostic message.
-	DxcDiagnostic_DisplaySeverity = 0x200
+  // Display the severity of the diagnostic message.
+  DxcDiagnostic_DisplaySeverity = 0x200
 } DxcDiagnosticDisplayOptions;
 
 typedef enum DxcTranslationUnitFlags
@@ -663,6 +664,8 @@ IDxcIntelliSense : public IUnknown
     _Out_ DxcDiagnosticDisplayOptions* pValue) = 0;
   virtual HRESULT STDMETHODCALLTYPE GetDefaultEditingTUOptions(_Out_ DxcTranslationUnitFlags* pValue) = 0;
   virtual HRESULT STDMETHODCALLTYPE CreateUnsavedFile(_In_ LPCSTR fileName, _In_ LPCSTR contents, unsigned contentLength, _Outptr_result_nullonfailure_ IDxcUnsavedFile** pResult) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcIntelliSense)
 };
 
 struct __declspec(uuid("937824a0-7f5a-4815-9ba7-7fc0424f4173"))
@@ -762,8 +765,15 @@ IDxcUnsavedFile : public IUnknown
 // Fun fact: 'extern' is required because const is by default static in C++, so
 // CLSID_DxcIntelliSense is not visible externally (this is OK in C, since const is
 // not by default static in C)
+
+#ifdef _MSC_VER
+#define EXTERN extern
+#else
+#define EXTERN
+#endif
+
 __declspec(selectany)
-extern const CLSID CLSID_DxcIntelliSense = { /* 3047833c-d1c0-4b8e-9d40-102878605985 */
+EXTERN const CLSID CLSID_DxcIntelliSense = { /* 3047833c-d1c0-4b8e-9d40-102878605985 */
     0x3047833c,
     0xd1c0,
     0x4b8e,

+ 8 - 1
include/dxc/dxctools.h

@@ -47,10 +47,17 @@ IDxcRewriter : public IUnknown {
                                                      _In_ UINT32  rewriteOption,
                                                      _COM_Outptr_ IDxcOperationResult **ppResult) = 0;
 
+  DECLARE_CROSS_PLATFORM_UUIDOF(IDxcRewriter)
 };
 
+#ifdef _MSC_VER
+#define EXTERN extern
+#else
+#define EXTERN
+#endif
+
 __declspec(selectany)
-extern const CLSID CLSID_DxcRewriter = { /* b489b951-e07f-40b3-968d-93e124734da4 */
+EXTERN const CLSID CLSID_DxcRewriter = { /* b489b951-e07f-40b3-968d-93e124734da4 */
   0xb489b951,
   0xe07f,
   0x40b3,

+ 8 - 0
include/llvm/Analysis/TargetLibraryInfo.def

@@ -431,9 +431,11 @@ TLI_DEFINE_STRING_INTERNAL("fmodl")
 /// FILE *fopen(const char *filename, const char *mode);
 TLI_DEFINE_ENUM_INTERNAL(fopen)
 TLI_DEFINE_STRING_INTERNAL("fopen")
+#if 0 // HLSL Change Starts - Exclude potentially duplicate 64bit versions
 /// FILE *fopen64(const char *filename, const char *opentype)
 TLI_DEFINE_ENUM_INTERNAL(fopen64)
 TLI_DEFINE_STRING_INTERNAL("fopen64")
+#endif // HLSL Change Ends
 /// int fprintf(FILE *stream, const char *format, ...);
 TLI_DEFINE_ENUM_INTERNAL(fprintf)
 TLI_DEFINE_STRING_INTERNAL("fprintf")
@@ -467,9 +469,11 @@ TLI_DEFINE_STRING_INTERNAL("fseek")
 /// int fseeko(FILE *stream, off_t offset, int whence);
 TLI_DEFINE_ENUM_INTERNAL(fseeko)
 TLI_DEFINE_STRING_INTERNAL("fseeko")
+#if 0 // HLSL Change Starts - Exclude potentially duplicate 64bit versions
 /// int fseeko64(FILE *stream, off64_t offset, int whence)
 TLI_DEFINE_ENUM_INTERNAL(fseeko64)
 TLI_DEFINE_STRING_INTERNAL("fseeko64")
+#endif // HLSL Change Ends
 /// int fsetpos(FILE *stream, const fpos_t *pos);
 TLI_DEFINE_ENUM_INTERNAL(fsetpos)
 TLI_DEFINE_STRING_INTERNAL("fsetpos")
@@ -491,9 +495,11 @@ TLI_DEFINE_STRING_INTERNAL("ftell")
 /// off_t ftello(FILE *stream);
 TLI_DEFINE_ENUM_INTERNAL(ftello)
 TLI_DEFINE_STRING_INTERNAL("ftello")
+#if 0 // HLSL Change Starts - Exclude potentially duplicate 64bit versions
 /// off64_t ftello64(FILE *stream)
 TLI_DEFINE_ENUM_INTERNAL(ftello64)
 TLI_DEFINE_STRING_INTERNAL("ftello64")
+#endif // HLSL Change Ends
 /// int ftrylockfile(FILE *file);
 TLI_DEFINE_ENUM_INTERNAL(ftrylockfile)
 TLI_DEFINE_STRING_INTERNAL("ftrylockfile")
@@ -955,9 +961,11 @@ TLI_DEFINE_STRING_INTERNAL("times")
 /// FILE *tmpfile(void);
 TLI_DEFINE_ENUM_INTERNAL(tmpfile)
 TLI_DEFINE_STRING_INTERNAL("tmpfile")
+#if 0 // HLSL Change Starts - Exclude potentially duplicate 64bit versions
 /// FILE *tmpfile64(void)
 TLI_DEFINE_ENUM_INTERNAL(tmpfile64)
 TLI_DEFINE_STRING_INTERNAL("tmpfile64")
+#endif // HLSL Change Ends
 /// int toascii(int c);
 TLI_DEFINE_ENUM_INTERNAL(toascii)
 TLI_DEFINE_STRING_INTERNAL("toascii")

+ 4 - 1
include/llvm/PassRegistry.h

@@ -39,7 +39,10 @@ struct PassRegistrationListener;
 /// threads simultaneously, you will need to use a separate PassRegistry on
 /// each thread.
 class PassRegistry {
-  //mutable sys::SmartRWMutex<true> Lock; // HLSL Change - no lock needed
+  #ifndef LLVM_ON_WIN32
+  // HLSL Change - no lock needed for Windows, as it will use its own mechanism defined in PassRegistry.cpp.
+  mutable sys::SmartRWMutex<true> Lock;
+  #endif
 
   /// PassInfoMap - Keep track of the PassInfo object for each registered pass.
   typedef DenseMap<const void *, const PassInfo *> MapType;

+ 8 - 0
include/llvm/Support/MSFileSystem.h

@@ -14,6 +14,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // MSFileSystem interface.
+struct stat;
 
 namespace llvm {
 namespace sys  {
@@ -86,6 +87,13 @@ public:
   virtual errno_t resize_file(_In_ LPCWSTR path, uint64_t size) throw() = 0; // A number of C calls.
   virtual int Read(int fd, _Out_bytecap_(count) void* buffer, unsigned int count) throw() = 0;
   virtual int Write(int fd, _In_bytecount_(count) const void* buffer, unsigned int count) throw() = 0;
+
+  // Unix interface
+#ifndef _WIN32
+  virtual int Open(const char *lpFileName, int flags, mode_t mode = 0) throw() = 0;
+  virtual int Stat(const char *lpFileName, struct stat *Status) throw() = 0;
+  virtual int Fstat(int FD, struct stat *Status) throw() = 0;
+#endif
 };
 
 

+ 3 - 3
include/llvm/Support/Mutex.h

@@ -71,10 +71,10 @@ namespace llvm
     /// @{
     private:
 #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
-#if 0 // HLSL Change
-      void* data_; ///< We don't know what the data will be
-#else
+#if LLVM_ON_WIN32 // HLSL Change
       char data_[sizeof(void*) == 8 ? 40 : 24]; // C_ASSERT this is CRITICAL_SECTION-sized
+#else
+      void* data_; ///< We don't know what the data will be
 #endif // HLSL Change
 #endif
 

+ 4 - 4
lib/Analysis/TargetLibraryInfo.cpp

@@ -350,16 +350,16 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
     TLI.setUnavailable(LibFunc::under_IO_getc);
     TLI.setUnavailable(LibFunc::under_IO_putc);
     TLI.setUnavailable(LibFunc::memalign);
-    TLI.setUnavailable(LibFunc::fopen64);
-    TLI.setUnavailable(LibFunc::fseeko64);
+    //TLI.setUnavailable(LibFunc::fopen64); // HLSL Change - duplicate 64bit versions
+    //TLI.setUnavailable(LibFunc::fseeko64); // HLSL Change - duplicate 64bit versions
     TLI.setUnavailable(LibFunc::fstat64);
     TLI.setUnavailable(LibFunc::fstatvfs64);
-    TLI.setUnavailable(LibFunc::ftello64);
+    //TLI.setUnavailable(LibFunc::ftello64); // HLSL Change - duplicate 64bit versions
     TLI.setUnavailable(LibFunc::lstat64);
     TLI.setUnavailable(LibFunc::open64);
     TLI.setUnavailable(LibFunc::stat64);
     TLI.setUnavailable(LibFunc::statvfs64);
-    TLI.setUnavailable(LibFunc::tmpfile64);
+    //TLI.setUnavailable(LibFunc::tmpfile64); // HLSL Change - duplicate 64bit versions
   }
 
   TLI.addVectorizableFunctionsFromVecLib(ClVectorLibrary);

+ 2 - 0
lib/DxcSupport/CMakeLists.txt

@@ -7,6 +7,8 @@ add_llvm_library(LLVMDxcSupport
   Global.cpp
   HLSLOptions.cpp
   Unicode.cpp
+  WinAdapter.cpp
+  WinFunctions.cpp
   )
 
 add_dependencies(LLVMDxcSupport TablegenHLSLOptions)

+ 14 - 16
lib/DxcSupport/FileIOHelper.cpp

@@ -14,43 +14,43 @@
 #include "dxc/Support/microcom.h"
 #include "dxc/Support/Unicode.h"
 #include "dxc/Support/FileIOHelper.h"
+#include "dxc/Support/WinFunctions.h"
 #include "dxc/dxcapi.h"
 
 #include <algorithm>
 #include <memory>
+
+#ifdef _WIN32
 #include <intsafe.h>
+#endif
 
 #define CP_UTF16 1200
 
 struct HeapMalloc : public IMalloc {
 public:
-  ULONG STDMETHODCALLTYPE AddRef() {
-    return 1;
-  }
-  ULONG STDMETHODCALLTYPE Release() {
-    return 1;
-  }
+  ULONG STDMETHODCALLTYPE AddRef() override { return 1; }
+  ULONG STDMETHODCALLTYPE Release() override { return 1; }
   STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override {
     return DoBasicQueryInterface<IMalloc>(this, iid, ppvObject);
   }
-  virtual void *STDMETHODCALLTYPE Alloc(
+  virtual void *STDMETHODCALLTYPE Alloc (
     /* [annotation][in] */
-    _In_  SIZE_T cb) {
+    _In_  SIZE_T cb) override {
     return HeapAlloc(GetProcessHeap(), 0, cb);
   }
 
-  virtual void *STDMETHODCALLTYPE Realloc(
+  virtual void *STDMETHODCALLTYPE Realloc (
     /* [annotation][in] */
     _In_opt_  void *pv,
     /* [annotation][in] */
-    _In_  SIZE_T cb)
+    _In_  SIZE_T cb) override
   {
     return HeapReAlloc(GetProcessHeap(), 0, pv, cb);
   }
 
-  virtual void STDMETHODCALLTYPE Free(
+  virtual void STDMETHODCALLTYPE Free (
     /* [annotation][in] */
-    _In_opt_  void *pv)
+    _In_opt_  void *pv) override
   {
     HeapFree(GetProcessHeap(), 0, pv);
   }
@@ -71,9 +71,7 @@ public:
   }
 
 
-  virtual void STDMETHODCALLTYPE HeapMinimize(void)
-  {
-  }
+  virtual void STDMETHODCALLTYPE HeapMinimize(void) {}
 };
 
 static HeapMalloc g_HeapMalloc;
@@ -311,9 +309,9 @@ static HRESULT CodePageBufferToUtf16(UINT32 codePage, LPCVOID bufferPointer,
   int numActuallyConvertedUTF16 =
       MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, (LPCSTR)bufferPointer,
                           bufferSize, utf16NewCopy, buffSizeUTF16);
+
   if (numActuallyConvertedUTF16 == 0)
     return HRESULT_FROM_WIN32(GetLastError());
-
   ((LPWSTR)utf16NewCopy)[numActuallyConvertedUTF16] = L'\0';
   *pConvertedCharCount = numActuallyConvertedUTF16;
 

+ 21 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -49,6 +49,10 @@ namespace {
 
 static HlslOptTable *g_HlslOptTable;
 
+#ifndef _WIN32
+#pragma GCC visibility push(hidden)
+#endif
+
 std::error_code hlsl::options::initHlslOptTable() {
   DXASSERT(g_HlslOptTable == nullptr, "else double-init");
   g_HlslOptTable = new (std::nothrow) HlslOptTable();
@@ -66,6 +70,10 @@ const OptTable * hlsl::options::getHlslOptTable() {
   return g_HlslOptTable;
 }
 
+#ifndef _WIN32
+#pragma GCC visibility pop
+#endif
+
 void DxcDefines::push_back(llvm::StringRef value) {
   // Skip empty defines.
   if (value.size() > 0) {
@@ -147,6 +155,17 @@ MainArgs::MainArgs(int argc, const wchar_t **argv, int skipArgCount) {
   }
 }
 
+MainArgs::MainArgs(int argc, const char **argv, int skipArgCount) {
+  if (argc > skipArgCount) {
+    Utf8StringVector.reserve(argc - skipArgCount);
+    Utf8CharPtrVector.reserve(argc - skipArgCount);
+    for (int i = skipArgCount; i < argc; ++i) {
+      Utf8StringVector.emplace_back(argv[i]);
+      Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
+    }
+  }
+}
+
 MainArgs::MainArgs(llvm::ArrayRef<llvm::StringRef> args) {
   Utf8StringVector.reserve(args.size());
   Utf8CharPtrVector.reserve(args.size());
@@ -525,6 +544,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #ifdef ENABLE_SPIRV_CODEGEN
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
+  opts.VkInvertW = Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false);
   opts.VkUseGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false);
   opts.VkUseDxLayout = Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false);
   opts.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
@@ -590,6 +610,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #else
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
+      Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||

+ 82 - 0
lib/DxcSupport/Unicode.cpp

@@ -17,6 +17,88 @@
 #include "dxc/Support/Unicode.h"
 #include "dxc/Support/WinIncludes.h"
 
+#ifndef _WIN32
+// MultiByteToWideChar which is a Windows-specific method.
+// This is a very simplistic implementation for non-Windows platforms. This
+// implementation completely ignores CodePage and dwFlags.
+int MultiByteToWideChar(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
+                        const char *lpMultiByteStr, int cbMultiByte,
+                        wchar_t *lpWideCharStr, int cchWideChar) {
+
+  if (cbMultiByte == 0) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
+
+  // if cbMultiByte is -1, it indicates that lpMultiByteStr is null-terminated
+  // and the entire string should be processed.
+  if (cbMultiByte == -1) {
+    for (cbMultiByte = 0; lpMultiByteStr[cbMultiByte] != '\0'; ++cbMultiByte)
+      ;
+    // Add 1 for the null-terminating character.
+    ++cbMultiByte;
+  }
+  // if zero is given as the destination size, this function should
+  // return the required size (including the null-terminating character).
+  if (cchWideChar == 0) {
+    wchar_t *tempStr = (wchar_t *)malloc(cbMultiByte * sizeof(wchar_t));
+    size_t requiredSize = mbstowcs(tempStr, lpMultiByteStr, cbMultiByte);
+    free(tempStr);
+    if (requiredSize == (size_t)cbMultiByte) return requiredSize;
+    return requiredSize + 1;
+  }
+
+  if (cchWideChar < cbMultiByte) {
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return 0;
+  }
+
+  size_t rv = mbstowcs(lpWideCharStr, lpMultiByteStr, cbMultiByte);
+  if (rv == (size_t)cbMultiByte) return rv;
+  return rv + 1; // mbstowcs excludes the terminating character
+}
+
+// WideCharToMultiByte is a Windows-specific method.
+// This is a very simplistic implementation for non-Windows platforms. This
+// implementation completely ignores CodePage and dwFlags.
+int WideCharToMultiByte(uint32_t /*CodePage*/, uint32_t /*dwFlags*/,
+                        const wchar_t *lpWideCharStr, int cchWideChar,
+                        char *lpMultiByteStr, int cbMultiByte,
+                        const char * /*lpDefaultChar*/,
+                        bool * /*lpUsedDefaultChar*/) {
+  // if cchWideChar is -1, it indicates that lpWideCharStr is null-terminated
+  // and the entire string should be processed.
+  if (cchWideChar == 0) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return 0;
+  }
+  if (cchWideChar == -1) {
+    for (cchWideChar = 0; lpWideCharStr[cchWideChar] != '\0'; ++cchWideChar)
+      ;
+    // Add 1 for the null-terminating character.
+    ++cchWideChar;
+  }
+  // if zero is given as the destination size, this function should
+  // return the required size (including the null-terminating character).
+  if (cbMultiByte == 0) {
+    char *tempStr = (char *)malloc(cchWideChar * sizeof(char));
+    size_t requiredSize = wcstombs(tempStr, lpWideCharStr, cchWideChar);
+    free(tempStr);
+    if (requiredSize == (size_t)cchWideChar) return requiredSize;
+    return requiredSize + 1;
+  }
+
+  if (cbMultiByte < cchWideChar) {
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return 0;
+  }
+
+  size_t rv = wcstombs(lpMultiByteStr, lpWideCharStr, cchWideChar);
+  if (rv == (size_t)cchWideChar) return rv;
+  return rv + 1; // mbstowcs excludes the terminating character
+}
+#endif // _WIN32
+
 namespace Unicode {
 
 _Success_(return != false)

+ 59 - 0
lib/DxcSupport/WinAdapter.cpp

@@ -0,0 +1,59 @@
+//===-- WinAdapter.cpp - Windows Adapter for other platforms ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _WIN32
+
+#include "dxc/Support/WinAdapter.h"
+#include "dxc/Support/WinFunctions.h"
+
+DEFINE_CROSS_PLATFORM_UUIDOF(IUnknown)
+DEFINE_CROSS_PLATFORM_UUIDOF(INoMarshal)
+DEFINE_CROSS_PLATFORM_UUIDOF(IStream)
+DEFINE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
+
+//===--------------------------- IUnknown ---------------------------------===//
+
+ULONG IUnknown::AddRef() {
+  ++m_count;
+  return m_count;
+}
+ULONG IUnknown::Release() {
+  ULONG result = --m_count;
+  if (m_count == 0) {
+    delete this;
+  }
+  return result;
+}
+IUnknown::~IUnknown() {}
+
+//===--------------------------- IMalloc ----------------------------------===//
+
+void *IMalloc::Alloc(size_t size) { return malloc(size); }
+void *IMalloc::Realloc(void *ptr, size_t size) { return realloc(ptr, size); }
+void IMalloc::Free(void *ptr) { free(ptr); }
+HRESULT IMalloc::QueryInterface(REFIID riid, void **ppvObject) {
+  assert(false && "QueryInterface not implemented for IMalloc.");
+  return E_NOINTERFACE;
+}
+
+//===--------------------------- CAllocator -------------------------------===//
+
+void *CAllocator::Reallocate(void *p, size_t nBytes) throw() {
+  return realloc(p, nBytes);
+}
+void *CAllocator::Allocate(size_t nBytes) throw() { return malloc(nBytes); }
+void CAllocator::Free(void *p) throw() { free(p); }
+
+//===--------------------------- CHandle -------------------------------===//
+
+CHandle::CHandle(HANDLE h) { m_h = h; }
+CHandle::~CHandle() { CloseHandle(m_h); }
+CHandle::operator HANDLE() const throw() { return m_h; }
+
+#endif

+ 337 - 0
lib/DxcSupport/WinFunctions.cpp

@@ -0,0 +1,337 @@
+//===-- WinFunctions.cpp - Windows Functions for other platforms --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Windows-specific functions used in the codebase for
+// non-Windows platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <map>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "dxc/Support/WinFunctions.h"
+
+HRESULT StringCchCopyEx(LPSTR pszDest, size_t cchDest, LPCSTR pszSrc,
+                        LPSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags) {
+  assert(dwFlags == 0 && "dwFlag values not supported in StringCchCopyEx");
+  char *zPtr = 0;
+
+  zPtr = stpncpy(pszDest, pszSrc, cchDest);
+
+  if (ppszDestEnd)
+    *ppszDestEnd = zPtr;
+
+  if (pcchRemaining)
+    *pcchRemaining = cchDest - (zPtr - pszDest);
+
+  return S_OK;
+}
+
+
+HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  va_list argscopy;
+  va_copy(argscopy, args);
+  // C++11 snprintf can return the size of the resulting string if it was to be
+  // constructed.
+  size_t size = vsnprintf(nullptr, 0, format, argscopy) + 1; // Extra space for '\0'
+  if (size > dstSize) {
+    *dst = '\0';
+  } else {
+    vsnprintf(dst, size, format, args);
+  }
+  va_end(argscopy);
+  va_end(args);
+  return S_OK;
+}
+HRESULT UIntAdd(UINT uAugend, UINT uAddend, UINT *puResult) {
+  HRESULT hr;
+  if ((uAugend + uAddend) >= uAugend) {
+    *puResult = (uAugend + uAddend);
+    hr = S_OK;
+  } else {
+    *puResult = 0xffffffff;
+    hr = ERROR_ARITHMETIC_OVERFLOW;
+  }
+  return hr;
+}
+HRESULT IntToUInt(int in, UINT *out) {
+  HRESULT hr;
+  if (in >= 0) {
+    *out = (UINT)in;
+    hr = S_OK;
+  } else {
+    *out = 0xffffffff;
+    hr = ERROR_ARITHMETIC_OVERFLOW;
+  }
+  return hr;
+}
+HRESULT SizeTToInt(size_t in, int *out) {
+  HRESULT hr;
+  if(in <= INT_MAX) {
+    *out = (int)in;
+    hr = S_OK;
+  }
+  else {
+    *out = 0xffffffff;
+    hr = ERROR_ARITHMETIC_OVERFLOW;
+  }
+  return hr;
+}
+HRESULT UInt32Mult(UINT a, UINT b, UINT *out) {
+  uint64_t result = (uint64_t)a * (uint64_t)b;
+  if (result > uint64_t(UINT_MAX))
+    return ERROR_ARITHMETIC_OVERFLOW;
+
+  *out = (uint32_t)result;
+  return S_OK;
+}
+
+int _stricmp(const char *str1, const char *str2) {
+  size_t i = 0;
+  for (; str1[i] && str2[i]; ++i) {
+    int d = std::tolower(str1[i]) - std::tolower(str2[i]);
+    if (d != 0)
+      return d;
+  }
+  return str1[i] - str2[i];
+}
+
+int _wcsicmp(const wchar_t *str1, const wchar_t *str2) {
+  size_t i = 0;
+  for (; str1[i] && str2[i]; ++i) {
+    int d = std::towlower(str1[i]) - std::towlower(str2[i]);
+    if (d != 0)
+      return d;
+  }
+  return str1[i] - str2[i];
+}
+
+int _wcsnicmp(const wchar_t *str1, const wchar_t *str2, size_t n) {
+  size_t i = 0;
+  for (; i < n && str1[i] && str2[i]; ++i) {
+    int d = std::towlower(str1[i]) - std::towlower(str2[i]);
+    if (d != 0)
+      return d;
+  }
+  if (i >= n) return 0;
+  return str1[i] - str2[i];
+}
+
+unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask) {
+  unsigned long l;
+  if (!Mask) return 0;
+  for (l=0; !(Mask&1); l++) Mask >>= 1;
+  *Index = l;
+  return 1;
+}
+
+HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc) {
+  *ppMalloc = new IMalloc;
+  (*ppMalloc)->AddRef();
+  return S_OK;
+}
+
+HANDLE CreateFile2(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition,
+                   _In_opt_ void *pCreateExParams) {
+  return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, pCreateExParams,
+                     dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
+}
+
+HANDLE CreateFileW(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_opt_ void *lpSecurityAttributes,
+                   _In_ DWORD dwCreationDisposition,
+                   _In_ DWORD dwFlagsAndAttributes,
+                   _In_opt_ HANDLE hTemplateFile) {
+  CW2A pUtf8FileName(lpFileName);
+  size_t fd = -1;
+  int flags = 0;
+
+  if (dwDesiredAccess & GENERIC_WRITE)
+    if (dwDesiredAccess & GENERIC_READ)
+      flags |= O_RDWR;
+    else
+      flags |= O_WRONLY;
+  else // dwDesiredAccess may be 0, but open() demands something here. This is mostly harmless
+    flags |= O_RDONLY;
+
+  if (dwCreationDisposition == CREATE_ALWAYS)
+    flags |= (O_CREAT | O_TRUNC);
+  if (dwCreationDisposition == OPEN_ALWAYS)
+    flags |= O_CREAT;
+  else if (dwCreationDisposition == CREATE_NEW)
+    flags |= (O_CREAT | O_EXCL);
+  else if (dwCreationDisposition == TRUNCATE_EXISTING)
+    flags |= O_TRUNC;
+  // OPEN_EXISTING represents default open() behavior
+
+  // Catch Implementation limitations.
+  assert(!lpSecurityAttributes && "security attributes not supported in CreateFileW yet");
+  assert(!hTemplateFile && "template file not supported in CreateFileW yet");
+  assert(dwFlagsAndAttributes == FILE_ATTRIBUTE_NORMAL &&
+         "Attributes other than NORMAL not supported in CreateFileW yet");
+
+  while ((int)(fd = open(pUtf8FileName, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
+    if (errno != EINTR)
+      return INVALID_HANDLE_VALUE;
+  }
+
+  return (HANDLE)fd;
+}
+
+BOOL GetFileSizeEx(_In_ HANDLE hFile, _Out_ PLARGE_INTEGER lpFileSize) {
+  int fd = (size_t)hFile;
+  struct stat fdstat;
+  int rv = fstat(fd, &fdstat);
+  if (!rv) {
+    lpFileSize->QuadPart = (LONGLONG)fdstat.st_size;
+    return true;
+  }
+  return false;
+}
+
+BOOL ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer,
+              _In_ DWORD nNumberOfBytesToRead,
+              _Out_opt_ LPDWORD lpNumberOfBytesRead,
+              _Inout_opt_ void *lpOverlapped) {
+  size_t fd = (size_t)hFile;
+  ssize_t rv = -1;
+
+  // Implementation limitation
+  assert(!lpOverlapped && "Overlapping not supported in ReadFile yet.");
+
+  rv = read(fd, lpBuffer, nNumberOfBytesToRead);
+  if (rv < 0)
+    return false;
+  *lpNumberOfBytesRead = rv;
+  return true;
+}
+
+BOOL WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer,
+               _In_ DWORD nNumberOfBytesToWrite,
+               _Out_opt_ LPDWORD lpNumberOfBytesWritten,
+               _Inout_opt_ void *lpOverlapped) {
+  size_t fd = (size_t)hFile;
+  ssize_t rv = -1;
+
+  // Implementation limitation
+  assert(!lpOverlapped && "Overlapping not supported in WriteFile yet.");
+
+  rv = write(fd, lpBuffer, nNumberOfBytesToWrite);
+  if (rv < 0)
+    return false;
+  *lpNumberOfBytesWritten = rv;
+  return true;
+}
+
+BOOL CloseHandle(_In_ HANDLE hObject) {
+  int fd = (size_t)hObject;
+  return !close(fd);
+}
+
+// Half-hearted implementation of a heap structure
+// Enables size queries, maximum allocation limit, and collective free at heap destruction
+// Does not perform any preallocation or allocation organization.
+// Does not respect any flags except for HEAP_ZERO_MEMORY
+struct SimpleAllocation {
+  LPVOID ptr;
+  SIZE_T size;
+};
+
+struct SimpleHeap {
+  std::map<LPCVOID, SimpleAllocation> allocs;
+  SIZE_T maxSize, curSize;
+};
+
+HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize , SIZE_T dwMaximumSize) {
+  SimpleHeap *simpHeap = new SimpleHeap;
+  simpHeap->maxSize = dwMaximumSize;
+  simpHeap->curSize = 0;
+  return (HANDLE)simpHeap;
+}
+
+BOOL HeapDestroy(HANDLE hHeap) {
+  SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
+
+  for (auto it = simpHeap->allocs.begin(), e = simpHeap->allocs.end(); it != e; it++)
+    free(it->second.ptr);
+
+  delete simpHeap;
+  return true;
+}
+
+LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
+  LPVOID ptr = nullptr;
+  SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
+
+  if (simpHeap->maxSize && simpHeap->curSize + dwBytes > simpHeap->maxSize)
+    return nullptr;
+
+  if (dwFlags == HEAP_ZERO_MEMORY)
+    ptr = calloc(1, dwBytes);
+  else
+    ptr = malloc(dwBytes);
+
+  simpHeap->allocs[ptr] = {ptr, dwBytes};
+  simpHeap->curSize += dwBytes;
+
+  return ptr;
+}
+
+LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes) {
+  LPVOID ptr = nullptr;
+  SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
+  SIZE_T oSize = simpHeap->allocs[lpMem].size;
+
+  if (simpHeap->maxSize && simpHeap->curSize - oSize + dwBytes > simpHeap->maxSize)
+    return nullptr;
+
+  ptr = realloc(lpMem, dwBytes);
+  if (dwFlags == HEAP_ZERO_MEMORY && oSize < dwBytes)
+    memset((char*)ptr + oSize, 0, dwBytes - oSize);
+
+  simpHeap->allocs.erase(lpMem);
+  simpHeap->curSize -= oSize;
+
+  simpHeap->allocs[ptr] = {ptr, dwBytes};
+  simpHeap->curSize += dwBytes;
+
+  return ptr;
+}
+
+BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
+  SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
+  SIZE_T oSize = simpHeap->allocs[lpMem].size;
+
+  free(lpMem);
+
+  simpHeap->allocs.erase(lpMem);
+  simpHeap->curSize -= oSize;
+
+  return true;
+}
+
+SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) {
+  SimpleHeap *simpHeap = (SimpleHeap*)hHeap;
+  return simpHeap->allocs[lpMem].size;
+}
+
+static SimpleHeap g_processHeap;
+
+HANDLE GetProcessHeap() {
+  return (HANDLE)&g_processHeap;
+}
+
+#endif // _WIN32

+ 8 - 1
lib/DxcSupport/dxcapi.use.cpp

@@ -13,6 +13,7 @@
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/Unicode.h"
+#include "dxc/Support/WinFunctions.h"
 
 namespace dxc {
 
@@ -37,6 +38,12 @@ static std::string GetWin32ErrorMessage(DWORD err) {
   }
   return std::string();
 }
+#else
+static std::string GetWin32ErrorMessage(DWORD err) {
+  // Since we use errno for handling messages, we use strerror to get the error
+  // message.
+  return std::string(std::strerror(err));
+}
 #endif // _WIN32
 
 void IFT_Data(HRESULT hr, LPCWSTR data) {
@@ -160,7 +167,7 @@ void WriteUtf8ToConsoleSizeT(_In_opt_count_(charCount) const char *pText,
     return;
   }
 
-  int charCountInt;
+  int charCountInt = 0;
   IFT(SizeTToInt(charCount, &charCountInt));
   WriteUtf8ToConsole(pText, charCountInt, streamType);
 }

+ 8 - 13
lib/DxcSupport/dxcmem.cpp

@@ -15,25 +15,16 @@
 #endif
 
 #include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
 #include "llvm/Support/ThreadLocal.h"
 #include <memory>
 
 static llvm::sys::ThreadLocal<IMalloc> *g_ThreadMallocTls;
 static IMalloc *g_pDefaultMalloc;
 
-// Used by DllMain to set up and tear down per-thread tracking.
-HRESULT DxcInitThreadMalloc() throw();
-void DxcCleanupThreadMalloc() throw();
-
-// Used by APIs that are entry points to set up per-thread/invocation allocator.
-void DxcSetThreadMalloc(IMalloc *pMalloc) throw();
-void DxcSetThreadMallocOrDefault(IMalloc *pMalloc) throw(); 
-void DxcClearThreadMalloc() throw();
-
-// Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
-IMalloc *DxcGetThreadMallocNoRef() throw();
-_Ret_maybenull_ _Post_writable_byte_size_(nBytes) void *DxcThreadAlloc(size_t nBytes) throw();
-void DxcThreadFree(void *) throw();
+#ifndef _WIN32
+#pragma GCC visibility push(hidden)
+#endif
 
 HRESULT DxcInitThreadMalloc() throw() {
   DXASSERT(g_pDefaultMalloc == nullptr, "else InitThreadMalloc already called");
@@ -96,3 +87,7 @@ IMalloc *DxcSwapThreadMalloc(IMalloc *pMalloc, IMalloc **ppPrior) throw() {
 IMalloc *DxcSwapThreadMallocOrDefault(IMalloc *pMallocOrNull, IMalloc **ppPrior) throw() {
   return DxcSwapThreadMalloc(pMallocOrNull ? pMallocOrNull : g_pDefaultMalloc, ppPrior);
 }
+
+#ifndef _WIN32
+#pragma GCC visibility pop
+#endif

+ 4 - 4
lib/HLSL/DxilContainerAssembler.cpp

@@ -1431,6 +1431,10 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
 
   // If we have debug information present, serialize it to a debug part, then use the stripped version as the canonical program version.
   CComPtr<AbstractMemoryStream> pProgramStream = pInputProgramStream;
+  const uint32_t DebugInfoNameHashLen = 32;   // 32 chars of MD5
+  const uint32_t DebugInfoNameSuffix = 4;     // '.lld'
+  const uint32_t DebugInfoNameNullAndPad = 4; // '\0\0\0\0'
+  CComPtr<AbstractMemoryStream> pHashStream;
   if (HasDebugInfo(*pModule->GetModule())) {
     uint32_t debugInUInt32, debugPaddingBytes;
     GetPaddedProgramPartSize(pInputProgramStream, debugInUInt32, debugPaddingBytes);
@@ -1450,16 +1454,12 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
     WriteBitcodeToFile(pModule->GetModule(), outStream, true);
 
     if (Flags & SerializeDxilFlags::IncludeDebugNamePart) {
-      CComPtr<AbstractMemoryStream> pHashStream;
       // If the debug name should be specific to the sources, base the name on the debug
       // bitcode, which will include the source references, line numbers, etc. Otherwise,
       // do it exclusively on the target shader bitcode.
       pHashStream = (int)(Flags & SerializeDxilFlags::DebugNameDependOnSource)
                         ? CComPtr<AbstractMemoryStream>(pModuleBitcode)
                         : CComPtr<AbstractMemoryStream>(pProgramStream);
-      const uint32_t DebugInfoNameHashLen = 32;   // 32 chars of MD5
-      const uint32_t DebugInfoNameSuffix = 4;     // '.lld'
-      const uint32_t DebugInfoNameNullAndPad = 4; // '\0\0\0\0'
       const uint32_t DebugInfoContentLen =
           sizeof(DxilShaderDebugName) + DebugInfoNameHashLen +
           DebugInfoNameSuffix + DebugInfoNameNullAndPad;

+ 10 - 0
lib/HLSL/DxilContainerReflection.cpp

@@ -30,8 +30,10 @@
 
 #include "dxc/dxcapi.h"
 
+#ifdef LLVM_ON_WIN32
 #include "d3d12shader.h" // for compatibility
 #include "d3d11shader.h" // for compatibility
+
 const GUID IID_ID3D11ShaderReflection_43 = {
     0x0a233719,
     0x3960,
@@ -2340,3 +2342,11 @@ ID3D12FunctionReflection *DxilLibraryReflection::GetFunctionByIndex(INT Function
 
 // DxilRuntimeReflection implementation
 #include "dxc/HLSL/DxilRuntimeReflection.inl"
+
+#else
+void hlsl::CreateDxcContainerReflection(IDxcContainerReflection **ppResult) {
+  *ppResult = nullptr;
+}
+
+DEFINE_CROSS_PLATFORM_UUIDOF(IDxcContainerReflection)
+#endif // LLVM_ON_WIN32

+ 2 - 0
lib/HLSL/DxilLegalizeSampleOffsetPass.cpp

@@ -153,6 +153,8 @@ void DxilLegalizeSampleOffsetPass::FinalCheck(
 void DxilLegalizeSampleOffsetPass::TryUnrollLoop(
     std::vector<Instruction *> &illegalOffsets, Function &F) {
   legacy::FunctionPassManager PM(F.getParent());
+  // Scalarize aggregates as mem2reg only applies on scalars.
+  PM.add(createSROAPass());
   // Always need mem2reg for simplify illegal offsets.
   PM.add(createPromoteMemoryToRegisterPass());
 

+ 1 - 0
lib/HLSL/DxilMetadataHelper.cpp

@@ -31,6 +31,7 @@
 #include <algorithm>
 
 #include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
 
 using namespace llvm;
 using std::string;

+ 5 - 6
lib/HLSL/DxilPreparePasses.cpp

@@ -330,12 +330,11 @@ public:
       // Strip parameters of entry function.
       StripEntryParameters(M, DM, IsLib);
 
-      // Skip shader flag for library.
-      if (!IsLib) {
-        DM.CollectShaderFlagsForModule(); // Update flags to reflect any changes.
-                                 // Update Validator Version
-        DM.UpgradeToMinValidatorVersion();
-      }
+      // Update flags to reflect any changes.
+      DM.CollectShaderFlagsForModule();
+
+      // Update Validator Version
+      DM.UpgradeToMinValidatorVersion();
 
       return true;
     }

+ 1 - 0
lib/HLSL/DxilRootSignature.cpp

@@ -14,6 +14,7 @@
 #include "dxc/HLSL/DxilPipelineStateValidation.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
 #include "dxc/Support/FileIOHelper.h"
 #include "dxc/dxcapi.h"
 

+ 31 - 7
lib/IR/PassRegistry.cpp

@@ -22,6 +22,7 @@
 
 using namespace llvm;
 
+#ifdef LLVM_ON_WIN32
 // HLSL Change Starts - managed statics are tied to DLL lifetime
 // Passes exist only in dxcompiler.dll or in a tool like opt that is updated.
 //
@@ -43,6 +44,7 @@ static void CheckThreadId() {
       "else updating PassRegistry from incorrect thread");
 }
 // HLSL Change Ends
+#endif
 
 // FIXME: We use ManagedStatic to erase the pass registrar on shutdown.
 // Unfortunately, passes are registered with static ctors, and having
@@ -61,13 +63,17 @@ PassRegistry *PassRegistry::getPassRegistry() {
 PassRegistry::~PassRegistry() {}
 
 const PassInfo *PassRegistry::getPassInfo(const void *TI) const {
-  // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifndef LLVM_ON_WIN32  // HLSL Change
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
   MapType::const_iterator I = PassInfoMap.find(TI);
   return I != PassInfoMap.end() ? I->second : nullptr;
 }
 
 const PassInfo *PassRegistry::getPassInfo(StringRef Arg) const {
-  // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifndef LLVM_ON_WIN32  // HLSL Change
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
   StringMapType::const_iterator I = PassInfoStringMap.find(Arg);
   return I != PassInfoStringMap.end() ? I->second : nullptr;
 }
@@ -77,7 +83,11 @@ const PassInfo *PassRegistry::getPassInfo(StringRef Arg) const {
 //
 
 void PassRegistry::registerPass(const PassInfo &PI, bool ShouldFree) {
-  CheckThreadId(); // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifdef LLVM_ON_WIN32  // HLSL Change
+  CheckThreadId();
+  #else
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
   bool Inserted =
       PassInfoMap.insert(std::make_pair(PI.getTypeInfo(), &PI)).second;
   assert(Inserted && "Pass registered multiple times!");
@@ -93,7 +103,9 @@ void PassRegistry::registerPass(const PassInfo &PI, bool ShouldFree) {
 }
 
 void PassRegistry::enumerateWith(PassRegistrationListener *L) {
-  // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifndef LLVM_ON_WIN32  // HLSL Change
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
   for (auto PassInfoPair : PassInfoMap)
     L->passEnumerate(PassInfoPair.second);
 }
@@ -117,7 +129,11 @@ void PassRegistry::registerAnalysisGroup(const void *InterfaceID,
     assert(ImplementationInfo &&
            "Must register pass before adding to AnalysisGroup!");
 
-    CheckThreadId(); // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+    #ifdef LLVM_ON_WIN32  // HLSL Change
+    CheckThreadId();
+    #else
+    sys::SmartScopedReader<true> Guard(Lock);
+    #endif
 
     // Make sure we keep track of the fact that the implementation implements
     // the interface.
@@ -140,12 +156,20 @@ void PassRegistry::registerAnalysisGroup(const void *InterfaceID,
 }
 
 void PassRegistry::addRegistrationListener(PassRegistrationListener *L) {
-  CheckThreadId(); // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifdef LLVM_ON_WIN32  // HLSL Change
+  CheckThreadId();
+  #else
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
   Listeners.push_back(L);
 }
 
 void PassRegistry::removeRegistrationListener(PassRegistrationListener *L) {
-  CheckThreadId(); // sys::SmartScopedReader<true> Guard(Lock); // HLSL Change
+  #ifdef LLVM_ON_WIN32  // HLSL Change
+  CheckThreadId();
+  #else
+  sys::SmartScopedReader<true> Guard(Lock);
+  #endif
 
   auto I = std::find(Listeners.begin(), Listeners.end(), L);
   Listeners.erase(I);

+ 197 - 0
lib/MSSupport/MSFileSystemImpl.cpp

@@ -89,105 +89,187 @@ public:
   virtual errno_t resize_file(_In_ LPCWSTR path, uint64_t size) throw() override;
   virtual int Read(int fd, _Out_bytecap_(count) void* buffer, unsigned int count) throw() override;
   virtual int Write(int fd, _In_bytecount_(count) const void* buffer, unsigned int count) throw() override;
+#ifndef _WIN32
+  virtual int Open(const char *lpFileName, int flags, mode_t mode) throw() override;
+  virtual int Stat(const char *lpFileName, struct stat *Status) throw() override;
+  virtual int Fstat(int FD, struct stat *Status) throw() override;
+#endif
 };
 
 MSFileSystemForDisk::MSFileSystemForDisk()
 {
+  #ifdef _WIN32
   _defaultAttributes = GetConsoleOutputTextAttributes();
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) throw()
 {
+  #ifdef _WIN32
   return ::FindNextFileW(hFindFile, lpFindFileData);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 HANDLE MSFileSystemForDisk::FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) throw()
 {
+  #ifdef _WIN32
   return ::FindFirstFileW(lpFileName, lpFindFileData);
+  #else
+  assert(false && "Not implemented for Unix");
+  return nullptr;
+  #endif
 }
 
 void MSFileSystemForDisk::FindClose(HANDLE findHandle) throw()
 {
+  #ifdef _WIN32
   ::FindClose(findHandle);
+  #else
+  assert(false && "Not implemented for Unix");
+  #endif
 }
 
 _Use_decl_annotations_
 HANDLE MSFileSystemForDisk::CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes) throw()
 {
+  #ifdef _WIN32
   return ::CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, nullptr, dwCreationDisposition, dwFlagsAndAttributes, nullptr);
+  #else
+  assert(false && "Not implemented for Unix");
+  return nullptr;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::SetFileTime(HANDLE hFile, _In_opt_ const FILETIME *lpCreationTime, _In_opt_ const FILETIME *lpLastAccessTime, _In_opt_ const FILETIME *lpLastWriteTime) throw()
 {
+  #ifdef _WIN32
   return ::SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation) throw()
 {
+  #ifdef _WIN32
   return ::GetFileInformationByHandle(hFile, lpFileInformation);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 DWORD MSFileSystemForDisk::GetFileType(HANDLE hFile) throw()
 {
+  #ifdef _WIN32
   return ::GetFileType(hFile);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::CreateHardLinkW(LPCWSTR lpFileName, LPCWSTR lpExistingFileName) throw()
 {
+  #ifdef _WIN32
   return ::CreateHardLinkW(lpFileName, lpExistingFileName, nullptr);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags) throw()
 {
+  #ifdef _WIN32
   return ::MoveFileExW(lpExistingFileName, lpNewFileName, dwFlags);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 DWORD MSFileSystemForDisk::GetFileAttributesW(LPCWSTR lpFileName) throw()
 {
+  #ifdef _WIN32
   return ::GetFileAttributesW(lpFileName);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::CloseHandle(HANDLE hObject) throw()
 {
+  #ifdef _WIN32
   return ::CloseHandle(hObject);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::DeleteFileW(LPCWSTR lpFileName) throw()
 {
+  #ifdef _WIN32
   return ::DeleteFileW(lpFileName);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::RemoveDirectoryW(LPCWSTR lpFileName) throw()
 {
+  #ifdef _WIN32
   return ::RemoveDirectoryW(lpFileName);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::CreateDirectoryW(LPCWSTR lpPathName) throw()
 {
+  #ifdef _WIN32
   return ::CreateDirectoryW(lpPathName, nullptr);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 DWORD MSFileSystemForDisk::GetCurrentDirectoryW(DWORD nBufferLength,  LPWSTR lpBuffer) throw()
 {
+  #ifdef _WIN32
   return ::GetCurrentDirectoryW(nBufferLength, lpBuffer);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 DWORD MSFileSystemForDisk::GetMainModuleFileNameW(LPWSTR lpFilename, DWORD nSize) throw()
 {
+  #ifdef _WIN32
   // Add some code to ensure that the result is null terminated.
   if (nSize <= 1)
   {
@@ -199,14 +281,24 @@ DWORD MSFileSystemForDisk::GetMainModuleFileNameW(LPWSTR lpFilename, DWORD nSize
   if (result == 0) return result;
   lpFilename[result] = L'\0';
   return result;
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 DWORD MSFileSystemForDisk::GetTempPathW(DWORD nBufferLength, LPWSTR lpBuffer) throw()
 {
+  #ifdef _WIN32
   return ::GetTempPathW(nBufferLength, lpBuffer);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
+#ifdef _WIN32
 namespace {
   typedef BOOLEAN(WINAPI *PtrCreateSymbolicLinkW)(
     /*__in*/ LPCWSTR lpSymlinkFileName,
@@ -217,103 +309,181 @@ namespace {
     PtrCreateSymbolicLinkW(::GetProcAddress(
     ::GetModuleHandleW(L"Kernel32.dll"), "CreateSymbolicLinkW"));
 }
+#endif
 
 _Use_decl_annotations_
 BOOLEAN MSFileSystemForDisk::CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags) throw()
 {
+  #ifdef _WIN32
   return create_symbolic_link_api(lpSymlinkFileName, lpTargetFileName, dwFlags);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 bool MSFileSystemForDisk::SupportsCreateSymbolicLink() throw()
 {
+  #ifdef _WIN32
   return create_symbolic_link_api != nullptr;
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, _Out_opt_ LPDWORD lpNumberOfBytesRead) throw()
 {
+  #ifdef _WIN32
   return ::ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, nullptr);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 _Use_decl_annotations_
 HANDLE MSFileSystemForDisk::CreateFileMappingW(HANDLE hFile, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow) throw()
 {
+  #ifdef _WIN32
   return ::CreateFileMappingW(hFile, nullptr, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, nullptr);
+  #else
+  assert(false && "Not implemented for Unix");
+  return nullptr;
+  #endif
 }
 
 _Use_decl_annotations_
 LPVOID MSFileSystemForDisk::MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) throw()
 {
+  #ifdef _WIN32
   return ::MapViewOfFile(hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap);
+  #else
+  assert(false && "Not implemented for Unix");
+  return nullptr;
+  #endif
 }
 
 _Use_decl_annotations_
 BOOL MSFileSystemForDisk::UnmapViewOfFile(LPCVOID lpBaseAddress) throw()
 {
+  #ifdef _WIN32
   return ::UnmapViewOfFile(lpBaseAddress);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 bool MSFileSystemForDisk::FileDescriptorIsDisplayed(int fd) throw()
 {
+  #ifdef _WIN32
   DWORD Mode;  // Unused
   return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
+  #else
+  assert(false && "Not implemented for Unix");
+  return false;
+  #endif
 }
 
 unsigned MSFileSystemForDisk::GetColumnCount(DWORD nStdHandle) throw()
 {
+  #ifdef _WIN32
   unsigned Columns = 0;
   CONSOLE_SCREEN_BUFFER_INFO csbi;
   if (::GetConsoleScreenBufferInfo(GetStdHandle(nStdHandle), &csbi))
     Columns = csbi.dwSize.X;
   return Columns;
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 unsigned MSFileSystemForDisk::GetConsoleOutputTextAttributes() throw()
 {
+  #ifdef _WIN32
   CONSOLE_SCREEN_BUFFER_INFO csbi;
   if (::GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
     return csbi.wAttributes;
   return 0;
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 void MSFileSystemForDisk::SetConsoleOutputTextAttributes(unsigned attributes) throw()
 {
+  #ifdef _WIN32
   ::SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attributes);
+  #else
+  assert(false && "Not implemented for Unix");
+  #endif
 }
 
 void MSFileSystemForDisk::ResetConsoleOutputTextAttributes() throw()
 {
+  #ifdef _WIN32
   ::SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _defaultAttributes);
+  #else
+  assert(false && "Not implemented for Unix");
+  #endif
 }
 
 int MSFileSystemForDisk::open_osfhandle(intptr_t osfhandle, int flags) throw()
 {
+  #ifdef _WIN32
   return ::_open_osfhandle(osfhandle, flags);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 intptr_t MSFileSystemForDisk::get_osfhandle(int fd) throw()
 {
+  #ifdef _WIN32
   return ::_get_osfhandle(fd);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 int MSFileSystemForDisk::close(int fd) throw()
 {
+  #ifdef _WIN32
   return ::_close(fd);
+  #else
+  return ::close(fd);
+  #endif
 }
 
 long MSFileSystemForDisk::lseek(int fd, long offset, int origin) throw()
 {
+  #ifdef _WIN32
   return ::_lseek(fd, offset, origin);
+  #else
+  return ::lseek(fd, offset, origin);
+  #endif
 }
 
 int MSFileSystemForDisk::setmode(int fd, int mode) throw()
 {
+  #ifdef _WIN32
   return ::_setmode(fd, mode);
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 errno_t MSFileSystemForDisk::resize_file(LPCWSTR path, uint64_t size) throw()
 {
+  #ifdef _WIN32
   int fd = ::_wopen(path, O_BINARY | _O_RDWR, S_IWRITE);
   if (fd == -1)
     return errno;
@@ -324,20 +494,47 @@ errno_t MSFileSystemForDisk::resize_file(LPCWSTR path, uint64_t size) throw()
 #endif
   ::_close(fd);
   return error;
+
+  #else
+  assert(false && "Not implemented for Unix");
+  return 0;
+  #endif
 }
 
 _Use_decl_annotations_
 int MSFileSystemForDisk::Read(int fd, void* buffer, unsigned int count) throw()
 {
+  #ifdef _WIN32
   return ::_read(fd, buffer, count);
+  #else
+  return ::read(fd, buffer, count);
+  #endif
 }
 
 _Use_decl_annotations_
 int MSFileSystemForDisk::Write(int fd, const void* buffer, unsigned int count) throw()
 {
+  #ifdef _WIN32
   return ::_write(fd, buffer, count);
+  #else
+  return ::write(fd, buffer, count);
+  #endif
+}
+
+#ifndef _WIN32
+int MSFileSystemForDisk::Open(const char *lpFileName, int flags, mode_t mode) throw() {
+  return ::open(lpFileName, flags, mode);
 }
 
+int MSFileSystemForDisk::Stat(const char *lpFileName, struct stat *Status) throw() {
+  return ::stat(lpFileName, Status);
+}
+
+int MSFileSystemForDisk::Fstat(int FD, struct stat *Status) throw() {
+  return ::fstat(FD, Status);
+}
+#endif
+
 } // end namespace fs
 } // end namespace sys
 } // end namespace llvm

+ 2 - 1
lib/Support/CMakeLists.txt

@@ -28,7 +28,7 @@ if( NOT MSVC )
 endif( NOT MSVC )
 
 # HLSL Change - add ignored sources
-set(HLSL_IGNORE_SOURCES DynamicLibrary.cpp PluginLoader.cpp)
+set(HLSL_IGNORE_SOURCES PluginLoader.cpp)
 
 add_llvm_library(LLVMSupport
   APFloat.cpp
@@ -52,6 +52,7 @@ add_llvm_library(LLVMSupport
   DeltaAlgorithm.cpp
   DAGDeltaAlgorithm.cpp
   Dwarf.cpp
+  DynamicLibrary.cpp
   ErrorHandling.cpp
   FileUtilities.cpp
   FileOutputBuffer.cpp

+ 3 - 3
lib/Support/ErrorHandling.cpp

@@ -87,7 +87,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
     handlerData = ErrorHandlerUserData;
   }
 
-#if 0 // HLSL Change - unwind if necessary, but don't terminate the process
+#ifndef LLVM_ON_WIN32 // HLSL Change - unwind if necessary, but don't terminate the process
   if (handler) {
     handler(handlerData, Reason.str(), GenCrashDiag);
   } else {
@@ -98,7 +98,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
     raw_svector_ostream OS(Buffer);
     OS << "LLVM ERROR: " << Reason << "\n";
     StringRef MessageStr = OS.str();
-    ssize_t written = ::_write(2, MessageStr.data(), MessageStr.size());
+    ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
     (void)written; // If something went wrong, we deliberately just give up.
   }
 
@@ -127,7 +127,7 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file,
   if (file)
     dbgs() << " at " << file << ":" << line;
   dbgs() << "!\n";
-#if 0 // HLSL Change - unwind if necessary, but don't terminate the process
+#ifndef LLVM_ON_WIN32 // HLSL Change - unwind if necessary, but don't terminate the process
   abort();
 #else
   RaiseException(STATUS_LLVM_UNREACHABLE, 0, 0, 0);

+ 34 - 0
lib/Support/MSFileSystemBasic.cpp

@@ -222,6 +222,11 @@ public:
   virtual errno_t resize_file(_In_ LPCWSTR path, uint64_t size) throw() override;
   virtual int Read(int fd, _Out_bytecap_(count) void* buffer, unsigned int count) throw() override;
   virtual int Write(int fd, _In_bytecount_(count) const void* buffer, unsigned int count) throw() override;
+#ifndef _WIN32
+  virtual int Open(const char *lpFileName, int flags, mode_t mode) throw() override;
+  virtual int Stat(const char *lpFileName, struct stat *Status) throw() override;
+  virtual int Fstat(int FD, struct stat *Status) throw() override;
+#endif
 };
 
 _Use_decl_annotations_
@@ -942,6 +947,23 @@ Cleanup:
   return (int)cbWritten;
 }
 
+#ifndef _WIN32
+int MSFileSystemForIface::Open(const char *lpFileName, int flags, mode_t mode) throw() {
+  SetLastError(ERROR_FUNCTION_NOT_CALLED);
+  return FALSE;
+}
+
+int MSFileSystemForIface::Stat(const char *lpFileName, struct stat *Status) throw() {
+  SetLastError(ERROR_FUNCTION_NOT_CALLED);
+  return FALSE;
+}
+
+int MSFileSystemForIface::Fstat(int FD, struct stat *Status) throw() {
+  SetLastError(ERROR_FUNCTION_NOT_CALLED);
+  return FALSE;
+}
+#endif
+
 } // end namespace fs
 } // end namespace sys
 } // end namespace llvm
@@ -1099,6 +1121,18 @@ public:
   virtual int Write(int fd, const void* buffer, unsigned int count) throw() override
   { return MSFileSystemBlockedErrno(); }
 
+  // Unix interface
+#ifndef _WIN32
+  virtual int Open(const char *lpFileName, int flags, mode_t mode) throw() override
+  { return MSFileSystemBlockedErrno(); }
+
+  virtual int Stat(const char *lpFileName, struct stat *Status) throw() override
+  { return MSFileSystemBlockedErrno(); }
+
+  virtual int Fstat(int FD, struct stat *Status) throw() override
+  { return MSFileSystemBlockedErrno(); }
+#endif
+
 };
 
 MSFileSystemBlocked::MSFileSystemBlocked()

+ 1 - 0
lib/Support/MemoryBuffer.cpp

@@ -377,6 +377,7 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
   char *BufPtr = const_cast<char *>(Buf->getBufferStart());
 
   size_t BytesLeft = MapSize;
+#undef HAVE_PREAD // HLSL Change - pread bypasses needed layers
 #ifndef HAVE_PREAD
   if (llvm::sys::fs::msf_lseek(FD, Offset, SEEK_SET) == -1)  // HLSL Change - use msf_lseek
     return std::error_code(errno, std::generic_category());

+ 93 - 4
lib/Support/Unix/Path.inc

@@ -60,6 +60,8 @@
 # define PATH_MAX 4096
 #endif
 
+#include "llvm/Support/MSFileSystem.h" // HLSL change
+
 using namespace llvm;
 
 namespace llvm {
@@ -379,13 +381,15 @@ std::error_code status(const Twine &Path, file_status &Result) {
   StringRef P = Path.toNullTerminatedStringRef(PathStorage);
 
   struct stat Status;
-  int StatRet = ::stat(P.begin(), &Status);
+  MSFileSystem* fsr = GetCurrentThreadFileSystem(); // HLSL Change
+  int StatRet = fsr->Stat(P.begin(), &Status); // HLSL Change - FS abstraction
   return fillStatus(StatRet, Status, Result);
 }
 
 std::error_code status(int FD, file_status &Result) {
   struct stat Status;
-  int StatRet = ::fstat(FD, &Status);
+  MSFileSystem* fsr = GetCurrentThreadFileSystem(); // HLSL Change
+  int StatRet = fsr->Fstat(FD, &Status); // HLSL Change - FS abstraction
   return fillStatus(StatRet, Status, Result);
 }
 
@@ -504,7 +508,8 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
 std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
   SmallString<128> Storage;
   StringRef P = Name.toNullTerminatedStringRef(Storage);
-  while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem(); // HLSL Change
+  while ((ResultFD = fsr->Open(P.begin(), O_RDONLY)) < 0) { // HLSL Change - FS abstraction
     if (errno != EINTR)
       return std::error_code(errno, std::generic_category());
   }
@@ -534,7 +539,8 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
 
   SmallString<128> Storage;
   StringRef P = Name.toNullTerminatedStringRef(Storage);
-  while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem(); // HLSL Change
+  while ((ResultFD = fsr->Open(P.begin(), OpenFlags, Mode)) < 0) { // HLSL Change - FS abstraction
     if (errno != EINTR)
       return std::error_code(errno, std::generic_category());
   }
@@ -619,3 +625,86 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
 
 } // end namespace sys
 } // end namespace llvm
+
+
+// The following is implementation of MSFileSystem for Unix.
+// This will make usages of MSFileSystem throughout DirectXShaderCompiler
+// compatible with Unix.
+namespace llvm {
+namespace sys  {
+namespace fs {
+
+thread_local MSFileSystem* threadFS = nullptr;
+
+std::error_code SetupPerThreadFileSystem() throw() {
+  // This method is now a no-op since we are using thread_local.
+  return std::error_code();
+}
+void CleanupPerThreadFileSystem() throw() {
+  // This method is now a no-op since we are using thread_local.
+}
+
+MSFileSystem* GetCurrentThreadFileSystem() throw() {
+  return threadFS;
+}
+
+std::error_code SetCurrentThreadFileSystem(MSFileSystem* value) throw() {
+  // For now, disallow reentrancy in APIs (i.e., replace the current instance with another one).
+  if (value != nullptr) {
+    MSFileSystem* current = GetCurrentThreadFileSystem();
+    if (current != nullptr) {
+      return std::error_code(1131L, std::system_category());
+    }
+  }
+  threadFS = value;
+  return std::error_code();
+}
+
+int msf_read(int fd, void* buffer, unsigned int count) throw() {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem();
+  if (fsr == nullptr) {
+    errno = EBADF;
+    return -1;
+  }
+  return fsr->Read(fd, buffer, count);
+}
+
+int msf_write(int fd, const void* buffer, unsigned int count) throw() {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem();
+  if (fsr == nullptr) {
+    errno = EBADF;
+    return -1;
+  }
+  return fsr->Write(fd, buffer, count);
+}
+
+int msf_close(int fd) throw() {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem();
+  if (fsr == nullptr) {
+    errno = EBADF;
+    return -1;
+  }
+  return fsr->close(fd);
+}
+
+long msf_lseek(int fd, long offset, int origin) {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem();
+  if (fsr == nullptr) {
+    errno = EBADF;
+    return -1;
+  }
+  return fsr->lseek(fd, offset, origin);
+}
+
+int msf_setmode(int fd, int mode) throw() {
+  MSFileSystem* fsr = GetCurrentThreadFileSystem();
+  if (fsr == nullptr) {
+    errno = EBADF;
+    return -1;
+  }
+  return fsr->setmode(fd, mode);
+}
+
+} // namespace fs
+} // namespace sys
+} // namespace llvm

+ 1 - 1
lib/Support/Unix/Process.inc

@@ -262,7 +262,7 @@ std::error_code Process::SafelyCloseFileDescriptor(int FD) {
   // We need to save the error, if one occurs, because our subsequent call to
   // pthread_sigmask might tamper with errno.
   int ErrnoFromClose = 0;
-  if (::close(FD) < 0)
+  if (fs::msf_close(FD) < 0)
     ErrnoFromClose = errno;
   // Restore the signal mask back to what we saved earlier.
   int EC = 0;

+ 13 - 0
lib/Support/assert.cpp

@@ -8,6 +8,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "assert.h"
+
+#ifdef _WIN32
+
 #include "windows.h"
 #include "dxc/Support/Global.h"
 
@@ -18,3 +21,13 @@ void llvm_assert(_In_z_ const char *_Message,
   OutputDebugFormatA("Error: assert(%s)\nFile:\n%s(%d)\nFunc:\t%s\n", _Message, _File, _Line, _Function);
   RaiseException(STATUS_LLVM_ASSERT, 0, 0, 0);
 }
+
+#else
+
+#include <assert.h>
+
+void llvm_assert(const char* message, const char*, unsigned) {
+  assert(false && message);
+}
+
+#endif

+ 4 - 1
lib/Support/regerror.c

@@ -108,12 +108,15 @@ llvm_regerror(int errcode, const llvm_regex_t *preg, _Out_writes_all_(errbuf_siz
 				assert(strlen(r->name) < sizeof(convbuf));
 				(void) llvm_strlcpy(convbuf, r->name, sizeof convbuf);
 			} else
+                          // Begin HLSL Change
 #ifdef _WIN32
 				(void)_snprintf_s(convbuf, _countof(convbuf), _countof(convbuf),
+				    "REG_0x%x", target);
 #else
 				(void)snprintf(convbuf, sizeof convbuf,
-#endif // WIN32
 				    "REG_0x%x", target);
+#endif // WIN32
+                          // End HLSL Change
 			s = convbuf;
 		} else
 			s = r->explain;

+ 3 - 3
lib/Support/regex_impl.h

@@ -35,8 +35,8 @@
  *	@(#)regex.h	8.1 (Berkeley) 6/2/93
  */
 
-#ifndef _REGEX_H_
-#define	_REGEX_H_
+#ifndef _REGEX_IMPL_H_ // HLSL Change
+#define _REGEX_IMPL_H_ // HLSL Change
 
 #include "dxc/Support/WinAdapter.h" // HLSL Change
 #include <sys/types.h>
@@ -119,4 +119,4 @@ size_t  llvm_strlcpy(
 }
 #endif
 
-#endif /* !_REGEX_H_ */
+#endif /* !_REGEX_IMPL_H_ */ // HLSL Change

+ 2 - 0
lib/Transforms/IPO/FunctionAttrs.cpp

@@ -1627,6 +1627,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) {
     setOnlyReadsMemory(F, 1);
     setOnlyReadsMemory(F, 2);
     break;
+#if 0 // HLSL Change Starts - Exclude potentially duplicate 64bit versions
   case LibFunc::fopen64:
     if (FTy->getNumParams() != 2 ||
         !FTy->getReturnType()->isPointerTy() ||
@@ -1653,6 +1654,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) {
     setDoesNotThrow(F);
     setDoesNotAlias(F, 0);
     break;
+#endif // HLSL Change Ends - Exclude potentially duplicate 64bit versions
   case LibFunc::fstat64:
   case LibFunc::fstatvfs64:
     if (FTy->getNumParams() != 2 || !FTy->getParamType(1)->isPointerTy())

+ 7 - 1
tools/CMakeLists.txt

@@ -17,7 +17,13 @@ endif()
 # add_llvm_tool_subdirectory(llvm-as) # HLSL Change
 # add_llvm_tool_subdirectory(llvm-dis) # HLSL Change
 # add_llvm_tool_subdirectory(llvm-mc) # HLSL Change
-add_llvm_tool_subdirectory(dxexp) # HLSL Change
+
+# HLSL Change Begins
+if (WIN32)
+# This target can currently only be built on Windows.
+add_llvm_tool_subdirectory(dxexp)
+endif (WIN32)
+# HLSL Change ends
 
 # add_llvm_tool_subdirectory(llc) # HLSL Change
 # add_llvm_tool_subdirectory(llvm-ar) # HLSL Change

+ 1 - 0
tools/clang/include/clang/AST/HlslTypes.h

@@ -34,6 +34,7 @@ namespace clang {
   class FunctionTemplateDecl;
   class InheritableAttr;
   class NamedDecl;
+  class Sema;
   class TypeSourceInfo;
   class TypedefDecl;
 }

+ 6 - 0
tools/clang/include/clang/Basic/Attr.td

@@ -754,6 +754,12 @@ def HLSLLinear : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
+def HLSLCenter : InheritableAttr {
+  let Spellings = [CXX11<"", "center", 2015>];
+  let Subjects = SubjectList<[Function, ParmVar, Field]>;
+  let Documentation = [Undocumented];
+}
+
 def HLSLNoPerspective : InheritableAttr {
   let Spellings = [CXX11<"", "noperspective", 2015>];
   let Subjects = SubjectList<[Function, ParmVar, Field]>;

+ 1 - 0
tools/clang/include/clang/Basic/TokenKinds.def

@@ -498,6 +498,7 @@ KEYWORD(out                         , KEYHLSL)
 KEYWORD(inout                       , KEYHLSL)
 KEYWORD(uniform                     , KEYHLSL)
 KEYWORD(precise                     , KEYHLSL)
+KEYWORD(center                      , KEYHLSL)
 KEYWORD(shared                      , KEYHLSL)
 KEYWORD(groupshared                 , KEYHLSL)
 KEYWORD(discard                     , KEYHLSL)

+ 12 - 0
tools/clang/include/clang/Basic/TokenKinds.h

@@ -100,6 +100,18 @@ inline bool isAnnotation(TokenKind K) {
   return false;
 }
 
+// HLSL Change Starts
+/// \brief Return true if this is a punctuator token.
+inline bool isPunctuator(TokenKind K) {
+#define PUNCTUATOR(NAME, SYMBOL) \
+  if (K == tok::NAME) \
+    return true;
+#include "clang/Basic/TokenKinds.def"
+#undef PUNCTUATOR
+  return false;
+}
+// HLSL Change Ends
+
 }  // end namespace tok
 }  // end namespace clang
 

+ 2 - 0
tools/clang/include/clang/Frontend/FrontendActions.h

@@ -137,6 +137,7 @@ public:
   bool hasCodeCompletionSupport() const override { return true; }
 };
 
+#if 0 // HLSL change - no support for modules or PCH
 /// \brief Dump information about the given module file, to be used for
 /// basic debugging and discovery.
 class DumpModuleInfoAction : public ASTFrontendAction {
@@ -162,6 +163,7 @@ protected:
 public:
   bool hasCodeCompletionSupport() const override { return false; }
 };
+#endif // HLSL changes
 
 /**
  * \brief Frontend action adaptor that merges ASTs together.

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

@@ -32,7 +32,8 @@ struct EmitSPIRVOptions {
   bool codeGenHighLevel;
   bool defaultRowMajor;
   bool disableValidation;
-  bool invertY;
+  bool invertY; // Additive inverse
+  bool invertW; // Multiplicative inverse
   bool useGlLayout;
   bool useDxLayout;
   bool enable16BitTypes;

+ 7 - 552
tools/clang/include/clang/SPIRV/InstBuilder.h

@@ -23,6 +23,7 @@
 #include "spirv/unified1/spirv.hpp11"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
 
 namespace clang {
 namespace spirv {
@@ -93,10 +94,10 @@ public:
   // Instruction building methods.
   InstBuilder &opNop();
   InstBuilder &opUndef(uint32_t result_type, uint32_t result_id);
-  InstBuilder &opSourceContinued(std::string continued_source);
+  InstBuilder &opSourceContinued(llvm::StringRef continued_source);
   InstBuilder &opSource(spv::SourceLanguage source_language, uint32_t version,
                         llvm::Optional<uint32_t> file,
-                        llvm::Optional<std::string> source);
+                        llvm::Optional<llvm::StringRef> source);
   InstBuilder &opSourceExtension(std::string extension);
   InstBuilder &opName(uint32_t target, std::string name);
   InstBuilder &opMemberName(uint32_t type, uint32_t member, std::string name);
@@ -307,179 +308,9 @@ public:
                                   uint32_t image);
   InstBuilder &opImageQuerySamples(uint32_t result_type, uint32_t result_id,
                                    uint32_t image);
-  InstBuilder &opConvertFToU(uint32_t result_type, uint32_t result_id,
-                             uint32_t float_value);
-  InstBuilder &opConvertFToS(uint32_t result_type, uint32_t result_id,
-                             uint32_t float_value);
-  InstBuilder &opConvertSToF(uint32_t result_type, uint32_t result_id,
-                             uint32_t signed_value);
-  InstBuilder &opConvertUToF(uint32_t result_type, uint32_t result_id,
-                             uint32_t unsigned_value);
-  InstBuilder &opUConvert(uint32_t result_type, uint32_t result_id,
-                          uint32_t unsigned_value);
-  InstBuilder &opSConvert(uint32_t result_type, uint32_t result_id,
-                          uint32_t signed_value);
-  InstBuilder &opFConvert(uint32_t result_type, uint32_t result_id,
-                          uint32_t float_value);
-  InstBuilder &opQuantizeToF16(uint32_t result_type, uint32_t result_id,
-                               uint32_t value);
-  InstBuilder &opConvertPtrToU(uint32_t result_type, uint32_t result_id,
-                               uint32_t pointer);
-  InstBuilder &opSatConvertSToU(uint32_t result_type, uint32_t result_id,
-                                uint32_t signed_value);
-  InstBuilder &opSatConvertUToS(uint32_t result_type, uint32_t result_id,
-                                uint32_t unsigned_value);
-  InstBuilder &opConvertUToPtr(uint32_t result_type, uint32_t result_id,
-                               uint32_t integer_value);
-  InstBuilder &opPtrCastToGeneric(uint32_t result_type, uint32_t result_id,
-                                  uint32_t pointer);
-  InstBuilder &opGenericCastToPtr(uint32_t result_type, uint32_t result_id,
-                                  uint32_t pointer);
-  InstBuilder &opGenericCastToPtrExplicit(uint32_t result_type,
-                                          uint32_t result_id, uint32_t pointer,
-                                          spv::StorageClass storage);
-  InstBuilder &opBitcast(uint32_t result_type, uint32_t result_id,
-                         uint32_t operand);
-  InstBuilder &opSNegate(uint32_t result_type, uint32_t result_id,
-                         uint32_t operand);
-  InstBuilder &opFNegate(uint32_t result_type, uint32_t result_id,
-                         uint32_t operand);
-  InstBuilder &opIAdd(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFAdd(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opISub(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFSub(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opIMul(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFMul(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opUDiv(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSDiv(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFDiv(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opUMod(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSRem(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSMod(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFRem(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFMod(uint32_t result_type, uint32_t result_id,
-                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opVectorTimesScalar(uint32_t result_type, uint32_t result_id,
-                                   uint32_t vector, uint32_t scalar);
-  InstBuilder &opMatrixTimesScalar(uint32_t result_type, uint32_t result_id,
-                                   uint32_t matrix, uint32_t scalar);
-  InstBuilder &opVectorTimesMatrix(uint32_t result_type, uint32_t result_id,
-                                   uint32_t vector, uint32_t matrix);
-  InstBuilder &opMatrixTimesVector(uint32_t result_type, uint32_t result_id,
-                                   uint32_t matrix, uint32_t vector);
-  InstBuilder &opMatrixTimesMatrix(uint32_t result_type, uint32_t result_id,
-                                   uint32_t left_matrix, uint32_t right_matrix);
-  InstBuilder &opOuterProduct(uint32_t result_type, uint32_t result_id,
-                              uint32_t vector_1, uint32_t vector_2);
-  InstBuilder &opDot(uint32_t result_type, uint32_t result_id,
-                     uint32_t vector_1, uint32_t vector_2);
-  InstBuilder &opIAddCarry(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opISubBorrow(uint32_t result_type, uint32_t result_id,
-                            uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opUMulExtended(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSMulExtended(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opAny(uint32_t result_type, uint32_t result_id, uint32_t vector);
-  InstBuilder &opAll(uint32_t result_type, uint32_t result_id, uint32_t vector);
-  InstBuilder &opIsNan(uint32_t result_type, uint32_t result_id, uint32_t x);
-  InstBuilder &opIsInf(uint32_t result_type, uint32_t result_id, uint32_t x);
-  InstBuilder &opIsFinite(uint32_t result_type, uint32_t result_id, uint32_t x);
-  InstBuilder &opIsNormal(uint32_t result_type, uint32_t result_id, uint32_t x);
-  InstBuilder &opSignBitSet(uint32_t result_type, uint32_t result_id,
-                            uint32_t x);
-  InstBuilder &opLessOrGreater(uint32_t result_type, uint32_t result_id,
-                               uint32_t x, uint32_t y);
-  InstBuilder &opOrdered(uint32_t result_type, uint32_t result_id, uint32_t x,
-                         uint32_t y);
-  InstBuilder &opUnordered(uint32_t result_type, uint32_t result_id, uint32_t x,
-                           uint32_t y);
-  InstBuilder &opLogicalEqual(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opLogicalNotEqual(uint32_t result_type, uint32_t result_id,
-                                 uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opLogicalOr(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opLogicalAnd(uint32_t result_type, uint32_t result_id,
-                            uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opLogicalNot(uint32_t result_type, uint32_t result_id,
-                            uint32_t operand);
   InstBuilder &opSelect(uint32_t result_type, uint32_t result_id,
                         uint32_t condition, uint32_t object_1,
                         uint32_t object_2);
-  InstBuilder &opIEqual(uint32_t result_type, uint32_t result_id,
-                        uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opINotEqual(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opUGreaterThan(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSGreaterThan(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opUGreaterThanEqual(uint32_t result_type, uint32_t result_id,
-                                   uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSGreaterThanEqual(uint32_t result_type, uint32_t result_id,
-                                   uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opULessThan(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSLessThan(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opULessThanEqual(uint32_t result_type, uint32_t result_id,
-                                uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opSLessThanEqual(uint32_t result_type, uint32_t result_id,
-                                uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdEqual(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordEqual(uint32_t result_type, uint32_t result_id,
-                             uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdNotEqual(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordNotEqual(uint32_t result_type, uint32_t result_id,
-                                uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdLessThan(uint32_t result_type, uint32_t result_id,
-                              uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordLessThan(uint32_t result_type, uint32_t result_id,
-                                uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdGreaterThan(uint32_t result_type, uint32_t result_id,
-                                 uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordGreaterThan(uint32_t result_type, uint32_t result_id,
-                                   uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdLessThanEqual(uint32_t result_type, uint32_t result_id,
-                                   uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordLessThanEqual(uint32_t result_type, uint32_t result_id,
-                                     uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFOrdGreaterThanEqual(uint32_t result_type, uint32_t result_id,
-                                      uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opFUnordGreaterThanEqual(uint32_t result_type,
-                                        uint32_t result_id, uint32_t operand_1,
-                                        uint32_t operand_2);
-  InstBuilder &opShiftRightLogical(uint32_t result_type, uint32_t result_id,
-                                   uint32_t base, uint32_t shift);
-  InstBuilder &opShiftRightArithmetic(uint32_t result_type, uint32_t result_id,
-                                      uint32_t base, uint32_t shift);
-  InstBuilder &opShiftLeftLogical(uint32_t result_type, uint32_t result_id,
-                                  uint32_t base, uint32_t shift);
-  InstBuilder &opBitwiseOr(uint32_t result_type, uint32_t result_id,
-                           uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opBitwiseXor(uint32_t result_type, uint32_t result_id,
-                            uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opBitwiseAnd(uint32_t result_type, uint32_t result_id,
-                            uint32_t operand_1, uint32_t operand_2);
-  InstBuilder &opNot(uint32_t result_type, uint32_t result_id,
-                     uint32_t operand);
   InstBuilder &opBitFieldInsert(uint32_t result_type, uint32_t result_id,
                                 uint32_t base, uint32_t insert, uint32_t offset,
                                 uint32_t count);
@@ -536,33 +367,6 @@ public:
   InstBuilder &opAtomicIDecrement(uint32_t result_type, uint32_t result_id,
                                   uint32_t pointer, uint32_t scope,
                                   uint32_t semantics);
-  InstBuilder &opAtomicIAdd(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicISub(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicSMin(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicUMin(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicSMax(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicUMax(uint32_t result_type, uint32_t result_id,
-                            uint32_t pointer, uint32_t scope,
-                            uint32_t semantics, uint32_t value);
-  InstBuilder &opAtomicAnd(uint32_t result_type, uint32_t result_id,
-                           uint32_t pointer, uint32_t scope, uint32_t semantics,
-                           uint32_t value);
-  InstBuilder &opAtomicOr(uint32_t result_type, uint32_t result_id,
-                          uint32_t pointer, uint32_t scope, uint32_t semantics,
-                          uint32_t value);
-  InstBuilder &opAtomicXor(uint32_t result_type, uint32_t result_id,
-                           uint32_t pointer, uint32_t scope, uint32_t semantics,
-                           uint32_t value);
   InstBuilder &
   opPhi(uint32_t result_type, uint32_t result_id,
         llvm::ArrayRef<std::pair<uint32_t, uint32_t>> variable_parent_);
@@ -581,145 +385,6 @@ public:
   InstBuilder &opReturn();
   InstBuilder &opReturnValue(uint32_t value);
   InstBuilder &opUnreachable();
-  InstBuilder &opLifetimeStart(uint32_t pointer, uint32_t size);
-  InstBuilder &opLifetimeStop(uint32_t pointer, uint32_t size);
-  InstBuilder &opGroupAsyncCopy(uint32_t result_type, uint32_t result_id,
-                                uint32_t execution, uint32_t destination,
-                                uint32_t source, uint32_t num_elements,
-                                uint32_t stride, uint32_t event);
-  InstBuilder &opGroupWaitEvents(uint32_t execution, uint32_t num_events,
-                                 uint32_t events_list);
-  InstBuilder &opGroupAll(uint32_t result_type, uint32_t result_id,
-                          uint32_t execution, uint32_t predicate);
-  InstBuilder &opGroupAny(uint32_t result_type, uint32_t result_id,
-                          uint32_t execution, uint32_t predicate);
-  InstBuilder &opGroupBroadcast(uint32_t result_type, uint32_t result_id,
-                                uint32_t execution, uint32_t value,
-                                uint32_t local_id);
-  InstBuilder &opGroupIAdd(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupFAdd(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupFMin(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupUMin(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupSMin(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupFMax(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupUMax(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opGroupSMax(uint32_t result_type, uint32_t result_id,
-                           uint32_t execution, spv::GroupOperation operation,
-                           uint32_t x);
-  InstBuilder &opReadPipe(uint32_t result_type, uint32_t result_id,
-                          uint32_t pipe, uint32_t pointer, uint32_t packet_size,
-                          uint32_t packet_alignment);
-  InstBuilder &opWritePipe(uint32_t result_type, uint32_t result_id,
-                           uint32_t pipe, uint32_t pointer,
-                           uint32_t packet_size, uint32_t packet_alignment);
-  InstBuilder &opReservedReadPipe(uint32_t result_type, uint32_t result_id,
-                                  uint32_t pipe, uint32_t reserve_id,
-                                  uint32_t index, uint32_t pointer,
-                                  uint32_t packet_size,
-                                  uint32_t packet_alignment);
-  InstBuilder &opReservedWritePipe(uint32_t result_type, uint32_t result_id,
-                                   uint32_t pipe, uint32_t reserve_id,
-                                   uint32_t index, uint32_t pointer,
-                                   uint32_t packet_size,
-                                   uint32_t packet_alignment);
-  InstBuilder &opReserveReadPipePackets(uint32_t result_type,
-                                        uint32_t result_id, uint32_t pipe,
-                                        uint32_t num_packets,
-                                        uint32_t packet_size,
-                                        uint32_t packet_alignment);
-  InstBuilder &opReserveWritePipePackets(uint32_t result_type,
-                                         uint32_t result_id, uint32_t pipe,
-                                         uint32_t num_packets,
-                                         uint32_t packet_size,
-                                         uint32_t packet_alignment);
-  InstBuilder &opCommitReadPipe(uint32_t pipe, uint32_t reserve_id,
-                                uint32_t packet_size,
-                                uint32_t packet_alignment);
-  InstBuilder &opCommitWritePipe(uint32_t pipe, uint32_t reserve_id,
-                                 uint32_t packet_size,
-                                 uint32_t packet_alignment);
-  InstBuilder &opIsValidReserveId(uint32_t result_type, uint32_t result_id,
-                                  uint32_t reserve_id);
-  InstBuilder &opGetNumPipePackets(uint32_t result_type, uint32_t result_id,
-                                   uint32_t pipe, uint32_t packet_size,
-                                   uint32_t packet_alignment);
-  InstBuilder &opGetMaxPipePackets(uint32_t result_type, uint32_t result_id,
-                                   uint32_t pipe, uint32_t packet_size,
-                                   uint32_t packet_alignment);
-  InstBuilder &opGroupReserveReadPipePackets(uint32_t result_type,
-                                             uint32_t result_id,
-                                             uint32_t execution, uint32_t pipe,
-                                             uint32_t num_packets,
-                                             uint32_t packet_size,
-                                             uint32_t packet_alignment);
-  InstBuilder &opGroupReserveWritePipePackets(uint32_t result_type,
-                                              uint32_t result_id,
-                                              uint32_t execution, uint32_t pipe,
-                                              uint32_t num_packets,
-                                              uint32_t packet_size,
-                                              uint32_t packet_alignment);
-  InstBuilder &opGroupCommitReadPipe(uint32_t execution, uint32_t pipe,
-                                     uint32_t reserve_id, uint32_t packet_size,
-                                     uint32_t packet_alignment);
-  InstBuilder &opGroupCommitWritePipe(uint32_t execution, uint32_t pipe,
-                                      uint32_t reserve_id, uint32_t packet_size,
-                                      uint32_t packet_alignment);
-  InstBuilder &opEnqueueMarker(uint32_t result_type, uint32_t result_id,
-                               uint32_t queue, uint32_t num_events,
-                               uint32_t wait_events, uint32_t ret_event);
-  InstBuilder &opEnqueueKernel(uint32_t result_type, uint32_t result_id,
-                               uint32_t queue, uint32_t flags,
-                               uint32_t nd_range, uint32_t num_events,
-                               uint32_t wait_events, uint32_t ret_event,
-                               uint32_t invoke, uint32_t param,
-                               uint32_t param_size, uint32_t param_align,
-                               llvm::ArrayRef<uint32_t> local_size);
-  InstBuilder &opGetKernelNDrangeSubGroupCount(uint32_t result_type,
-                                               uint32_t result_id,
-                                               uint32_t nd_range,
-                                               uint32_t invoke, uint32_t param,
-                                               uint32_t param_size,
-                                               uint32_t param_align);
-  InstBuilder &
-  opGetKernelNDrangeMaxSubGroupSize(uint32_t result_type, uint32_t result_id,
-                                    uint32_t nd_range, uint32_t invoke,
-                                    uint32_t param, uint32_t param_size,
-                                    uint32_t param_align);
-  InstBuilder &opGetKernelWorkGroupSize(uint32_t result_type,
-                                        uint32_t result_id, uint32_t invoke,
-                                        uint32_t param, uint32_t param_size,
-                                        uint32_t param_align);
-  InstBuilder &opGetKernelPreferredWorkGroupSizeMultiple(
-      uint32_t result_type, uint32_t result_id, uint32_t invoke, uint32_t param,
-      uint32_t param_size, uint32_t param_align);
-  InstBuilder &opRetainEvent(uint32_t event);
-  InstBuilder &opReleaseEvent(uint32_t event);
-  InstBuilder &opCreateUserEvent(uint32_t result_type, uint32_t result_id);
-  InstBuilder &opIsValidEvent(uint32_t result_type, uint32_t result_id,
-                              uint32_t event);
-  InstBuilder &opSetUserEventStatus(uint32_t event, uint32_t status);
-  InstBuilder &opCaptureEventProfilingInfo(uint32_t event,
-                                           uint32_t profiling_info,
-                                           uint32_t value);
-  InstBuilder &opGetDefaultQueue(uint32_t result_type, uint32_t result_id);
-  InstBuilder &opBuildNDRange(uint32_t result_type, uint32_t result_id,
-                              uint32_t global_work_size,
-                              uint32_t local_work_size,
-                              uint32_t global_work_offset);
   InstBuilder &opImageSparseSampleImplicitLod(
       uint32_t result_type, uint32_t result_id, uint32_t sampled_image,
       uint32_t coordinate,
@@ -806,219 +471,6 @@ public:
   InstBuilder &opModuleProcessed(std::string process);
   InstBuilder &opExecutionModeId(uint32_t entry_point, spv::ExecutionMode mode);
   InstBuilder &opDecorateId(uint32_t target, spv::Decoration decoration);
-  InstBuilder &opGroupNonUniformElect(uint32_t result_type, uint32_t result_id,
-                                      uint32_t execution);
-  InstBuilder &opGroupNonUniformAll(uint32_t result_type, uint32_t result_id,
-                                    uint32_t execution, uint32_t predicate);
-  InstBuilder &opGroupNonUniformAny(uint32_t result_type, uint32_t result_id,
-                                    uint32_t execution, uint32_t predicate);
-  InstBuilder &opGroupNonUniformAllEqual(uint32_t result_type,
-                                         uint32_t result_id, uint32_t execution,
-                                         uint32_t value);
-  InstBuilder &opGroupNonUniformBroadcast(uint32_t result_type,
-                                          uint32_t result_id,
-                                          uint32_t execution, uint32_t value,
-                                          uint32_t id);
-  InstBuilder &opGroupNonUniformBroadcastFirst(uint32_t result_type,
-                                               uint32_t result_id,
-                                               uint32_t execution,
-                                               uint32_t value);
-  InstBuilder &opGroupNonUniformBallot(uint32_t result_type, uint32_t result_id,
-                                       uint32_t execution, uint32_t predicate);
-  InstBuilder &opGroupNonUniformInverseBallot(uint32_t result_type,
-                                              uint32_t result_id,
-                                              uint32_t execution,
-                                              uint32_t value);
-  InstBuilder &opGroupNonUniformBallotBitExtract(uint32_t result_type,
-                                                 uint32_t result_id,
-                                                 uint32_t execution,
-                                                 uint32_t value,
-                                                 uint32_t index);
-  InstBuilder &opGroupNonUniformBallotBitCount(uint32_t result_type,
-                                               uint32_t result_id,
-                                               uint32_t execution,
-                                               spv::GroupOperation operation,
-                                               uint32_t value);
-  InstBuilder &opGroupNonUniformBallotFindLSB(uint32_t result_type,
-                                              uint32_t result_id,
-                                              uint32_t execution,
-                                              uint32_t value);
-  InstBuilder &opGroupNonUniformBallotFindMSB(uint32_t result_type,
-                                              uint32_t result_id,
-                                              uint32_t execution,
-                                              uint32_t value);
-  InstBuilder &opGroupNonUniformShuffle(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        uint32_t value, uint32_t id);
-  InstBuilder &opGroupNonUniformShuffleXor(uint32_t result_type,
-                                           uint32_t result_id,
-                                           uint32_t execution, uint32_t value,
-                                           uint32_t mask);
-  InstBuilder &opGroupNonUniformShuffleUp(uint32_t result_type,
-                                          uint32_t result_id,
-                                          uint32_t execution, uint32_t value,
-                                          uint32_t delta);
-  InstBuilder &opGroupNonUniformShuffleDown(uint32_t result_type,
-                                            uint32_t result_id,
-                                            uint32_t execution, uint32_t value,
-                                            uint32_t delta);
-  InstBuilder &opGroupNonUniformIAdd(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformFAdd(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformIMul(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformFMul(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformSMin(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformUMin(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformFMin(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformSMax(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformUMax(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformFMax(uint32_t result_type, uint32_t result_id,
-                                     uint32_t execution,
-                                     spv::GroupOperation operation,
-                                     uint32_t value,
-                                     llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformBitwiseAnd(uint32_t result_type, uint32_t result_id,
-                              uint32_t execution, spv::GroupOperation operation,
-                              uint32_t value,
-                              llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformBitwiseOr(uint32_t result_type, uint32_t result_id,
-                             uint32_t execution, spv::GroupOperation operation,
-                             uint32_t value,
-                             llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformBitwiseXor(uint32_t result_type, uint32_t result_id,
-                              uint32_t execution, spv::GroupOperation operation,
-                              uint32_t value,
-                              llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformLogicalAnd(uint32_t result_type, uint32_t result_id,
-                              uint32_t execution, spv::GroupOperation operation,
-                              uint32_t value,
-                              llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformLogicalOr(uint32_t result_type, uint32_t result_id,
-                             uint32_t execution, spv::GroupOperation operation,
-                             uint32_t value,
-                             llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &
-  opGroupNonUniformLogicalXor(uint32_t result_type, uint32_t result_id,
-                              uint32_t execution, spv::GroupOperation operation,
-                              uint32_t value,
-                              llvm::Optional<uint32_t> cluster_size);
-  InstBuilder &opGroupNonUniformQuadBroadcast(uint32_t result_type,
-                                              uint32_t result_id,
-                                              uint32_t execution,
-                                              uint32_t value, uint32_t index);
-  InstBuilder &opGroupNonUniformQuadSwap(uint32_t result_type,
-                                         uint32_t result_id, uint32_t execution,
-                                         uint32_t value, uint32_t direction);
-  InstBuilder &opSubgroupBallotKHR(uint32_t result_type, uint32_t result_id,
-                                   uint32_t predicate);
-  InstBuilder &opSubgroupFirstInvocationKHR(uint32_t result_type,
-                                            uint32_t result_id, uint32_t value);
-  InstBuilder &opSubgroupAllKHR(uint32_t result_type, uint32_t result_id,
-                                uint32_t predicate);
-  InstBuilder &opSubgroupAnyKHR(uint32_t result_type, uint32_t result_id,
-                                uint32_t predicate);
-  InstBuilder &opSubgroupAllEqualKHR(uint32_t result_type, uint32_t result_id,
-                                     uint32_t predicate);
-  InstBuilder &opSubgroupReadInvocationKHR(uint32_t result_type,
-                                           uint32_t result_id, uint32_t value,
-                                           uint32_t index);
-  InstBuilder &opGroupIAddNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupFAddNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupFMinNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupUMinNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupSMinNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupFMaxNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupUMaxNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opGroupSMaxNonUniformAMD(uint32_t result_type,
-                                        uint32_t result_id, uint32_t execution,
-                                        spv::GroupOperation operation,
-                                        uint32_t x);
-  InstBuilder &opFragmentMaskFetchAMD(uint32_t result_type, uint32_t result_id,
-                                      uint32_t image, uint32_t coordinate);
-  InstBuilder &opFragmentFetchAMD(uint32_t result_type, uint32_t result_id,
-                                  uint32_t image, uint32_t coordinate,
-                                  uint32_t fragment_index);
-  InstBuilder &opSubgroupShuffleINTEL(uint32_t result_type, uint32_t result_id,
-                                      uint32_t data, uint32_t invocation_id);
-  InstBuilder &opSubgroupShuffleDownINTEL(uint32_t result_type,
-                                          uint32_t result_id, uint32_t current,
-                                          uint32_t next, uint32_t delta);
-  InstBuilder &opSubgroupShuffleUpINTEL(uint32_t result_type,
-                                        uint32_t result_id, uint32_t previous,
-                                        uint32_t current, uint32_t delta);
-  InstBuilder &opSubgroupShuffleXorINTEL(uint32_t result_type,
-                                         uint32_t result_id, uint32_t data,
-                                         uint32_t value);
-  InstBuilder &opSubgroupBlockReadINTEL(uint32_t result_type,
-                                        uint32_t result_id, uint32_t ptr);
-  InstBuilder &opSubgroupBlockWriteINTEL(uint32_t ptr, uint32_t data);
-  InstBuilder &opSubgroupImageBlockReadINTEL(uint32_t result_type,
-                                             uint32_t result_id, uint32_t image,
-                                             uint32_t coordinate);
-  InstBuilder &opSubgroupImageBlockWriteINTEL(uint32_t image,
-                                              uint32_t coordinate,
-                                              uint32_t data);
   InstBuilder &opDecorateStringGOOGLE(uint32_t target,
                                       spv::Decoration decoration);
   InstBuilder &opMemberDecorateStringGOOGLE(uint32_t struct_type,
@@ -1033,6 +485,9 @@ public:
   InstBuilder &specConstantBinaryOp(spv::Op op, uint32_t result_type,
                                     uint32_t result_id, uint32_t lhs,
                                     uint32_t rhs);
+  InstBuilder &atomicOp(spv::Op op, uint32_t result_type, uint32_t result_id,
+                        uint32_t pointer, uint32_t scope, uint32_t semantics,
+                        uint32_t value);
 
   // All-in-one methods for creating OpGroupNonUniform* operations.
   InstBuilder &groupNonUniformOp(spv::Op op, uint32_t result_type,
@@ -1092,7 +547,7 @@ private:
   void encodeMemoryAccess(spv::MemoryAccessMask value);
   void encodeExecutionMode(spv::ExecutionMode value);
   void encodeDecoration(spv::Decoration value);
-  void encodeString(std::string value);
+  void encodeString(llvm::StringRef value);
 
   WordConsumer TheConsumer;
   std::vector<uint32_t> TheInst;       ///< The instruction under construction.

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

@@ -341,6 +341,8 @@ public:
   /// \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 Sets the main source file content.
+  inline void setSourceFileContent(llvm::StringRef content);
 
   /// \brief Adds an execution mode to the module under construction.
   void addExecutionMode(uint32_t entryPointId, spv::ExecutionMode em,
@@ -553,6 +555,10 @@ void ModuleBuilder::setSourceFileName(uint32_t id, std::string name) {
   theModule.setSourceFileName(id, std::move(name));
 }
 
+void ModuleBuilder::setSourceFileContent(llvm::StringRef content) {
+  theModule.setSourceFileContent(content);
+}
+
 } // end namespace spirv
 } // end namespace clang
 

+ 6 - 0
tools/clang/include/clang/SPIRV/Structure.h

@@ -308,6 +308,7 @@ public:
   inline void addExecutionMode(Instruction &&);
   inline void setShaderModelVersion(uint32_t);
   inline void setSourceFileName(uint32_t id, std::string name);
+  inline void setSourceFileContent(llvm::StringRef content);
   // TODO: source code debug information
   inline void addDebugName(uint32_t targetId, llvm::StringRef name,
                            llvm::Optional<uint32_t> memberIndex = llvm::None);
@@ -341,6 +342,7 @@ private:
   uint32_t shaderModelVersion;
   uint32_t sourceFileNameId; // The <result-id> for the OpString for file name
   std::string sourceFileName;
+  llvm::StringRef sourceFileContent;
   // TODO: source code debug information
   std::set<DebugName> debugNames;
   llvm::SetVector<std::pair<uint32_t, const Decoration *>> decorations;
@@ -503,6 +505,10 @@ void SPIRVModule::setSourceFileName(uint32_t id, std::string name) {
   sourceFileName = std::move(name);
 }
 
+void SPIRVModule::setSourceFileContent(llvm::StringRef content) {
+  sourceFileContent = content;
+}
+
 void SPIRVModule::addDebugName(uint32_t targetId, llvm::StringRef name,
                                llvm::Optional<uint32_t> memberIndex) {
 

+ 5 - 2
tools/clang/include/clang/SPIRV/Type.h

@@ -18,6 +18,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringRef.h"
 
 namespace clang {
 namespace spirv {
@@ -95,7 +96,7 @@ public:
                                      DecorationSet decs = {});
   static const Type *getStruct(SPIRVContext &ctx,
                                llvm::ArrayRef<uint32_t> members,
-                               DecorationSet d = {});
+                               llvm::StringRef name = {}, DecorationSet d = {});
   static const Type *getPointer(SPIRVContext &ctx,
                                 spv::StorageClass storage_class, uint32_t type,
                                 DecorationSet decs = {});
@@ -109,7 +110,8 @@ public:
 
 private:
   /// \brief Private constructor.
-  Type(spv::Op op, std::vector<uint32_t> arg = {}, DecorationSet dec = {});
+  Type(spv::Op op, std::vector<uint32_t> arg = {}, DecorationSet dec = {},
+       llvm::StringRef name = {});
 
   /// \brief Returns the unique Type pointer within the given context.
   static const Type *getUniqueType(SPIRVContext &, const Type &);
@@ -117,6 +119,7 @@ private:
 private:
   spv::Op opcode;             ///< OpCode of the Type defined in SPIR-V Spec
   std::vector<uint32_t> args; ///< Arguments needed to define the type
+  std::string name;           ///< Source code name of this type
 
   /// The decorations that are applied to a type.
   /// Note: we use a SetVector because:

+ 1 - 1
tools/clang/lib/AST/ItaniumMangle.cpp

@@ -2040,7 +2040,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   case BuiltinType::OCLSampler: Out << "11ocl_sampler"; break;
   case BuiltinType::OCLEvent: Out << "9ocl_event"; break;
     // HLSL Change starts
-  case BuiltinType::Min12Int: Out << "min21_int"; break;
+  case BuiltinType::Min12Int: Out << "min12_int"; break;
   case BuiltinType::LitInt: Out << "lit_int"; break;
   case BuiltinType::LitFloat: Out << "lit_float"; break;
   case BuiltinType::Min10Float: Out << "min10_float"; break;

+ 8 - 1
tools/clang/lib/Frontend/CompilerInvocation.cpp

@@ -1910,10 +1910,17 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
   // where we have a dxc-based command-line. We choose to accept additional
   // options even if they don't get applied.
   const unsigned IncludedFlagsBitmask = 0;
+#ifdef _WIN32
+  const unsigned ExcludedFlagsBitmask = 0;
+#else
+  // Exception: Exclude cl.exe like arguments that can trip up Unix systems
+  const unsigned ExcludedFlagsBitmask = options::CLOption;
+#endif
+  // End HLSL Change
   unsigned MissingArgIndex, MissingArgCount;
   InputArgList Args =
       Opts->ParseArgs(llvm::makeArrayRef(ArgBegin, ArgEnd), MissingArgIndex,
-                      MissingArgCount, IncludedFlagsBitmask);
+                      MissingArgCount, IncludedFlagsBitmask, ExcludedFlagsBitmask);
 
   // Check for missing argument error.
   if (MissingArgCount) {

+ 1 - 2
tools/clang/lib/Frontend/FrontendActions.cpp

@@ -408,6 +408,7 @@ SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   return llvm::make_unique<ASTConsumer>();
 }
 
+#if 0 // HLSL Change Starts - no support for modules or PCH
 std::unique_ptr<ASTConsumer>
 DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
                                         StringRef InFile) {
@@ -419,8 +420,6 @@ VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   return llvm::make_unique<ASTConsumer>();
 }
 
-#if 0 // HLSL Change Starts - no support for modules or PCH
-
 void VerifyPCHAction::ExecuteAction() {
   CompilerInstance &CI = getCompilerInstance();
   bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;

+ 4 - 0
tools/clang/lib/Parse/HLSLRootSignature.cpp

@@ -17,7 +17,11 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
 #include "HLSLRootSignature.h"
+
+#include <float.h>
+
 using namespace llvm;
 using namespace hlsl;
 

+ 43 - 6
tools/clang/lib/Parse/ParseDecl.cpp

@@ -229,12 +229,14 @@ static void ParseRegisterNumberForHLSL(_In_z_ const char *name,
   // It's valid to omit the register name.
   if (*name) {
     char *nameEnd;
+    unsigned long num;
     errno = 0;
-    *registerNumber = strtoul(name, &nameEnd, 10);
-    if (*nameEnd != '\0' || errno == ERANGE) {
+    num = strtoul(name, &nameEnd, 10);
+    if (*nameEnd != '\0' || errno == ERANGE || num > UINT32_MAX) {
       *diagId = diag::err_hlsl_unsupported_register_number;
       return;
     }
+    *registerNumber = num;
   } else {
     *registerNumber = 0;
   }
@@ -721,6 +723,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
     //case AttributeList::AT_HLSLIn:
     //case AttributeList::AT_HLSLInOut:
     //case AttributeList::AT_HLSLLinear:
+    //case AttributeList::AT_HLSLCenter:
     //case AttributeList::AT_HLSLNoInterpolation:
     //case AttributeList::AT_HLSLNoPerspective:
     //case AttributeList::AT_HLSLOut:
@@ -3715,10 +3718,8 @@ HLSLReservedKeyword:
       isStorageClass = true;
       break;
     // HLSL Change Starts
-    case tok::kw_precise:
     case tok::kw_shared:
     case tok::kw_groupshared:
-    case tok::kw_globallycoherent:
     case tok::kw_uniform:
     case tok::kw_in:
     case tok::kw_out:
@@ -3726,7 +3727,6 @@ HLSLReservedKeyword:
     case tok::kw_linear:
     case tok::kw_nointerpolation:
     case tok::kw_noperspective:
-    case tok::kw_sample:
     case tok::kw_centroid:
     case tok::kw_column_major:
     case tok::kw_row_major:
@@ -3747,7 +3747,22 @@ HLSLReservedKeyword:
         }
       }
       break;
-    // HLSL Change Ends
+    case tok::kw_precise:
+    case tok::kw_sample:
+    case tok::kw_globallycoherent:
+    case tok::kw_center:
+      // Back-compat: 'precise', 'globallycoherent', 'center' and 'sample' are keywords when used as an interpolation 
+      // modifiers, but in FXC they can also be used an identifiers. If the decl type has already been specified
+      // we need to update the token to be handled as an identifier.
+      if (getLangOpts().HLSL) {
+        if (DS.getTypeSpecType() != DeclSpec::TST_unspecified) {
+          Tok.setKind(tok::identifier);
+          continue;
+        }
+        DS.getAttributes().addNew(Tok.getIdentifierInfo(), Tok.getLocation(), 0, SourceLocation(), 0, 0, AttributeList::AS_CXX11);
+      }
+      break;
+      // HLSL Change Ends
     case tok::kw_auto:
       if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - auto is reserved for HLSL
       if (getLangOpts().CPlusPlus11) {
@@ -5163,6 +5178,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
 
   // HLSL Change Starts
   case tok::kw_precise:
+  case tok::kw_center:
   case tok::kw_shared:
   case tok::kw_groupshared:
   case tok::kw_globallycoherent:
@@ -5949,6 +5965,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
       // the l_paren token.
     }
 
+    // HLSL Change Starts
+    // FXC compatiblity: these are keywords when used as modifiers, but in
+    // FXC they can also be used an identifiers. If the next token is a
+    // punctuator, then we are using them as identifers. Need to change
+    // the token type to tok::identifier and fall through to the next case.
+    // E.g., <type> left, center, right;
+    if (getLangOpts().HLSL) {
+      switch (Tok.getKind()) {
+      case tok::kw_center:
+      case tok::kw_globallycoherent:
+      case tok::kw_precise:
+      case tok::kw_sample:
+        if (tok::isPunctuator(NextToken().getKind()))
+          Tok.setKind(tok::identifier);
+        break;
+      default:
+        break;
+      }
+    }
+    // HLSL Change Ends
+
     if (Tok.isOneOf(tok::identifier, tok::kw_operator, tok::annot_template_id,
                     tok::tilde)) {
       // We found something that indicates the start of an unqualified-id.

+ 23 - 5
tools/clang/lib/Parse/ParseExpr.cpp

@@ -788,7 +788,18 @@ HLSLReservedKeyword:
       return ExprError();
     assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
     return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
-      
+
+    // HLSL Change Starts
+  case tok::kw_precise:
+  case tok::kw_sample:
+  case tok::kw_globallycoherent:
+  case tok::kw_center:
+    // Back-compat: 'precise', 'globallycoherent', 'center' and 'sample' are keywords when used as an interpolation 
+    // modifiers, but in FXC they can also be used an identifiers. No interpolation modifiers are expected here
+    // so we need to change the token type to tok::identifier and fall through to the next case.
+    Tok.setKind(tok::identifier);
+    __fallthrough;
+    // HLSL Change Ends
   case tok::identifier: {      // primary-expression: identifier
                                // unqualified-id: identifier
                                // constant: enumeration-constant
@@ -1702,13 +1713,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       }
 
       // HLSL Change Starts
-      // 'sample' is a keyword when used as an interpolation modifier, but it is
-      // also a built-in field of some types. By the time we're considering a
+      // 'sample' and others are keywords when used as modifiers, but they are
+      // also built-in field of some types. By the time we're considering a
       // field access, update the token if necessary to reflect this.
       if (getLangOpts().HLSL) {
-        if (Tok.is(tok::kw_sample)) {
+        switch (auto tk = Tok.getKind()) {
+        case tok::kw_center:
+        case tok::kw_globallycoherent:
+        case tok::kw_precise:
+        case tok::kw_sample:
           Tok.setKind(tok::identifier);
-          Tok.setIdentifierInfo(PP.getIdentifierInfo(StringRef("sample")));
+          Tok.setIdentifierInfo(PP.getIdentifierInfo(getKeywordSpelling(tk)));
+          break;
+        default:
+          break;
         }
       }
       // HLSL Change Ends

+ 19 - 0
tools/clang/lib/Parse/ParseStmt.cpp

@@ -175,6 +175,25 @@ Retry:
     cutOffParsing();
     return StmtError();
 
+    // HLSL Change Starts
+  case tok::kw_precise:
+  case tok::kw_sample:
+  case tok::kw_globallycoherent:
+  case tok::kw_center: {
+    // FXC compatiblity: these are keywords when used as modifiers, but in
+    // FXC they can also be used an identifiers. If the next token is a
+    // punctuator, then we are using them as identifers. Need to change
+    // the token type to tok::identifier and fall through to the next case.
+    // E.g., center = <RHS>.
+    if (tok::isPunctuator(NextToken().getKind())) {
+      Tok.setKind(tok::identifier);
+      __fallthrough;
+    } else {
+      goto tok_default_case;
+    }
+  }
+    // HLSL Change Ends
+
   case tok::identifier: {
     Token Next = NextToken();
     if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement

+ 16 - 3
tools/clang/lib/Parse/ParseTentative.cpp

@@ -1271,6 +1271,22 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
     return TPResult::True;
 
   // HLSL Change Starts
+  case tok::kw_sample:
+  case tok::kw_precise:
+  case tok::kw_center:
+  case tok::kw_globallycoherent:
+    // FXC compatiblity: these are keywords when used as modifiers, but in
+    // FXC they can also be used an identifiers. If the next token is a
+    // punctuator, then we are using them as identifers. Need to change
+    // the token type to tok::identifier and return false.
+    // E.g., return (center);
+    if (tok::isPunctuator(NextToken().getKind())) {
+      Tok.setKind(tok::identifier);
+      return TPResult::False;
+    } else {
+      return TPResult::True;
+    }
+
   case tok::kw_in:
   case tok::kw_inout:
   case tok::kw_out:
@@ -1278,11 +1294,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
   case tok::kw_centroid:
   case tok::kw_nointerpolation:
   case tok::kw_noperspective:
-  case tok::kw_sample:
-  case tok::kw_precise:
   case tok::kw_shared:
   case tok::kw_groupshared:
-  case tok::kw_globallycoherent:
   case tok::kw_uniform:
   case tok::kw_row_major:
   case tok::kw_column_major:

+ 27 - 6
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -214,13 +214,17 @@ bool DeclResultIdMapper::createStageOutputVar(const DeclaratorDecl *decl,
 
   SemanticInfo inheritSemantic = {};
 
+  // If storedValue is 0, it means this parameter in the original source code is
+  // not used at all. Avoid writing back.
+  //
+  // Write back of stage output variables in GS is manually controlled by
+  // .Append() intrinsic method, implemented in writeBackOutputStream(). So
+  // ignoreValue should be set to true for GS.
+  const bool noWriteBack = storedValue == 0 || shaderModel.IsGS();
+
   return createStageVars(sigPoint, decl, /*asInput=*/false, type,
                          /*arraySize=*/0, "out.var", llvm::None, &storedValue,
-                         // Write back of stage output variables in GS is
-                         // manually controlled by .Append() intrinsic method,
-                         // implemented in writeBackOutputStream(). So
-                         // noWriteBack should be set to true for GS.
-                         shaderModel.IsGS(), &inheritSemantic);
+                         noWriteBack, &inheritSemantic);
 }
 
 bool DeclResultIdMapper::createStageOutputVar(const DeclaratorDecl *decl,
@@ -1494,12 +1498,16 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
               theBuilder.getVecType(srcVecElemTypeId, 2), *value, *value,
               {0, 1});
       }
+
+      // Reciprocate SV_Position.w if requested
+      if (semanticKind == hlsl::Semantic::Kind::Position)
+        *value = invertWIfRequested(*value);
     } else {
       if (noWriteBack)
         return true;
 
       // Negate SV_Position.y if requested
-      if (semanticToUse->semantic->GetKind() == hlsl::Semantic::Kind::Position)
+      if (semanticKind == hlsl::Semantic::Kind::Position)
         *value = invertYIfRequested(*value);
 
       uint32_t ptr = varId;
@@ -1786,6 +1794,19 @@ uint32_t DeclResultIdMapper::invertYIfRequested(uint32_t position) {
   return position;
 }
 
+uint32_t DeclResultIdMapper::invertWIfRequested(uint32_t position) {
+  // Reciprocate SV_Position.w if requested
+  if (spirvOptions.invertW && shaderModel.IsPS()) {
+    const auto f32Type = theBuilder.getFloat32Type();
+    const auto v4f32Type = theBuilder.getVecType(f32Type, 4);
+    const auto oldW = theBuilder.createCompositeExtract(f32Type, position, {3});
+    const auto newW = theBuilder.createBinaryOp(
+        spv::Op::OpFDiv, f32Type, theBuilder.getConstantFloat32(1), oldW);
+    position = theBuilder.createCompositeInsert(v4f32Type, position, {3}, newW);
+  }
+  return position;
+}
+
 void DeclResultIdMapper::decoratePSInterpolationMode(const NamedDecl *decl,
                                                      QualType type,
                                                      uint32_t varId) {

+ 7 - 3
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -433,9 +433,13 @@ public:
   bool writeBackOutputStream(const NamedDecl *decl, QualType type,
                              uint32_t value);
 
-  /// \brief Inverts SV_Position.y is requested.
+  /// \brief Negates to get the additive inverse of SV_Position.y if requested.
   uint32_t invertYIfRequested(uint32_t position);
 
+  /// \brief Reciprocates to get the multiplicative inverse of SV_Position.w
+  /// if requested.
+  uint32_t invertWIfRequested(uint32_t position);
+
   /// \brief Decorates all stage input and output variables with proper
   /// location and returns true on success.
   ///
@@ -744,8 +748,8 @@ DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
                                        const EmitSPIRVOptions &options)
     : shaderModel(model), theBuilder(builder), spirvOptions(options),
       astContext(context), diags(context.getDiagnostics()),
-      typeTranslator(translator), entryFunctionId(0),
-      laneCountBuiltinId(0), laneIndexBuiltinId(0), needsLegalization(false),
+      typeTranslator(translator), entryFunctionId(0), laneCountBuiltinId(0),
+      laneIndexBuiltinId(0), needsLegalization(false),
       glPerVertex(model, context, builder, typeTranslator) {}
 
 bool DeclResultIdMapper::decorateStageIOLocations() {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 266 - 342
tools/clang/lib/SPIRV/InstBuilderAuto.cpp


+ 30 - 1
tools/clang/lib/SPIRV/InstBuilderManual.cpp

@@ -84,6 +84,35 @@ InstBuilder &InstBuilder::specConstantBinaryOp(spv::Op op, uint32_t result_type,
   return *this;
 }
 
+InstBuilder &InstBuilder::atomicOp(spv::Op op, uint32_t result_type,
+                                   uint32_t result_id, uint32_t pointer,
+                                   uint32_t scope, uint32_t semantics,
+                                   uint32_t value) {
+  if (!TheInst.empty()) {
+    TheStatus = Status::NestedInst;
+    return *this;
+  }
+  if (result_type == 0) {
+    TheStatus = Status::ZeroResultType;
+    return *this;
+  }
+  if (result_id == 0) {
+    TheStatus = Status::ZeroResultId;
+    return *this;
+  }
+
+  TheInst.reserve(7);
+  TheInst.emplace_back(static_cast<uint32_t>(op));
+  TheInst.emplace_back(result_type);
+  TheInst.emplace_back(result_id);
+  TheInst.emplace_back(pointer);
+  TheInst.emplace_back(scope);
+  TheInst.emplace_back(semantics);
+  TheInst.emplace_back(value);
+
+  return *this;
+}
+
 InstBuilder &InstBuilder::groupNonUniformOp(spv::Op op, uint32_t result_type,
                                             uint32_t result_id,
                                             uint32_t exec_scope) {
@@ -234,7 +263,7 @@ InstBuilder &InstBuilder::opSpecConstant(uint32_t resultType, uint32_t resultId,
   return *this;
 }
 
-void InstBuilder::encodeString(std::string value) {
+void InstBuilder::encodeString(llvm::StringRef value) {
   const auto &words = string::encodeSPIRVString(value);
   TheInst.insert(TheInst.end(), words.begin(), words.end());
 }

+ 9 - 48
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -301,51 +301,10 @@ uint32_t ModuleBuilder::createAtomicOp(spv::Op opcode, uint32_t resultType,
                                        uint32_t valueToOp) {
   assert(insertPoint && "null insert point");
   const uint32_t id = theContext.takeNextId();
-  switch (opcode) {
-  case spv::Op::OpAtomicIAdd:
-    instBuilder.opAtomicIAdd(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicISub:
-    instBuilder.opAtomicISub(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicAnd:
-    instBuilder.opAtomicAnd(resultType, id, orignalValuePtr, scopeId,
-                            memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicOr:
-    instBuilder.opAtomicOr(resultType, id, orignalValuePtr, scopeId,
-                           memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicXor:
-    instBuilder.opAtomicXor(resultType, id, orignalValuePtr, scopeId,
-                            memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicUMax:
-    instBuilder.opAtomicUMax(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicUMin:
-    instBuilder.opAtomicUMin(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicSMax:
-    instBuilder.opAtomicSMax(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicSMin:
-    instBuilder.opAtomicSMin(resultType, id, orignalValuePtr, scopeId,
-                             memorySemanticsId, valueToOp);
-    break;
-  case spv::Op::OpAtomicExchange:
-    instBuilder.opAtomicExchange(resultType, id, orignalValuePtr, scopeId,
-                                 memorySemanticsId, valueToOp);
-    break;
-  default:
-    assert(false && "unimplemented atomic opcode");
-  }
-  instBuilder.x();
+  instBuilder
+      .atomicOp(opcode, resultType, id, orignalValuePtr, scopeId,
+                memorySemanticsId, valueToOp)
+      .x();
   insertPoint->appendInstruction(std::move(constructSite));
   return id;
 }
@@ -1026,7 +985,8 @@ ModuleBuilder::getStructType(llvm::ArrayRef<uint32_t> fieldTypes,
                              llvm::StringRef structName,
                              llvm::ArrayRef<llvm::StringRef> fieldNames,
                              Type::DecorationSet decorations) {
-  const Type *type = Type::getStruct(theContext, fieldTypes, decorations);
+  const Type *type =
+      Type::getStruct(theContext, fieldTypes, structName, decorations);
   bool isRegistered = false;
   const uint32_t typeId = theContext.getResultIdForType(type, &isRegistered);
   theModule.addType(type, typeId);
@@ -1112,7 +1072,8 @@ uint32_t ModuleBuilder::getImageType(uint32_t sampledType, spv::Dim dim,
     requireCapability(spv::Capability::StorageImageExtendedFormats);
     break;
   default:
-    // Only image formats requiring extended formats are relevant. The rest just pass through.
+    // Only image formats requiring extended formats are relevant. The rest just
+    // pass through.
     break;
   }
 
@@ -1204,7 +1165,7 @@ uint32_t ModuleBuilder::getByteAddressBufferType(bool isRW) {
   if (!isRW)
     typeDecs.push_back(Decoration::getNonWritable(theContext, 0));
 
-  const Type *type = Type::getStruct(theContext, {raTypeId}, typeDecs);
+  const Type *type = Type::getStruct(theContext, {raTypeId}, "", typeDecs);
   const uint32_t typeId = theContext.getResultIdForType(type);
   theModule.addType(type, typeId);
   theModule.addDebugName(typeId, isRW ? "type.RWByteAddressBuffer"

+ 138 - 37
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -230,7 +230,8 @@ bool spirvToolsOptimize(spv_target_env env, std::vector<uint32_t> *module,
 }
 
 bool spirvToolsValidate(spv_target_env env, std::vector<uint32_t> *module,
-                        std::string *messages, bool relaxLogicalPointer) {
+                        std::string *messages, bool relaxLogicalPointer,
+                        bool glLayout, bool dxLayout) {
   spvtools::SpirvTools tools(env);
 
   tools.SetMessageConsumer(
@@ -240,6 +241,11 @@ bool spirvToolsValidate(spv_target_env env, std::vector<uint32_t> *module,
 
   spvtools::ValidatorOptions options;
   options.SetRelaxLogicalPointer(relaxLogicalPointer);
+  // GL: strict block layout rules
+  // VK: relaxed block layout rules
+  // DX: Skip block layout rules
+  options.SetRelaxBlockLayout(!glLayout && !dxLayout);
+  options.SetSkipBlockLayout(dxLayout);
 
   return tools.Validate(module->data(), module->size(), options);
 }
@@ -604,9 +610,18 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
 
   // Set debug info
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
-  if (options.enableDebugInfo && !inputFiles.empty())
+  if (options.enableDebugInfo && !inputFiles.empty()) {
+    // File name
     theBuilder.setSourceFileName(theContext.takeNextId(),
                                  inputFiles.front().getFile().str());
+
+    // Source code
+    const auto &sm = ci.getSourceManager();
+    const llvm::MemoryBuffer *mainFile =
+        sm.getBuffer(sm.getMainFileID(), SourceLocation());
+    theBuilder.setSourceFileContent(
+        StringRef(mainFile->getBufferStart(), mainFile->getBufferSize()));
+  }
 }
 
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -692,8 +707,9 @@ void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
   // Validate the generated SPIR-V code
   if (!spirvOptions.disableValidation) {
     std::string messages;
-    if (!spirvToolsValidate(targetEnv, &m, &messages,
-                            declIdMapper.requiresLegalization())) {
+    if (!spirvToolsValidate(
+            targetEnv, &m, &messages, declIdMapper.requiresLegalization(),
+            spirvOptions.useGlLayout, spirvOptions.useDxLayout)) {
       emitFatalError("generated SPIR-V is invalid: %0", {}) << messages;
       emitNote("please file a bug report on "
                "https://github.com/Microsoft/DirectXShaderCompiler/issues "
@@ -1937,7 +1953,7 @@ SPIRVEmitter::doArraySubscriptExpr(const ArraySubscriptExpr *expr) {
   }
 
   if (!indices.empty()) {
-    (void)turnIntoElementPtr(info, expr->getType(), indices);
+    (void)turnIntoElementPtr(base->getType(), info, expr->getType(), indices);
   }
 
   return info;
@@ -2430,7 +2446,8 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
       baseIndices[i] = theBuilder.getConstantUint32(baseIndices[i]);
 
     auto derivedInfo = doExpr(subExpr);
-    return turnIntoElementPtr(derivedInfo, expr->getType(), baseIndices);
+    return turnIntoElementPtr(subExpr->getType(), derivedInfo, expr->getType(),
+                              baseIndices);
   }
   default:
     emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc())
@@ -2929,7 +2946,8 @@ SPIRVEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) {
 }
 
 uint32_t
-SPIRVEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr) {
+SPIRVEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr,
+                                          bool unclamped) {
   // Possible signatures are as follows:
   // Texture1D(Array).CalculateLevelOfDetail(SamplerState S, float x);
   // Texture2D(Array).CalculateLevelOfDetail(SamplerState S, float2 xy);
@@ -2957,9 +2975,11 @@ SPIRVEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr) {
       theBuilder.getVecType(theBuilder.getFloat32Type(), 2u);
   const uint32_t query = theBuilder.createBinaryOp(
       spv::Op::OpImageQueryLod, queryResultType, sampledImage, coordinate);
+
   // The first component of the float2 contains the mipmap array layer.
+  // The second component of the float2 represents the unclamped lod.
   return theBuilder.createCompositeExtract(theBuilder.getFloat32Type(), query,
-                                           {0});
+                                           unclamped ? 1 : 0);
 }
 
 uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
@@ -3148,7 +3168,21 @@ SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(
   QualType elemType = sampledType;
   uint32_t elemCount = 1;
   uint32_t elemTypeId = 0;
-  (void)TypeTranslator::isVectorType(sampledType, &elemType, &elemCount);
+  bool isTemplateOverStruct = false;
+
+  // Check whether the template type is a vector type or struct type.
+  if (!TypeTranslator::isVectorType(sampledType, &elemType, &elemCount)) {
+    if (sampledType->getAsStructureType()) {
+      isTemplateOverStruct = true;
+      // For struct type, we need to make sure it can fit into a 4-component
+      // vector. Detailed failing reasons will be emitted by the function so
+      // we don't need to emit errors here.
+      if (!typeTranslator.canFitIntoOneRegister(sampledType, &elemType,
+                                                &elemCount))
+        return 0;
+    }
+  }
+
   if (elemType->isFloatingType()) {
     elemTypeId = theBuilder.getFloat32Type();
   } else if (elemType->isSignedIntegerType()) {
@@ -3156,7 +3190,7 @@ SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(
   } else if (elemType->isUnsignedIntegerType()) {
     elemTypeId = theBuilder.getUint32Type();
   } else {
-    emitError("buffer/texture type unimplemented", object->getExprLoc());
+    emitError("loading %0 value unsupported", object->getExprLoc()) << type;
     return 0;
   }
 
@@ -3169,6 +3203,10 @@ SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(
   // If the result type is a vec1, vec2, or vec3, some extra processing
   // (extraction) is required.
   uint32_t retVal = extractVecFromVec4(texel, elemCount, elemTypeId);
+  if (isTemplateOverStruct) {
+    // Convert to the struct so that we are consistent with types in the AST.
+    retVal = convertVectorToStruct(sampledType, elemTypeId, retVal);
+  }
   return SpirvEvalInfo(retVal).setRValue();
 }
 
@@ -3277,7 +3315,7 @@ SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) {
   const uint32_t zero = theBuilder.getConstantInt32(0);
   const uint32_t index = doExpr(expr->getArg(0));
 
-  return turnIntoElementPtr(info, structType, {zero, index});
+  return turnIntoElementPtr(buffer->getType(), info, structType, {zero, index});
 }
 
 uint32_t SPIRVEmitter::incDecRWACSBufferCounter(const CXXMemberCallExpr *expr,
@@ -3471,7 +3509,8 @@ SPIRVEmitter::processACSBufferAppendConsume(const CXXMemberCallExpr *expr) {
 
   const auto bufferElemTy = hlsl::GetHLSLResourceResultType(object->getType());
 
-  (void)turnIntoElementPtr(bufferInfo, bufferElemTy, {zero, index});
+  (void)turnIntoElementPtr(object->getType(), bufferInfo, bufferElemTy,
+                           {zero, index});
 
   if (isAppend) {
     // Write out the value
@@ -3820,7 +3859,9 @@ SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
     retVal = processGetDimensions(expr);
     break;
   case IntrinsicOp::MOP_CalculateLevelOfDetail:
-    retVal = processTextureLevelOfDetail(expr);
+    retVal = processTextureLevelOfDetail(expr, /* unclamped */ false);
+  case IntrinsicOp::MOP_CalculateLevelOfDetailUnclamped:
+    retVal = processTextureLevelOfDetail(expr, /* unclamped */ true);
     break;
   case IntrinsicOp::MOP_IncrementCounter:
     retVal = theBuilder.createUnaryOp(
@@ -3865,7 +3906,6 @@ SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
   case IntrinsicOp::MOP_GatherCmpGreen:
   case IntrinsicOp::MOP_GatherCmpBlue:
   case IntrinsicOp::MOP_GatherCmpAlpha:
-  case IntrinsicOp::MOP_CalculateLevelOfDetailUnclamped:
     emitError("no equivalent for %0 intrinsic method in Vulkan",
               expr->getCallee()->getExprLoc())
         << expr->getMethodDecl()->getName();
@@ -4394,7 +4434,8 @@ SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
     base = createTemporaryVar(baseExpr->getType(), "vector", base);
   }
 
-  return turnIntoElementPtr(base, expr->getType(), indices);
+  return turnIntoElementPtr(baseExpr->getType(), base, expr->getType(),
+                            indices);
 }
 
 SpirvEvalInfo
@@ -4579,19 +4620,7 @@ SpirvEvalInfo SPIRVEmitter::doMemberExpr(const MemberExpr *expr) {
   auto info = loadIfAliasVarRef(base);
 
   if (!indices.empty()) {
-    // Sometime we are accessing the member of a rvalue, e.g.,
-    // <some-function-returing-a-struct>().<some-field>
-    // Create a temporary variable to hold the rvalue so that we can use access
-    // chain to index into it.
-    if (info.isRValue()) {
-      SpirvEvalInfo tempVar = createTemporaryVar(
-          base->getType(), TypeTranslator::getName(base->getType()), info);
-      (void)turnIntoElementPtr(tempVar, expr->getType(), indices);
-      info.setResultId(theBuilder.createLoad(
-          typeTranslator.translateType(expr->getType()), tempVar));
-    } else {
-      (void)turnIntoElementPtr(info, expr->getType(), indices);
-    }
+    (void)turnIntoElementPtr(base->getType(), info, expr->getType(), indices);
   }
 
   return info;
@@ -5453,6 +5482,38 @@ void SPIRVEmitter::splitVecLastElement(QualType vecType, uint32_t vec,
       theBuilder.createCompositeExtract(elemTypeId, vec, {count - 1});
 }
 
+uint32_t SPIRVEmitter::convertVectorToStruct(QualType structType,
+                                             uint32_t elemTypeId,
+                                             uint32_t vector) {
+  assert(structType->isStructureType());
+
+  const auto *structDecl = structType->getAsStructureType()->getDecl();
+  uint32_t vectorIndex = 0;
+  uint32_t elemCount = 1;
+  llvm::SmallVector<uint32_t, 4> members;
+
+  for (const auto *field : structDecl->fields()) {
+    if (TypeTranslator::isScalarType(field->getType())) {
+      members.push_back(theBuilder.createCompositeExtract(elemTypeId, vector,
+                                                          {vectorIndex++}));
+    } else if (TypeTranslator::isVectorType(field->getType(), nullptr,
+                                            &elemCount)) {
+      llvm::SmallVector<uint32_t, 4> indices;
+      for (uint32_t i = 0; i < elemCount; ++i)
+        indices.push_back(vectorIndex++);
+
+      const uint32_t type = theBuilder.getVecType(elemTypeId, elemCount);
+      members.push_back(
+          theBuilder.createVectorShuffle(type, vector, vector, indices));
+    } else {
+      assert(false && "unhandled type");
+    }
+  }
+
+  return theBuilder.createCompositeConstruct(
+      typeTranslator.translateType(structType), members);
+}
+
 SpirvEvalInfo
 SPIRVEmitter::tryToGenFloatVectorScale(const BinaryOperator *expr) {
   const QualType type = expr->getType();
@@ -5630,7 +5691,7 @@ SPIRVEmitter::tryToAssignToVectorElements(const Expr *lhs,
       const auto result = tryToAssignToRWBufferRWTexture(base, newVec);
       assert(result); // Definitely RWBuffer/RWTexture assignment
       (void)result;
-      return rhs;     // TODO: incorrect for compound assignments
+      return rhs; // TODO: incorrect for compound assignments
     } else {
       // Assigning to one normal vector component. Nothing special, just fall
       // back to the normal CodeGen path.
@@ -6029,13 +6090,40 @@ const Expr *SPIRVEmitter::collectArrayStructIndices(
 }
 
 SpirvEvalInfo &SPIRVEmitter::turnIntoElementPtr(
-    SpirvEvalInfo &info, QualType elemType,
+    QualType baseType, SpirvEvalInfo &base, QualType elemType,
     const llvm::SmallVector<uint32_t, 4> &indices) {
-  assert(!info.isRValue());
-  const uint32_t ptrType = theBuilder.getPointerType(
-      typeTranslator.translateType(elemType, info.getLayoutRule()),
-      info.getStorageClass());
-  return info.setResultId(theBuilder.createAccessChain(ptrType, info, indices));
+  // If this is a rvalue, we need a temporary object to hold it
+  // so that we can get access chain from it.
+  const bool needTempVar = base.isRValue();
+
+  if (needTempVar) {
+    auto varName = TypeTranslator::getName(baseType);
+    const auto var = createTemporaryVar(baseType, varName, base);
+    base.setResultId(var)
+        .setLayoutRule(LayoutRule::Void)
+        .setStorageClass(spv::StorageClass::Function);
+  }
+
+  const uint32_t elemTypeId =
+      typeTranslator.translateType(elemType, base.getLayoutRule());
+  const uint32_t ptrType =
+      theBuilder.getPointerType(elemTypeId, base.getStorageClass());
+  base.setResultId(theBuilder.createAccessChain(ptrType, base, indices));
+
+  // Okay, this part seems weird, but it is intended:
+  // If the base is originally a rvalue, the whole AST involving the base
+  // is consistently set up to handle rvalues. By copying the base into
+  // a temporary variable and grab an access chain from it, we are breaking
+  // the consistency by turning the base from rvalue into lvalue. Keep in
+  // mind that there will be no LValueToRValue casts in the AST for us
+  // to rely on to load the access chain if a rvalue is expected. Therefore,
+  // we must do the load here. Otherwise, it's up to the consumer of this
+  // access chain to do the load, and that can be everywhere.
+  if (needTempVar) {
+    base.setResultId(theBuilder.createLoad(elemTypeId, base));
+  }
+
+  return base;
 }
 
 uint32_t SPIRVEmitter::castToBool(const uint32_t fromVal, QualType fromType,
@@ -6663,6 +6751,13 @@ SPIRVEmitter::processIntrinsicInterlockedMethod(const CallExpr *expr,
   const uint32_t scope = theBuilder.getConstantUint32(1); // Device
   const auto *dest = expr->getArg(0);
   const auto baseType = dest->getType();
+
+  if (!baseType->isIntegerType()) {
+    emitError("can only perform atomic operations on scalar integer values",
+              dest->getLocStart());
+    return 0;
+  }
+
   const uint32_t baseTypeId = typeTranslator.translateType(baseType);
 
   const auto doArg = [baseType, this](const CallExpr *callExpr,
@@ -9378,7 +9473,10 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
       if (!declIdMapper.createStageInputVar(param, &loadedValue, false))
         return false;
 
-      theBuilder.createStore(tempVar, loadedValue);
+      // Only initialize the temporary variable if the parameter is indeed used.
+      if (param->isUsed()) {
+        theBuilder.createStore(tempVar, loadedValue);
+      }
 
       // Record the temporary variable holding SV_OutputControlPointID,
       // SV_PrimitiveID, and SV_ViewID. It may be used later in the patch
@@ -9427,10 +9525,13 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
       const uint32_t typeId = typeTranslator.translateType(param->getType());
       uint32_t loadedParam = 0;
 
+      // No need to write back the value if the parameter is not used at all in
+      // the original entry function.
+      //
       // Write back of stage output variables in GS is manually controlled by
       // .Append() intrinsic method. No need to load the parameter since we
       // won't need to write back here.
-      if (!shaderModel.IsGS())
+      if (param->isUsed() && !shaderModel.IsGS())
         loadedParam = theBuilder.createLoad(typeId, params[i]);
 
       if (!declIdMapper.createStageOutputVar(param, loadedParam, false))

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

@@ -222,6 +222,14 @@ private:
   void splitVecLastElement(QualType vecType, uint32_t vec, uint32_t *residual,
                            uint32_t *lastElement);
 
+  /// Converts a vector value into the given struct type with its element type's
+  /// <result-id> as elemTypeId.
+  ///
+  /// Assumes the vector and the struct have matching number of elements. Panics
+  /// otherwise.
+  uint32_t convertVectorToStruct(QualType structType, uint32_t elemTypeId,
+                                 uint32_t vector);
+
   /// Translates a floatN * float multiplication into SPIR-V instructions and
   /// returns the <result-id>. Returns 0 if the given binary operation is not
   /// floatN * float.
@@ -288,7 +296,7 @@ private:
   /// Creates an access chain to index into the given SPIR-V evaluation result
   /// and overwrites and returns the new SPIR-V evaluation result.
   SpirvEvalInfo &
-  turnIntoElementPtr(SpirvEvalInfo &info, QualType elemType,
+  turnIntoElementPtr(QualType baseType, SpirvEvalInfo &base, QualType elemType,
                      const llvm::SmallVector<uint32_t, 4> &indices);
 
 private:
@@ -747,8 +755,11 @@ private:
   uint32_t processTextureGatherCmp(const CXXMemberCallExpr *expr);
 
   /// \brief Returns the calculated level-of-detail (a single float value) for
-  /// the given texture. Handles intrinsic HLSL CalculateLevelOfDetail function.
-  uint32_t processTextureLevelOfDetail(const CXXMemberCallExpr *expr);
+  /// the given texture. Handles intrinsic HLSL CalculateLevelOfDetail or
+  /// CalculateLevelOfDetailUnclamped function depending on the given unclamped
+  /// parameter.
+  uint32_t processTextureLevelOfDetail(const CXXMemberCallExpr *expr,
+                                       bool unclamped);
 
   /// \brief Processes the .GetDimensions() call on supported objects.
   uint32_t processGetDimensions(const CXXMemberCallExpr *);

+ 38 - 1
tools/clang/lib/SPIRV/Structure.cpp

@@ -17,6 +17,32 @@ namespace spirv {
 namespace {
 constexpr uint32_t kGeneratorNumber = 14;
 constexpr uint32_t kToolVersion = 0;
+
+/// Chops the given original string into multiple smaller ones to make sure they
+/// can be encoded in a sequence of OpSourceContinued instructions following an
+/// OpSource instruction.
+void chopString(llvm::StringRef original,
+                llvm::SmallVectorImpl<llvm::StringRef> *chopped) {
+  const uint32_t maxCharInOpSource = 0xFFFFu - 5u; // Minus operands and nul
+  const uint32_t maxCharInContinue = 0xFFFFu - 2u; // Minus opcode and nul
+
+  chopped->clear();
+  if (original.size() > maxCharInOpSource) {
+    chopped->push_back(llvm::StringRef(original.data(), maxCharInOpSource));
+    original = llvm::StringRef(original.data() + maxCharInOpSource,
+                               original.size() - maxCharInOpSource);
+    while (original.size() > maxCharInContinue) {
+      chopped->push_back(llvm::StringRef(original.data(), maxCharInContinue));
+      original = llvm::StringRef(original.data() + maxCharInContinue,
+                                 original.size() - maxCharInContinue);
+    }
+    if (!original.empty()) {
+      chopped->push_back(original);
+    }
+  } else if (!original.empty()) {
+    chopped->push_back(original);
+  }
+}
 } // namespace
 
 // === Instruction implementations ===
@@ -289,10 +315,21 @@ void SPIRVModule::take(InstBuilder *builder) {
       fileName = sourceFileNameId;
     }
 
+    llvm::SmallVector<llvm::StringRef, 2> choppedSrcCode;
+    llvm::Optional<llvm::StringRef> firstSnippet;
+    chopString(sourceFileContent, &choppedSrcCode);
+    if (!choppedSrcCode.empty()) {
+      firstSnippet = llvm::Optional<llvm::StringRef>(choppedSrcCode.front());
+    }
+
     builder
         ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, fileName,
-                   llvm::None)
+                   firstSnippet)
         .x();
+
+    for (uint32_t i = 1; i < choppedSrcCode.size(); ++i) {
+      builder->opSourceContinued(choppedSrcCode[i]).x();
+    }
   }
 
   // BasicBlock debug names should be emitted only for blocks that are

+ 7 - 5
tools/clang/lib/SPIRV/Type.cpp

@@ -14,8 +14,9 @@
 namespace clang {
 namespace spirv {
 
-Type::Type(spv::Op op, std::vector<uint32_t> arg, DecorationSet decs)
-    : opcode(op), args(std::move(arg)) {
+Type::Type(spv::Op op, std::vector<uint32_t> arg, DecorationSet decs,
+           llvm::StringRef n)
+    : opcode(op), args(std::move(arg)), name(n.str()) {
   decorations = llvm::SetVector<const Decoration *>(decs.begin(), decs.end());
 }
 
@@ -126,8 +127,9 @@ const Type *Type::getRuntimeArray(SPIRVContext &context,
   return getUniqueType(context, t);
 }
 const Type *Type::getStruct(SPIRVContext &context,
-                            llvm::ArrayRef<uint32_t> members, DecorationSet d) {
-  Type t = Type(spv::Op::OpTypeStruct, std::vector<uint32_t>(members), d);
+                            llvm::ArrayRef<uint32_t> members,
+                            llvm::StringRef name, DecorationSet d) {
+  Type t = Type(spv::Op::OpTypeStruct, std::vector<uint32_t>(members), d, name);
   return getUniqueType(context, t);
 }
 const Type *Type::getPointer(SPIRVContext &context,
@@ -148,7 +150,7 @@ const Type *Type::getFunction(SPIRVContext &context, uint32_t return_type,
 
 bool Type::operator==(const Type &other) const {
   if (opcode == other.opcode && args == other.args &&
-      decorations.size() == other.decorations.size()) {
+      decorations.size() == other.decorations.size() && name == other.name) {
     // If two types have the same decorations, but in different order,
     // they are in fact the same type.
     for (const Decoration *dec : decorations) {

+ 102 - 20
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -1045,7 +1045,8 @@ bool TypeTranslator::isOrContainsNonFpColMajorMatrix(QualType type,
                                                      const Decl *decl) const {
   const auto isColMajorDecl = [this](const Decl *decl) {
     return decl->hasAttr<HLSLColumnMajorAttr>() ||
-           (!decl->hasAttr<HLSLRowMajorAttr>() && !spirvOptions.defaultRowMajor);
+           (!decl->hasAttr<HLSLRowMajorAttr>() &&
+            !spirvOptions.defaultRowMajor);
   };
 
   QualType elemType = {};
@@ -1190,13 +1191,21 @@ bool TypeTranslator::isSameType(QualType type1, QualType type2) {
 QualType TypeTranslator::getElementType(QualType type) {
   QualType elemType = {};
   if (isScalarType(type, &elemType) || isVectorType(type, &elemType) ||
-      isMxNMatrix(type, &elemType)) {
-  } else if (const auto *arrType = astContext.getAsConstantArrayType(type)) {
-    elemType = arrType->getElementType();
-  } else {
-    assert(false && "unhandled type");
+      isMxNMatrix(type, &elemType) || canFitIntoOneRegister(type, &elemType)) {
+    return elemType;
   }
-  return elemType;
+
+  if (const auto *arrType = astContext.getAsConstantArrayType(type)) {
+    return arrType->getElementType();
+  }
+
+  emitError("unsupported resource type parameter %0") << type;
+  // Note: We are returning the original type instead of a null QualType here
+  // to keep the translation going and avoid hitting asserts trying to query
+  // info from null QualType in other places of the compiler. Although we are
+  // likely generating invalid code here, it should be fine since the error
+  // reported will prevent the CodeGen from actually outputing.
+  return type;
 }
 
 uint32_t TypeTranslator::getComponentVectorType(QualType matrixType) {
@@ -1296,11 +1305,12 @@ llvm::SmallVector<const Decoration *, 4> TypeTranslator::getLayoutDecorations(
 
     if (rule == LayoutRule::RelaxedGLSLStd140 ||
         rule == LayoutRule::RelaxedGLSLStd430 ||
-        rule == LayoutRule::FxcCTBuffer)
-      alignUsingHLSLRelaxedLayout(fieldType, memberSize, &memberAlignment,
+        rule == LayoutRule::FxcCTBuffer) {
+      alignUsingHLSLRelaxedLayout(fieldType, memberSize, memberAlignment,
                                   &offset);
-    else
+    } else {
       offset = roundToPow2(offset, memberAlignment);
+    }
 
     // The vk::offset attribute takes precedence over all.
     if (const auto *offsetAttr = decl->getAttr<VKOffsetAttr>()) {
@@ -1533,6 +1543,16 @@ uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule) {
   if (name == "Buffer" || name == "RWBuffer") {
     theBuilder.requireCapability(spv::Capability::SampledBuffer);
     const auto sampledType = hlsl::GetHLSLResourceResultType(type);
+    if (sampledType->isStructureType() && name.startswith("RW")) {
+      // Note: actually fxc supports RWBuffer over struct types. However, the
+      // struct member must fit into a 4-component vector and writing to a
+      // RWBuffer element must write all components. This is a feature that are
+      // rarely used by developers. We just emit an error saying not supported
+      // for now.
+      emitError("cannot instantiate RWBuffer with struct type %0")
+          << sampledType;
+      return 0;
+    }
     const auto format = translateSampledTypeToImageFormat(sampledType);
     return theBuilder.getImageType(
         translateType(getElementType(sampledType)), spv::Dim::Buffer,
@@ -1578,7 +1598,8 @@ TypeTranslator::translateSampledTypeToImageFormat(QualType sampledType) {
   uint32_t elemCount = 1;
   QualType ty = {};
   if (isScalarType(sampledType, &ty) ||
-      isVectorType(sampledType, &ty, &elemCount)) {
+      isVectorType(sampledType, &ty, &elemCount) ||
+      canFitIntoOneRegister(sampledType, &ty, &elemCount)) {
     if (const auto *builtinType = ty->getAs<BuiltinType>()) {
       switch (builtinType->getKind()) {
       case BuiltinType::Int:
@@ -1599,13 +1620,65 @@ TypeTranslator::translateSampledTypeToImageFormat(QualType sampledType) {
       }
     }
   }
-  emitError("resource type %0 unimplemented") << sampledType.getAsString();
+  emitError(
+      "cannot translate resource type parameter %0 to proper image format")
+      << sampledType;
   return spv::ImageFormat::Unknown;
 }
 
+bool TypeTranslator::canFitIntoOneRegister(QualType structType,
+                                           QualType *elemType,
+                                           uint32_t *elemCount) {
+  if (structType->getAsStructureType() == nullptr)
+    return false;
+
+  const auto *structDecl = structType->getAsStructureType()->getDecl();
+  QualType firstElemType;
+  uint32_t totalCount = 0;
+
+  for (const auto *field : structDecl->fields()) {
+    QualType type;
+    uint32_t count = 1;
+
+    if (isScalarType(field->getType(), &type) ||
+        isVectorType(field->getType(), &type, &count)) {
+      if (firstElemType.isNull()) {
+        firstElemType = type;
+      } else {
+        if (!canTreatAsSameScalarType(firstElemType, type)) {
+          emitError("all struct members should have the same element type for "
+                    "resource template instantiation",
+                    structDecl->getLocation());
+          return false;
+        }
+      }
+      totalCount += count;
+    } else {
+      emitError("unsupported struct element type for resource template "
+                "instantiation",
+                structDecl->getLocation());
+      return false;
+    }
+  }
+
+  if (totalCount > 4) {
+    emitError(
+        "resource template element type %0 cannot fit into four 32-bit scalars",
+        structDecl->getLocation())
+        << structType;
+    return false;
+  }
+
+  if (elemType)
+    *elemType = firstElemType;
+  if (elemCount)
+    *elemCount = totalCount;
+  return true;
+}
+
 void TypeTranslator::alignUsingHLSLRelaxedLayout(QualType fieldType,
                                                  uint32_t fieldSize,
-                                                 uint32_t *fieldAlignment,
+                                                 uint32_t fieldAlignment,
                                                  uint32_t *currentOffset) {
   QualType vecElemType = {};
   const bool fieldIsVecType = isVectorType(fieldType, &vecElemType);
@@ -1618,17 +1691,17 @@ void TypeTranslator::alignUsingHLSLRelaxedLayout(QualType fieldType,
     std::tie(scalarAlignment, std::ignore) =
         getAlignmentAndSize(vecElemType, LayoutRule::Void, nullptr);
     if (scalarAlignment <= 4)
-      *fieldAlignment = scalarAlignment;
+      fieldAlignment = scalarAlignment;
   }
 
-  *currentOffset = roundToPow2(*currentOffset, *fieldAlignment);
+  *currentOffset = roundToPow2(*currentOffset, fieldAlignment);
 
   // Adjust according to HLSL relaxed layout rules.
   // Bump to 4-component vector alignment if there is a bad straddle
   if (fieldIsVecType &&
       improperStraddle(fieldType, fieldSize, *currentOffset)) {
-    *fieldAlignment = kStd140Vec4Alignment;
-    *currentOffset = roundToPow2(*currentOffset, *fieldAlignment);
+    fieldAlignment = kStd140Vec4Alignment;
+    *currentOffset = roundToPow2(*currentOffset, fieldAlignment);
   }
 }
 
@@ -1811,11 +1884,20 @@ TypeTranslator::getAlignmentAndSize(QualType type, LayoutRule rule,
 
       if (rule == LayoutRule::RelaxedGLSLStd140 ||
           rule == LayoutRule::RelaxedGLSLStd430 ||
-          rule == LayoutRule::FxcCTBuffer)
+          rule == LayoutRule::FxcCTBuffer) {
         alignUsingHLSLRelaxedLayout(field->getType(), memberSize,
-                                    &memberAlignment, &structSize);
-      else
+                                    memberAlignment, &structSize);
+      } else {
         structSize = roundToPow2(structSize, memberAlignment);
+      }
+
+      // Reset the current offset to the one specified in the source code
+      // if exists. It's debatable whether we should do sanity check here.
+      // If the developers want manually control the layout, we leave
+      // everything to them.
+      if (const auto *offsetAttr = field->getAttr<VKOffsetAttr>()) {
+        structSize = offsetAttr->getOffset();
+      }
 
       // The base alignment of the structure is N, where N is the largest
       // base alignment value of any of its members...

+ 8 - 1
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -233,6 +233,13 @@ public:
   /// matrix type.
   uint32_t getComponentVectorType(QualType matrixType);
 
+  /// \brief Returns true if all members in structType are of the same element
+  /// type and can be fit into a 4-component vector. Writes element type and
+  /// count to *elemType and *elemCount if not nullptr. Otherwise, emit errors
+  /// explaining why not.
+  bool canFitIntoOneRegister(QualType structType, QualType *elemType = nullptr,
+                             uint32_t *elemCount = nullptr);
+
   /// \brief Returns the capability required for the given storage image type.
   /// Returns Capability::Max to mean no capability requirements.
   static spv::Capability getCapabilityForStorageImageReadWrite(QualType type);
@@ -302,7 +309,7 @@ private:
   /// fieldSize and fieldAlignment are the original size and alignment
   /// calculated without considering the HLSL vector relaxed rule.
   void alignUsingHLSLRelaxedLayout(QualType fieldType, uint32_t fieldSize,
-                                   uint32_t *fieldAlignment,
+                                   uint32_t fieldAlignment,
                                    uint32_t *currentOffset);
 
 public:

+ 28 - 0
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -3736,6 +3736,11 @@ public:
     DXASSERT_VALIDBASICKIND(componentType);
 
     QualType pType;  // The type to return.
+    if (componentType < AR_BASIC_COUNT) {
+      // If basic numeric, call LookupScalarTypeDef to ensure on-demand
+      // initialization
+      LookupScalarTypeDef(ScalarTypeForBasic(componentType));
+    }
     QualType pEltType = GetBasicKindType(componentType);
     DXASSERT(!pEltType.isNull(), "otherwise caller is specifying an incorrect basic kind type");
 
@@ -10494,6 +10499,7 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
       A.getAttributeSpellingListIndex());
     break;
   case AttributeList::AT_HLSLLinear:
+  case AttributeList::AT_HLSLCenter:
     declAttr = ::new (S.Context) HLSLLinearAttr(A.getRange(), S.Context,
       A.getAttributeSpellingListIndex());
     break;
@@ -11183,6 +11189,7 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
     *pNoPerspective = nullptr,
     *pSample = nullptr,
     *pCentroid = nullptr,
+    *pCenter = nullptr,
     *pAnyLinear = nullptr,                   // first linear attribute found
     *pTopology = nullptr;
   bool usageIn = false;
@@ -11274,6 +11281,7 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
       break;
 
     case AttributeList::AT_HLSLLinear:
+    case AttributeList::AT_HLSLCenter:
     case AttributeList::AT_HLSLNoPerspective:
     case AttributeList::AT_HLSLSample:
     case AttributeList::AT_HLSLCentroid:
@@ -11294,6 +11302,13 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
         }
         pLinear = pAttr;
         break;
+      case AttributeList::AT_HLSLCenter:
+        if (pCenter) {
+          Diag(pAttr->getLoc(), diag::warn_hlsl_duplicate_specifier)
+            << pAttr->getName() << pAttr->getRange();
+        }
+        pCenter = pAttr;
+        break;
       case AttributeList::AT_HLSLNoPerspective:
         if (pNoPerspective) {
           Diag(pAttr->getLoc(), diag::warn_hlsl_duplicate_specifier)
@@ -11361,6 +11376,14 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
     Diag(pCentroid->getLoc(), diag::warn_hlsl_specifier_overridden)
         << pCentroid->getName() << pSample->getName() << pCentroid->getRange();
   }
+  if (pCenter && pCentroid) {
+    Diag(pCenter->getLoc(), diag::warn_hlsl_specifier_overridden)
+      << pCenter->getName() << pCentroid->getName() << pCenter->getRange();
+  }
+  if (pSample && pCenter) {
+    Diag(pCenter->getLoc(), diag::warn_hlsl_specifier_overridden)
+      << pCenter->getName() << pSample->getName() << pCenter->getRange();
+  }
   clang::AttributeList *pNonUniformAttr = pAnyLinear ? pAnyLinear : (
     pNoInterpolation ? pNoInterpolation : pTopology);
   if (pUniform && pNonUniformAttr) {
@@ -11648,6 +11671,10 @@ void hlsl::CustomPrintHLSLAttr(const clang::Attr *A, llvm::raw_ostream &Out, con
     Out << "linear ";
     break;
 
+  case clang::attr::HLSLCenter:
+    Out << "center ";
+    break;
+
   case clang::attr::HLSLCentroid:
     Out << "centroid ";
     break;
@@ -11924,6 +11951,7 @@ bool hlsl::IsHLSLAttr(clang::attr::Kind AttrKind) {
   case clang::attr::HLSLInOut:
   case clang::attr::HLSLInstance:
   case clang::attr::HLSLLinear:
+  case clang::attr::HLSLCenter:
   case clang::attr::HLSLLoop:
   case clang::attr::HLSLMaxTessFactor:
   case clang::attr::HLSLNoInterpolation:

+ 11 - 0
tools/clang/test/CodeGenHLSL/quick-test/center_kwd.hlsl

@@ -0,0 +1,11 @@
+// RUN: %dxc -T ps_6_0 -Od -E main %s | FileCheck %s 
+
+// CHECK: %center = alloca float, align 4
+
+// make sure 'center' is allowed as an interpolation modifier
+float main(center float t : T) : SV_TARGET
+{
+    // and also as an identifier
+    float center = 10.0f;
+    return center * 2;
+}

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

@@ -0,0 +1,13 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// Make sure this works on function that returns matrix
+// CHECK: call %dx.types.CBufRet.f32 @dx.op.cbufferLoad
+
+float4x4 m;
+float4x4 GetMat() {
+  return m;
+}
+
+float main() : SV_Target {
+  return GetMat()._m01;
+}

+ 11 - 0
tools/clang/test/CodeGenHLSL/quick-test/min10float.hlsl

@@ -0,0 +1,11 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// CHECK: warning: min10float is promoted to min16float
+// CHECK: define void @main
+// CHECK: ret void
+
+[RootSignature("")]
+min10float main( min10float mf:P ) : SV_Target
+{
+    return  mf * 2;
+}

+ 21 - 0
tools/clang/test/CodeGenHLSL/quick-test/min10float_to_float.hlsl

@@ -0,0 +1,21 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// CHECK: warning: min10float is promoted to min16float
+// CHECK: define void @main
+// CHECK: ret void
+
+[RootSignature("")]
+float2 main( min10float mf:P , int s:Q) : SV_Target
+{
+    if(s > 1)
+    {
+        min10float new_mf = mf * mf;
+        new_mf = new_mf / 2.0;
+        float f = float(new_mf);
+        f = (f * 4.0) / 3.3;
+        min10float new_mf1 = min10float(f);
+        new_mf1 = new_mf1 + new_mf;
+        return float2(new_mf1, new_mf1);
+    }
+    return float2(1.0, 1.0);
+}

+ 11 - 0
tools/clang/test/CodeGenHLSL/quick-test/min12int.hlsl

@@ -0,0 +1,11 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// CHECK: warning: min12int is promoted to min16int
+// CHECK: define void @main
+// CHECK: ret void
+
+[RootSignature("")]
+min12int main( min12int mi:P ) : SV_Target
+{
+    return  mi * 2;
+}

+ 21 - 0
tools/clang/test/CodeGenHLSL/quick-test/min12int_to_int.hlsl

@@ -0,0 +1,21 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// CHECK: warning: min12int is promoted to min16int
+// CHECK: define void @main
+// CHECK: ret void
+
+[RootSignature("")]
+int2 main( min12int mi:P , int s:Q) : SV_Target
+{
+    if(s > 1)
+    {
+        min12int new_mi = mi * mi;
+        new_mi = min12int(new_mi * 2);
+        int f = int(new_mi);
+        f = (f * 4) / 3;
+        min12int new_mi1 = min12int(f);
+        new_mi1 = new_mi1 + new_mi;
+        return int2(new_mi1, new_mi1);
+    }
+    return int2(1, 1);
+}

+ 12 - 0
tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test01.hlsl

@@ -0,0 +1,12 @@
+// RUN: %dxc /O0 /Tps_6_0 /Emain > %s | FileCheck %s
+// CHECK: define void @main()
+// CHECK: entry
+Texture2D g_Tex;
+SamplerState g_Sampler;
+void unused() { }
+float4 main(float4 pos : SV_Position, float4 user : USER, bool b : B) : SV_Target {
+	unused();
+	int2 offset = int2(0,-1);
+	if (b) user = g_Tex.SampleLevel(g_Sampler, pos.xy, 0.0, offset.xy);
+	return user * pos;
+}

+ 14 - 0
tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test02.hlsl

@@ -0,0 +1,14 @@
+// RUN: %dxc /O0 /Tps_6_0 /Emain > %s | FileCheck %s
+// CHECK: define void @main()
+// CHECK: entry
+Texture2D g_Tex;
+SamplerState g_Sampler;
+void unused() { }
+float4 main(float4 pos : SV_Position, float4 user : USER, bool b : B) : SV_Target {
+	unused();
+	int2 offset = int2(0,-1);
+	float4 g_Buffer = {-1.0, 1.0, -2.0, 2.0};
+	float4 shift = float4(g_Buffer[offset.x], g_Buffer[offset.x], g_Buffer[offset.x], g_Buffer[offset.y]);
+	if (b) user = g_Tex.SampleLevel(g_Sampler, pos.xy, 0.0, offset.xy);
+	return user * (pos * shift);
+}

+ 18 - 0
tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test03.hlsl

@@ -0,0 +1,18 @@
+// RUN: %dxc /O0 /Od /Tps_6_0 /Emain > %s | FileCheck %s
+// CHECK: define void @main()
+// CHECK: entry
+Texture2D g_Tex;
+SamplerState g_Sampler;
+void unused() { }
+float4 main(float4 pos : SV_Position, float4 user : USER, bool b : B) : SV_Target {
+	unused();
+	int2 offset = int2(0,1);
+	float2x4 g_Buffer =
+	{
+	-1.0, 1.0, -2.0, 2.0,
+	-1.0, -1.0, 2.0, -2.0,
+	};
+	float4 shift = float4(g_Buffer[offset.x][offset.x], g_Buffer[offset.y][offset.x], g_Buffer[offset.x][offset.y], g_Buffer[offset.y][offset.y]);
+	if (b) user = g_Tex.SampleLevel(g_Sampler, pos.xy, 0.0, offset.xy);
+	return user * (pos * shift);
+}

+ 12 - 0
tools/clang/test/CodeGenHLSL/quick-test/sample-offset-imm-test04.hlsl

@@ -0,0 +1,12 @@
+// RUN: %dxc /O0 /Od /Tps_6_0 /Emain > %s | FileCheck %s
+// CHECK: define void @main()
+// CHECK: entry
+Texture2D g_Tex;
+SamplerState g_Sampler;
+void unused() { }
+float4 main(float4 pos : SV_Position, float4 user : USER, bool b : B) : SV_Target {
+	unused();
+	int2 offset[2] = { int2(0,1), int2(1,0) };
+	if (b) user = g_Tex.SampleLevel(g_Sampler, pos.xy, 0.0, int2(offset[1].x, offset[0].y));
+	return user * pos;
+}

+ 49 - 0
tools/clang/test/CodeGenHLSL/quick-test/sample_kwd.hlsl

@@ -0,0 +1,49 @@
+// RUN: %dxc -T ps_6_0 -Od -E main %s | FileCheck %s
+
+// CHECK: %precise = alloca float, align 4
+// CHECK: %globallycoherent = alloca i32, align 4
+// CHECK: %sample = alloca float, align 4
+// CHECK: %center = alloca float, align 4
+
+// CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %MyBuffer_UAV_structbuf, i32 0, i32 0)
+// CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %MyBuffer_UAV_structbuf, i32 0, i32 16)
+// CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %MyBuffer_UAV_structbuf, i32 0, i32 32)
+// CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %MyBuffer_UAV_structbuf, i32 0, i32 48)
+
+// Check function parameters are accepted
+float3 foo(float3 sample) {
+    return sample;
+}
+
+// Check member fields are accepted
+struct S {
+  float4 center;
+  float4 precise;
+  float4 sample;
+  float4 globallycoherent;
+};
+
+RWStructuredBuffer<S> MyBuffer;
+
+float4 main(float4 input : SV_POSITION) : SV_TARGET
+{
+    // Check declarations are accepted
+    float precise = 1.0f;
+    int globallycoherent = 1;
+    float sample;
+
+    // Check assignments are accepted
+    sample = 1.0f;
+    globallycoherent += 10;
+
+    // Check declaration group is accepted
+    float left, center = 1.0, right;
+
+    // Check parentheses are accepted
+    // (they go through the path for type cast in frontend)
+    float w = (center).x;
+
+    return float4(foo(float3(precise, globallycoherent, sample)), w) +
+           MyBuffer[0].center + MyBuffer[0].precise +
+           MyBuffer[0].sample + MyBuffer[0].globallycoherent;
+}

+ 0 - 3
tools/clang/test/CodeGenSPIRV/bezier.domain.hlsl2spv

@@ -167,10 +167,8 @@ DS_OUTPUT BezierEvalDS( HS_CONSTANT_DATA_OUTPUT input,
 // %35 = OpLoad %_arr_v3float_uint_4 %in_var_TANVCORNER
 // %38 = OpLoad %v4float %in_var_TANWEIGHTS
 // %39 = OpCompositeConstruct %HS_CONSTANT_DATA_OUTPUT %22 %25 %28 %31 %33 %35 %38
-// OpStore %param_var_input %39
 // %44 = OpLoad %v3float %gl_TessCoord
 // %45 = OpVectorShuffle %v2float %44 %44 0 1
-// OpStore %param_var_UV %45
 // %51 = OpLoad %_arr_v3float_uint_4 %in_var_BEZIERPOS
 // %52 = OpCompositeExtract %v3float %51 0
 // %53 = OpCompositeConstruct %BEZIER_CONTROL_POINT %52
@@ -181,7 +179,6 @@ DS_OUTPUT BezierEvalDS( HS_CONSTANT_DATA_OUTPUT input,
 // %58 = OpCompositeExtract %v3float %51 3
 // %59 = OpCompositeConstruct %BEZIER_CONTROL_POINT %58
 // %60 = OpCompositeConstruct %_arr_BEZIER_CONTROL_POINT_uint_4 %53 %55 %57 %59
-// OpStore %param_var_bezpatch %60
 // %62 = OpFunctionCall %DS_OUTPUT %src_BezierEvalDS %param_var_input %param_var_UV %param_var_bezpatch
 // %63 = OpCompositeExtract %v3float %62 0
 // OpStore %out_var_NORMAL %63

+ 0 - 3
tools/clang/test/CodeGenSPIRV/bezier.hull.hlsl2spv

@@ -212,11 +212,8 @@ BEZIER_CONTROL_POINT SubDToBezierHS(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POIN
 // %35 = OpCompositeExtract %v3float %24 2
 // %36 = OpCompositeConstruct %VS_CONTROL_POINT_OUTPUT %33 %34 %35
 // %37 = OpCompositeConstruct %_arr_VS_CONTROL_POINT_OUTPUT_uint_3 %28 %32 %36
-// OpStore %param_var_ip %37
 // %42 = OpLoad %uint %gl_InvocationID
-// OpStore %param_var_cpid %42
 // %45 = OpLoad %uint %gl_PrimitiveID
-// OpStore %param_var_PatchID %45
 // %47 = OpFunctionCall %BEZIER_CONTROL_POINT %src_SubDToBezierHS %param_var_ip %param_var_cpid %param_var_PatchID
 // %48 = OpCompositeExtract %v3float %47 0
 // %52 = OpAccessChain %_ptr_Output_v3float %out_var_BEZIERPOS %42

+ 9 - 7
tools/clang/test/CodeGenSPIRV/empty-struct-interface.vs.hlsl2spv

@@ -22,25 +22,27 @@ VSOut main(VSIn input)
 // OpName %main "main"
 // OpName %VSIn "VSIn"
 // OpName %param_var_input "param.var.input"
+// OpName %VSOut "VSOut"
 // OpName %input "input"
 // OpName %result "result"
 // %void = OpTypeVoid
 // %3 = OpTypeFunction %void
 // %VSIn = OpTypeStruct
 // %_ptr_Function_VSIn = OpTypePointer Function %VSIn
-// %11 = OpTypeFunction %VSIn %_ptr_Function_VSIn
+// %VSOut = OpTypeStruct
+// %12 = OpTypeFunction %VSOut %_ptr_Function_VSIn
+// %_ptr_Function_VSOut = OpTypePointer Function %VSOut
 // %main = OpFunction %void None %3
 // %5 = OpLabel
 // %param_var_input = OpVariable %_ptr_Function_VSIn Function
 // %9 = OpCompositeConstruct %VSIn
-// OpStore %param_var_input %9
-// %10 = OpFunctionCall %VSIn %src_main %param_var_input
+// %11 = OpFunctionCall %VSOut %src_main %param_var_input
 // OpReturn
 // OpFunctionEnd
-// %src_main = OpFunction %VSIn None %11
+// %src_main = OpFunction %VSOut None %12
 // %input = OpFunctionParameter %_ptr_Function_VSIn
 // %bb_entry = OpLabel
-// %result = OpVariable %_ptr_Function_VSIn Function
-// %15 = OpLoad %VSIn %result
-// OpReturnValue %15
+// %result = OpVariable %_ptr_Function_VSOut Function
+// %17 = OpLoad %VSOut %result
+// OpReturnValue %17
 // OpFunctionEnd

+ 1 - 1
tools/clang/test/CodeGenSPIRV/hs.pcf.primitive-id.1.hlsl

@@ -45,6 +45,6 @@ HS_CONSTANT_DATA_OUTPUT PCF(uint PatchID : SV_PrimitiveID) {
 BEZIER_CONTROL_POINT main(InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
   VS_CONTROL_POINT_OUTPUT vsOutput;
   BEZIER_CONTROL_POINT result;
-  result.vPosition = vsOutput.vPosition;
+  result.vPosition = vsOutput.vPosition + PatchID;
   return result;
 }

+ 1 - 1
tools/clang/test/CodeGenSPIRV/hs.pcf.view-id.1.hlsl

@@ -44,7 +44,7 @@ HsCpOut main(InputPatch<HsCpIn, NumOutPoints> patch,
              uint id : SV_OutputControlPointID,
              uint viewid : SV_ViewID) {
     HsCpOut output;
-    output = (HsCpOut)0;
+    output.bar = viewid;
     return output;
 // CHECK:             %main = OpFunction %void None {{%\d+}}
 // CHECK: %param_var_viewid = OpVariable %_ptr_Function_uint Function

+ 19 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.interlocked-methods.error.hlsl

@@ -0,0 +1,19 @@
+// Run: %dxc -T cs_6_0 -E main
+
+groupshared float MyFloat;
+RWBuffer<float> MyBuffer;
+
+typedef int MyIntegerType;
+RWStructuredBuffer<MyIntegerType> MySBuffer;
+
+[numthreads(1, 1, 1)]
+void main()
+{
+  InterlockedAdd(MyFloat, 1);
+  InterlockedCompareStore(MyBuffer[0], MySBuffer[0], MySBuffer[1]);
+  InterlockedXor(MySBuffer[2], 5);
+}
+
+// CHECK:     :12:18: error: can only perform atomic operations on scalar integer values
+// CHECK:     :13:27: error: can only perform atomic operations on scalar integer values
+// CHECK-NOT:         error: can only perform atomic operations on scalar integer values

+ 33 - 0
tools/clang/test/CodeGenSPIRV/op.buffer.access.hlsl

@@ -15,6 +15,14 @@ RWBuffer<int4> int4buf;
 RWBuffer<uint4> uint4buf;
 RWBuffer<float4> float4buf;
 
+struct S {
+  float  a;
+  float2 b;
+  float1 c;
+};
+
+  Buffer<S> sBuf;
+
 void main() {
   int address;
 
@@ -102,4 +110,29 @@ void main() {
 // CHECK-NEXT:     [[b:%\d+]] = OpLoad %float [[ac14]]
 // CHECK-NEXT:                  OpStore %b [[b]]
   float b = float4buf[address][2];
+
+// CHECK:        [[img:%\d+]] = OpLoad %type_buffer_image_7 %sBuf
+// CHECK-NEXT: [[fetch:%\d+]] = OpImageFetch %v4float [[img]] %uint_0 None
+// CHECK-NEXT:   [[s_a:%\d+]] = OpCompositeExtract %float [[fetch]] 0
+// CHECK-NEXT:   [[s_b:%\d+]] = OpVectorShuffle %v2float [[fetch]] [[fetch]] 1 2
+// CHECK-NEXT:   [[s_c:%\d+]] = OpCompositeExtract %float [[fetch]] 3
+// CHECK-NEXT:     [[s:%\d+]] = OpCompositeConstruct %S [[s_a]] [[s_b]] [[s_c]]
+// CHECK-NEXT:                  OpStore %temp_var_S [[s]]
+// CHECK-NEXT:   [[ptr:%\d+]] = OpAccessChain %_ptr_Function_float %temp_var_S %int_0
+// CHECK-NEXT:     [[c:%\d+]] = OpLoad %float [[ptr]]
+// CHECK-NEXT:                  OpStore %c [[c]]
+  float c = sBuf[0].a;
+
+// CHECK:        [[img:%\d+]] = OpLoad %type_buffer_image_7 %sBuf
+// CHECK-NEXT: [[fetch:%\d+]] = OpImageFetch %v4float [[img]] %uint_1 None
+// CHECK-NEXT:   [[s_a:%\d+]] = OpCompositeExtract %float [[fetch]] 0
+// CHECK-NEXT:   [[s_b:%\d+]] = OpVectorShuffle %v2float [[fetch]] [[fetch]] 1 2
+// CHECK-NEXT:   [[s_c:%\d+]] = OpCompositeExtract %float [[fetch]] 3
+// CHECK-NEXT:     [[s:%\d+]] = OpCompositeConstruct %S [[s_a]] [[s_b]] [[s_c]]
+// CHECK-NEXT:                  OpStore %temp_var_S_0 [[s]]
+// CHECK-NEXT:   [[ptr:%\d+]] = OpAccessChain %_ptr_Function_v2float %temp_var_S_0 %int_1
+// CHECK-NEXT:   [[val:%\d+]] = OpLoad %v2float [[ptr]]
+// CHECK-NEXT:     [[d:%\d+]] = OpCompositeExtract %float [[val]] 1
+// CHECK-NEXT:                  OpStore %d [[d]]
+  float d = sBuf[1].b.y;
 }

+ 29 - 3
tools/clang/test/CodeGenSPIRV/op.struct.access.hlsl

@@ -1,10 +1,13 @@
 // Run: %dxc -T ps_6_0 -E main
 
 struct S {
-    bool a;
-    uint2 b;
+    bool     a;
+    uint2    b;
     float2x3 c;
-    float4 d;
+    float4   d;
+    float4   e[1];
+    float    f[4];
+    int      g;
 };
 
 struct T {
@@ -17,6 +20,17 @@ T foo() {
     return ret;
 }
 
+S bar() {
+    S ret = (S)0;
+    return ret;
+}
+
+ConstantBuffer<S> MyBuffer;
+
+S baz() {
+    return MyBuffer;
+}
+
 float4 main() : SV_Target {
     T t;
 
@@ -75,6 +89,18 @@ float4 main() : SV_Target {
 // CHECK-NEXT: OpStore [[c0]] {{%\d+}}
     t.i.c[0] = v6;
 
+// CHECK:       [[baz:%\d+]] = OpFunctionCall %S %baz
+// CHECK-NEXT:                 OpStore %temp_var_S [[baz]]
+// CHECK-NEXT:                 OpAccessChain %_ptr_Function_v4float %temp_var_S %int_4 %int_0
+// CHECK:       [[bar:%\d+]] = OpFunctionCall %S %bar
+// CHECK-NEXT:                 OpStore %temp_var_S_0 [[bar]]
+// CHECK-NEXT:                 OpAccessChain %_ptr_Function_float %temp_var_S_0 %int_5 %int_1
+    float4 val1 = bar().f[1] * baz().e[0];
+
+// CHECK:        [[ac:%\d+]] = OpAccessChain %_ptr_Function_int %temp_var_S_1 %int_6
+// CHECK-NEXT:                 OpLoad %int [[ac]]
+    bool val2 = bar().g; // Need cast on rvalue function return
+
 // CHECK:      [[ret:%\d+]] = OpFunctionCall %T %foo
 // CHECK-NEXT: OpStore %temp_var_T [[ret]]
 // CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Function_v4float %temp_var_T %int_1 %int_3

+ 19 - 0
tools/clang/test/CodeGenSPIRV/op.texture.access.hlsl

@@ -10,6 +10,13 @@ Texture2DArray   <int3>   t6;
 // There is no operator[] for TextureCubeArray in HLSL reference.
 // There is no operator[] for Texture2DMSArray in HLSL reference.
 
+struct S {
+  float  a;
+  float2 b;
+  float1 c;
+};
+
+Texture2D <S> tStruct;
 
 // CHECK:  [[cu12:%\d+]] = OpConstantComposite %v2uint %uint_1 %uint_2
 // CHECK: [[cu123:%\d+]] = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
@@ -55,4 +62,16 @@ void main() {
 // CHECK-NEXT: [[result6:%\d+]] = OpVectorShuffle %v3int [[f6]] [[f6]] 0 1 2
 // CHECK-NEXT: OpStore %a6 [[result6]]
   int3   a6 = t6[uint3(1,2,3)];
+
+// CHECK:        [[tex:%\d+]] = OpLoad %type_2d_image_1 %tStruct
+// CHECK-NEXT: [[fetch:%\d+]] = OpImageFetch %v4float [[tex]] {{%\d+}} Lod %uint_0
+// CHECK-NEXT:     [[a:%\d+]] = OpCompositeExtract %float [[fetch]] 0
+// CHECK-NEXT:     [[b:%\d+]] = OpVectorShuffle %v2float [[fetch]] [[fetch]] 1 2
+// CHECK-NEXT:     [[c:%\d+]] = OpCompositeExtract %float [[fetch]] 3
+// CHECK-NEXT:     [[s:%\d+]] = OpCompositeConstruct %S [[a]] [[b]] [[c]]
+// CHECK-NEXT:                  OpStore %temp_var_S [[s]]
+// CHECK-NEXT:   [[ptr:%\d+]] = OpAccessChain %_ptr_Function_float %temp_var_S %int_2
+// CHECK-NEXT:   [[val:%\d+]] = OpLoad %float [[ptr]]
+// CHECK-NEXT:                  OpStore %a7 [[val]]
+  float  a7 = tStruct[uint2(1, 2)].c;
 }

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor