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 <[email protected]> Date: Thu, 19 Mar 2026 15:16:17 -0700 Subject: [PATCH 1/2] 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@-1 {{no matching function for call to 'cross'}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 0 were provided}} + // expected-note@hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 0 were provided}} + // expected-note@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@-1 {{no matching function for call to 'cross'}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}} + // expected-note@hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function not viable: requires 2 arguments, but 3 were provided}} + // expected-note@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@-1 {{call to 'cross' is ambiguous}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function}} - // expected-note@hlsl/hlsl_alias_intrinsics.h:* {{candidate function}} + // expected-note@hlsl/hlsl_alias_intrinsics_gen.inc:* {{candidate function}} + // expected-note@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@-1 {{no matching function for call to 'dot2add'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 0 were provided}} + // expected-note@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@-1 {{no matching function for call to 'dot2add'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 4 were provided}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 2 were provided}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-error@-1 {{call to 'refract' is ambiguous}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}} + // expected-error@-1 {{call to 'refract' is ambiguous}} + // expected-note@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@-1 {{no matching function for call to 'refract'}} - // expected-note@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@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@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@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@-1 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}} + // expected-warning@-2 {{implicit conversion turns vector to scalar: 'float1' (aka 'vector<float, 1>') to 'float'}} + // expected-warning@-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@-1 {{no matching function for call to 'refract'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: deduced conflicting types for parameter 'T' ('float5' (vector of 5 'float' values) vs. 'float')}} - // expected-note@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@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@-1 {{call to 'refract' is ambiguous}} + // expected-note@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@-1 {{call to 'refract' is ambiguous}} + // expected-note@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@-1 {{call to 'refract' is ambiguous}} + // expected-note@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 <[email protected]> Date: Thu, 19 Mar 2026 16:47:52 -0700 Subject: [PATCH 2/2] 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) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
