Skip to content

Commit daec3b9

Browse files
authored
[HLSL] Implement TableGen for builtin HLSL intrinsics (#187610)
This PR introduces a TableGen-based code generation system for HLSL intrinsic overloads as described in proposal [[0043]](https://github.com/llvm/wg-hlsl/blob/main/proposals/0043-hlsl-intrinsic-tablegen.md) for replacing hand-written boilerplate with declarative .td definitions. Actual changes to `hlsl_intrinsics.h` and `hlsl_alias_intrinsics.h` to replace handwritten HLSL intrinsic overloads with TableGen is left to follow-up PRs. Assisted-by: GitHub Copilot (powered by Claude Opus 4.6)
1 parent 2ae3d8a commit daec3b9

File tree

9 files changed

+1415
-1
lines changed

9 files changed

+1415
-1
lines changed
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines HLSL intrinsic functions in tablegen. The HLSLEmitter
10+
// backend processes these definitions and generates two .inc files:
11+
// - hlsl_alias_intrinsics_gen.inc: builtin alias declarations using
12+
// _HLSL_BUILTIN_ALIAS, included by hlsl_alias_intrinsics.h.
13+
// - hlsl_inline_intrinsics_gen.inc: inline function definitions (detail
14+
// helper calls and literal bodies), included by hlsl_intrinsics.h.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
//===----------------------------------------------------------------------===//
19+
// Argument and return type base classes
20+
//===----------------------------------------------------------------------===//
21+
22+
// Base class for argument and return type positions.
23+
class HLSLArgType;
24+
25+
// Base class for return type positions.
26+
class HLSLReturnType;
27+
28+
// Void return type.
29+
def VoidTy : HLSLReturnType;
30+
31+
//===----------------------------------------------------------------------===//
32+
// HLSL element types
33+
//===----------------------------------------------------------------------===//
34+
35+
// Represents a concrete HLSL scalar element type.
36+
// Can be used directly as an argument or return type for a fixed scalar
37+
// (e.g., FloatTy in Args produces a 'float' argument).
38+
class HLSLType<string name> : HLSLArgType, HLSLReturnType {
39+
string Name = name;
40+
string TypeName = name;
41+
42+
// When set, overloads using this type are guarded by
43+
// #ifdef __HLSL_ENABLE_16_BIT and emitted with
44+
// _HLSL_AVAILABILITY(shadermodel, 6.2), or the intrinsic's Availability
45+
// if it is greater.
46+
bit Is16Bit = 0;
47+
48+
// When set, overloads using this type are emitted with
49+
// _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) instead of _HLSL_AVAILABILITY.
50+
// This macro expands to an availability attribute only when
51+
// __HLSL_ENABLE_16_BIT is defined (i.e. half is a true 16-bit float);
52+
// otherwise it expands to nothing since half is an alias for float.
53+
// If the intrinsic's Availability is >= SM6.2, _HLSL_AVAILABILITY is used
54+
// instead because 16-bit support is already implied.
55+
bit IsConditionally16Bit = 0;
56+
}
57+
58+
def BoolTy : HLSLType<"bool">;
59+
def HalfTy : HLSLType<"half"> { let IsConditionally16Bit = 1; }
60+
def FloatTy : HLSLType<"float">;
61+
def DoubleTy : HLSLType<"double">;
62+
def Int16Ty : HLSLType<"int16_t"> { let Is16Bit = 1; }
63+
def UInt16Ty : HLSLType<"uint16_t"> { let Is16Bit = 1; }
64+
def IntTy : HLSLType<"int">;
65+
def UIntTy : HLSLType<"uint">;
66+
def Int64Ty : HLSLType<"int64_t">;
67+
def UInt64Ty : HLSLType<"uint64_t">;
68+
69+
//===----------------------------------------------------------------------===//
70+
// Element type groups
71+
//===----------------------------------------------------------------------===//
72+
73+
defvar AllFloatTypes = [HalfTy, FloatTy, DoubleTy];
74+
defvar SignedIntTypes = [Int16Ty, IntTy, Int64Ty];
75+
defvar UnsignedIntTypes = [UInt16Ty, UIntTy, UInt64Ty];
76+
defvar AllIntTypes = [Int16Ty, UInt16Ty, IntTy, UIntTy,
77+
Int64Ty, UInt64Ty];
78+
defvar SignedTypes = [Int16Ty, HalfTy, IntTy, FloatTy,
79+
Int64Ty, DoubleTy];
80+
defvar AllNumericTypes = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
81+
FloatTy, Int64Ty, UInt64Ty, DoubleTy];
82+
defvar AllTypesWithBool = [BoolTy, Int16Ty, UInt16Ty, HalfTy,
83+
IntTy, UIntTy, FloatTy, Int64Ty,
84+
UInt64Ty, DoubleTy];
85+
defvar NumericTypesNoDbl = [Int16Ty, UInt16Ty, HalfTy, IntTy, UIntTy,
86+
FloatTy, Int64Ty, UInt64Ty];
87+
88+
//===----------------------------------------------------------------------===//
89+
// Argument/return types
90+
//
91+
// These classes are usable in both argument and return type positions.
92+
//===----------------------------------------------------------------------===//
93+
94+
// The varying type — expanded per VaryingTypes.
95+
// As an argument: the arg type varies with each overload.
96+
// As a return type: returns the same type as the varying arg.
97+
def Varying : HLSLArgType, HLSLReturnType;
98+
99+
// The scalar element of the varying type.
100+
// As an argument: always the scalar element type regardless of overload shape.
101+
// As a return type: returns the scalar element type (e.g., float dot(float3, float3)).
102+
def VaryingElemType : HLSLArgType, HLSLReturnType;
103+
104+
// The varying shape with a fixed element type.
105+
// As an argument: same shape as Varying but with the given element type.
106+
// As a return type: same shape as the varying arg but with the given element type.
107+
// For example, VaryingShape<UIntTy> with a float3 overload produces uint3.
108+
class VaryingShape<HLSLType ty> : HLSLArgType, HLSLReturnType {
109+
HLSLType ElementType = ty;
110+
}
111+
112+
// A concrete vector type (e.g., VectorType<UIntTy, 4> -> uint4).
113+
// As an argument: the arg is always this vector type.
114+
// As a return type: always returns this vector type, ignoring argument shape.
115+
class VectorType<HLSLType ty, int size> : HLSLArgType, HLSLReturnType {
116+
HLSLType ElementType = ty;
117+
int Size = size;
118+
}
119+
120+
//===----------------------------------------------------------------------===//
121+
// Shader model versions
122+
//===----------------------------------------------------------------------===//
123+
124+
// Represents a shader model version
125+
class ShaderModel<int major, int minor> {
126+
int Major = major;
127+
int Minor = minor;
128+
}
129+
130+
// Sentinel: no shader model requirement.
131+
def NoSM : ShaderModel<0, 0>;
132+
133+
// Valid Shader Model records
134+
foreach i = 0...9 in {
135+
def SM6_ #i : ShaderModel<6, i>;
136+
}
137+
138+
//===----------------------------------------------------------------------===//
139+
// Matrix dimension records
140+
//===----------------------------------------------------------------------===//
141+
142+
class MatDim<int rows, int cols> {
143+
int Rows = rows;
144+
int Cols = cols;
145+
}
146+
147+
foreach r = 1...4 in
148+
foreach c = 1...4 in
149+
def Mat#r#"x"#c : MatDim<r, c>;
150+
151+
// All non-1x1 matrix dimensions (1x2 through 4x4).
152+
defvar AllMatDims = [Mat1x2, Mat1x3, Mat1x4,
153+
Mat2x1, Mat2x2, Mat2x3, Mat2x4,
154+
Mat3x1, Mat3x2, Mat3x3, Mat3x4,
155+
Mat4x1, Mat4x2, Mat4x3, Mat4x4];
156+
157+
//===----------------------------------------------------------------------===//
158+
// HLSLBuiltin class
159+
//===----------------------------------------------------------------------===//
160+
161+
class HLSLBuiltin<string name, string builtin = ""> {
162+
string Name = name;
163+
164+
// When set, generates a _HLSL_BUILTIN_ALIAS(Builtin) declaration that
165+
// aliases the named Clang builtin. Mutually exclusive with DetailFunc
166+
// and Body.
167+
string Builtin = builtin;
168+
169+
// Doxygen documentation comment emitted before overloads in generated code.
170+
string Doc = "";
171+
172+
// When set, generates an inline function body calling
173+
// __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS(Builtin).
174+
// Parameters are named p0, p1, p2, ... by default, or use ParamNames to
175+
// specify custom names. Mutually exclusive with Body and Builtin.
176+
string DetailFunc = "";
177+
178+
// When set, generates an inline function with this literal body text.
179+
// Intended for single-statement functions. Multi-line functions should
180+
// instead be defined as a helper and called with DetailFunc.
181+
// Parameters are named p0, p1, p2, ... by default, or use ParamNames to
182+
// specify custom names. Mutually exclusive with DetailFunc and Builtin.
183+
code Body = "";
184+
185+
// Determines how the return type is derived for each overload.
186+
HLSLReturnType ReturnType = VoidTy;
187+
188+
// Argument list. Each entry is either:
189+
// Varying - type varies with VaryingTypes (expanded per type)
190+
// HLSLType - a fixed scalar type at that position (e.g., UIntTy)
191+
// VectorType - a fixed vector type at that position
192+
// The number of arguments is deduced from the length of this list.
193+
// Examples:
194+
// [Varying] -> func(T)
195+
// [Varying, Varying, Varying] -> func(T, T, T)
196+
// [Varying, UIntTy] -> func(T, uint)
197+
// [UIntTy, UIntTy, IntTy] -> func(uint, uint, int)
198+
// [] -> func()
199+
list<HLSLArgType> Args = [];
200+
201+
// Custom parameter names for generated functions.
202+
// When empty, inline functions (Body or DetailFunc) use p0, p1, p2, ...
203+
// and alias functions omit parameter names.
204+
list<string> ParamNames = [];
205+
206+
// When set, emits 'constexpr' instead of 'inline' for inline functions
207+
// (i.e., functions using Body or DetailFunc).
208+
bit IsConstexpr = 0;
209+
210+
// Whether the function has the convergent attribute
211+
bit IsConvergent = 0;
212+
213+
// Argument element types — drives overload expansion.
214+
// One overload set is generated per type (scalar + vectors + matrices).
215+
// Only used when Args contains Varying entries.
216+
list<HLSLType> VaryingTypes = [];
217+
218+
// Whether to generate scalar overloads for Varying typed arguments.
219+
bit VaryingScalar = 0;
220+
221+
// Vector sizes to generate for Varying typed arguments (e.g., [2,3,4]).
222+
list<int> VaryingVecSizes = [];
223+
224+
// Matrix dimensions to generate for Varying typed arguments.
225+
list<MatDim> VaryingMatDims = [];
226+
227+
// Default shader model availability version for all types.
228+
// Use NoSM for no availability requirement.
229+
ShaderModel Availability = NoSM;
230+
}
231+
232+
//===----------------------------------------------------------------------===//
233+
// HLSLBuiltin helper subclasses
234+
//===----------------------------------------------------------------------===//
235+
236+
// T func(T) with scalar + vec2/3/4 + matrix overloads.
237+
class HLSLOneArgBuiltin<string name, string builtin>
238+
: HLSLBuiltin<name, builtin> {
239+
let Args = [Varying];
240+
let ReturnType = Varying;
241+
let VaryingScalar = 1;
242+
let VaryingVecSizes = [2, 3, 4];
243+
let VaryingMatDims = AllMatDims;
244+
}
245+
246+
// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
247+
class HLSLTwoArgBuiltin<string name, string builtin>
248+
: HLSLBuiltin<name, builtin> {
249+
let Args = [Varying, Varying];
250+
let ReturnType = Varying;
251+
let VaryingScalar = 1;
252+
let VaryingVecSizes = [2, 3, 4];
253+
let VaryingMatDims = AllMatDims;
254+
}
255+
256+
// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
257+
class HLSLThreeArgBuiltin<string name, string builtin>
258+
: HLSLBuiltin<name, builtin> {
259+
let Args = [Varying, Varying, Varying];
260+
let ReturnType = Varying;
261+
let VaryingScalar = 1;
262+
let VaryingVecSizes = [2, 3, 4];
263+
let VaryingMatDims = AllMatDims;
264+
}
265+
266+
// Detail function base: generates inline function bodies calling
267+
// __detail::DetailFunc(args...) instead of _HLSL_BUILTIN_ALIAS.
268+
class HLSLDetail<string name, string detail> : HLSLBuiltin<name> {
269+
let DetailFunc = detail;
270+
}
271+
272+
// T func(T) with scalar + vec2/3/4 + matrix overloads.
273+
class HLSLOneArgDetail<string name, string detail>
274+
: HLSLDetail<name, detail> {
275+
let Args = [Varying];
276+
let ReturnType = Varying;
277+
let VaryingScalar = 1;
278+
let VaryingVecSizes = [2, 3, 4];
279+
let VaryingMatDims = AllMatDims;
280+
}
281+
282+
// T func(T, T) with scalar + vec2/3/4 + matrix overloads.
283+
class HLSLTwoArgDetail<string name, string detail>
284+
: HLSLDetail<name, detail> {
285+
let Args = [Varying, Varying];
286+
let ReturnType = Varying;
287+
let VaryingScalar = 1;
288+
let VaryingVecSizes = [2, 3, 4];
289+
let VaryingMatDims = AllMatDims;
290+
}
291+
292+
// T func(T, T, T) with scalar + vec2/3/4 + matrix overloads.
293+
class HLSLThreeArgDetail<string name, string detail>
294+
: HLSLDetail<name, detail> {
295+
let Args = [Varying, Varying, Varying];
296+
let ReturnType = Varying;
297+
let VaryingScalar = 1;
298+
let VaryingVecSizes = [2, 3, 4];
299+
let VaryingMatDims = AllMatDims;
300+
}
301+
302+
// Inline body variant: T func(T) with a literal inline body (no builtin alias).
303+
// Body must be specified (e.g., let Body = "return p0;").
304+
class HLSLOneArgInlineBuiltin<string name> : HLSLBuiltin<name> {
305+
let Args = [Varying];
306+
let ReturnType = Varying;
307+
let VaryingScalar = 1;
308+
let VaryingVecSizes = [2, 3, 4];
309+
let VaryingMatDims = AllMatDims;
310+
}
311+
312+
//===----------------------------------------------------------------------===//
313+
// Intrinsic definitions (sorted alphabetically by function name)
314+
//===----------------------------------------------------------------------===//
315+
316+
// TODO: Convert hand-written overloads from hlsl_intrinsics.h and
317+
// hlsl_alias_intrinsics.h into TableGen below.
318+
// Include "hlsl_alias_intrinsics_gen.inc" in hlsl_alias_intrinsics.h
319+
// Include "hlsl_inline_intrinsics_gen.inc" in hlsl_intrinsics.h
320+

clang/lib/Headers/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,22 @@ if(RISCV IN_LIST LLVM_TARGETS_TO_BUILD)
504504
)
505505
endif()
506506

