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.
The long term goal of this project is to enable Clang to function as a replacement for the DirectXShaderCompiler (DXC) 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.
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.
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.
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.
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.
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.
HLSL’s Sema implementation will also provide an
ExternalSemaSource. In DXC,
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.
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.
The HLSL language is insufficiently documented, and not formally specified. Documentation is available on Microsoft’s website. 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.
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.
HLSL does not support referring to values by address. Semantically all variables
are value-types and behave as such. HLSL disallows the pointer dereference
->), 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 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.
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.
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
select are available, and
operators short circuit matching C behavior.
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.
precise qualifier applies in the inverse direction from normal
qualifiers. Rather than signifying that the declaration containing
qualifier be precise, it signifies that the operations contributing to the
declaration’s value be
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
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.
HLSL uses the OpenCL vector extensions, and also provides C++-style constructors for vectors that are not supported by Clang.
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.
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:
Variable Length Arrays
C Threads or Atomics (or Obj-C blocks)
uniontypes (in progress for HLSL 202x)
Most features C11 and later
HLSL does not support the following C++ features:
Anonymous or inline namespaces
deleteoperators in all of their forms (array, placement, etc)
Constructors and destructors
Any use of the
Most features C++11 and later