| ============ |
| HLSL Support |
| ============ |
| |
| .. contents:: |
| :local: |
| |
| Introduction |
| ============ |
| |
| HLSL Support is under active development in the Clang codebase. This document |
| describes the high level goals of the project, the guiding principles, as well |
| as some idiosyncrasies of the HLSL language and how we intend to support them in |
| Clang. |
| |
| Project Goals |
| ============= |
| |
| The long term goal of this project is to enable Clang to function as a |
| replacement for the `DirectXShaderCompiler (DXC) |
| <https://github.com/microsoft/DirectXShaderCompiler/>`_ in all its supported |
| use cases. Accomplishing that goal will require Clang to be able to process most |
| existing HLSL programs with a high degree of source compatibility. |
| |
| Non-Goals |
| --------- |
| |
| HLSL ASTs do not need to be compatible between DXC and Clang. We do not expect |
| identical code generation or that features will resemble DXC's implementation or |
| architecture. In fact, we explicitly expect to deviate from DXC's implementation |
| in key ways. |
| |
| Guiding Principles |
| ================== |
| |
| This document lacks details for architectural decisions that are not yet |
| finalized. Our top priorities are quality, maintainability, and flexibility. In |
| accordance with community standards we are expecting a high level of test |
| coverage, and we will engineer our solutions with long term maintenance in mind. |
| We are also working to limit modifications to the Clang C++ code paths and |
| share as much functionality as possible. |
| |
| Architectural Direction |
| ======================= |
| |
| HLSL support in Clang is expressed as C++ minus unsupported C and C++ features. |
| This is different from how other Clang languages are implemented. Most languages |
| in Clang are additive on top of C. |
| |
| HLSL is not a formally or fully specified language, and while our goals require |
| a high level of source compatibility, implementations can vary and we have some |
| flexibility to be more or less permissive in some cases. For modern HLSL DXC is |
| the reference implementation. |
| |
| The HLSL effort prioritizes following similar patterns for other languages, |
| drivers, runtimes and targets. Specifically, We will maintain separation between |
| HSLS-specific code and the rest of Clang as much as possible following patterns |
| in use in Clang code today (i.e. ParseHLSL.cpp, SemaHLSL.cpp, CGHLSL*.cpp...). |
| We will use inline checks on language options where the code is simple and |
| isolated, and prefer HLSL-specific implementation files for any code of |
| reasonable complexity. |
| |
| In places where the HLSL language is in conflict with C and C++, we will seek to |
| make minimally invasive changes guarded under the HLSL language options. We will |
| seek to make HLSL language support as minimal a maintenance burden as possible. |
| |
| DXC Driver |
| ---------- |
| |
| A DXC driver mode will provide command-line compatibility with DXC, supporting |
| DXC's options and flags. The DXC driver is HLSL-specific and will create an |
| HLSLToolchain which will provide the basis to support targeting both DirectX and |
| Vulkan. |
| |
| Parser |
| ------ |
| |
| Following the examples of other parser extensions HLSL will add a ParseHLSL.cpp |
| file to contain the implementations of HLSL-specific extensions to the Clang |
| parser. The HLSL grammar shares most of its structure with C and C++, so we will |
| use the existing C/C++ parsing code paths. |
| |
| Sema |
| ---- |
| |
| HLSL's Sema implementation will also provide an ``ExternalSemaSource``. In DXC, |
| an ``ExternalSemaSource`` is used to provide definitions for HLSL built-in data |
| types and built-in templates. Clang is already designed to allow an attached |
| ``ExternalSemaSource`` to lazily complete data types, which is a **huge** |
| performance win for HLSL. |
| |
| If precompiled headers are used when compiling HLSL, the ``ExternalSemaSource`` |
| will be a ``MultiplexExternalSemaSource`` which includes both the ``ASTReader`` |
| and -. For Built-in declarations that are already |
| completed in the serialized AST, the ``HLSLExternalSemaSource`` will reuse the |
| existing declarations and not introduce new declarations. If the built-in types |
| are not completed in the serialized AST, the ``HLSLExternalSemaSource`` will |
| create new declarations and connect the de-serialized decls as the previous |
| declaration. |
| |
| CodeGen |
| ------- |
| |
| Like OpenCL, HLSL relies on capturing a lot of information into IR metadata. |
| *hand wave* *hand wave* *hand wave* As a design principle here we want our IR to |
| be idiomatic Clang IR as much as possible. We will use IR attributes wherever we |
| can, and use metadata as sparingly as possible. One example of a difference from |
| DXC already implemented in Clang is the use of target triples to communicate |
| shader model versions and shader stages. |
| |
| Our HLSL CodeGen implementation should also have an eye toward generating IR |
| that will map directly to targets other than DXIL. While IR itself is generally |
| not re-targetable, we want to share the Clang CodeGen implementation for HLSL |
| with other GPU graphics targets like SPIR-V and possibly other GPU and even CPU |
| targets. |
| |
| hlsl.h |
| ------ |
| |
| HLSL has a library of standalone functions. This is similar to OpenCL and CUDA, |
| and is analogous to C's standard library. The implementation approach for the |
| HLSL library functionality draws from patterns in use by OpenCL and other Clang |
| resource headers. All of the clang resource headers are part of the |
| ``ClangHeaders`` component found in the source tree under |
| `clang/lib/Headers <https://github.com/llvm/llvm-project/tree/main/clang/lib/Headers>`_. |
| |
| .. note:: |
| |
| HLSL's complex data types are not defined in HLSL's header because many of |
| the semantics of those data types cannot be expressed in HLSL due to missing |
| language features. Data types that can't be expressed in HLSL are defined in |
| code in the ``HLSLExternalSemaSource``. |
| |
| Similar to OpenCL, the HLSL library functionality is implicitly declared in |
| translation units without needing to include a header to provide declarations. |
| In Clang this is handled by making ``hlsl.h`` an implicitly included header |
| distributed as part of the Clang resource directory. |
| |
| Similar to OpenCL, HLSL's implicit header will explicitly declare all overloads, |
| and each overload will map to a corresponding ``__builtin*`` compiler intrinsic |
| that is handled in ClangCodeGen. CUDA uses a similar pattern although many CUDA |
| functions have full definitions in the included headers which in turn call |
| corresponding ``__builtin*`` compiler intrinsics. By not having bodies HLSL |
| avoids the need for the inliner to clean up and inline large numbers of small |
| library functions. |
| |
| HLSL's implicit headers also define some of HLSL's typedefs. This is consistent |
| with how the AVX vector header is implemented. |
| |
| Concerns have been expressed that this approach may result in slower compile |
| times than the approach DXC uses where library functions are treated more like |
| Clang ``__builtin*`` intrinsics. No real world use cases have been identified |
| where parsing is a significant compile-time overhead, but the HLSL implicit |
| headers can be compiled into a module for performance if needed. |
| |
| Further, by treating these as functions rather than ``__builtin*`` compiler |
| intrinsics, the language behaviors are more consistent and aligned with user |
| expectation because normal overload resolution rules and implicit conversions |
| apply as expected. |
| |
| It is a feature of this design that clangd-powered "go to declaration" for |
| library functions will jump to a valid header declaration and all overloads will |
| be user readable. |
| |
| HLSL Language |
| ============= |
| |
| The HLSL language is insufficiently documented, and not formally specified. |
| Documentation is available on `Microsoft's website |
| <https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl>`_. |
| The language syntax is similar enough to C and C++ that carefully written C and |
| C++ code is valid HLSL. HLSL has some key differences from C & C++ which we will |
| need to handle in Clang. |
| |
| HLSL is not a conforming or valid extension or superset of C or C++. The |
| language has key incompatibilities with C and C++, both syntactically and |
| semantically. |
| |
| An Aside on GPU Languages |
| ------------------------- |
| |
| Due to HLSL being a GPU targeted language HLSL is a Single Program Multiple Data |
| (SPMD) language relying on the implicit parallelism provided by GPU hardware. |
| Some language features in HLSL enable programmers to take advantage of the |
| parallel nature of GPUs in a hardware abstracted language. |
| |
| HLSL also prohibits some features of C and C++ which can have catastrophic |
| performance or are not widely supportable on GPU hardware or drivers. As an |
| example, register spilling is often excessively expensive on GPUs, so HLSL |
| requires all functions to be inlined during code generation, and does not |
| support a runtime calling convention. |
| |
| Pointers & References |
| --------------------- |
| |
| HLSL does not support referring to values by address. Semantically all variables |
| are value-types and behave as such. HLSL disallows the pointer dereference |
| operators (unary ``*``, and ``->``), as well as the address of operator (unary |
| &). While HLSL disallows pointers and references in the syntax, HLSL does use |
| reference types in the AST, and we intend to use pointer decay in the AST in |
| the Clang implementation. |
| |
| HLSL ``this`` Keyword |
| --------------------- |
| |
| HLSL does support member functions, and (in HLSL 2021) limited operator |
| overloading. With member function support, HLSL also has a ``this`` keyword. The |
| ``this`` keyword is an example of one of the places where HLSL relies on |
| references in the AST, because ``this`` is a reference. |
| |
| Bitshifts |
| --------- |
| |
| In deviation from C, HLSL bitshifts are defined to mask the shift count by the |
| size of the type. In DXC, the semantics of LLVM IR were altered to accommodate |
| this, in Clang we intend to generate the mask explicitly in the IR. In cases |
| where the shift value is constant, this will be constant folded appropriately, |
| in other cases we can clean it up in the DXIL target. |
| |
| Non-short Circuiting Logical Operators |
| -------------------------------------- |
| |
| In HLSL 2018 and earlier, HLSL supported logical operators (and the ternary |
| operator) on vector types. This behavior required that operators not short |
| circuit. The non-short circuiting behavior applies to all data types until HLSL |
| 2021. In HLSL 2021, logical and ternary operators do not support vector types |
| instead builtin functions ``and``, ``or`` and ``select`` are available, and |
| operators short circuit matching C behavior. |
| |
| Precise Qualifier |
| ----------------- |
| |
| HLSL has a ``precise`` qualifier that behaves unlike anything else in the C |
| language. The support for this qualifier in DXC is buggy, so our bar for |
| compatibility is low. |
| |
| The ``precise`` qualifier applies in the inverse direction from normal |
| qualifiers. Rather than signifying that the declaration containing ``precise`` |
| qualifier be precise, it signifies that the operations contributing to the |
| declaration's value be ``precise``. Additionally, ``precise`` is a misnomer: |
| values attributed as ``precise`` comply with IEEE-754 floating point semantics, |
| and are prevented from optimizations which could decrease *or increase* |
| precision. |
| |
| Differences in Templates |
| ------------------------ |
| |
| HLSL uses templates to define builtin types and methods, but disallowed |
| user-defined templates until HLSL 2021. HLSL also allows omitting empty template |
| parameter lists when all template parameters are defaulted. This is an ambiguous |
| syntax in C++, but Clang detects the case and issues a diagnostic. This makes |
| supporting the case in Clang minimally invasive. |
| |
| Vector Extensions |
| ----------------- |
| |
| HLSL uses the OpenCL vector extensions, and also provides C++-style constructors |
| for vectors that are not supported by Clang. |
| |
| Standard Library |
| ---------------- |
| |
| HLSL does not support the C or C++ standard libraries. Like OpenCL, HLSL |
| describes its own library of built in types, complex data types, and functions. |
| |
| Unsupported C & C++ Features |
| ---------------------------- |
| |
| HLSL does not support all features of C and C++. In implementing HLSL in Clang |
| use of some C and C++ features will produce diagnostics under HLSL, and others |
| will be supported as language extensions. In general, any C or C++ feature that |
| can be supported by the DXIL and SPIR-V code generation targets could be treated |
| as a clang HLSL extension. Features that cannot be lowered to DXIL or SPIR-V, |
| must be diagnosed as errors. |
| |
| HLSL does not support the following C features: |
| |
| * Pointers |
| * References |
| * ``goto`` or labels |
| * Variable Length Arrays |
| * ``_Complex`` and ``_Imaginary`` |
| * C Threads or Atomics (or Obj-C blocks) |
| * ``union`` types `(in progress for HLSL 202x) <https://github.com/microsoft/DirectXShaderCompiler/pull/4132>`_ |
| * Most features C11 and later |
| |
| HLSL does not support the following C++ features: |
| |
| * RTTI |
| * Exceptions |
| * Multiple inheritance |
| * Access specifiers |
| * Anonymous or inline namespaces |
| * ``new`` & ``delete`` operators in all of their forms (array, placement, etc) |
| * Constructors and destructors |
| * Any use of the ``virtual`` keyword |
| * Most features C++11 and later |