Skip to content

[HLSL] Implement TableGen for builtin HLSL intrinsics#187610

Merged
Icohedron merged 20 commits intollvm:mainfrom
Icohedron:hlsl-intrinsic-tablegen
Mar 24, 2026
Merged

[HLSL] Implement TableGen for builtin HLSL intrinsics#187610
Icohedron merged 20 commits intollvm:mainfrom
Icohedron:hlsl-intrinsic-tablegen

Conversation

@Icohedron
Copy link
Copy Markdown
Contributor

@Icohedron Icohedron commented Mar 19, 2026

This PR introduces a TableGen-based code generation system for HLSL intrinsic overloads as described in proposal [0043] for replacing hand-written boilerplate with declarative .td definitions.

Actual changes to hlsl_intrinsics.h and hlsl_alias_intrinsics.h to replace handwritten HLSL intrinsic overloads with TableGen is left to follow-up PRs.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics HLSL HLSL Language Support labels Mar 19, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 19, 2026

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-x86

Author: Deric C. (Icohedron)

Changes

This PR introduces a TableGen-based code generation system for HLSL intrinsic overloads as described in proposal [0043], replacing hand-written boilerplate with declarative .td definitions. A representative set of 8 intrinsics (abs, and, cross, dot, dot2add, GroupMemoryBarrierWithGroupSync, isinf, refract) are migrated to demonstrate all the current features of the TableGen infrastructure. The remaining intrinsics stay manually defined for follow-up PRs to rewrite into TableGen.

Why the 8 representative intrinsics where chosen:

  • abs has two sets of overloads split between aliasing the clang builtin __builtin_elementwise_abs and inline identity functions on unsigned integer types. It also operates on 16-bit types and the half type to demonstrate the automatic inclusion of #ifdef __HLSL_ENABLE_16_BIT guards and _HLSL_AVAILABILITY(shadermodel, 6.2) for 16-bit integer types, and _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) for half types.

  • and demonstrates creating overloads with matrix types, and demonstrates the ability to restrict the Varying type to only booleans.

  • cross aliases two different clang builtins (__builtin_hlsl_crossf32 and __builtin_hlsl_crossf16) and demonstrates the use of fixed vector-type arguments.

  • dot has overloads for all vector types except for double-typed vectors, so the double-typed variant is split into its own scalar-only overload. It also demonstrates the use of VaryingElemType to always return the element type for the current overload.

  • dot2add demonstrates the use of DetailFunc to create an inline function that calls __detail::dot2add_impl(A, B, C). It also demonstrates the use of fixed-type arguments and return type (both scalar and vector), and the use of the Availability field to set the minimum shader model requirement.

  • GroupMemoryBarrierWithGroupSync demonstrates creating an overload with void return type and no arguments, as well as being a wave function that needs to be annotated with __attribute__((convergent)) by setting the IsConvergent field to 1.

  • isinf demonstrates the use of VaryingShape<T> to specify a return type that is of the same shape as the Varying type for the current overload but with a fixed element type (BoolTy in this case).

  • The defining of refract in TableGen instead of templates introduces some significant changes to error messages and also introduces a new offload test suite failure in the fp16 test because a call to refract(x, y, 0.5) where x and y are half-typed vectors is ambiguous due to 0.5 being a 32-bit float literal.

The generated hlsl_alias_intrinsic_gen.inc and hlsl_inline_intrinsic_gen.inc files for this PR can be viewed with this GitHub gist: https://gist.github.com/Icohedron/5ca4e1cc7e811ae72b091472478e9222
They can also be found in the build folder after building Clang, under the paths lib/clang/23/include/hlsl/hlsl_alias_intrinsics_gen.inc and lib/clang/23/include/hlsl/hlsl_inline_intrinsics_gen.inc.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)


Patch is 71.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/187610.diff