507+
# Generate HLSL intrinsic overloads
508+
clang_generate_header(-gen-hlsl-alias-intrinsics HLSLIntrinsics.td
509+
hlsl/hlsl_alias_intrinsics_gen.inc)
510+
clang_generate_header(-gen-hlsl-inline-intrinsics HLSLIntrinsics.td
511+
hlsl/hlsl_inline_intrinsics_gen.inc)
512+
set(hlsl_generated_files
513+
"${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_alias_intrinsics_gen.inc"
514+
"${CMAKE_CURRENT_BINARY_DIR}/hlsl/hlsl_inline_intrinsics_gen.inc")
507515

508516
# Check if the generated headers are included in a target specific lists
509517
# Currently, all generated headers are target specific.
510518
set(all_target_specific_generated_files
511519
${arm_common_generated_files}
512520
${arm_only_generated_files}
513521
${aarch64_only_generated_files}
522+
${hlsl_generated_files}
514523
${riscv_generated_files})
515524
foreach( f ${generated_files} )
516525
if (NOT ${f} IN_LIST all_target_specific_generated_files)
@@ -579,7 +588,7 @@ add_header_target("x86-resource-headers" "${x86_files}")
579588
add_header_target("gpu-resource-headers" "${gpu_files}")
580589

581590
# Other header groupings
582-
add_header_target("hlsl-resource-headers" ${hlsl_files})
591+
add_header_target("hlsl-resource-headers" "${hlsl_files};${hlsl_generated_files}")
583592
add_header_target("spirv-resource-headers" ${spirv_files})
584593
add_header_target("opencl-resource-headers" ${opencl_files})
585594
add_header_target("llvm-libc-resource-headers" ${llvm_libc_wrapper_files})

clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ namespace hlsl {
3838
#define _HLSL_16BIT_AVAILABILITY_SHADERMODEL_DEFAULT()
3939
#endif
4040

41+
// Generated by clang-tblgen from HLSLIntrinsics.td (alias intrinsics).
42+
#include "hlsl_alias_intrinsics_gen.inc"
43+
4144
//===----------------------------------------------------------------------===//
4245
// abs builtins
4346
//===----------------------------------------------------------------------===//

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
namespace hlsl {
1515

16+
// Generated by clang-tblgen from HLSLIntrinsics.td (detail/inline intrinsics).
17+
#include "hlsl_inline_intrinsics_gen.inc"
18+
1619
//===----------------------------------------------------------------------===//
1720
// asfloat builtins
1821
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)