| # HLSL Support | |
| ## 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 | |