11 Files Affected:

  • (added) clang/include/clang/Basic/HLSLIntrinsics.td (+480)
  • (modified) clang/lib/Headers/CMakeLists.txt (+13-2)
  • (modified) clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h (+2-309)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+3-74)
  • (modified) clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl (+6-6)
  • (modified) clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl (+2-2)
  • (modified) clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl (+25-33)
  • (modified) clang/utils/TableGen/CMakeLists.txt (+1)
  • (added) clang/utils/TableGen/HLSLEmitter.cpp (+585)
  • (modified) clang/utils/TableGen/TableGen.cpp (+14)
  • (modified) clang/utils/TableGen/TableGenBackends.h (+5)
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
new file mode 100644
index 0000000000000..4676d9b3b611e
--- /dev/null
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -0,0 +1,480 @@
+//===--- HLSLIntrinsics.td - HLSL intrinsic declarations ---*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines HLSL intrinsic functions in tablegen. The HLSLEmitter
+// backend processes these definitions and generates two .inc files:
+//   - hlsl_alias_intrinsics_gen.inc: builtin alias declarations using
+//     _HLSL_BUILTIN_ALIAS, included by hlsl_alias_intrinsics.h.
+//   - hlsl_inline_intrinsics_gen.inc: inline function definitions (detail
+//     helper calls and literal bodies), included by hlsl_intrinsics.h.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Argument and return type base classes
+//===----------------------------------------------------------------------===//
+
+// Base class for argument and return type positions.
+class HLSLArgType;
+
+// Base class for return type positions.
+class HLSLReturnType;
+
+// Void return type.
+def VoidTy : HLSLReturnType;
+
+//===----------------------------------------------------------------------===//
+// HLSL element types
+//===----------------------------------------------------------------------===//
+
+// Represents a concrete HLSL scalar element type.
+// Can be used directly as an argument or return type for a fixed scalar
+// (e.g., FloatTy in Args produces a 'float' argument).
+class HLSLType<string name> : HLSLArgType, HLSLReturnType {
+  string Name = name;
+  string TypeName = name;
+
+  // When set, overloads using this type are guarded by
+  // #ifdef __HLSL_ENABLE_16_BIT and emitted with
+  // _HLSL_AVAILABILITY(shadermodel, 6.2), or the intrinsic's Availability
+  // if it is greater.
+  bit Is16Bit = 0;
+
+  // When set, overloads using this type are emitted with
+  // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) instead of _HLSL_AVAILABILITY.
+  // This macro expands to an availability attribute only when
+  // __HLSL_ENABLE_16_BIT is defined (i.e. half is a true 16-bit float);
+  // otherwise it expands to nothing since half is an alias for float.
+  // If the intrinsic's Availability is >= SM6.2, _HLSL_AVAILABILITY is used
+  // instead because 16-bit support is already implied.
+  bit IsConditionally16Bit = 0;
+}
+
+def BoolTy   : HLSLType<"bool">;
+def HalfTy   : HLSLType<"half">   { let IsConditionally16Bit = 1; }
+def FloatTy  : HLSLType<"float">;
+def DoubleTy : HLSLType<"double">;
+def Int16Ty  : HLSLType<"int16_t">  { let Is16Bit = 1; }
+def UInt16Ty : HLSLType<"uint16_t"> { let Is16Bit = 1; }
+def IntTy    : HLSLType<"int">;
+def UIntTy   : HLSLType<"uint">;
+def Int64Ty  : HLSLType<"int64_t">;
+def UInt64Ty : HLSLType<"uint64_t">;
+def UInt32Ty : HLSLType<"uint32_t">;
+
+//===----------------------------------------------------------------------===//
+// Element type groups
+//===----------------------------------------------------------------------===//
+
+defvar AllFloatTypes = [HalfTy, FloatTy, DoubleTy];
+defvar SignedIntTypes = [Int16Ty, IntTy, Int64Ty];
+defvar UnsignedIntTypes = [UInt16Ty, UIntTy, UInt64Ty];
+defvar AllIntTypes = [Int16Ty, UInt16Ty, IntTy, UIntTy,
+                      Int64Ty, UInt64Ty];
+defvar SignedTypes = [Int16Ty, HalfTy, IntTy, FloatTy,
+                      Int64Ty, DoubleTy];
+defvar AllNumericTypes = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
+                          FloatTy, Int64Ty, UInt64Ty, DoubleTy];
+defvar AllTypesWithBool = [BoolTy, Int16Ty, UInt16Ty, HalfTy,
+                           IntTy, UIntTy, FloatTy, Int64Ty,
+                           UInt64Ty, DoubleTy];
+defvar NumericTypesNoDbl = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
+                            FloatTy, Int64Ty, UInt64Ty];
+
+//===----------------------------------------------------------------------===//
+// Argument/return types
+//
+// These classes are usable in both argument and return type positions.
+//===----------------------------------------------------------------------===//
+
+// The varying type — expanded per VaryingTypes.
+// As an argument: the arg type varies with each overload.
+// As a return type: returns the same type as the varying arg.
+def Varying : HLSLArgType, HLSLReturnType;
+
+// The scalar element of the varying type.
+// As an argument: always the scalar element type regardless of overload shape.
+// As a return type: returns the scalar element type (e.g., float dot(float3, float3)).
+def VaryingElemType : HLSLArgType, HLSLReturnType;
+
+// The varying shape with a fixed element type.
+// As an argument: same shape as Varying but with the given element type.
+// As a return type: same shape as the varying arg but with the given element type.
+// For example, VaryingShape<UIntTy> with a float3 overload produces uint3.
+class VaryingShape<HLSLType ty> : HLSLArgType, HLSLReturnType {
+  HLSLType ElementType = ty;
+}
+
+// A concrete vector type (e.g., VectorType<UIntTy, 4> -> uint4).
+// As an argument: the arg is always this vector type.
+// As a return type: always returns this vector type, ignoring argument shape.
+class VectorType<HLSLType ty, int size> : HLSLArgType, HLSLReturnType {
+  HLSLType ElementType = ty;
+  int Size = size;
+}
+
+//===----------------------------------------------------------------------===//
+// Shader model versions
+//===----------------------------------------------------------------------===//
+
+// Represents a shader model version
+class ShaderModel<int major, int minor> {
+  int Major = major;
+  int Minor = minor;
+}
+
+// Sentinel: no shader model requirement.
+def NoSM  : ShaderModel<0, 0>;
+
+// Valid Shader Model records
+foreach i = 0...9 in {
+  def SM6_ #i : ShaderModel<6, i>;
+}
+
+//===----------------------------------------------------------------------===//
+// Matrix dimension records
+//===----------------------------------------------------------------------===//
+
+class MatDim<int rows, int cols> {
+  int Rows = rows;
+  int Cols = cols;
+}
+
+foreach r = 1...4 in
+  foreach c = 1...4 in
+    def Mat#r#"x"#c : MatDim<r, c>;
+
+// All non-1x1 matrix dimensions (1x2 through 4x4).
+defvar AllMatDims = [Mat1x2, Mat1x3, Mat1x4,
+                     Mat2x1, Mat2x2, Mat2x3, Mat2x4,
+                     Mat3x1, Mat3x2, Mat3x3, Mat3x4,
+                     Mat4x1, Mat4x2, Mat4x3, Mat4x4];
+
+//===----------------------------------------------------------------------===//
+// HLSLBuiltin class
+//===----------------------------------------------------------------------===//
+
+class HLSLBuiltin<string name, string builtin = ""> {
+  string Name = name;
+
+  // When set, generates a _HLSL_BUILTIN_ALIAS(Builtin) declaration that
+  // aliases the named Clang builtin. Mutually exclusive with DetailFunc
+  // and Body.
+  string Builtin = builtin;
+
+  // Doxygen documentation comment emitted before overloads in generated code.
+  string Doc = "";
+
+  // When set, generates an inline function body calling
+  // __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS(Builtin).
+  // Parameters are named p0, p1, p2, ... by default, or use ParamNames to
+  // specify custom names. Mutually exclusive with Body and Builtin.
+  string DetailFunc = "";
+
+  // When set, generates an inline function with this literal body text.
+  // Intended for single-statement functions. Multi-line functions should
+  // instead be defined as a helper and called with DetailFunc.
+  // Parameters are named p0, p1, p2, ... by default, or use ParamNames to
+  // specify custom names. Mutually exclusive with DetailFunc and Builtin.
+  code Body = "";
+
+  // Determines how the return type is derived for each overload.
+  HLSLReturnType ReturnType = VoidTy;
+
+  // Argument list. Each entry is either:
+  //   Varying     - type varies with VaryingTypes (expanded per type)
+  //   HLSLType    - a fixed scalar type at that position (e.g., UIntTy)
+  //   VectorType  - a fixed vector type at that position
+  // The number of arguments is deduced from the length of this list.
+  // Examples:
+  //   [Varying]                              -> func(T)
+  //   [Varying, Varying, Varying]            -> func(T, T, T)
+  //   [Varying, UInt32Ty]                    -> func(T, uint32_t)
+  //   [UIntTy, UIntTy, IntTy]                -> func(uint, uint, int)
+  //   []                                     -> func()
+  list<HLSLArgType> Args = [];
+
+  // Custom parameter names for generated functions.
+  // When empty, inline functions (Body or DetailFunc) use p0, p1, p2, ...
+  // and alias functions omit parameter names.
+  list<string> ParamNames = [];
+
+  // When set, emits 'constexpr' instead of 'inline' for inline functions
+  // (i.e., functions using Body or DetailFunc).
+  bit IsConstexpr = 0;
+
+  // Whether the function has the convergent attribute
+  bit IsConvergent = 0;
+
+  // Argument element types — drives overload expansion.
+  // One overload set is generated per type (scalar + vectors + matrices).
+  // Only used when Args contains Varying entries.
+  list<HLSLType> VaryingTypes = [];
+
+  // Whether to generate scalar overloads for Varying typed arguments.
+  bit VaryingScalar = 0;
+
+  // Vector sizes to generate for Varying typed arguments (e.g., [2,3,4]).
+  list<int> VaryingVecSizes = [];
+
+  // Matrix dimensions to generate for Varying typed arguments.
+  list<MatDim> VaryingMatDims = [];
+
+  // Default shader model availability version for all types.
+  // Use NoSM for no availability requirement.
+  ShaderModel Availability = NoSM;
+}
+
+//===----------------------------------------------------------------------===//
+// HLSLBuiltin helper subclasses
+//===----------------------------------------------------------------------===//
+
+// T func(T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLOneArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLTwoArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLThreeArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying, Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// Detail function base: generates inline function bodies calling
+// __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS.
+class HLSLDetail<string name, string detail> : HLSLBuiltin<name> {
+  let DetailFunc = detail;
+}
+
+// T func(T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLOneArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLTwoArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLThreeArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying, Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// Inline body variant: T func(T) with a literal inline body (no builtin alias).
+// Body must be specified (e.g., let Body = "return p0;").
+class HLSLOneArgInlineBuiltin<string name> : HLSLBuiltin<name> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+//===----------------------------------------------------------------------===//
+// Intrinsic definitions (sorted alphabetically by function name)
+//===----------------------------------------------------------------------===//
+
+// Returns the absolute value of the input value, Val.
+def hlsl_abs : HLSLOneArgBuiltin<"abs", "__builtin_elementwise_abs"> {
+  let Doc = [{
+\fn T abs(T Val)
+\brief Returns the absolute value of the input value, \a Val.
+\param Val The input value.
+}];
+  let VaryingTypes = SignedTypes;
+  let VaryingMatDims = [];
+}
+
+// Unsigned abs is a constexpr identity — unsigned values are already non-negative.
+def hlsl_abs_unsigned : HLSLOneArgInlineBuiltin<"abs"> {
+  let ParamNames = ["V"];
+  let Body = "return V;";
+  let IsConstexpr = 1;
+  let VaryingTypes = UnsignedIntTypes;
+  let VaryingMatDims = [];
+}
+
+// Returns the boolean AND of two bool values or vectors.
+def hlsl_and : HLSLTwoArgBuiltin<"and", "__builtin_hlsl_and"> {
+  let Doc = [{
+\fn bool and(bool x, bool y)
+\brief Logically ands two boolean vectors or matrices elementwise and
+produces a bool vector or matrix output.
+}];
+  let VaryingTypes = [BoolTy];
+}
+
+// Returns the cross product of two floating-point, 3D vectors.
+// Two separate defs are needed because the float and half variants alias
+// different builtins (__builtin_hlsl_crossf32 vs __builtin_hlsl_crossf16).
+def hlsl_cross_float : HLSLBuiltin<"cross", "__builtin_hlsl_crossf32"> {
+  let Doc = [{
+\fn T cross(T x, T y)
+\brief Returns the cross product of two floating-point, 3D vectors.
+\param x [in] The first floating-point, 3D vector.
+\param y [in] The second floating-point, 3D vector.
+
+Result is the cross product of x and y, i.e., the resulting
+components are, in order :
+x[1] * y[2] - y[1] * x[2]
+x[2] * y[0] - y[2] * x[0]
+x[0] * y[1] - y[0] * x[1]
+}];
+  let Args = [VectorType<FloatTy, 3>, VectorType<FloatTy, 3>];
+  let ReturnType = VectorType<FloatTy, 3>;
+}
+
+def hlsl_cross_half : HLSLBuiltin<"cross", "__builtin_hlsl_crossf16"> {
+  let Args = [VectorType<HalfTy, 3>, VectorType<HalfTy, 3>];
+  let ReturnType = VectorType<HalfTy, 3>;
+  // Do not specify Availability = SM6_2 here because HalfTy is a 32-bit float
+  // and is therefore available before SM6_2 if 16-bit types is not enabled.
+  // Because HalfTy IsConditionally16Bit, the emitter will automatically specify
+  // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) with this overload.
+}
+
+// Returns the dot product (a scalar value) of X and Y.
+def hlsl_dot : HLSLTwoArgBuiltin<"dot", "__builtin_hlsl_dot"> {
+  let Doc = [{
+\fn K dot(T X, T Y)
+\brief Return the dot product (a scalar value) of \a X and \a Y.
+\param X The X input value.
+\param Y The Y input value.
+}];
+  let ReturnType = VaryingElemType;
+  let VaryingTypes = NumericTypesNoDbl;
+  let VaryingMatDims = [];
+}
+
+// double dot only has scalar overload (no vectors).
+def hlsl_dot_double : HLSLBuiltin<"dot", "__builtin_hlsl_dot"> {
+  let Args = [Varying, Varying];
+  let ReturnType = VaryingElemType;
+  let VaryingTypes = [DoubleTy];
+  let VaryingScalar = 1;
+}
+
+// Dot product of 2 half vectors plus a float scalar.
+def hlsl_dot2add : HLSLBuiltin<"dot2add"> {
+  let Doc = [{
+\fn float dot2add(half2 A, half2 B, float C)
+\brief Dot product of 2 vector of type half and add a float scalar value.
+\param A The first input value to dot product.
+\param B The second input value to dot product.
+\param C The input value added to the dot product.
+}];
+  let DetailFunc = "dot2add_impl";
+  let Args = [VectorType<HalfTy, 2>, VectorType<HalfTy, 2>, FloatTy];
+  let ReturnType = FloatTy;
+  let ParamNames = ["A", "B", "C"];
+  let Availability = SM6_4;
+}
+
+// Blocks execution of all threads in a group until all group shared accesses
+// have been completed and all threads in the group have reached this call.
+def hlsl_group_memory_barrier_with_group_sync :
+    HLSLBuiltin<"GroupMemoryBarrierWithGroupSync",
+                "__builtin_hlsl_group_memory_barrier_with_group_sync"> {
+  let Doc = [{
+\fn void GroupMemoryBarrierWithGroupSync(void)
+\brief Blocks execution of all threads in a group until all group shared
+accesses have been completed and all threads in the group have reached this
+call.
+}];
+  let IsConvergent = 1;
+}
+
+// Determines if the specified value x is infinite.
+def hlsl_isinf : HLSLOneArgBuiltin<"isinf", "__builtin_hlsl_elementwise_isinf"> {
+  let Doc = [{
+\fn T isinf(T x)
+\brief Determines if the specified value \a x is infinite.
+\param x The specified input value.
+
+Returns a value of the same size as the input, with a value set
+to True if the x parameter is +INF or -INF. Otherwise, False.
+}];
+  let ReturnType = VaryingShape<BoolTy>;
+  let VaryingTypes = [HalfTy, FloatTy];
+  let VaryingMatDims = [];
+}
+
+// Returns a refraction vector using an entering ray, a surface normal, and
+// a refraction index.
+def hlsl_refract : HLSLBuiltin<"refract"> {
+  let Doc = [{
+\fn T refract(T I, T N, T eta)
+\brief Returns a refraction using an entering ray, \a I, a surface
+normal, \a N and refraction index \a eta
+\param I The entering ray.
+\param N The surface normal.
+\param eta The refraction index.
+
+The return value is a floating-point vector that represents the refraction
+using the refraction index, \a eta, for the direction of the entering ray,
+\a I, off a surface with the normal \a N.
+
+This function calculates the refraction vector using the following formulas:
+k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+if k < 0.0 the result is 0.0
+otherwise, the result is eta * I - (eta * dot(N, I) + sqrt(k)) * N
+
+I and N must already be normalized in order to achieve the desired result.
+
+I and N must be a scalar or vector whose component type is
+floating-point.
+
+eta must be a 16-bit or 32-bit floating-point scalar.
+
+Result type, the type of I, and the type of N must all be the same type.
+}];
+  let DetailFunc = "refract_impl";
+  let Args = [Varying, Varying, VaryingElemType];
+  let ReturnType = Varying;
+  let VaryingTypes = [HalfTy, FloatTy];
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = [];
+  let ParamNames = ["I", "N", "eta"];
+}
+
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index c6c299bb61af3..702eca4d4690f 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -504,6 +504,16 @@ if(RISCV IN_LIST LLVM_TARGETS_TO_BUILD)
     )
 endif()
 
