[clang] [HLSL] Implement TableGen for builtin HLSL intrinsics (PR #187610)
Deric C. via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 19 18:57:47 PDT 2026
https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/187610
>From 6d71771e9220af9b9c1f80b772352745f6634e99 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 15:16:17 -0700
Subject: [PATCH 01/12] Implement TableGen for builtin HLSL intrinsics
Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
---
clang/include/clang/Basic/HLSLIntrinsics.td | 480 ++++++++++++++
clang/lib/Headers/CMakeLists.txt | 15 +-
.../lib/Headers/hlsl/hlsl_alias_intrinsics.h | 311 +---------
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 77 +--
.../test/SemaHLSL/BuiltIns/cross-errors.hlsl | 12 +-
.../SemaHLSL/BuiltIns/dot2add-errors.hlsl | 4 +-
.../SemaHLSL/BuiltIns/refract-errors.hlsl | 58 +-
clang/utils/TableGen/CMakeLists.txt | 1 +
clang/utils/TableGen/HLSLEmitter.cpp | 585 ++++++++++++++++++
clang/utils/TableGen/TableGen.cpp | 14 +
clang/utils/TableGen/TableGenBackends.h | 5 +
11 files changed, 1136 insertions(+), 426 deletions(-)
create mode 100644 clang/include/clang/Basic/HLSLIntrinsics.td
create mode 100644 clang/utils/TableGen/HLSLEmitter.cpp
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("hlsl-resource-headers" ${hlsl_files})
+add_header_target("hlsl-resource-headers" "${hlsl_files};${hlsl_generated_files}")
add_header_target("spirv-resource-headers" ${spirv_files})
add_header_target("opencl-resource-headers" ${opencl_files})
add_header_target("llvm-libc-resource-headers" ${llvm_libc_wrapper_files})
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index c2e4d74af6873..35a95a17768f7 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -38,96 +38,8 @@ namespace hlsl {
#define _HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
#endif
-//===----------------------------------------------------------------------===//
-// abs builtins
-//===----------------------------------------------------------------------===//
-
-/// \fn T abs(T Val)
-/// \brief Returns the absolute value of the input value, \a Val.
-/// \param Val The input value.
-
-#ifdef __HLSL_ENABLE_16_BIT
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int16_t abs(int16_t);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int16_t2 abs(int16_t2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int16_t3 abs(int16_t3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int16_t4 abs(int16_t4);
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-constexpr uint16_t abs(uint16_t V) { return V; }
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-constexpr uint16_t2 abs(uint16_t2 V) { return V; }
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-constexpr uint16_t3 abs(uint16_t3 V) { return V; }
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-constexpr uint16_t4 abs(uint16_t4 V) { return V; }
-#endif
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-half abs(half);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-half2 abs(half2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-half3 abs(half3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-half4 abs(half4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int abs(int);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int2 abs(int2);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int3 abs(int3);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int4 abs(int4);
-
-constexpr uint abs(uint V) { return V; }
-constexpr uint2 abs(uint2 V) { return V; }
-constexpr uint3 abs(uint3 V) { return V; }
-constexpr uint4 abs(uint4 V) { return V; }
-
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-float abs(float);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-float2 abs(float2);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-float3 abs(float3);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-float4 abs(float4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int64_t abs(int64_t);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int64_t2 abs(int64_t2);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int64_t3 abs(int64_t3);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-int64_t4 abs(int64_t4);
-
-constexpr uint64_t abs(uint64_t V) { return V; }
-constexpr uint64_t2 abs(uint64_t2 V) { return V; }
-constexpr uint64_t3 abs(uint64_t3 V) { return V; }
-constexpr uint64_t4 abs(uint64_t4 V) { return V; }
-
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-double abs(double);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-double2 abs(double2);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-double3 abs(double3);
-_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
-double4 abs(double4);
+// Generated by clang-tblgen from HLSLIntrinsics.td (alias intrinsics).
+#include "hlsl_alias_intrinsics_gen.inc"
//===----------------------------------------------------------------------===//
// acos builtins
@@ -292,60 +204,6 @@ bool all(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_all)
bool all(double4);
-//===----------------------------------------------------------------------===//
-// and builtins
-//===----------------------------------------------------------------------===//
-
-/// \fn bool and(bool x, bool y)
-/// \brief Logically ands two boolean vectors or matrices elementwise and
-/// produces a bool vector or matrix output.
-
-// TODO: Clean up clang-format marker once we've resolved
-// https://github.com/llvm/llvm-project/issues/127851
-//
-// clang-format off
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool and(bool x, bool y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2 and(bool2 x, bool2 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3 and(bool3 x, bool3 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4 and(bool4 x, bool4 y);
-
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool1x2 and(bool1x2 x, bool1x2 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool1x3 and(bool1x3 x, bool1x3 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool1x4 and(bool1x4 x, bool1x4 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2x1 and(bool2x1 x, bool2x1 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2x2 and(bool2x2 x, bool2x2 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2x3 and(bool2x3 x, bool2x3 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool2x4 and(bool2x4 x, bool2x4 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3x1 and(bool3x1 x, bool3x1 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3x2 and(bool3x2 x, bool3x2 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3x3 and(bool3x3 x, bool3x3 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool3x4 and(bool3x4 x, bool3x4 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4x1 and(bool4x1 x, bool4x1 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4x2 and(bool4x2 x, bool4x2 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4x3 and(bool4x3 x, bool4x3 y);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
-bool4x4 and(bool4x4 x, bool4x4 y);
-// clang-format on
-
//===----------------------------------------------------------------------===//
// any builtins
//===----------------------------------------------------------------------===//
@@ -909,104 +767,6 @@ float3 degrees(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float4 degrees(float4);
-//===----------------------------------------------------------------------===//
-// dot product builtins
-//===----------------------------------------------------------------------===//
-
-/// \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.
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-half dot(half, half);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-half dot(half2, half2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-half dot(half3, half3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-half dot(half4, half4);
-
-#ifdef __HLSL_ENABLE_16_BIT
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int16_t dot(int16_t, int16_t);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int16_t dot(int16_t2, int16_t2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int16_t dot(int16_t3, int16_t3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int16_t dot(int16_t4, int16_t4);
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint16_t dot(uint16_t, uint16_t);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint16_t dot(uint16_t2, uint16_t2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint16_t dot(uint16_t3, uint16_t3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint16_t dot(uint16_t4, uint16_t4);
-#endif
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-float dot(float, float);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-float dot(float2, float2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-float dot(float3, float3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-float dot(float4, float4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-double dot(double, double);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int dot(int, int);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int dot(int2, int2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int dot(int3, int3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int dot(int4, int4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint dot(uint, uint);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint dot(uint2, uint2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint dot(uint3, uint3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint dot(uint4, uint4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int64_t dot(int64_t, int64_t);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int64_t dot(int64_t2, int64_t2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int64_t dot(int64_t3, int64_t3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-int64_t dot(int64_t4, int64_t4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint64_t dot(uint64_t, uint64_t);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint64_t dot(uint64_t2, uint64_t2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint64_t dot(uint64_t3, uint64_t3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
-uint64_t dot(uint64_t4, uint64_t4);
-
//===----------------------------------------------------------------------===//
// dot4add builtins
//===----------------------------------------------------------------------===//
@@ -1264,39 +1024,6 @@ float3 frac(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frac)
float4 frac(float4);
-//===----------------------------------------------------------------------===//
-// isinf builtins
-//===----------------------------------------------------------------------===//
-
-/// \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.
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool isinf(half);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool2 isinf(half2);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool3 isinf(half3);
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool4 isinf(half4);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool isinf(float);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool2 isinf(float2);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool3 isinf(float3);
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
-bool4 isinf(float4);
-
//===----------------------------------------------------------------------===//
// isnan builtins
//===----------------------------------------------------------------------===//
@@ -2016,28 +1743,6 @@ uint64_t3 reversebits(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse)
uint64_t4 reversebits(uint64_t4);
-//===----------------------------------------------------------------------===//
-// cross builtins
-//===----------------------------------------------------------------------===//
-
-/// \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]
-
-_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_crossf16)
-half3 cross(half3, half3);
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_crossf32)
-float3 cross(float3, float3);
-
//===----------------------------------------------------------------------===//
// rcp builtins
//===----------------------------------------------------------------------===//
@@ -3736,18 +3441,6 @@ float3 radians(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_radians)
float4 radians(float4);
-//===----------------------------------------------------------------------===//
-// GroupMemoryBarrierWithGroupSync builtins
-//===----------------------------------------------------------------------===//
-
-/// \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.
-
-_HLSL_BUILTIN_ALIAS(__builtin_hlsl_group_memory_barrier_with_group_sync)
-__attribute__((convergent)) void GroupMemoryBarrierWithGroupSync(void);
-
//===----------------------------------------------------------------------===//
// ddx_coarse builtin
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 25d36f5483943..95d77eed41853 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -13,6 +13,9 @@
namespace hlsl {
+// Generated by clang-tblgen from HLSLIntrinsics.td (detail/inline intrinsics).
+#include "hlsl_inline_intrinsics_gen.inc"
+
//===----------------------------------------------------------------------===//
// asfloat builtins
//===----------------------------------------------------------------------===//
@@ -175,21 +178,6 @@ const inline float distance(__detail::HLSL_FIXED_VECTOR<float, N> X,
return __detail::distance_vec_impl(X, Y);
}
-//===----------------------------------------------------------------------===//
-// dot2add builtins
-//===----------------------------------------------------------------------===//
-
-/// \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.
-
-_HLSL_AVAILABILITY(shadermodel, 6.4)
-const inline float dot2add(half2 A, half2 B, float C) {
- return __detail::dot2add_impl(A, B, C);
-}
-
//===----------------------------------------------------------------------===//
// dst builtins
//===----------------------------------------------------------------------===//
@@ -560,65 +548,6 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
return __detail::reflect_vec_impl(I, N);
}
-//===----------------------------------------------------------------------===//
-// refract builtin
-//===----------------------------------------------------------------------===//
-
-/// \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.
-
-template <typename T>
-_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
-const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
- __detail::is_same<half, T>::value,
- T> refract(T I, T N, T eta) {
- return __detail::refract_impl(I, N, eta);
-}
-
-template <typename T>
-const inline __detail::enable_if_t<
- __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
-refract(T I, T N, T eta) {
- return __detail::refract_impl(I, N, eta);
-}
-
-template <int L>
-_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
-const inline __detail::HLSL_FIXED_VECTOR<half, L> refract(
- __detail::HLSL_FIXED_VECTOR<half, L> I,
- __detail::HLSL_FIXED_VECTOR<half, L> N, half eta) {
- return __detail::refract_impl(I, N, eta);
-}
-
-template <int L>
-const inline __detail::HLSL_FIXED_VECTOR<float, L>
-refract(__detail::HLSL_FIXED_VECTOR<float, L> I,
- __detail::HLSL_FIXED_VECTOR<float, L> N, float eta) {
- return __detail::refract_impl(I, N, eta);
-}
-
//===----------------------------------------------------------------------===//
// smoothstep builtin
//===----------------------------------------------------------------------===//
diff --git a/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
index 2c3e8d1560c87..c9bd1bdd3cb8e 100644
--- a/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
@@ -4,8 +4,8 @@ void test_too_few_arg()
{
return cross();
// expected-error at -1 {{no matching function for call to 'cross'}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
}
void test_too_few_arg_f32()
@@ -24,8 +24,8 @@ void test_too_many_arg(float3 p0)
{
return cross(p0, p0, p0);
// expected-error at -1 {{no matching function for call to 'cross'}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
}
void test_too_many_arg_f32(float3 p0)
@@ -56,6 +56,6 @@ void test_ambiguous(int p0)
{
return cross(p0,p0);
// expected-error at -1 {{call to 'cross' is ambiguous}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function}}
- // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function}}
+ // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function}}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
index 84333ba08b9b8..e576f73669002 100644
--- a/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
@@ -3,11 +3,11 @@
float test_too_few_arg() {
return dot2add();
// expected-error at -1 {{no matching function for call to 'dot2add'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* {{candidate function not viable: requires 3 arguments, but 0 were provided}}
}
float test_too_many_arg(half2 p1, half2 p2, float p3) {
return dot2add(p1, p2, p3, p1);
// expected-error at -1 {{no matching function for call to 'dot2add'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
index fce41a4a46d38..8d9949f52aeb0 100644
--- a/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
@@ -3,64 +3,56 @@
float test_no_second_arg(float3 p0) {
return refract(p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 1 was provided}}
}
float test_no_third_arg(float3 p0) {
return refract(p0, p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 2 were provided}}
}
float test_too_many_arg(float2 p0) {
return refract(p0, p0, p0, p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 4 were provided}}
}
float test_double_inputs(double p0, double p1, double p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-error at -1 {{call to 'refract' is ambiguous}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 2 {{candidate function}}
}
float test_int_inputs(int p0, int p1, int p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-error at -1 {{call to 'refract' is ambiguous}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 2 {{candidate function}}
}
float1 test_vec1_inputs(float1 p0, float1 p1, float1 p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+ // expected-warning at -1 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
+ // expected-warning at -2 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
+ // expected-warning at -3 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
}
typedef float float5 __attribute__((ext_vector_type(5)));
-float5 test_vec5_inputs(float5 p0, float5 p1, float p2) {
+float5 test_vec5_inputs(float5 p0, float5 p1, float p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
- // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
+ // expected-error at -1 {{call to 'refract' is ambiguous}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 4 {{candidate function}}
+}
+
+half3 test_half_inputs_with_float(half3 p0, half3 p1, float p3) {
+ return refract(p0, p1, p3);
+ // expected-error at -1 {{call to 'refract' is ambiguous}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 6 {{candidate function}}
+}
+
+half3 test_half_inputs_with_float_literal(half3 p0, half3 p1) {
+ return refract(p0, p1, 0.5);
+ // expected-error at -1 {{call to 'refract' is ambiguous}}
+ // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 6 {{candidate function}}
}
diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt
index 14f13824e9575..8b5e00c189cb9 100644
--- a/clang/utils/TableGen/CMakeLists.txt
+++ b/clang/utils/TableGen/CMakeLists.txt
@@ -21,6 +21,7 @@ add_tablegen(clang-tblgen CLANG
ClangSACheckersEmitter.cpp
ClangSyntaxEmitter.cpp
ClangTypeNodesEmitter.cpp
+ HLSLEmitter.cpp
MveEmitter.cpp
NeonEmitter.cpp
RISCVVEmitter.cpp
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
new file mode 100644
index 0000000000000..6505f0402a709
--- /dev/null
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -0,0 +1,585 @@
+//===--- HLSLEmitter.cpp - HLSL intrinsic header generator ----------------===//
+//
+// 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 tablegen backend generates hlsl_alias_intrinsics_gen.inc (alias
+// overloads) and hlsl_inline_intrinsics_gen.inc (inline/detail overloads) for
+// HLSL intrinsic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
+
+using namespace llvm;
+
+namespace {
+
+/// Minimum shader model version that supports 16-bit types.
+constexpr StringLiteral SM6_2 = "6.2";
+
+//===----------------------------------------------------------------------===//
+// Type name helpers
+//===----------------------------------------------------------------------===//
+
+static std::string getVectorTypeName(StringRef ElemType, unsigned N) {
+ return (ElemType + Twine(N)).str();
+}
+
+static std::string getMatrixTypeName(StringRef ElemType, unsigned Rows,
+ unsigned Cols) {
+ return (ElemType + Twine(Rows) + "x" + Twine(Cols)).str();
+}
+
+/// Get the fixed type name string for a VectorType or HLSLType record.
+static std::string getFixedTypeName(const Record *R) {
+ if (R->isSubClassOf("VectorType"))
+ return getVectorTypeName(
+ R->getValueAsDef("ElementType")->getValueAsString("Name"),
+ R->getValueAsInt("Size"));
+ assert(R->isSubClassOf("HLSLType"));
+ return R->getValueAsString("Name").str();
+}
+
+/// For a VectorType, return its ElementType record; for an HLSLType, return
+/// the record itself (it is already a scalar element type).
+static const Record *getElementTypeRecord(const Record *R) {
+ if (R->isSubClassOf("VectorType"))
+ return R->getValueAsDef("ElementType");
+ assert(R->isSubClassOf("HLSLType"));
+ return R;
+}
+
+//===----------------------------------------------------------------------===//
+// Type information
+//===----------------------------------------------------------------------===//
+
+/// Classifies how a type varies across overloads.
+enum TypeKindEnum {
+ TK_Varying = 0, ///< Type matches the full varying type (e.g. float3).
+ TK_ElemType = 1, ///< Type is the scalar element type (e.g. float).
+ TK_VaryingShape = 2, ///< Type uses the varying shape with a fixed element.
+ TK_FixedType = 3, ///< Type is a fixed concrete type (e.g. "half2").
+ TK_Void = 4 ///< Type is void (only valid for return types).
+};
+
+/// Metadata describing how a type (argument or return) varies across overloads.
+struct TypeInfo {
+ /// Classification of how this type varies across overloads.
+ TypeKindEnum Kind = TK_Varying;
+
+ /// Fixed type name (e.g. "half2") for types with a concrete type that does
+ /// not vary across overloads. Empty for varying types.
+ std::string FixedType;
+
+ /// Element type name for TK_VaryingShape types (e.g. "bool" for
+ /// VaryingShape<BoolTy>). Empty for other type kinds.
+ StringRef ShapeElemType;
+
+ /// Explicit parameter name (e.g. "eta"). Empty to use the default "p0",
+ /// "p1", ... naming. Only meaningful for argument types.
+ StringRef Name;
+
+ /// Construct a TypeInfo from a TableGen record.
+ static TypeInfo resolve(const Record *Rec) {
+ TypeInfo TI;
+ if (Rec->getName() == "VoidTy") {
+ TI.Kind = TK_Void;
+ } else if (Rec->getName() == "Varying") {
+ TI.Kind = TK_Varying;
+ } else if (Rec->getName() == "VaryingElemType") {
+ TI.Kind = TK_ElemType;
+ } else if (Rec->isSubClassOf("VaryingShape")) {
+ TI.Kind = TK_VaryingShape;
+ TI.ShapeElemType =
+ Rec->getValueAsDef("ElementType")->getValueAsString("Name");
+ } else if (Rec->isSubClassOf("VectorType") ||
+ Rec->isSubClassOf("HLSLType")) {
+ TI.Kind = TK_FixedType;
+ TI.FixedType = getFixedTypeName(Rec);
+ } else {
+ llvm_unreachable("unhandled record for type resolution");
+ }
+ return TI;
+ }
+
+ /// Resolve this type to a concrete type name string.
+ /// \p ElemType is the scalar element type for the current overload.
+ /// \p FormatVarying formats a scalar element type into the shaped type name.
+ std::string
+ toTypeString(StringRef ElemType,
+ function_ref<std::string(StringRef)> FormatVarying) const {
+ switch (Kind) {
+ case TK_Void:
+ return "void";
+ case TK_Varying:
+ return FormatVarying(ElemType);
+ case TK_ElemType:
+ return ElemType.str();
+ case TK_VaryingShape:
+ return FormatVarying(ShapeElemType);
+ case TK_FixedType:
+ assert(!FixedType.empty() && "TK_FixedType requires non-empty FixedType");
+ return FixedType;
+ }
+ llvm_unreachable("unhandled TypeKindEnum");
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Availability helpers
+//===----------------------------------------------------------------------===//
+
+static void emitAvailability(raw_ostream &OS, StringRef Version,
+ bool Use16Bit = false) {
+ if (Use16Bit) {
+ OS << "_HLSL_16BIT_AVAILABILITY(shadermodel, " << Version << ")\n";
+ } else {
+ OS << "_HLSL_AVAILABILITY(shadermodel, " << Version << ")\n";
+ }
+}
+static std::string getVersionString(const Record *SM) {
+ unsigned Major = SM->getValueAsInt("Major");
+ unsigned Minor = SM->getValueAsInt("Minor");
+ if (Major == 0 && Minor == 0)
+ return "";
+ return (Twine(Major) + "." + Twine(Minor)).str();
+}
+
+//===----------------------------------------------------------------------===//
+// Type work item — describes one element type to emit overloads for
+//===----------------------------------------------------------------------===//
+
+/// A single entry in the worklist of types to process for an intrinsic.
+struct TypeWorkItem {
+ /// Element type name (e.g. "half", "float"). Empty for fixed-arg-only
+ /// intrinsics with no type expansion.
+ StringRef ElemType;
+
+ /// Version string for the availability attribute (e.g. "6.2"). Empty if
+ /// no availability annotation is needed.
+ StringRef Availability;
+
+ /// If true, emit _HLSL_16BIT_AVAILABILITY instead of _HLSL_AVAILABILITY.
+ bool Use16BitAvail = false;
+
+ /// If true, wrap overloads in #ifdef __HLSL_ENABLE_16_BIT / #endif.
+ bool NeedsIfdefGuard = false;
+};
+
+/// Fixed canonical ordering for overload types. Types are grouped as:
+/// 0: conditionally-16-bit (half)
+/// 1-2: 16-bit integers (int16_t, uint16_t) — ifdef-guarded
+/// 3+: regular types (bool, int, uint, int64_t, uint64_t, float, double)
+/// Within each group, signed precedes unsigned, smaller precedes larger,
+/// and integer types precede floating-point types.
+static int getTypeSortPriority(const Record *ET) {
+ return StringSwitch<int>(ET->getValueAsString("Name"))
+ .Case("half", 0)
+ .Case("int16_t", 1)
+ .Case("uint16_t", 2)
+ .Case("bool", 3)
+ .Case("int", 4)
+ .Case("uint", 5)
+ .Case("uint32_t", 6)
+ .Case("int64_t", 7)
+ .Case("uint64_t", 8)
+ .Case("float", 9)
+ .Case("double", 10)
+ .Default(11);
+}
+
+//===----------------------------------------------------------------------===//
+// Overload context — shared state across all overloads of one intrinsic
+//===----------------------------------------------------------------------===//
+
+/// Shared state for emitting all overloads of a single HLSL intrinsic.
+struct OverloadContext {
+ /// Output stream to write generated code to.
+ raw_ostream &OS;
+
+ /// Builtin name for _HLSL_BUILTIN_ALIAS (e.g. "__builtin_hlsl_dot").
+ /// Empty for inline/detail intrinsics.
+ StringRef Builtin;
+
+ /// __detail helper function to call (e.g. "refract_impl").
+ /// Empty for alias and inline-body intrinsics.
+ StringRef DetailFunc;
+
+ /// Literal inline function body (e.g. "return p0;").
+ /// Empty for alias and detail intrinsics.
+ StringRef Body;
+
+ /// The HLSL function name to emit (e.g. "dot", "refract").
+ StringRef FuncName;
+
+ /// Metadata describing the return type and its variation behavior.
+ TypeInfo RetType;
+
+ /// Per-argument metadata describing type and variation behavior.
+ SmallVector<TypeInfo, 4> Args;
+
+ /// Whether to emit the function as constexpr.
+ bool IsConstexpr = false;
+
+ /// Whether to emit the __attribute__((convergent)) annotation.
+ bool IsConvergent = false;
+
+ /// Whether any fixed arg has a 16-bit integer type (e.g. int16_t).
+ bool Uses16BitType = false;
+
+ /// Whether any fixed arg has a conditionally-16-bit type (half).
+ bool UsesConditionally16BitType = false;
+
+ explicit OverloadContext(raw_ostream &OS) : OS(OS) {}
+};
+
+/// Emit a complete function declaration or definition with pre-resolved types.
+static void emitDeclaration(const OverloadContext &Ctx, StringRef RetType,
+ ArrayRef<std::string> ArgTypes) {
+ raw_ostream &OS = Ctx.OS;
+ bool IsDetail = !Ctx.DetailFunc.empty();
+ bool IsInline = !Ctx.Body.empty();
+ bool HasBody = IsDetail || IsInline;
+
+ bool EmitNames = HasBody || llvm::any_of(Ctx.Args, [](const TypeInfo &A) {
+ return !A.Name.empty();
+ });
+
+ auto GetParamName = [&](unsigned I) -> std::string {
+ if (!Ctx.Args[I].Name.empty())
+ return Ctx.Args[I].Name.str();
+ return ("p" + Twine(I)).str();
+ };
+
+ if (!HasBody)
+ OS << "_HLSL_BUILTIN_ALIAS(" << Ctx.Builtin << ")\n";
+ if (Ctx.IsConvergent)
+ OS << "__attribute__((convergent)) ";
+ if (HasBody)
+ OS << (Ctx.IsConstexpr ? "constexpr " : "inline ");
+ OS << RetType << " " << Ctx.FuncName << "(";
+
+ for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
+ if (I > 0)
+ OS << ", ";
+ OS << ArgTypes[I];
+ if (EmitNames)
+ OS << " " << GetParamName(I);
+ }
+
+ if (IsDetail) {
+ OS << ") {\n return __detail::" << Ctx.DetailFunc << "(";
+ for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
+ if (I > 0)
+ OS << ", ";
+ OS << GetParamName(I);
+ }
+ OS << ");\n}\n";
+ } else if (IsInline) {
+ OS << ") { " << Ctx.Body << " }\n";
+ } else {
+ OS << ");\n";
+ }
+}
+
+/// Emit a single overload declaration by resolving all types through
+/// \p FormatVarying, which maps element types to their shaped form.
+static void emitOverload(const OverloadContext &Ctx, StringRef ElemType,
+ function_ref<std::string(StringRef)> FormatVarying) {
+ std::string RetType = Ctx.RetType.toTypeString(ElemType, FormatVarying);
+ SmallVector<std::string> ArgTypes;
+ for (const TypeInfo &TI : Ctx.Args)
+ ArgTypes.push_back(TI.toTypeString(ElemType, FormatVarying));
+ emitDeclaration(Ctx, RetType, ArgTypes);
+}
+
+/// Emit a scalar overload for the given element type.
+static void emitScalarOverload(const OverloadContext &Ctx, StringRef ElemType) {
+ emitOverload(Ctx, ElemType, [](StringRef ET) { return ET.str(); });
+}
+
+/// Emit a vector overload for the given element type and vector size.
+static void emitVectorOverload(const OverloadContext &Ctx, StringRef ElemType,
+ unsigned VecSize) {
+ emitOverload(Ctx, ElemType, [VecSize](StringRef ET) {
+ return getVectorTypeName(ET, VecSize);
+ });
+}
+
+/// Emit a matrix overload for the given element type and matrix dimensions.
+static void emitMatrixOverload(const OverloadContext &Ctx, StringRef ElemType,
+ unsigned Rows, unsigned Cols) {
+ emitOverload(Ctx, ElemType, [Rows, Cols](StringRef ET) {
+ return getMatrixTypeName(ET, Rows, Cols);
+ });
+}
+
+//===----------------------------------------------------------------------===//
+// Main emission logic
+//===----------------------------------------------------------------------===//
+
+/// Build an OverloadContext from an HLSLBuiltin record.
+static void buildOverloadContext(const Record *R, OverloadContext &Ctx) {
+ Ctx.Builtin = R->getValueAsString("Builtin");
+ Ctx.DetailFunc = R->getValueAsString("DetailFunc");
+ Ctx.Body = R->getValueAsString("Body");
+ Ctx.FuncName = R->getValueAsString("Name");
+ Ctx.IsConstexpr = R->getValueAsBit("IsConstexpr");
+ Ctx.IsConvergent = R->getValueAsBit("IsConvergent");
+
+ // Note use of 16-bit fixed types in the overload context.
+ auto Update16BitFlags = [&Ctx](const Record *Rec) {
+ const Record *ElemTy = getElementTypeRecord(Rec);
+ Ctx.Uses16BitType |= ElemTy->getValueAsBit("Is16Bit");
+ Ctx.UsesConditionally16BitType |=
+ ElemTy->getValueAsBit("IsConditionally16Bit");
+ };
+
+ // Resolve return and argument types.
+ const Record *RetRec = R->getValueAsDef("ReturnType");
+ Ctx.RetType = TypeInfo::resolve(RetRec);
+ if (Ctx.RetType.Kind == TK_FixedType)
+ Update16BitFlags(RetRec);
+
+ std::vector<const Record *> ArgRecords = R->getValueAsListOfDefs("Args");
+ std::vector<StringRef> ParamNames = R->getValueAsListOfStrings("ParamNames");
+
+ for (const auto &[I, Arg] : llvm::enumerate(ArgRecords)) {
+ TypeInfo TI = TypeInfo::resolve(Arg);
+ if (I < ParamNames.size())
+ TI.Name = ParamNames[I];
+ if (TI.Kind == TK_FixedType)
+ Update16BitFlags(Arg);
+ Ctx.Args.push_back(TI);
+ }
+}
+
+/// Build the worklist of element types to emit overloads for, sorted in
+/// canonical order (see getTypeSortPriority).
+static void buildWorklist(const Record *R, SmallVectorImpl<TypeWorkItem> &Worklist,
+ const OverloadContext &Ctx) {
+ const Record *AvailRec = R->getValueAsDef("Availability");
+ std::string Availability = getVersionString(AvailRec);
+ bool AvailabilityIsAtLeastSM6_2 = AvailRec->getValueAsInt("Major") > 6 ||
+ (AvailRec->getValueAsInt("Major") == 6 &&
+ AvailRec->getValueAsInt("Minor") >= 2);
+
+ std::vector<const Record *> VaryingTypeRecords =
+ R->getValueAsListOfDefs("VaryingTypes");
+
+ // Populate the availability and guard fields of a TypeWorkItem based on
+ // whether the type is 16-bit, conditionally 16-bit, or a regular type.
+ auto SetAvailability = [&](TypeWorkItem &Item, bool Is16Bit,
+ bool IsCond16Bit) {
+ Item.NeedsIfdefGuard = Is16Bit;
+ if (Is16Bit || IsCond16Bit) {
+ if (AvailabilityIsAtLeastSM6_2) {
+ Item.Availability = Availability;
+ } else {
+ Item.Availability = SM6_2;
+ Item.Use16BitAvail = IsCond16Bit;
+
+ // Note: If Availability = x where x < 6.2 and a half type is used,
+ // neither _HLSL_AVAILABILITY(shadermodel, x) nor
+ // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) are correct:
+ //
+ // _HLSL_AVAILABILITY(shadermodel, x) will set the availbility for the
+ // half overload to x even when 16-bit types are enabled, but x < 6.2
+ // and 6.2 is required for 16-bit half.
+ //
+ // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) will set the
+ // availability for the half overload to 6.2 when 16-bit types are
+ // enabled, but there will be no availability set when 16-bit types
+ // are not enabled.
+ //
+ // A possible solution to this is to make _HLSL_16BIT_AVAILABILITY
+ // accept 3 args: (shadermodel, X, Y) where X is the availability for
+ // the 16-bit half type overload (which will typically be 6.2), and Y is
+ // the availability for the non-16-bit half overload. However, this
+ // sitation does not currently arise, so we just assert below that this
+ // case will never occur.
+ assert(
+ !(IsCond16Bit && !Availability.empty()) &&
+ "Can not handle availability for an intrinsic using half types and"
+ " which has an explicit shader model requirement older than 6.2");
+ }
+ } else {
+ Item.Availability = Availability;
+ }
+ };
+
+ // If no Varying types are specified, just add a single work item.
+ // This is for HLSLBuiltin records that don't use Varying types.
+ if (VaryingTypeRecords.empty()) {
+ TypeWorkItem Item;
+ SetAvailability(Item, Ctx.Uses16BitType, Ctx.UsesConditionally16BitType);
+ Worklist.push_back(Item);
+ return;
+ }
+
+ // Sort Varying types so that overloads are always emitted in canonical order.
+ llvm::sort(VaryingTypeRecords, [](const Record *A, const Record *B) {
+ return getTypeSortPriority(A) < getTypeSortPriority(B);
+ });
+
+ // Add a work item for each Varying element type.
+ for (size_t I = 0, N = VaryingTypeRecords.size(); I < N; ++I) {
+ const Record *ElemTy = VaryingTypeRecords[I];
+
+ TypeWorkItem Item;
+ Item.ElemType = ElemTy->getValueAsString("Name");
+ bool Is16Bit = Ctx.Uses16BitType || ElemTy->getValueAsBit("Is16Bit");
+ bool IsCond16Bit = Ctx.UsesConditionally16BitType ||
+ ElemTy->getValueAsBit("IsConditionally16Bit");
+ SetAvailability(Item, Is16Bit, IsCond16Bit);
+
+ Worklist.push_back(Item);
+ }
+}
+
+/// Emit a Doxygen documentation comment from the Doc field.
+void emitDocComment(raw_ostream &OS, const Record *R) {
+ StringRef Doc = R->getValueAsString("Doc");
+ if (Doc.empty())
+ return;
+ Doc = Doc.trim();
+ SmallVector<StringRef> DocLines;
+ Doc.split(DocLines, '\n');
+ for (StringRef Line : DocLines) {
+ if (Line.empty())
+ OS << "///\n";
+ else
+ OS << "/// " << Line << "\n";
+ }
+}
+
+/// Process the worklist: emit all shape variants for each type with
+/// availability annotations and #ifdef guards.
+static void emitWorklistOverloads(raw_ostream &OS, const OverloadContext &Ctx,
+ ArrayRef<TypeWorkItem> Worklist,
+ bool EmitScalarOverload,
+ ArrayRef<int64_t> VectorSizes,
+ ArrayRef<const Record *> MatrixDimensions) {
+ bool InIfdef = false;
+ for (const TypeWorkItem &Item : Worklist) {
+ if (Item.NeedsIfdefGuard && !InIfdef) {
+ OS << "#ifdef __HLSL_ENABLE_16_BIT\n";
+ InIfdef = true;
+ }
+
+ auto EmitAvail = [&]() {
+ if (!Item.Availability.empty())
+ emitAvailability(OS, Item.Availability, Item.Use16BitAvail);
+ };
+
+ if (EmitScalarOverload) {
+ EmitAvail();
+ emitScalarOverload(Ctx, Item.ElemType);
+ }
+ for (int64_t N : VectorSizes) {
+ EmitAvail();
+ emitVectorOverload(Ctx, Item.ElemType, N);
+ }
+ for (const Record *MD : MatrixDimensions) {
+ EmitAvail();
+ emitMatrixOverload(Ctx, Item.ElemType, MD->getValueAsInt("Rows"),
+ MD->getValueAsInt("Cols"));
+ }
+
+ if (InIfdef) {
+ bool NextIsUnguarded =
+ (&Item == &Worklist.back()) || !(&Item + 1)->NeedsIfdefGuard;
+ if (NextIsUnguarded) {
+ OS << "#endif\n";
+ InIfdef = false;
+ }
+ }
+
+ OS << "\n";
+ }
+}
+
+/// Emit all overloads for a single HLSLBuiltin record.
+static void emitBuiltinOverloads(raw_ostream &OS, const Record *R) {
+ OverloadContext Ctx(OS);
+ buildOverloadContext(R, Ctx);
+
+ SmallVector<TypeWorkItem> Worklist;
+ buildWorklist(R, Worklist, Ctx);
+
+ emitDocComment(OS, R);
+ OS << "// " << Ctx.FuncName << " overloads\n";
+
+ // Emit a scalar overload if a scalar Varying overload was requested.
+ // If no Varying types are used at all, emit a scalar overload to handle
+ // emitting a single overload for fixed-typed args or arg-less functions.
+ bool EmitScalarOverload = R->getValueAsBit("VaryingScalar") ||
+ R->getValueAsListOfDefs("VaryingTypes").empty();
+
+ std::vector<int64_t> VectorSizes = R->getValueAsListOfInts("VaryingVecSizes");
+ std::vector<const Record *> MatrixDimensions =
+ R->getValueAsListOfDefs("VaryingMatDims");
+
+ // Sort vector sizes and matrix dimensions for consistent output order.
+ llvm::sort(VectorSizes);
+ llvm::sort(MatrixDimensions, [](const Record *A, const Record *B) {
+ int RowA = A->getValueAsInt("Rows"), RowB = B->getValueAsInt("Rows");
+ if (RowA != RowB)
+ return RowA < RowB;
+ return A->getValueAsInt("Cols") < B->getValueAsInt("Cols");
+ });
+
+ emitWorklistOverloads(OS, Ctx, Worklist, EmitScalarOverload, VectorSizes,
+ MatrixDimensions);
+}
+/// Emit alias overloads for a single HLSLBuiltin record.
+/// Skips records that have inline bodies (DetailFunc or Body).
+static void emitAliasBuiltin(raw_ostream &OS, const Record *R) {
+ if (!R->getValueAsString("DetailFunc").empty() ||
+ !R->getValueAsString("Body").empty())
+ return;
+ emitBuiltinOverloads(OS, R);
+}
+
+/// Emit inline overloads for a single HLSLBuiltin record.
+/// Skips records that are pure alias declarations.
+static void emitInlineBuiltin(raw_ostream &OS, const Record *R) {
+ if (R->getValueAsString("DetailFunc").empty() &&
+ R->getValueAsString("Body").empty())
+ return;
+ emitBuiltinOverloads(OS, R);
+}
+
+} // anonymous namespace
+
+namespace clang {
+
+void EmitHLSLAliasIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
+ OS << "// This file is auto-generated by clang-tblgen from "
+ "HLSLIntrinsics.td.\n";
+ OS << "// Do not edit this file directly.\n\n";
+
+ for (const Record *R : Records.getAllDerivedDefinitions("HLSLBuiltin"))
+ emitAliasBuiltin(OS, R);
+}
+
+void EmitHLSLInlineIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
+ OS << "// This file is auto-generated by clang-tblgen from "
+ "HLSLIntrinsics.td.\n";
+ OS << "// Do not edit this file directly.\n\n";
+
+ for (const Record *R : Records.getAllDerivedDefinitions("HLSLBuiltin"))
+ emitInlineBuiltin(OS, R);
+}
+
+} // namespace clang
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index bd8573dcb940f..0ce9d8306ae16 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -118,6 +118,8 @@ enum ActionType {
GenRISCVAndesVectorBuiltins,
GenRISCVAndesVectorBuiltinCG,
GenRISCVAndesVectorBuiltinSema,
+ GenHLSLAliasIntrinsics,
+ GenHLSLInlineIntrinsics,
GenAttrDocs,
GenBuiltinDocs,
GenDiagDocs,
@@ -346,6 +348,12 @@ cl::opt<ActionType> Action(
clEnumValN(GenRISCVAndesVectorBuiltinSema,
"gen-riscv-andes-vector-builtin-sema",
"Generate riscv_andes_vector_builtin_sema.inc for clang"),
+ clEnumValN(GenHLSLAliasIntrinsics, "gen-hlsl-alias-intrinsics",
+ "Generate HLSL alias intrinsic overloads for "
+ "hlsl_alias_intrinsics.h"),
+ clEnumValN(GenHLSLInlineIntrinsics, "gen-hlsl-inline-intrinsics",
+ "Generate HLSL inline intrinsic overloads for "
+ "hlsl_intrinsics.h"),
clEnumValN(GenAttrDocs, "gen-attr-docs",
"Generate attribute documentation"),
clEnumValN(GenBuiltinDocs, "gen-builtin-docs",
@@ -654,6 +662,12 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case GenRISCVAndesVectorBuiltinSema:
EmitRVVBuiltinSema(Records, OS);
break;
+ case GenHLSLAliasIntrinsics:
+ EmitHLSLAliasIntrinsics(Records, OS);
+ break;
+ case GenHLSLInlineIntrinsics:
+ EmitHLSLInlineIntrinsics(Records, OS);
+ break;
case GenAttrDocs:
EmitClangAttrDocs(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index 98dc9f4611917..f9bd7ccf9d0d8 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -191,6 +191,11 @@ void EmitCdeBuiltinCG(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitCdeBuiltinAliases(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
+void EmitHLSLAliasIntrinsics(const llvm::RecordKeeper &Records,
+ llvm::raw_ostream &OS);
+void EmitHLSLInlineIntrinsics(const llvm::RecordKeeper &Records,
+ llvm::raw_ostream &OS);
+
void EmitClangAttrDocs(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangDiagDocs(const llvm::RecordKeeper &Records,
>From d55f823a21e0cfe01607da20749068170dc14ebf Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 16:47:52 -0700
Subject: [PATCH 02/12] Apply clang-format
---
clang/utils/TableGen/HLSLEmitter.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index 6505f0402a709..6c15ca96f67c2 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -366,8 +366,9 @@ static void buildOverloadContext(const Record *R, OverloadContext &Ctx) {
/// Build the worklist of element types to emit overloads for, sorted in
/// canonical order (see getTypeSortPriority).
-static void buildWorklist(const Record *R, SmallVectorImpl<TypeWorkItem> &Worklist,
- const OverloadContext &Ctx) {
+static void buildWorklist(const Record *R,
+ SmallVectorImpl<TypeWorkItem> &Worklist,
+ const OverloadContext &Ctx) {
const Record *AvailRec = R->getValueAsDef("Availability");
std::string Availability = getVersionString(AvailRec);
bool AvailabilityIsAtLeastSM6_2 = AvailRec->getValueAsInt("Major") > 6 ||
@@ -466,10 +467,10 @@ void emitDocComment(raw_ostream &OS, const Record *R) {
/// Process the worklist: emit all shape variants for each type with
/// availability annotations and #ifdef guards.
static void emitWorklistOverloads(raw_ostream &OS, const OverloadContext &Ctx,
- ArrayRef<TypeWorkItem> Worklist,
- bool EmitScalarOverload,
- ArrayRef<int64_t> VectorSizes,
- ArrayRef<const Record *> MatrixDimensions) {
+ ArrayRef<TypeWorkItem> Worklist,
+ bool EmitScalarOverload,
+ ArrayRef<int64_t> VectorSizes,
+ ArrayRef<const Record *> MatrixDimensions) {
bool InIfdef = false;
for (const TypeWorkItem &Item : Worklist) {
if (Item.NeedsIfdefGuard && !InIfdef) {
>From 1845ec0837ec15b25da868632d1015e50a5f72d8 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 17:31:20 -0700
Subject: [PATCH 03/12] Add TableGen tests
Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
---
clang/test/TableGen/hlsl-intrinsics.td | 386 +++++++++++++++++++++++++
1 file changed, 386 insertions(+)
create mode 100644 clang/test/TableGen/hlsl-intrinsics.td
diff --git a/clang/test/TableGen/hlsl-intrinsics.td b/clang/test/TableGen/hlsl-intrinsics.td
new file mode 100644
index 0000000000000..d3b4615419669
--- /dev/null
+++ b/clang/test/TableGen/hlsl-intrinsics.td
@@ -0,0 +1,386 @@
+// RUN: clang-tblgen -gen-hlsl-alias-intrinsics -I%p/../../include %s | FileCheck %s --check-prefix=ALIAS
+// RUN: clang-tblgen -gen-hlsl-inline-intrinsics -I%p/../../include %s | FileCheck %s --check-prefix=INLINE
+
+// Tests for the HLSL intrinsic TableGen backend (HLSLEmitter). Each test def
+// exercises a specific feature. Def names are numbered (test_NN_) to control
+// TableGen's alphabetical emission order so that CHECK lines read top-to-bottom.
+
+include "clang/Basic/HLSLIntrinsics.td"
+
+//===----------------------------------------------------------------------===//
+// Basic alias builtin: scalar + vector overloads, no availability.
+// Exercises: Varying arg/return, VaryingScalar, VaryingVecSizes, builtin
+// alias emission, multiple regular types.
+//===----------------------------------------------------------------------===//
+
+def test_01_basic_alias : HLSLBuiltin<"myfunc", "__builtin_myfunc"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [2, 3];
+ let VaryingTypes = [IntTy, FloatTy];
+}
+
+// ALIAS-LABEL: // myfunc overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: int myfunc(int);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: int2 myfunc(int2);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: int3 myfunc(int3);
+// ALIAS: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: float myfunc(float);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: float2 myfunc(float2);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_myfunc)
+// ALIAS-NEXT: float3 myfunc(float3);
+
+//===----------------------------------------------------------------------===//
+// VaryingElemType return: return type is scalar even for vector args.
+// Exercises: VaryingElemType as ReturnType, two Varying args.
+//===----------------------------------------------------------------------===//
+
+def test_02_elem_return : HLSLBuiltin<"dotlike", "__builtin_dotlike"> {
+ let Args = [Varying, Varying];
+ let ReturnType = VaryingElemType;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [3];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // dotlike overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_dotlike)
+// ALIAS-NEXT: float dotlike(float, float);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_dotlike)
+// ALIAS-NEXT: float dotlike(float3, float3);
+
+//===----------------------------------------------------------------------===//
+// VaryingShape return: return shape matches arg shape but with a different
+// element type.
+// Exercises: VaryingShape<BoolTy> as ReturnType.
+//===----------------------------------------------------------------------===//
+
+def test_03_shape_return : HLSLBuiltin<"isspecial", "__builtin_isspecial"> {
+ let Args = [Varying];
+ let ReturnType = VaryingShape<BoolTy>;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [2];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // isspecial overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_isspecial)
+// ALIAS-NEXT: bool isspecial(float);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_isspecial)
+// ALIAS-NEXT: bool2 isspecial(float2);
+
+//===----------------------------------------------------------------------===//
+// Fixed VectorType args and return: no Varying types at all.
+// Exercises: VectorType in Args and ReturnType, single overload.
+//===----------------------------------------------------------------------===//
+
+def test_04_fixed_vector : HLSLBuiltin<"fixedfunc", "__builtin_fixedfunc"> {
+ let Args = [VectorType<FloatTy, 3>, VectorType<FloatTy, 3>];
+ let ReturnType = VectorType<FloatTy, 3>;
+}
+
+// ALIAS-LABEL: // fixedfunc overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_fixedfunc)
+// ALIAS-NEXT: float3 fixedfunc(float3, float3);
+
+//===----------------------------------------------------------------------===//
+// Matrix overloads.
+// Exercises: VaryingMatDims emission with matrix type names.
+//===----------------------------------------------------------------------===//
+
+def test_05_matrix : HLSLBuiltin<"matfunc", "__builtin_matfunc"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingMatDims = [Mat2x3];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // matfunc overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_matfunc)
+// ALIAS-NEXT: float2x3 matfunc(float2x3);
+
+//===----------------------------------------------------------------------===//
+// Half type: conditionally-16-bit availability.
+// Exercises: _HLSL_16BIT_AVAILABILITY for half, no ifdef guard.
+//===----------------------------------------------------------------------===//
+
+def test_06_half : HLSLBuiltin<"halffunc", "__builtin_halffunc"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [HalfTy, FloatTy];
+}
+
+// ALIAS-LABEL: // halffunc overloads
+// ALIAS-NEXT: _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_halffunc)
+// ALIAS-NEXT: half halffunc(half);
+// ALIAS: _HLSL_BUILTIN_ALIAS(__builtin_halffunc)
+// ALIAS-NEXT: float halffunc(float);
+
+//===----------------------------------------------------------------------===//
+// 16-bit integer type: ifdef guard + availability.
+// Exercises: #ifdef __HLSL_ENABLE_16_BIT guard, _HLSL_AVAILABILITY for
+// Is16Bit types, guard closing before non-16-bit types.
+//===----------------------------------------------------------------------===//
+
+def test_07_16bit : HLSLBuiltin<"i16func", "__builtin_i16func"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [Int16Ty, IntTy];
+}
+
+// ALIAS-LABEL: // i16func overloads
+// ALIAS-NEXT: #ifdef __HLSL_ENABLE_16_BIT
+// ALIAS-NEXT: _HLSL_AVAILABILITY(shadermodel, 6.2)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_i16func)
+// ALIAS-NEXT: int16_t i16func(int16_t);
+// ALIAS-NEXT: #endif
+// ALIAS: _HLSL_BUILTIN_ALIAS(__builtin_i16func)
+// ALIAS-NEXT: int i16func(int);
+
+//===----------------------------------------------------------------------===//
+// Explicit availability (>= SM6.2): half and int16_t both use
+// _HLSL_AVAILABILITY with the intrinsic's version instead of the 16-bit
+// specific macros, since SM >= 6.2 already implies 16-bit support.
+// Exercises: Availability field, SM override for conditionally-16-bit and
+// 16-bit integer types.
+//===----------------------------------------------------------------------===//
+
+def test_08_avail_ge62 : HLSLBuiltin<"availfunc", "__builtin_availfunc"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [HalfTy, Int16Ty, IntTy, FloatTy];
+ let Availability = SM6_4;
+}
+
+// ALIAS-LABEL: // availfunc overloads
+// ALIAS-NEXT: _HLSL_AVAILABILITY(shadermodel, 6.4)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availfunc)
+// ALIAS-NEXT: half availfunc(half);
+// ALIAS: #ifdef __HLSL_ENABLE_16_BIT
+// ALIAS-NEXT: _HLSL_AVAILABILITY(shadermodel, 6.4)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availfunc)
+// ALIAS-NEXT: int16_t availfunc(int16_t);
+// ALIAS-NEXT: #endif
+// ALIAS: _HLSL_AVAILABILITY(shadermodel, 6.4)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availfunc)
+// ALIAS-NEXT: int availfunc(int);
+// ALIAS: _HLSL_AVAILABILITY(shadermodel, 6.4)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availfunc)
+// ALIAS-NEXT: float availfunc(float);
+
+//===----------------------------------------------------------------------===//
+// Explicit availability (< SM6.2) with 16-bit integer types: the ifdef guard
+// and _HLSL_AVAILABILITY(shadermodel, 6.2) are used for int16_t regardless of
+// the intrinsic's stated availability, because 16-bit types require SM6.2.
+// Note: half (IsConditionally16Bit) cannot be used here — the emitter asserts
+// because neither _HLSL_AVAILABILITY nor _HLSL_16BIT_AVAILABILITY can correctly
+// express availability for half when the intrinsic's SM < 6.2.
+// Exercises: Availability < SM6.2 with Is16Bit types.
+//===----------------------------------------------------------------------===//
+
+def test_08b_avail_lt62 : HLSLBuiltin<"availlt62", "__builtin_availlt62"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [Int16Ty, IntTy];
+ let Availability = SM6_1;
+}
+
+// ALIAS-LABEL: // availlt62 overloads
+// ALIAS-NEXT: #ifdef __HLSL_ENABLE_16_BIT
+// ALIAS-NEXT: _HLSL_AVAILABILITY(shadermodel, 6.2)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availlt62)
+// ALIAS-NEXT: int16_t availlt62(int16_t);
+// ALIAS-NEXT: #endif
+// ALIAS: _HLSL_AVAILABILITY(shadermodel, 6.1)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_availlt62)
+// ALIAS-NEXT: int availlt62(int);
+
+//===----------------------------------------------------------------------===//
+// Fixed half VectorType arg: conditionally-16-bit flag from fixed arg.
+// Exercises: 16-bit flag propagation through fixed VectorType args.
+//===----------------------------------------------------------------------===//
+
+def test_09_fixed_half_vec : HLSLBuiltin<"fixedhalffunc", "__builtin_fixedhalffunc"> {
+ let Args = [VectorType<HalfTy, 2>, VectorType<HalfTy, 2>, FloatTy];
+ let ReturnType = FloatTy;
+}
+
+// ALIAS-LABEL: // fixedhalffunc overloads
+// ALIAS-NEXT: _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_fixedhalffunc)
+// ALIAS-NEXT: float fixedhalffunc(half2, half2, float);
+
+//===----------------------------------------------------------------------===//
+// No-arg void function with convergent attribute.
+// Exercises: VoidTy return, empty Args, IsConvergent.
+//===----------------------------------------------------------------------===//
+
+def test_10_void_convergent : HLSLBuiltin<"barrier", "__builtin_barrier"> {
+ let IsConvergent = 1;
+}
+
+// ALIAS-LABEL: // barrier overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_barrier)
+// ALIAS-NEXT: __attribute__((convergent)) void barrier();
+
+//===----------------------------------------------------------------------===//
+// Inline body: constexpr function with literal body.
+// Exercises: Body field, IsConstexpr, ParamNames, inline backend only.
+//===----------------------------------------------------------------------===//
+
+def test_11_inline_body : HLSLBuiltin<"inline_only_func"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [UIntTy];
+ let Body = "return V;";
+ let ParamNames = ["V"];
+ let IsConstexpr = 1;
+}
+
+// INLINE-LABEL: // inline_only_func overloads
+// INLINE-NEXT: constexpr uint inline_only_func(uint V) { return V; }
+
+//===----------------------------------------------------------------------===//
+// Detail function: inline function calling __detail::helper.
+// Exercises: DetailFunc, ParamNames, VaryingElemType arg, mixed Varying and
+// non-Varying args in inline backend.
+//===----------------------------------------------------------------------===//
+
+def test_12_detail_func : HLSLBuiltin<"detailfunc"> {
+ let DetailFunc = "detail_impl";
+ let Args = [Varying, Varying, VaryingElemType];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [2];
+ let VaryingTypes = [FloatTy];
+ let ParamNames = ["A", "B", "C"];
+}
+
+// INLINE-LABEL: // detailfunc overloads
+// INLINE-NEXT: inline float detailfunc(float A, float B, float C) {
+// INLINE-NEXT: return __detail::detail_impl(A, B, C);
+// INLINE-NEXT: }
+// INLINE-NEXT: inline float2 detailfunc(float2 A, float2 B, float C) {
+// INLINE-NEXT: return __detail::detail_impl(A, B, C);
+// INLINE-NEXT: }
+
+//===----------------------------------------------------------------------===//
+// Doc comment emission.
+// Exercises: Doc field producing /// lines with blank-line handling.
+//===----------------------------------------------------------------------===//
+
+def test_13_doc : HLSLBuiltin<"docfunc", "__builtin_docfunc"> {
+ let Doc = [{
+\fn void docfunc()
+\brief A documented function.
+}];
+}
+
+// ALIAS: /// \fn void docfunc()
+// ALIAS-NEXT: /// \brief A documented function.
+// ALIAS-NEXT: // docfunc overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_docfunc)
+// ALIAS-NEXT: void docfunc();
+
+//===----------------------------------------------------------------------===//
+// Canonical type sort order: types emitted in priority order regardless of
+// declaration order.
+// Exercises: getTypeSortPriority ordering (half before int before float).
+//===----------------------------------------------------------------------===//
+
+def test_14_sort_order : HLSLBuiltin<"sortedfunc", "__builtin_sortedfunc"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingTypes = [FloatTy, IntTy, HalfTy];
+}
+
+// ALIAS-LABEL: // sortedfunc overloads
+// ALIAS-NEXT: _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_sortedfunc)
+// ALIAS-NEXT: half sortedfunc(half);
+// ALIAS: _HLSL_BUILTIN_ALIAS(__builtin_sortedfunc)
+// ALIAS-NEXT: int sortedfunc(int);
+// ALIAS: _HLSL_BUILTIN_ALIAS(__builtin_sortedfunc)
+// ALIAS-NEXT: float sortedfunc(float);
+
+//===----------------------------------------------------------------------===//
+// Vector and matrix dimension sort order: vector sizes are emitted ascending
+// and matrix dimensions sorted by rows then columns, regardless of declaration
+// order.
+// Exercises: VaryingVecSizes sorting, VaryingMatDims sorting.
+//===----------------------------------------------------------------------===//
+
+def test_15_shape_sort : HLSLBuiltin<"shapesorted", "__builtin_shapesorted"> {
+ let Args = [Varying];
+ let ReturnType = Varying;
+ let VaryingVecSizes = [4, 2, 3];
+ let VaryingMatDims = [Mat3x2, Mat2x1, Mat2x3];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // shapesorted overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float2 shapesorted(float2);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float3 shapesorted(float3);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float4 shapesorted(float4);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float2x1 shapesorted(float2x1);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float2x3 shapesorted(float2x3);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapesorted)
+// ALIAS-NEXT: float3x2 shapesorted(float3x2);
+
+//===----------------------------------------------------------------------===//
+// VaryingElemType as argument: arg is always the scalar element type even when
+// the overload shape is a vector.
+// Exercises: VaryingElemType in Args position.
+//===----------------------------------------------------------------------===//
+
+def test_16_elemtype_arg : HLSLBuiltin<"elemarg", "__builtin_elemarg"> {
+ let Args = [Varying, VaryingElemType];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [3];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // elemarg overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_elemarg)
+// ALIAS-NEXT: float elemarg(float, float);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_elemarg)
+// ALIAS-NEXT: float3 elemarg(float3, float);
+
+//===----------------------------------------------------------------------===//
+// VaryingShape as argument: arg uses the varying shape but with a fixed element
+// type.
+// Exercises: VaryingShape<UIntTy> in Args position.
+//===----------------------------------------------------------------------===//
+
+def test_17_shape_arg : HLSLBuiltin<"shapearg", "__builtin_shapearg"> {
+ let Args = [Varying, VaryingShape<UIntTy>];
+ let ReturnType = Varying;
+ let VaryingScalar = 1;
+ let VaryingVecSizes = [2];
+ let VaryingTypes = [FloatTy];
+}
+
+// ALIAS-LABEL: // shapearg overloads
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapearg)
+// ALIAS-NEXT: float shapearg(float, uint);
+// ALIAS-NEXT: _HLSL_BUILTIN_ALIAS(__builtin_shapearg)
+// ALIAS-NEXT: float2 shapearg(float2, uint2);
+
>From 20d9fe78d43b2dab5c9d11435988d01754206ede Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:18:40 -0700
Subject: [PATCH 04/12] Remove changes to existing HLSL intrinsic headers
---
clang/include/clang/Basic/HLSLIntrinsics.td | 167 +---------
.../lib/Headers/hlsl/hlsl_alias_intrinsics.h | 311 +++++++++++++++++-
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 77 ++++-
.../test/SemaHLSL/BuiltIns/cross-errors.hlsl | 12 +-
.../SemaHLSL/BuiltIns/dot2add-errors.hlsl | 4 +-
.../SemaHLSL/BuiltIns/refract-errors.hlsl | 58 ++--
6 files changed, 428 insertions(+), 201 deletions(-)
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index 4676d9b3b611e..a0517dd8f7e37 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -314,167 +314,8 @@ class HLSLOneArgInlineBuiltin<string name> : HLSLBuiltin<name> {
// 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"];
-}
+// TODO: Convert hand-written overloads from hlsl_intrinsics.h and
+// hlsl_alias_intrinsics.h into TableGen below.
+// Include "hlsl_alias_intrinsics_gen.inc" in hlsl_alias_intrinsics.h
+// Include "hlsl_inline_intrinsics_gen.inc" in hlsl_intrinsics.h
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index 35a95a17768f7..c2e4d74af6873 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -38,8 +38,96 @@ namespace hlsl {
#define _HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
#endif
-// Generated by clang-tblgen from HLSLIntrinsics.td (alias intrinsics).
-#include "hlsl_alias_intrinsics_gen.inc"
+//===----------------------------------------------------------------------===//
+// abs builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T abs(T Val)
+/// \brief Returns the absolute value of the input value, \a Val.
+/// \param Val The input value.
+
+#ifdef __HLSL_ENABLE_16_BIT
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int16_t abs(int16_t);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int16_t2 abs(int16_t2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int16_t3 abs(int16_t3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int16_t4 abs(int16_t4);
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+constexpr uint16_t abs(uint16_t V) { return V; }
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+constexpr uint16_t2 abs(uint16_t2 V) { return V; }
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+constexpr uint16_t3 abs(uint16_t3 V) { return V; }
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+constexpr uint16_t4 abs(uint16_t4 V) { return V; }
+#endif
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+half abs(half);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+half2 abs(half2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+half3 abs(half3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+half4 abs(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int abs(int);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int2 abs(int2);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int3 abs(int3);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int4 abs(int4);
+
+constexpr uint abs(uint V) { return V; }
+constexpr uint2 abs(uint2 V) { return V; }
+constexpr uint3 abs(uint3 V) { return V; }
+constexpr uint4 abs(uint4 V) { return V; }
+
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+float abs(float);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+float2 abs(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+float3 abs(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+float4 abs(float4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int64_t abs(int64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int64_t2 abs(int64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int64_t3 abs(int64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+int64_t4 abs(int64_t4);
+
+constexpr uint64_t abs(uint64_t V) { return V; }
+constexpr uint64_t2 abs(uint64_t2 V) { return V; }
+constexpr uint64_t3 abs(uint64_t3 V) { return V; }
+constexpr uint64_t4 abs(uint64_t4 V) { return V; }
+
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+double abs(double);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+double2 abs(double2);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+double3 abs(double3);
+_HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs)
+double4 abs(double4);
//===----------------------------------------------------------------------===//
// acos builtins
@@ -204,6 +292,60 @@ bool all(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_all)
bool all(double4);
+//===----------------------------------------------------------------------===//
+// and builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn bool and(bool x, bool y)
+/// \brief Logically ands two boolean vectors or matrices elementwise and
+/// produces a bool vector or matrix output.
+
+// TODO: Clean up clang-format marker once we've resolved
+// https://github.com/llvm/llvm-project/issues/127851
+//
+// clang-format off
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool and(bool x, bool y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2 and(bool2 x, bool2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3 and(bool3 x, bool3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4 and(bool4 x, bool4 y);
+
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool1x2 and(bool1x2 x, bool1x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool1x3 and(bool1x3 x, bool1x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool1x4 and(bool1x4 x, bool1x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x1 and(bool2x1 x, bool2x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x2 and(bool2x2 x, bool2x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x3 and(bool2x3 x, bool2x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool2x4 and(bool2x4 x, bool2x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x1 and(bool3x1 x, bool3x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x2 and(bool3x2 x, bool3x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x3 and(bool3x3 x, bool3x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool3x4 and(bool3x4 x, bool3x4 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x1 and(bool4x1 x, bool4x1 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x2 and(bool4x2 x, bool4x2 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x3 and(bool4x3 x, bool4x3 y);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_and)
+bool4x4 and(bool4x4 x, bool4x4 y);
+// clang-format on
+
//===----------------------------------------------------------------------===//
// any builtins
//===----------------------------------------------------------------------===//
@@ -767,6 +909,104 @@ float3 degrees(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float4 degrees(float4);
+//===----------------------------------------------------------------------===//
+// dot product builtins
+//===----------------------------------------------------------------------===//
+
+/// \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.
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+half dot(half, half);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+half dot(half2, half2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+half dot(half3, half3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+half dot(half4, half4);
+
+#ifdef __HLSL_ENABLE_16_BIT
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int16_t dot(int16_t, int16_t);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int16_t dot(int16_t2, int16_t2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int16_t dot(int16_t3, int16_t3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int16_t dot(int16_t4, int16_t4);
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint16_t dot(uint16_t, uint16_t);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint16_t dot(uint16_t2, uint16_t2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint16_t dot(uint16_t3, uint16_t3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint16_t dot(uint16_t4, uint16_t4);
+#endif
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+float dot(float, float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+float dot(float2, float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+float dot(float3, float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+float dot(float4, float4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+double dot(double, double);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int dot(int, int);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int dot(int2, int2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int dot(int3, int3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int dot(int4, int4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint dot(uint, uint);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint dot(uint2, uint2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint dot(uint3, uint3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint dot(uint4, uint4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int64_t dot(int64_t, int64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int64_t dot(int64_t2, int64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int64_t dot(int64_t3, int64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+int64_t dot(int64_t4, int64_t4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint64_t dot(uint64_t, uint64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint64_t dot(uint64_t2, uint64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint64_t dot(uint64_t3, uint64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
+uint64_t dot(uint64_t4, uint64_t4);
+
//===----------------------------------------------------------------------===//
// dot4add builtins
//===----------------------------------------------------------------------===//
@@ -1024,6 +1264,39 @@ float3 frac(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frac)
float4 frac(float4);
+//===----------------------------------------------------------------------===//
+// isinf builtins
+//===----------------------------------------------------------------------===//
+
+/// \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.
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool isinf(half);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool2 isinf(half2);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool3 isinf(half3);
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool4 isinf(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool isinf(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool2 isinf(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool3 isinf(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
+bool4 isinf(float4);
+
//===----------------------------------------------------------------------===//
// isnan builtins
//===----------------------------------------------------------------------===//
@@ -1743,6 +2016,28 @@ uint64_t3 reversebits(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse)
uint64_t4 reversebits(uint64_t4);
+//===----------------------------------------------------------------------===//
+// cross builtins
+//===----------------------------------------------------------------------===//
+
+/// \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]
+
+_HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_crossf16)
+half3 cross(half3, half3);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_crossf32)
+float3 cross(float3, float3);
+
//===----------------------------------------------------------------------===//
// rcp builtins
//===----------------------------------------------------------------------===//
@@ -3441,6 +3736,18 @@ float3 radians(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_radians)
float4 radians(float4);
+//===----------------------------------------------------------------------===//
+// GroupMemoryBarrierWithGroupSync builtins
+//===----------------------------------------------------------------------===//
+
+/// \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.
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_group_memory_barrier_with_group_sync)
+__attribute__((convergent)) void GroupMemoryBarrierWithGroupSync(void);
+
//===----------------------------------------------------------------------===//
// ddx_coarse builtin
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 95d77eed41853..25d36f5483943 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -13,9 +13,6 @@
namespace hlsl {
-// Generated by clang-tblgen from HLSLIntrinsics.td (detail/inline intrinsics).
-#include "hlsl_inline_intrinsics_gen.inc"
-
//===----------------------------------------------------------------------===//
// asfloat builtins
//===----------------------------------------------------------------------===//
@@ -178,6 +175,21 @@ const inline float distance(__detail::HLSL_FIXED_VECTOR<float, N> X,
return __detail::distance_vec_impl(X, Y);
}
+//===----------------------------------------------------------------------===//
+// dot2add builtins
+//===----------------------------------------------------------------------===//
+
+/// \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.
+
+_HLSL_AVAILABILITY(shadermodel, 6.4)
+const inline float dot2add(half2 A, half2 B, float C) {
+ return __detail::dot2add_impl(A, B, C);
+}
+
//===----------------------------------------------------------------------===//
// dst builtins
//===----------------------------------------------------------------------===//
@@ -548,6 +560,65 @@ reflect(__detail::HLSL_FIXED_VECTOR<float, L> I,
return __detail::reflect_vec_impl(I, N);
}
+//===----------------------------------------------------------------------===//
+// refract builtin
+//===----------------------------------------------------------------------===//
+
+/// \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.
+
+template <typename T>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
+ __detail::is_same<half, T>::value,
+ T> refract(T I, T N, T eta) {
+ return __detail::refract_impl(I, N, eta);
+}
+
+template <typename T>
+const inline __detail::enable_if_t<
+ __detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
+refract(T I, T N, T eta) {
+ return __detail::refract_impl(I, N, eta);
+}
+
+template <int L>
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+const inline __detail::HLSL_FIXED_VECTOR<half, L> refract(
+ __detail::HLSL_FIXED_VECTOR<half, L> I,
+ __detail::HLSL_FIXED_VECTOR<half, L> N, half eta) {
+ return __detail::refract_impl(I, N, eta);
+}
+
+template <int L>
+const inline __detail::HLSL_FIXED_VECTOR<float, L>
+refract(__detail::HLSL_FIXED_VECTOR<float, L> I,
+ __detail::HLSL_FIXED_VECTOR<float, L> N, float eta) {
+ return __detail::refract_impl(I, N, eta);
+}
+
//===----------------------------------------------------------------------===//
// smoothstep builtin
//===----------------------------------------------------------------------===//
diff --git a/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
index c9bd1bdd3cb8e..2c3e8d1560c87 100644
--- a/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/cross-errors.hlsl
@@ -4,8 +4,8 @@ void test_too_few_arg()
{
return cross();
// expected-error at -1 {{no matching function for call to 'cross'}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}}
}
void test_too_few_arg_f32()
@@ -24,8 +24,8 @@ void test_too_many_arg(float3 p0)
{
return cross(p0, p0, p0);
// expected-error at -1 {{no matching function for call to 'cross'}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
}
void test_too_many_arg_f32(float3 p0)
@@ -56,6 +56,6 @@ void test_ambiguous(int p0)
{
return cross(p0,p0);
// expected-error at -1 {{call to 'cross' is ambiguous}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function}}
- // expected-note at hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function}}
+ // expected-note at hlsl/hlsl_alias_intrinsics.h:* {{candidate function}}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
index e576f73669002..84333ba08b9b8 100644
--- a/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl
@@ -3,11 +3,11 @@
float test_too_few_arg() {
return dot2add();
// expected-error at -1 {{no matching function for call to 'dot2add'}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* {{candidate function not viable: requires 3 arguments, but 0 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 0 were provided}}
}
float test_too_many_arg(half2 p1, half2 p2, float p3) {
return dot2add(p1, p2, p3, p1);
// expected-error at -1 {{no matching function for call to 'dot2add'}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
index 8d9949f52aeb0..fce41a4a46d38 100644
--- a/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/refract-errors.hlsl
@@ -3,56 +3,64 @@
float test_no_second_arg(float3 p0) {
return refract(p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}}
}
float test_no_third_arg(float3 p0) {
return refract(p0, p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 2 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}}
}
float test_too_many_arg(float2 p0) {
return refract(p0, p0, p0, p0);
// expected-error at -1 {{no matching function for call to 'refract'}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 8 {{candidate function not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}}
}
float test_double_inputs(double p0, double p1, double p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{call to 'refract' is ambiguous}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 2 {{candidate function}}
+ // expected-error at -1 {{no matching function for call to 'refract'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
}
float test_int_inputs(int p0, int p1, int p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{call to 'refract' is ambiguous}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 2 {{candidate function}}
+ // expected-error at -1 {{no matching function for call to 'refract'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
}
float1 test_vec1_inputs(float1 p0, float1 p1, float1 p2) {
return refract(p0, p1, p2);
- // expected-warning at -1 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
- // expected-warning at -2 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
- // expected-warning at -3 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}}
+ // expected-error at -1 {{no matching function for call to 'refract'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
}
typedef float float5 __attribute__((ext_vector_type(5)));
-float5 test_vec5_inputs(float5 p0, float5 p1, float p2) {
+float5 test_vec5_inputs(float5 p0, float5 p1, float p2) {
return refract(p0, p1, p2);
- // expected-error at -1 {{call to 'refract' is ambiguous}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 4 {{candidate function}}
-}
-
-half3 test_half_inputs_with_float(half3 p0, half3 p1, float p3) {
- return refract(p0, p1, p3);
- // expected-error at -1 {{call to 'refract' is ambiguous}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 6 {{candidate function}}
-}
-
-half3 test_half_inputs_with_float_literal(half3 p0, half3 p1) {
- return refract(p0, p1, 0.5);
- // expected-error at -1 {{call to 'refract' is ambiguous}}
- // expected-note at hlsl/hlsl_inline_intrinsics_gen.inc:* 6 {{candidate function}}
+ // expected-error at -1 {{no matching function for call to 'refract'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
+ // expected-note at hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with L = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
}
>From d250935490e2ec553f3dfa2def12e67fa25b1297 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:20:59 -0700
Subject: [PATCH 05/12] Remove file name from headers
---
clang/include/clang/Basic/HLSLIntrinsics.td | 2 +-
clang/utils/TableGen/HLSLEmitter.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index a0517dd8f7e37..948080d4ae3c4 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -1,4 +1,4 @@
-//===--- 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.
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index 6c15ca96f67c2..af8f42206667e 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -1,4 +1,4 @@
-//===--- HLSLEmitter.cpp - HLSL intrinsic header generator ----------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
>From cbe11b4e14e95418b1cd98b8b134e66f3f25a0a3 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:27:56 -0700
Subject: [PATCH 06/12] Only wrap classes, enums, and structs in anon
namespaces. Add missing static to emitDocComment
---
clang/utils/TableGen/HLSLEmitter.cpp | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index af8f42206667e..bca279c3feba3 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -22,10 +22,8 @@
using namespace llvm;
-namespace {
-
/// Minimum shader model version that supports 16-bit types.
-constexpr StringLiteral SM6_2 = "6.2";
+static constexpr StringLiteral SM6_2 = "6.2";
//===----------------------------------------------------------------------===//
// Type name helpers
@@ -63,6 +61,8 @@ static const Record *getElementTypeRecord(const Record *R) {
// Type information
//===----------------------------------------------------------------------===//
+namespace {
+
/// Classifies how a type varies across overloads.
enum TypeKindEnum {
TK_Varying = 0, ///< Type matches the full varying type (e.g. float3).
@@ -135,6 +135,8 @@ struct TypeInfo {
}
};
+} // anonymous namespace
+
//===----------------------------------------------------------------------===//
// Availability helpers
//===----------------------------------------------------------------------===//
@@ -159,6 +161,8 @@ static std::string getVersionString(const Record *SM) {
// Type work item — describes one element type to emit overloads for
//===----------------------------------------------------------------------===//
+namespace {
+
/// A single entry in the worklist of types to process for an intrinsic.
struct TypeWorkItem {
/// Element type name (e.g. "half", "float"). Empty for fixed-arg-only
@@ -176,6 +180,8 @@ struct TypeWorkItem {
bool NeedsIfdefGuard = false;
};
+} // anonymous namespace
+
/// Fixed canonical ordering for overload types. Types are grouped as:
/// 0: conditionally-16-bit (half)
/// 1-2: 16-bit integers (int16_t, uint16_t) — ifdef-guarded
@@ -202,6 +208,8 @@ static int getTypeSortPriority(const Record *ET) {
// Overload context — shared state across all overloads of one intrinsic
//===----------------------------------------------------------------------===//
+namespace {
+
/// Shared state for emitting all overloads of a single HLSL intrinsic.
struct OverloadContext {
/// Output stream to write generated code to.
@@ -243,6 +251,8 @@ struct OverloadContext {
explicit OverloadContext(raw_ostream &OS) : OS(OS) {}
};
+} // anonymous namespace
+
/// Emit a complete function declaration or definition with pre-resolved types.
static void emitDeclaration(const OverloadContext &Ctx, StringRef RetType,
ArrayRef<std::string> ArgTypes) {
@@ -449,7 +459,7 @@ static void buildWorklist(const Record *R,
}
/// Emit a Doxygen documentation comment from the Doc field.
-void emitDocComment(raw_ostream &OS, const Record *R) {
+static void emitDocComment(raw_ostream &OS, const Record *R) {
StringRef Doc = R->getValueAsString("Doc");
if (Doc.empty())
return;
@@ -561,8 +571,6 @@ static void emitInlineBuiltin(raw_ostream &OS, const Record *R) {
emitBuiltinOverloads(OS, R);
}
-} // anonymous namespace
-
namespace clang {
void EmitHLSLAliasIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
>From dad45dd7fa3310d0c19cc1cf3bc23388fbdf1b30 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:38:00 -0700
Subject: [PATCH 07/12] Use namespace qualifier to define previously declared
EmitHLSLAliasIntrinsics and EmitHLSLInlineIntrinsics
---
clang/utils/TableGen/HLSLEmitter.cpp | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index bca279c3feba3..a3377c0e99c38 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -571,9 +572,8 @@ static void emitInlineBuiltin(raw_ostream &OS, const Record *R) {
emitBuiltinOverloads(OS, R);
}
-namespace clang {
-
-void EmitHLSLAliasIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitHLSLAliasIntrinsics(const RecordKeeper &Records,
+ raw_ostream &OS) {
OS << "// This file is auto-generated by clang-tblgen from "
"HLSLIntrinsics.td.\n";
OS << "// Do not edit this file directly.\n\n";
@@ -582,7 +582,8 @@ void EmitHLSLAliasIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
emitAliasBuiltin(OS, R);
}
-void EmitHLSLInlineIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitHLSLInlineIntrinsics(const RecordKeeper &Records,
+ raw_ostream &OS) {
OS << "// This file is auto-generated by clang-tblgen from "
"HLSLIntrinsics.td.\n";
OS << "// Do not edit this file directly.\n\n";
@@ -590,5 +591,3 @@ void EmitHLSLInlineIntrinsics(const RecordKeeper &Records, raw_ostream &OS) {
for (const Record *R : Records.getAllDerivedDefinitions("HLSLBuiltin"))
emitInlineBuiltin(OS, R);
}
-
-} // namespace clang
>From 4ef34989f863e6596784c3c0855ab307318a79be Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:42:20 -0700
Subject: [PATCH 08/12] Remove braces from single-statement if-else
---
clang/utils/TableGen/HLSLEmitter.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index a3377c0e99c38..85562dedf99f0 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -144,11 +144,10 @@ struct TypeInfo {
static void emitAvailability(raw_ostream &OS, StringRef Version,
bool Use16Bit = false) {
- if (Use16Bit) {
+ if (Use16Bit)
OS << "_HLSL_16BIT_AVAILABILITY(shadermodel, " << Version << ")\n";
- } else {
+ else
OS << "_HLSL_AVAILABILITY(shadermodel, " << Version << ")\n";
- }
}
static std::string getVersionString(const Record *SM) {
unsigned Major = SM->getValueAsInt("Major");
>From 00ec61f931a39bf93e8fcd3e397165a448555f06 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:43:46 -0700
Subject: [PATCH 09/12] Add missing blank lines between functions
---
clang/utils/TableGen/HLSLEmitter.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index 85562dedf99f0..fc07f042d25b9 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -149,6 +149,7 @@ static void emitAvailability(raw_ostream &OS, StringRef Version,
else
OS << "_HLSL_AVAILABILITY(shadermodel, " << Version << ")\n";
}
+
static std::string getVersionString(const Record *SM) {
unsigned Major = SM->getValueAsInt("Major");
unsigned Minor = SM->getValueAsInt("Minor");
@@ -553,6 +554,7 @@ static void emitBuiltinOverloads(raw_ostream &OS, const Record *R) {
emitWorklistOverloads(OS, Ctx, Worklist, EmitScalarOverload, VectorSizes,
MatrixDimensions);
}
+
/// Emit alias overloads for a single HLSLBuiltin record.
/// Skips records that have inline bodies (DetailFunc or Body).
static void emitAliasBuiltin(raw_ostream &OS, const Record *R) {
>From 4c192d57d153852873ca118bc54293901a1b1a31 Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:47:11 -0700
Subject: [PATCH 10/12] Use ListSeparator for inserting commas and spaces
---
clang/utils/TableGen/HLSLEmitter.cpp | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index fc07f042d25b9..8571a2baf36be 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -15,6 +15,7 @@
#include "TableGenBackends.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -280,21 +281,20 @@ static void emitDeclaration(const OverloadContext &Ctx, StringRef RetType,
OS << (Ctx.IsConstexpr ? "constexpr " : "inline ");
OS << RetType << " " << Ctx.FuncName << "(";
- for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
- if (I > 0)
- OS << ", ";
- OS << ArgTypes[I];
- if (EmitNames)
- OS << " " << GetParamName(I);
+ {
+ ListSeparator LS;
+ for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
+ OS << LS << ArgTypes[I];
+ if (EmitNames)
+ OS << " " << GetParamName(I);
+ }
}
if (IsDetail) {
OS << ") {\n return __detail::" << Ctx.DetailFunc << "(";
- for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
- if (I > 0)
- OS << ", ";
- OS << GetParamName(I);
- }
+ ListSeparator LS;
+ for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I)
+ OS << LS << GetParamName(I);
OS << ");\n}\n";
} else if (IsInline) {
OS << ") { " << Ctx.Body << " }\n";
>From 2ce1cf6f6ed406efc93857528c9f2ff7353fa87f Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:49:43 -0700
Subject: [PATCH 11/12] Use range for-loop over VaryingTypeRecords
---
clang/utils/TableGen/HLSLEmitter.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/utils/TableGen/HLSLEmitter.cpp b/clang/utils/TableGen/HLSLEmitter.cpp
index 8571a2baf36be..c2275f3aaf87c 100644
--- a/clang/utils/TableGen/HLSLEmitter.cpp
+++ b/clang/utils/TableGen/HLSLEmitter.cpp
@@ -445,16 +445,13 @@ static void buildWorklist(const Record *R,
});
// Add a work item for each Varying element type.
- for (size_t I = 0, N = VaryingTypeRecords.size(); I < N; ++I) {
- const Record *ElemTy = VaryingTypeRecords[I];
-
+ for (const Record *ElemTy : VaryingTypeRecords) {
TypeWorkItem Item;
Item.ElemType = ElemTy->getValueAsString("Name");
bool Is16Bit = Ctx.Uses16BitType || ElemTy->getValueAsBit("Is16Bit");
bool IsCond16Bit = Ctx.UsesConditionally16BitType ||
ElemTy->getValueAsBit("IsConditionally16Bit");
SetAvailability(Item, Is16Bit, IsCond16Bit);
-
Worklist.push_back(Item);
}
}
>From 89742d717c0f49189a5496c2f73508c1bc8c756f Mon Sep 17 00:00:00 2001
From: Deric Cheung <cheung.deric at gmail.com>
Date: Thu, 19 Mar 2026 18:57:09 -0700
Subject: [PATCH 12/12] Reintroduce includes to hlsl intrinsics headers
---
clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h | 3 +++
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
index c2e4d74af6873..c8acd258f694e 100644
--- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h
@@ -38,6 +38,9 @@ namespace hlsl {
#define _HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
#endif
+// Generated by clang-tblgen from HLSLIntrinsics.td (alias intrinsics).
+#include "hlsl_alias_intrinsics_gen.inc"
+
//===----------------------------------------------------------------------===//
// abs builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 25d36f5483943..6a37a50064411 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -13,6 +13,9 @@
namespace hlsl {
+// Generated by clang-tblgen from HLSLIntrinsics.td (detail/inline intrinsics).
+#include "hlsl_inline_intrinsics_gen.inc"
+
//===----------------------------------------------------------------------===//
// asfloat builtins
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list