+# Generate HLSL intrinsic overloads
+if(CLANG_ENABLE_HLSL)
+  clang_generate_header(-gen-hlsl-alias-intrinsics HLSLIntrinsics.td
+                        hlsl/hlsl_alias_intrinsics_gen.inc)
+  clang_generate_header(-gen-hlsl-inline-intrinsics HLSLIntrinsics.td
+                        hlsl/hlsl_inline_intrinsics_gen.inc)
+  set(hlsl_generated_files
+    "${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_alias_intrinsics_gen.inc"
+    "${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_inline_intrinsics_gen.inc")
+endif()
 
 # Check if the generated headers are included in a target specific lists
 # Currently, all generated headers are target specific.
@@ -511,7 +521,8 @@ set(all_target_specific_generated_files
   ${arm_common_generated_files}
   ${arm_only_generated_files}
   ${aarch64_only_generated_files}
-  ${riscv_generated_files})
+  ${riscv_generated_files}
+  ${hlsl_generated_files})
 foreach( f ${generated_files} )
   if (NOT ${f} IN_LIST all_target_specific_generated_files)
     message(WARNING "${f} is a generated header but it is not included in any "
@@ -579,7 +590,7 @@ add_header_target("x86-resource-headers" "${x86_files}")
 add_header_target("gpu-resource-headers" "${gpu_files}")
 
 # Other header groupings
-add_header_target("h...
[truncated]

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 19, 2026

@llvm/pr-subscribers-hlsl

Author: Deric C. (Icohedron)

Changes

This PR introduces a TableGen-based code generation system for HLSL intrinsic overloads as described in proposal [0043], replacing hand-written boilerplate with declarative .td definitions. A representative set of 8 intrinsics (abs, and, cross, dot, dot2add, GroupMemoryBarrierWithGroupSync, isinf, refract) are migrated to demonstrate all the current features of the TableGen infrastructure. The remaining intrinsics stay manually defined for follow-up PRs to rewrite into TableGen.

Why the 8 representative intrinsics where chosen:

  • abs has two sets of overloads split between aliasing the clang builtin __builtin_elementwise_abs and inline identity functions on unsigned integer types. It also operates on 16-bit types and the half type to demonstrate the automatic inclusion of #ifdef __HLSL_ENABLE_16_BIT guards and _HLSL_AVAILABILITY(shadermodel, 6.2) for 16-bit integer types, and _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) for half types.

  • and demonstrates creating overloads with matrix types, and demonstrates the ability to restrict the Varying type to only booleans.

  • cross aliases two different clang builtins (__builtin_hlsl_crossf32 and __builtin_hlsl_crossf16) and demonstrates the use of fixed vector-type arguments.

  • dot has overloads for all vector types except for double-typed vectors, so the double-typed variant is split into its own scalar-only overload. It also demonstrates the use of VaryingElemType to always return the element type for the current overload.

  • dot2add demonstrates the use of DetailFunc to create an inline function that calls __detail::dot2add_impl(A, B, C). It also demonstrates the use of fixed-type arguments and return type (both scalar and vector), and the use of the Availability field to set the minimum shader model requirement.

  • GroupMemoryBarrierWithGroupSync demonstrates creating an overload with void return type and no arguments, as well as being a wave function that needs to be annotated with __attribute__((convergent)) by setting the IsConvergent field to 1.

  • isinf demonstrates the use of VaryingShape&lt;T&gt; to specify a return type that is of the same shape as the Varying type for the current overload but with a fixed element type (BoolTy in this case).

  • The defining of refract in TableGen instead of templates introduces some significant changes to error messages and also introduces a new offload test suite failure in the fp16 test because a call to refract(x, y, 0.5) where x and y are half-typed vectors is ambiguous due to 0.5 being a 32-bit float literal.

The generated hlsl_alias_intrinsic_gen.inc and hlsl_inline_intrinsic_gen.inc files for this PR can be viewed with this GitHub gist: https://gist.github.com/Icohedron/5ca4e1cc7e811ae72b091472478e9222
They can also be found in the build folder after building Clang, under the paths lib/clang/23/include/hlsl/hlsl_alias_intrinsics_gen.inc and lib/clang/23/include/hlsl/hlsl_inline_intrinsics_gen.inc.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)


Patch is 71.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/187610.diff

11 Files Affected:

  • (added) clang/include/clang/Basic/HLSLIntrinsics.td (+480)
  • (modified) clang/lib/Headers/CMakeLists.txt (+13-2)
  • (modified) clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h (+2-309)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+3-74)
  • (modified) clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl (+6-6)
  • (modified) clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl (+2-2)
  • (modified) clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl (+25-33)
  • (modified) clang/utils/TableGen/CMakeLists.txt (+1)
  • (added) clang/utils/TableGen/HLSLEmitter.cpp (+585)
  • (modified) clang/utils/TableGen/TableGen.cpp (+14)
  • (modified) clang/utils/TableGen/TableGenBackends.h (+5)
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
new file mode 100644
index 0000000000000..4676d9b3b611e
--- /dev/null
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -0,0 +1,480 @@
+//===--- HLSLIntrinsics.td - HLSL intrinsic declarations ---*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines HLSL intrinsic functions in tablegen. The HLSLEmitter
+// backend processes these definitions and generates two .inc files:
+//   - hlsl_alias_intrinsics_gen.inc: builtin alias declarations using
+//     _HLSL_BUILTIN_ALIAS, included by hlsl_alias_intrinsics.h.
+//   - hlsl_inline_intrinsics_gen.inc: inline function definitions (detail
+//     helper calls and literal bodies), included by hlsl_intrinsics.h.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Argument and return type base classes
+//===----------------------------------------------------------------------===//
+
+// Base class for argument and return type positions.
+class HLSLArgType;
+
+// Base class for return type positions.
+class HLSLReturnType;
+
+// Void return type.
+def VoidTy : HLSLReturnType;
+
+//===----------------------------------------------------------------------===//
+// HLSL element types
+//===----------------------------------------------------------------------===//
+
+// Represents a concrete HLSL scalar element type.
+// Can be used directly as an argument or return type for a fixed scalar
+// (e.g., FloatTy in Args produces a 'float' argument).
+class HLSLType<string name> : HLSLArgType, HLSLReturnType {
+  string Name = name;
+  string TypeName = name;
+
+  // When set, overloads using this type are guarded by
+  // #ifdef __HLSL_ENABLE_16_BIT and emitted with
+  // _HLSL_AVAILABILITY(shadermodel, 6.2), or the intrinsic's Availability
+  // if it is greater.
+  bit Is16Bit = 0;
+
+  // When set, overloads using this type are emitted with
+  // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) instead of _HLSL_AVAILABILITY.
+  // This macro expands to an availability attribute only when
+  // __HLSL_ENABLE_16_BIT is defined (i.e. half is a true 16-bit float);
+  // otherwise it expands to nothing since half is an alias for float.
+  // If the intrinsic's Availability is >= SM6.2, _HLSL_AVAILABILITY is used
+  // instead because 16-bit support is already implied.
+  bit IsConditionally16Bit = 0;
+}
+
+def BoolTy   : HLSLType<"bool">;
+def HalfTy   : HLSLType<"half">   { let IsConditionally16Bit = 1; }
+def FloatTy  : HLSLType<"float">;
+def DoubleTy : HLSLType<"double">;
+def Int16Ty  : HLSLType<"int16_t">  { let Is16Bit = 1; }
+def UInt16Ty : HLSLType<"uint16_t"> { let Is16Bit = 1; }
+def IntTy    : HLSLType<"int">;
+def UIntTy   : HLSLType<"uint">;
+def Int64Ty  : HLSLType<"int64_t">;
+def UInt64Ty : HLSLType<"uint64_t">;
+def UInt32Ty : HLSLType<"uint32_t">;
+
+//===----------------------------------------------------------------------===//
+// Element type groups
+//===----------------------------------------------------------------------===//
+
+defvar AllFloatTypes = [HalfTy, FloatTy, DoubleTy];
+defvar SignedIntTypes = [Int16Ty, IntTy, Int64Ty];
+defvar UnsignedIntTypes = [UInt16Ty, UIntTy, UInt64Ty];
+defvar AllIntTypes = [Int16Ty, UInt16Ty, IntTy, UIntTy,
+                      Int64Ty, UInt64Ty];
+defvar SignedTypes = [Int16Ty, HalfTy, IntTy, FloatTy,
+                      Int64Ty, DoubleTy];
+defvar AllNumericTypes = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
+                          FloatTy, Int64Ty, UInt64Ty, DoubleTy];
+defvar AllTypesWithBool = [BoolTy, Int16Ty, UInt16Ty, HalfTy,
+                           IntTy, UIntTy, FloatTy, Int64Ty,
+                           UInt64Ty, DoubleTy];
+defvar NumericTypesNoDbl = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
+                            FloatTy, Int64Ty, UInt64Ty];
+
+//===----------------------------------------------------------------------===//
+// Argument/return types
+//
+// These classes are usable in both argument and return type positions.
+//===----------------------------------------------------------------------===//
+
+// The varying type — expanded per VaryingTypes.
+// As an argument: the arg type varies with each overload.
+// As a return type: returns the same type as the varying arg.
+def Varying : HLSLArgType, HLSLReturnType;
+
+// The scalar element of the varying type.
+// As an argument: always the scalar element type regardless of overload shape.
+// As a return type: returns the scalar element type (e.g., float dot(float3, float3)).
+def VaryingElemType : HLSLArgType, HLSLReturnType;
+
+// The varying shape with a fixed element type.
+// As an argument: same shape as Varying but with the given element type.
+// As a return type: same shape as the varying arg but with the given element type.
+// For example, VaryingShape<UIntTy> with a float3 overload produces uint3.
+class VaryingShape<HLSLType ty> : HLSLArgType, HLSLReturnType {
+  HLSLType ElementType = ty;
+}
+
+// A concrete vector type (e.g., VectorType<UIntTy, 4> -> uint4).
+// As an argument: the arg is always this vector type.
+// As a return type: always returns this vector type, ignoring argument shape.
+class VectorType<HLSLType ty, int size> : HLSLArgType, HLSLReturnType {
+  HLSLType ElementType = ty;
+  int Size = size;
+}
+
+//===----------------------------------------------------------------------===//
+// Shader model versions
+//===----------------------------------------------------------------------===//
+
+// Represents a shader model version
+class ShaderModel<int major, int minor> {
+  int Major = major;
+  int Minor = minor;
+}
+
+// Sentinel: no shader model requirement.
+def NoSM  : ShaderModel<0, 0>;
+
+// Valid Shader Model records
+foreach i = 0...9 in {
+  def SM6_ #i : ShaderModel<6, i>;
+}
+
+//===----------------------------------------------------------------------===//
+// Matrix dimension records
+//===----------------------------------------------------------------------===//
+
+class MatDim<int rows, int cols> {
+  int Rows = rows;
+  int Cols = cols;
+}
+
+foreach r = 1...4 in
+  foreach c = 1...4 in
+    def Mat#r#"x"#c : MatDim<r, c>;
+
+// All non-1x1 matrix dimensions (1x2 through 4x4).
+defvar AllMatDims = [Mat1x2, Mat1x3, Mat1x4,
+                     Mat2x1, Mat2x2, Mat2x3, Mat2x4,
+                     Mat3x1, Mat3x2, Mat3x3, Mat3x4,
+                     Mat4x1, Mat4x2, Mat4x3, Mat4x4];
+
+//===----------------------------------------------------------------------===//
+// HLSLBuiltin class
+//===----------------------------------------------------------------------===//
+
+class HLSLBuiltin<string name, string builtin = ""> {
+  string Name = name;
+
+  // When set, generates a _HLSL_BUILTIN_ALIAS(Builtin) declaration that
+  // aliases the named Clang builtin. Mutually exclusive with DetailFunc
+  // and Body.
+  string Builtin = builtin;
+
+  // Doxygen documentation comment emitted before overloads in generated code.
+  string Doc = "";
+
+  // When set, generates an inline function body calling
+  // __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS(Builtin).
+  // Parameters are named p0, p1, p2, ... by default, or use ParamNames to
+  // specify custom names. Mutually exclusive with Body and Builtin.
+  string DetailFunc = "";
+
+  // When set, generates an inline function with this literal body text.
+  // Intended for single-statement functions. Multi-line functions should
+  // instead be defined as a helper and called with DetailFunc.
+  // Parameters are named p0, p1, p2, ... by default, or use ParamNames to
+  // specify custom names. Mutually exclusive with DetailFunc and Builtin.
+  code Body = "";
+
+  // Determines how the return type is derived for each overload.
+  HLSLReturnType ReturnType = VoidTy;
+
+  // Argument list. Each entry is either:
+  //   Varying     - type varies with VaryingTypes (expanded per type)
+  //   HLSLType    - a fixed scalar type at that position (e.g., UIntTy)
+  //   VectorType  - a fixed vector type at that position
+  // The number of arguments is deduced from the length of this list.
+  // Examples:
+  //   [Varying]                              -> func(T)
+  //   [Varying, Varying, Varying]            -> func(T, T, T)
+  //   [Varying, UInt32Ty]                    -> func(T, uint32_t)
+  //   [UIntTy, UIntTy, IntTy]                -> func(uint, uint, int)
+  //   []                                     -> func()
+  list<HLSLArgType> Args = [];
+
+  // Custom parameter names for generated functions.
+  // When empty, inline functions (Body or DetailFunc) use p0, p1, p2, ...
+  // and alias functions omit parameter names.
+  list<string> ParamNames = [];
+
+  // When set, emits 'constexpr' instead of 'inline' for inline functions
+  // (i.e., functions using Body or DetailFunc).
+  bit IsConstexpr = 0;
+
+  // Whether the function has the convergent attribute
+  bit IsConvergent = 0;
+
+  // Argument element types — drives overload expansion.
+  // One overload set is generated per type (scalar + vectors + matrices).
+  // Only used when Args contains Varying entries.
+  list<HLSLType> VaryingTypes = [];
+
+  // Whether to generate scalar overloads for Varying typed arguments.
+  bit VaryingScalar = 0;
+
+  // Vector sizes to generate for Varying typed arguments (e.g., [2,3,4]).
+  list<int> VaryingVecSizes = [];
+
+  // Matrix dimensions to generate for Varying typed arguments.
+  list<MatDim> VaryingMatDims = [];
+
+  // Default shader model availability version for all types.
+  // Use NoSM for no availability requirement.
+  ShaderModel Availability = NoSM;
+}
+
+//===----------------------------------------------------------------------===//
+// HLSLBuiltin helper subclasses
+//===----------------------------------------------------------------------===//
+
+// T func(T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLOneArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLTwoArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLThreeArgBuiltin<string name, string builtin>
+    : HLSLBuiltin<name, builtin> {
+  let Args = [Varying, Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// Detail function base: generates inline function bodies calling
+// __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS.
+class HLSLDetail<string name, string detail> : HLSLBuiltin<name> {
+  let DetailFunc = detail;
+}
+
+// T func(T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLOneArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLTwoArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
+class HLSLThreeArgDetail<string name, string detail>
+    : HLSLDetail<name, detail> {
+  let Args = [Varying, Varying, Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+// Inline body variant: T func(T) with a literal inline body (no builtin alias).
+// Body must be specified (e.g., let Body = "return p0;").
+class HLSLOneArgInlineBuiltin<string name> : HLSLBuiltin<name> {
+  let Args = [Varying];
+  let ReturnType = Varying;
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = AllMatDims;
+}
+
+//===----------------------------------------------------------------------===//
+// Intrinsic definitions (sorted alphabetically by function name)
+//===----------------------------------------------------------------------===//
+
+// Returns the absolute value of the input value, Val.
+def hlsl_abs : HLSLOneArgBuiltin<"abs", "__builtin_elementwise_abs"> {
+  let Doc = [{
+\fn T abs(T Val)
+\brief Returns the absolute value of the input value, \a Val.
+\param Val The input value.
+}];
+  let VaryingTypes = SignedTypes;
+  let VaryingMatDims = [];
+}
+
+// Unsigned abs is a constexpr identity — unsigned values are already non-negative.
+def hlsl_abs_unsigned : HLSLOneArgInlineBuiltin<"abs"> {
+  let ParamNames = ["V"];
+  let Body = "return V;";
+  let IsConstexpr = 1;
+  let VaryingTypes = UnsignedIntTypes;
+  let VaryingMatDims = [];
+}
+
+// Returns the boolean AND of two bool values or vectors.
+def hlsl_and : HLSLTwoArgBuiltin<"and", "__builtin_hlsl_and"> {
+  let Doc = [{
+\fn bool and(bool x, bool y)
+\brief Logically ands two boolean vectors or matrices elementwise and
+produces a bool vector or matrix output.
+}];
+  let VaryingTypes = [BoolTy];
+}
+
+// Returns the cross product of two floating-point, 3D vectors.
+// Two separate defs are needed because the float and half variants alias
+// different builtins (__builtin_hlsl_crossf32 vs __builtin_hlsl_crossf16).
+def hlsl_cross_float : HLSLBuiltin<"cross", "__builtin_hlsl_crossf32"> {
+  let Doc = [{
+\fn T cross(T x, T y)
+\brief Returns the cross product of two floating-point, 3D vectors.
+\param x [in] The first floating-point, 3D vector.
+\param y [in] The second floating-point, 3D vector.
+
+Result is the cross product of x and y, i.e., the resulting
+components are, in order :
+x[1] * y[2] - y[1] * x[2]
+x[2] * y[0] - y[2] * x[0]
+x[0] * y[1] - y[0] * x[1]
+}];
+  let Args = [VectorType<FloatTy, 3>, VectorType<FloatTy, 3>];
+  let ReturnType = VectorType<FloatTy, 3>;
+}
+
+def hlsl_cross_half : HLSLBuiltin<"cross", "__builtin_hlsl_crossf16"> {
+  let Args = [VectorType<HalfTy, 3>, VectorType<HalfTy, 3>];
+  let ReturnType = VectorType<HalfTy, 3>;
+  // Do not specify Availability = SM6_2 here because HalfTy is a 32-bit float
+  // and is therefore available before SM6_2 if 16-bit types is not enabled.
+  // Because HalfTy IsConditionally16Bit, the emitter will automatically specify
+  // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) with this overload.
+}
+
+// Returns the dot product (a scalar value) of X and Y.
+def hlsl_dot : HLSLTwoArgBuiltin<"dot", "__builtin_hlsl_dot"> {
+  let Doc = [{
+\fn K dot(T X, T Y)
+\brief Return the dot product (a scalar value) of \a X and \a Y.
+\param X The X input value.
+\param Y The Y input value.
+}];
+  let ReturnType = VaryingElemType;
+  let VaryingTypes = NumericTypesNoDbl;
+  let VaryingMatDims = [];
+}
+
+// double dot only has scalar overload (no vectors).
+def hlsl_dot_double : HLSLBuiltin<"dot", "__builtin_hlsl_dot"> {
+  let Args = [Varying, Varying];
+  let ReturnType = VaryingElemType;
+  let VaryingTypes = [DoubleTy];
+  let VaryingScalar = 1;
+}
+
+// Dot product of 2 half vectors plus a float scalar.
+def hlsl_dot2add : HLSLBuiltin<"dot2add"> {
+  let Doc = [{
+\fn float dot2add(half2 A, half2 B, float C)
+\brief Dot product of 2 vector of type half and add a float scalar value.
+\param A The first input value to dot product.
+\param B The second input value to dot product.
+\param C The input value added to the dot product.
+}];
+  let DetailFunc = "dot2add_impl";
+  let Args = [VectorType<HalfTy, 2>, VectorType<HalfTy, 2>, FloatTy];
+  let ReturnType = FloatTy;
+  let ParamNames = ["A", "B", "C"];
+  let Availability = SM6_4;
+}
+
+// Blocks execution of all threads in a group until all group shared accesses
+// have been completed and all threads in the group have reached this call.
+def hlsl_group_memory_barrier_with_group_sync :
+    HLSLBuiltin<"GroupMemoryBarrierWithGroupSync",
+                "__builtin_hlsl_group_memory_barrier_with_group_sync"> {
+  let Doc = [{
+\fn void GroupMemoryBarrierWithGroupSync(void)
+\brief Blocks execution of all threads in a group until all group shared
+accesses have been completed and all threads in the group have reached this
+call.
+}];
+  let IsConvergent = 1;
+}
+
+// Determines if the specified value x is infinite.
+def hlsl_isinf : HLSLOneArgBuiltin<"isinf", "__builtin_hlsl_elementwise_isinf"> {
+  let Doc = [{
+\fn T isinf(T x)
+\brief Determines if the specified value \a x is infinite.
+\param x The specified input value.
+
+Returns a value of the same size as the input, with a value set
+to True if the x parameter is +INF or -INF. Otherwise, False.
+}];
+  let ReturnType = VaryingShape<BoolTy>;
+  let VaryingTypes = [HalfTy, FloatTy];
+  let VaryingMatDims = [];
+}
+
+// Returns a refraction vector using an entering ray, a surface normal, and
+// a refraction index.
+def hlsl_refract : HLSLBuiltin<"refract"> {
+  let Doc = [{
+\fn T refract(T I, T N, T eta)
+\brief Returns a refraction using an entering ray, \a I, a surface
+normal, \a N and refraction index \a eta
+\param I The entering ray.
+\param N The surface normal.
+\param eta The refraction index.
+
+The return value is a floating-point vector that represents the refraction
+using the refraction index, \a eta, for the direction of the entering ray,
+\a I, off a surface with the normal \a N.
+
+This function calculates the refraction vector using the following formulas:
+k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+if k < 0.0 the result is 0.0
+otherwise, the result is eta * I - (eta * dot(N, I) + sqrt(k)) * N
+
+I and N must already be normalized in order to achieve the desired result.
+
+I and N must be a scalar or vector whose component type is
+floating-point.
+
+eta must be a 16-bit or 32-bit floating-point scalar.
+
+Result type, the type of I, and the type of N must all be the same type.
+}];
+  let DetailFunc = "refract_impl";
+  let Args = [Varying, Varying, VaryingElemType];
+  let ReturnType = Varying;
+  let VaryingTypes = [HalfTy, FloatTy];
+  let VaryingScalar = 1;
+  let VaryingVecSizes = [2, 3, 4];
+  let VaryingMatDims = [];
+  let ParamNames = ["I", "N", "eta"];
+}
+
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index c6c299bb61af3..702eca4d4690f 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -504,6 +504,16 @@ if(RISCV IN_LIST LLVM_TARGETS_TO_BUILD)
     )
 endif()
 
+# Generate HLSL intrinsic overloads
+if(CLANG_ENABLE_HLSL)
+  clang_generate_header(-gen-hlsl-alias-intrinsics HLSLIntrinsics.td
+                        hlsl/hlsl_alias_intrinsics_gen.inc)
+  clang_generate_header(-gen-hlsl-inline-intrinsics HLSLIntrinsics.td
+                        hlsl/hlsl_inline_intrinsics_gen.inc)
+  set(hlsl_generated_files
+    "${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_alias_intrinsics_gen.inc"
+    "${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_inline_intrinsics_gen.inc")
+endif()
 
 # Check if the generated headers are included in a target specific lists
 # Currently, all generated headers are target specific.
@@ -511,7 +521,8 @@ set(all_target_specific_generated_files
   ${arm_common_generated_files}
   ${arm_only_generated_files}
   ${aarch64_only_generated_files}
-  ${riscv_generated_files})
+  ${riscv_generated_files}
+  ${hlsl_generated_files})
 foreach( f ${generated_files} )
   if (NOT ${f} IN_LIST all_target_specific_generated_files)
     message(WARNING "${f} is a generated header but it is not included in any "
@@ -579,7 +590,7 @@ add_header_target("x86-resource-headers" "${x86_files}")
 add_header_target("gpu-resource-headers" "${gpu_files}")
 
 # Other header groupings
-add_header_target("h...
[truncated]

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 19, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
@jurahul
Copy link
Copy Markdown
Contributor

jurahul commented Mar 20, 2026

I am drive-by reviewing, assuming it still needs review by HLSL folks.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 23, 2026

🪟 Windows x64 Test Results

  • 54999 tests passed
  • 2373 tests skipped

✅ The build succeeded and all tests passed.

Copy link
Copy Markdown
Contributor

@inbelic inbelic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM, just some nits to resolve

@farzonl
Copy link
Copy Markdown
Member

farzonl commented Mar 24, 2026

Should we consider redoing clang/lib/Headers/hlsl/hlsl_compat_overloads.h to use tablegen, or do we want the compat overloads to be case by case?

Copy link
Copy Markdown
Member

@farzonl farzonl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Icohedron
Copy link
Copy Markdown
Contributor Author

Icohedron commented Mar 24, 2026

Should we consider redoing clang/lib/Headers/hlsl/hlsl_compat_overloads.h to use tablegen, or do we want the compat overloads to be case by case?

Perhaps, but with the current HLSL intrinsic TableGen framework it is not possible to express those compat overloads in TableGen.
The current preprocessor-defined overloads seems to be straight-forward and organized well enough for now.
Adding capability for generating the compat overloads with TableGen can be done in a follow-up PR if desired.

@Icohedron Icohedron merged commit daec3b9 into llvm:main Mar 24, 2026
11 checks passed
@farzonl
Copy link
Copy Markdown
Member

farzonl commented Mar 25, 2026

This pr looks to have caused an issue with check-flang can you take a look #187440 (comment)

@cianciosa
Copy link
Copy Markdown

I'm getting a build error using the make generator at least when performing parallel builds.

% make -j10
...
[ 12%] Building hlsl/hlsl_alias_intrinsics_gen.inc...
../../../../bin/clang-tblgen: error opening /Users/m4c/Projects/graph_framework/build/_deps/llvm-build/tools/clang/lib/Headers/hlsl/hlsl_alias_intrinsics_gen.inc: No such file or directory
make[2]: *** [_deps/llvm-build/tools/clang/lib/Headers/hlsl/hlsl_alias_intrinsics_gen.inc] Error 1
make[1]: *** [_deps/llvm-build/tools/clang/lib/Headers/CMakeFiles/hlsl-resource-headers.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
[ 12%] Building arm_sme.h...
[ 12%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/Types.cpp.o
[ 12%] Linking CXX shared module ../DoublerPlugin.dylib
[ 12%] Building Attrs.inc...
[ 14%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/Utils.cpp.o
[ 14%] Building arm_sve.h...
[ 14%] Built target ClangAttrClasses
[ 14%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/VarLenCodeEmitterGen.cpp.o
[ 14%] Built target DoublerPlugin
[ 14%] Building arm_vector_types.h...
[ 14%] Built target aarch64-resource-headers
[ 14%] Built target obj.LLVMTableGenCommon
make: *** [all] Error 2

I'm checking a serial build now.

Note: I'm building this as dependency of different project using FetchContent.

@Icohedron
Copy link
Copy Markdown
Contributor Author

Icohedron commented Mar 25, 2026

I'm getting a build error using the make generator at least when performing parallel builds.

% make -j10
...
[ 12%] Building hlsl/hlsl_alias_intrinsics_gen.inc...
../../../../bin/clang-tblgen: error opening /Users/m4c/Projects/graph_framework/build/_deps/llvm-build/tools/clang/lib/Headers/hlsl/hlsl_alias_intrinsics_gen.inc: No such file or directory
make[2]: *** [_deps/llvm-build/tools/clang/lib/Headers/hlsl/hlsl_alias_intrinsics_gen.inc] Error 1
make[1]: *** [_deps/llvm-build/tools/clang/lib/Headers/CMakeFiles/hlsl-resource-headers.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
[ 12%] Building arm_sme.h...
[ 12%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/Types.cpp.o
[ 12%] Linking CXX shared module ../DoublerPlugin.dylib
[ 12%] Building Attrs.inc...
[ 14%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/Utils.cpp.o
[ 14%] Building arm_sve.h...
[ 14%] Built target ClangAttrClasses
[ 14%] Building CXX object _deps/llvm-build/utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/VarLenCodeEmitterGen.cpp.o
[ 14%] Built target DoublerPlugin
[ 14%] Building arm_vector_types.h...
[ 14%] Built target aarch64-resource-headers
[ 14%] Built target obj.LLVMTableGenCommon
make: *** [all] Error 2

I'm checking a serial build now.

Note: I'm building this as dependency of different project using FetchContent.

I will put up a PR to attempt to fix this. Seems the hlsl folder isn't always created and that causes clang_generate_header to fail when trying to generate a header into it.

@vzakhari
Copy link
Copy Markdown
Contributor

Right, the issue does not reproduce with Ninja generator, only with Unix Makefiles.

@Icohedron
Copy link
Copy Markdown
Contributor Author

@cianciosa let me know if PR #188618 fixes the issue for you

Icohedron added a commit that referenced this pull request Mar 25, 2026
This PR should fix an issue reported by
#187440 (comment)
and
#187610 (comment)
where using `clang_generate_header` to generate a header into a
directory that did not exist caused an error.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Mar 25, 2026
…(#188618)

This PR should fix an issue reported by
llvm/llvm-project#187440 (comment)
and
llvm/llvm-project#187610 (comment)
where using `clang_generate_header` to generate a header into a
directory that did not exist caused an error.
ambergorzynski pushed a commit to ambergorzynski/llvm-project that referenced this pull request Mar 27, 2026
This PR introduces a TableGen-based code generation system for HLSL
intrinsic overloads as described in proposal
[[0043]](https://github.com/llvm/wg-hlsl/blob/main/proposals/0043-hlsl-intrinsic-tablegen.md)
for replacing hand-written boilerplate with declarative .td definitions.

Actual changes to `hlsl_intrinsics.h` and `hlsl_alias_intrinsics.h` to
replace handwritten HLSL intrinsic overloads with TableGen is left to
follow-up PRs.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
ambergorzynski pushed a commit to ambergorzynski/llvm-project that referenced this pull request Mar 27, 2026
This PR should fix an issue reported by
llvm#187440 (comment)
and
llvm#187610 (comment)
where using `clang_generate_header` to generate a header into a
directory that did not exist caused an error.
Aadarsh-Keshri pushed a commit to Aadarsh-Keshri/llvm-project that referenced this pull request Mar 28, 2026
This PR introduces a TableGen-based code generation system for HLSL
intrinsic overloads as described in proposal
[[0043]](https://github.com/llvm/wg-hlsl/blob/main/proposals/0043-hlsl-intrinsic-tablegen.md)
for replacing hand-written boilerplate with declarative .td definitions.

Actual changes to `hlsl_intrinsics.h` and `hlsl_alias_intrinsics.h` to
replace handwritten HLSL intrinsic overloads with TableGen is left to
follow-up PRs.

Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
Aadarsh-Keshri pushed a commit to Aadarsh-Keshri/llvm-project that referenced this pull request Mar 28, 2026
This PR should fix an issue reported by
llvm#187440 (comment)
and
llvm#187610 (comment)
where using `clang_generate_header` to generate a header into a
directory that did not exist caused an error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a TableGen to C header generator for all HLSL intrinsics

7 participants