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 tablegen backend generates hlsl_alias_intrinsics_gen.inc (alias
10// overloads) and hlsl_inline_intrinsics_gen.inc (inline/detail overloads) for
11// HLSL intrinsic functions.
12//
13//===----------------------------------------------------------------------===//
14
15#include "TableGenBackends.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/StringSwitch.h"
21#include "llvm/Support/ErrorHandling.h"
22#include "llvm/Support/raw_ostream.h"
23#include "llvm/TableGen/Record.h"
24
25using namespace llvm;
26
27/// Minimum shader model version that supports 16-bit types.
28static constexpr StringLiteral SM6_2 = "6.2";
29
30//===----------------------------------------------------------------------===//
31// Type name helpers
32//===----------------------------------------------------------------------===//
33
34static std::string getVectorTypeName(StringRef ElemType, unsigned N) {
35 return (ElemType + Twine(N)).str();
36}
37
38static std::string getMatrixTypeName(StringRef ElemType, unsigned Rows,
39 unsigned Cols) {
40 return (ElemType + Twine(Rows) + "x" + Twine(Cols)).str();
41}
42
43/// Get the fixed type name string for a VectorType or HLSLType record.
44static std::string getFixedTypeName(const Record *R) {
45 if (R->isSubClassOf(Name: "VectorType"))
46 return getVectorTypeName(
47 ElemType: R->getValueAsDef(FieldName: "ElementType")->getValueAsString(FieldName: "Name"),
48 N: R->getValueAsInt(FieldName: "Size"));
49 assert(R->isSubClassOf("HLSLType"));
50 return R->getValueAsString(FieldName: "Name").str();
51}
52
53/// For a VectorType, return its ElementType record; for an HLSLType, return
54/// the record itself (it is already a scalar element type).
55static const Record *getElementTypeRecord(const Record *R) {
56 if (R->isSubClassOf(Name: "VectorType"))
57 return R->getValueAsDef(FieldName: "ElementType");
58 assert(R->isSubClassOf("HLSLType"));
59 return R;
60}
61
62//===----------------------------------------------------------------------===//
63// Type information
64//===----------------------------------------------------------------------===//
65
66namespace {
67
68/// Classifies how a type varies across overloads.
69enum TypeKindEnum {
70 TK_Varying = 0, ///< Type matches the full varying type (e.g. float3).
71 TK_ElemType = 1, ///< Type is the scalar element type (e.g. float).
72 TK_VaryingShape = 2, ///< Type uses the varying shape with a fixed element.
73 TK_FixedType = 3, ///< Type is a fixed concrete type (e.g. "half2").
74 TK_Void = 4 ///< Type is void (only valid for return types).
75};
76
77/// Metadata describing how a type (argument or return) varies across overloads.
78struct TypeInfo {
79 /// Classification of how this type varies across overloads.
80 TypeKindEnum Kind = TK_Varying;
81
82 /// Fixed type name (e.g. "half2") for types with a concrete type that does
83 /// not vary across overloads. Empty for varying types.
84 std::string FixedType;
85
86 /// Element type name for TK_VaryingShape types (e.g. "bool" for
87 /// VaryingShape<BoolTy>). Empty for other type kinds.
88 StringRef ShapeElemType;
89
90 /// Explicit parameter name (e.g. "eta"). Empty to use the default "p0",
91 /// "p1", ... naming. Only meaningful for argument types.
92 StringRef Name;
93
94 /// Construct a TypeInfo from a TableGen record.
95 static TypeInfo resolve(const Record *Rec) {
96 TypeInfo TI;
97 if (Rec->getName() == "VoidTy") {
98 TI.Kind = TK_Void;
99 } else if (Rec->getName() == "Varying") {
100 TI.Kind = TK_Varying;
101 } else if (Rec->getName() == "VaryingElemType") {
102 TI.Kind = TK_ElemType;
103 } else if (Rec->isSubClassOf(Name: "VaryingShape")) {
104 TI.Kind = TK_VaryingShape;
105 TI.ShapeElemType =
106 Rec->getValueAsDef(FieldName: "ElementType")->getValueAsString(FieldName: "Name");
107 } else if (Rec->isSubClassOf(Name: "VectorType") ||
108 Rec->isSubClassOf(Name: "HLSLType")) {
109 TI.Kind = TK_FixedType;
110 TI.FixedType = getFixedTypeName(R: Rec);
111 } else {
112 llvm_unreachable("unhandled record for type resolution");
113 }
114 return TI;
115 }
116
117 /// Resolve this type to a concrete type name string.
118 /// \p ElemType is the scalar element type for the current overload.
119 /// \p FormatVarying formats a scalar element type into the shaped type name.
120 std::string
121 toTypeString(StringRef ElemType,
122 function_ref<std::string(StringRef)> FormatVarying) const {
123 switch (Kind) {
124 case TK_Void:
125 return "void";
126 case TK_Varying:
127 return FormatVarying(ElemType);
128 case TK_ElemType:
129 return ElemType.str();
130 case TK_VaryingShape:
131 return FormatVarying(ShapeElemType);
132 case TK_FixedType:
133 assert(!FixedType.empty() && "TK_FixedType requires non-empty FixedType");
134 return FixedType;
135 }
136 llvm_unreachable("unhandled TypeKindEnum");
137 }
138};
139
140} // anonymous namespace
141
142//===----------------------------------------------------------------------===//
143// Availability helpers
144//===----------------------------------------------------------------------===//
145
146static void emitAvailability(raw_ostream &OS, StringRef Version,
147 bool Use16Bit = false) {
148 if (Use16Bit)
149 OS << "_HLSL_16BIT_AVAILABILITY(shadermodel, " << Version << ")\n";
150 else
151 OS << "_HLSL_AVAILABILITY(shadermodel, " << Version << ")\n";
152}
153
154static std::string getVersionString(const Record *SM) {
155 unsigned Major = SM->getValueAsInt(FieldName: "Major");
156 unsigned Minor = SM->getValueAsInt(FieldName: "Minor");
157 if (Major == 0 && Minor == 0)
158 return "";
159 return (Twine(Major) + "." + Twine(Minor)).str();
160}
161
162//===----------------------------------------------------------------------===//
163// Type work item — describes one element type to emit overloads for
164//===----------------------------------------------------------------------===//
165
166namespace {
167
168/// A single entry in the worklist of types to process for an intrinsic.
169struct TypeWorkItem {
170 /// Element type name (e.g. "half", "float"). Empty for fixed-arg-only
171 /// intrinsics with no type expansion.
172 StringRef ElemType;
173
174 /// Version string for the availability attribute (e.g. "6.2"). Empty if
175 /// no availability annotation is needed.
176 std::string Availability;
177
178 /// If true, emit _HLSL_16BIT_AVAILABILITY instead of _HLSL_AVAILABILITY.
179 bool Use16BitAvail = false;
180
181 /// If true, wrap overloads in #ifdef __HLSL_ENABLE_16_BIT / #endif.
182 bool NeedsIfdefGuard = false;
183};
184
185} // anonymous namespace
186
187/// Fixed canonical ordering for overload types. Types are grouped as:
188/// 0: conditionally-16-bit (half)
189/// 1-2: 16-bit integers (int16_t, uint16_t) — ifdef-guarded
190/// 3+: regular types (bool, int, uint, int64_t, uint64_t, float, double)
191/// Within each group, signed precedes unsigned, smaller precedes larger,
192/// and integer types precede floating-point types.
193static int getTypeSortPriority(const Record *ET) {
194 return StringSwitch<int>(ET->getValueAsString(FieldName: "Name"))
195 .Case(S: "half", Value: 0)
196 .Case(S: "int16_t", Value: 1)
197 .Case(S: "uint16_t", Value: 2)
198 .Case(S: "bool", Value: 3)
199 .Case(S: "int", Value: 4)
200 .Case(S: "uint", Value: 5)
201 .Case(S: "int64_t", Value: 7)
202 .Case(S: "uint64_t", Value: 8)
203 .Case(S: "float", Value: 9)
204 .Case(S: "double", Value: 10)
205 .Default(Value: 11);
206}
207
208//===----------------------------------------------------------------------===//
209// Overload context — shared state across all overloads of one intrinsic
210//===----------------------------------------------------------------------===//
211
212namespace {
213
214/// Shared state for emitting all overloads of a single HLSL intrinsic.
215struct OverloadContext {
216 /// Output stream to write generated code to.
217 raw_ostream &OS;
218
219 /// Builtin name for _HLSL_BUILTIN_ALIAS (e.g. "__builtin_hlsl_dot").
220 /// Empty for inline/detail intrinsics.
221 StringRef Builtin;
222
223 /// __detail helper function to call (e.g. "refract_impl").
224 /// Empty for alias and inline-body intrinsics.
225 StringRef DetailFunc;
226
227 /// Literal inline function body (e.g. "return p0;").
228 /// Empty for alias and detail intrinsics.
229 StringRef Body;
230
231 /// The HLSL function name to emit (e.g. "dot", "refract").
232 StringRef FuncName;
233
234 /// Metadata describing the return type and its variation behavior.
235 TypeInfo RetType;
236
237 /// Per-argument metadata describing type and variation behavior.
238 SmallVector<TypeInfo, 4> Args;
239
240 /// Whether to emit the function as constexpr.
241 bool IsConstexpr = false;
242
243 /// Whether to emit the __attribute__((convergent)) annotation.
244 bool IsConvergent = false;
245
246 /// Whether any fixed arg has a 16-bit integer type (e.g. int16_t).
247 bool Uses16BitType = false;
248
249 /// Whether any fixed arg has a conditionally-16-bit type (half).
250 bool UsesConditionally16BitType = false;
251
252 explicit OverloadContext(raw_ostream &OS) : OS(OS) {}
253};
254
255} // anonymous namespace
256
257/// Emit a complete function declaration or definition with pre-resolved types.
258static void emitDeclaration(const OverloadContext &Ctx, StringRef RetType,
259 ArrayRef<std::string> ArgTypes) {
260 raw_ostream &OS = Ctx.OS;
261 bool IsDetail = !Ctx.DetailFunc.empty();
262 bool IsInline = !Ctx.Body.empty();
263 bool HasBody = IsDetail || IsInline;
264
265 bool EmitNames = HasBody || llvm::any_of(Range: Ctx.Args, P: [](const TypeInfo &A) {
266 return !A.Name.empty();
267 });
268
269 auto GetParamName = [&](unsigned I) -> std::string {
270 if (!Ctx.Args[I].Name.empty())
271 return Ctx.Args[I].Name.str();
272 return ("p" + Twine(I)).str();
273 };
274
275 if (!HasBody)
276 OS << "_HLSL_BUILTIN_ALIAS(" << Ctx.Builtin << ")\n";
277 if (Ctx.IsConvergent)
278 OS << "__attribute__((convergent)) ";
279 if (HasBody)
280 OS << (Ctx.IsConstexpr ? "constexpr " : "inline ");
281 OS << RetType << " " << Ctx.FuncName << "(";
282
283 {
284 ListSeparator LS;
285 for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I) {
286 OS << LS << ArgTypes[I];
287 if (EmitNames)
288 OS << " " << GetParamName(I);
289 }
290 }
291
292 if (IsDetail) {
293 OS << ") {\n return __detail::" << Ctx.DetailFunc << "(";
294 ListSeparator LS;
295 for (unsigned I = 0, N = ArgTypes.size(); I < N; ++I)
296 OS << LS << GetParamName(I);
297 OS << ");\n}\n";
298 } else if (IsInline) {
299 OS << ") { " << Ctx.Body << " }\n";
300 } else {
301 OS << ");\n";
302 }
303}
304
305/// Emit a single overload declaration by resolving all types through
306/// \p FormatVarying, which maps element types to their shaped form.
307static void emitOverload(const OverloadContext &Ctx, StringRef ElemType,
308 function_ref<std::string(StringRef)> FormatVarying) {
309 std::string RetType = Ctx.RetType.toTypeString(ElemType, FormatVarying);
310 SmallVector<std::string> ArgTypes;
311 for (const TypeInfo &TI : Ctx.Args)
312 ArgTypes.push_back(Elt: TI.toTypeString(ElemType, FormatVarying));
313 emitDeclaration(Ctx, RetType, ArgTypes);
314}
315
316/// Emit a scalar overload for the given element type.
317static void emitScalarOverload(const OverloadContext &Ctx, StringRef ElemType) {
318 emitOverload(Ctx, ElemType, FormatVarying: [](StringRef ET) { return ET.str(); });
319}
320
321/// Emit a vector overload for the given element type and vector size.
322static void emitVectorOverload(const OverloadContext &Ctx, StringRef ElemType,
323 unsigned VecSize) {
324 emitOverload(Ctx, ElemType, FormatVarying: [VecSize](StringRef ET) {
325 return getVectorTypeName(ElemType: ET, N: VecSize);
326 });
327}
328
329/// Emit a matrix overload for the given element type and matrix dimensions.
330static void emitMatrixOverload(const OverloadContext &Ctx, StringRef ElemType,
331 unsigned Rows, unsigned Cols) {
332 emitOverload(Ctx, ElemType, FormatVarying: [Rows, Cols](StringRef ET) {
333 return getMatrixTypeName(ElemType: ET, Rows, Cols);
334 });
335}
336
337//===----------------------------------------------------------------------===//
338// Main emission logic
339//===----------------------------------------------------------------------===//
340
341/// Build an OverloadContext from an HLSLBuiltin record.
342static void buildOverloadContext(const Record *R, OverloadContext &Ctx) {
343 Ctx.Builtin = R->getValueAsString(FieldName: "Builtin");
344 Ctx.DetailFunc = R->getValueAsString(FieldName: "DetailFunc");
345 Ctx.Body = R->getValueAsString(FieldName: "Body");
346 Ctx.FuncName = R->getValueAsString(FieldName: "Name");
347 Ctx.IsConstexpr = R->getValueAsBit(FieldName: "IsConstexpr");
348 Ctx.IsConvergent = R->getValueAsBit(FieldName: "IsConvergent");
349
350 // Note use of 16-bit fixed types in the overload context.
351 auto Update16BitFlags = [&Ctx](const Record *Rec) {
352 const Record *ElemTy = getElementTypeRecord(R: Rec);
353 Ctx.Uses16BitType |= ElemTy->getValueAsBit(FieldName: "Is16Bit");
354 Ctx.UsesConditionally16BitType |=
355 ElemTy->getValueAsBit(FieldName: "IsConditionally16Bit");
356 };
357
358 // Resolve return and argument types.
359 const Record *RetRec = R->getValueAsDef(FieldName: "ReturnType");
360 Ctx.RetType = TypeInfo::resolve(Rec: RetRec);
361 if (Ctx.RetType.Kind == TK_FixedType)
362 Update16BitFlags(RetRec);
363
364 std::vector<const Record *> ArgRecords = R->getValueAsListOfDefs(FieldName: "Args");
365 std::vector<StringRef> ParamNames = R->getValueAsListOfStrings(FieldName: "ParamNames");
366
367 for (const auto &[I, Arg] : llvm::enumerate(First&: ArgRecords)) {
368 TypeInfo TI = TypeInfo::resolve(Rec: Arg);
369 if (I < ParamNames.size())
370 TI.Name = ParamNames[I];
371 if (TI.Kind == TK_FixedType)
372 Update16BitFlags(Arg);
373 Ctx.Args.push_back(Elt: TI);
374 }
375}
376
377/// Build the worklist of element types to emit overloads for, sorted in
378/// canonical order (see getTypeSortPriority).
379static void buildWorklist(const Record *R,
380 SmallVectorImpl<TypeWorkItem> &Worklist,
381 const OverloadContext &Ctx) {
382 const Record *AvailRec = R->getValueAsDef(FieldName: "Availability");
383 std::string Availability = getVersionString(SM: AvailRec);
384 bool AvailabilityIsAtLeastSM6_2 = AvailRec->getValueAsInt(FieldName: "Major") > 6 ||
385 (AvailRec->getValueAsInt(FieldName: "Major") == 6 &&
386 AvailRec->getValueAsInt(FieldName: "Minor") >= 2);
387
388 std::vector<const Record *> VaryingTypeRecords =
389 R->getValueAsListOfDefs(FieldName: "VaryingTypes");
390
391 // Populate the availability and guard fields of a TypeWorkItem based on
392 // whether the type is 16-bit, conditionally 16-bit, or a regular type.
393 auto SetAvailability = [&](TypeWorkItem &Item, bool Is16Bit,
394 bool IsCond16Bit) {
395 Item.NeedsIfdefGuard = Is16Bit;
396 if (Is16Bit || IsCond16Bit) {
397 if (AvailabilityIsAtLeastSM6_2) {
398 Item.Availability = Availability;
399 } else {
400 Item.Availability = SM6_2;
401 Item.Use16BitAvail = IsCond16Bit;
402
403 // Note: If Availability = x where x < 6.2 and a half type is used,
404 // neither _HLSL_AVAILABILITY(shadermodel, x) nor
405 // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) are correct:
406 //
407 // _HLSL_AVAILABILITY(shadermodel, x) will set the availbility for the
408 // half overload to x even when 16-bit types are enabled, but x < 6.2
409 // and 6.2 is required for 16-bit half.
410 //
411 // _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) will set the
412 // availability for the half overload to 6.2 when 16-bit types are
413 // enabled, but there will be no availability set when 16-bit types
414 // are not enabled.
415 //
416 // A possible solution to this is to make _HLSL_16BIT_AVAILABILITY
417 // accept 3 args: (shadermodel, X, Y) where X is the availability for
418 // the 16-bit half type overload (which will typically be 6.2), and Y is
419 // the availability for the non-16-bit half overload. However, this
420 // situation does not currently arise, so we just assert below that this
421 // case will never occur.
422 assert(
423 !(IsCond16Bit && !Availability.empty()) &&
424 "Can not handle availability for an intrinsic using half types and"
425 " which has an explicit shader model requirement older than 6.2");
426 }
427 } else {
428 Item.Availability = Availability;
429 }
430 };
431
432 // If no Varying types are specified, just add a single work item.
433 // This is for HLSLBuiltin records that don't use Varying types.
434 if (VaryingTypeRecords.empty()) {
435 TypeWorkItem Item;
436 SetAvailability(Item, Ctx.Uses16BitType, Ctx.UsesConditionally16BitType);
437 Worklist.push_back(Elt: Item);
438 return;
439 }
440
441 // Sort Varying types so that overloads are always emitted in canonical order.
442 llvm::sort(C&: VaryingTypeRecords, Comp: [](const Record *A, const Record *B) {
443 return getTypeSortPriority(ET: A) < getTypeSortPriority(ET: B);
444 });
445
446 // Add a work item for each Varying element type.
447 for (const Record *ElemTy : VaryingTypeRecords) {
448 TypeWorkItem Item;
449 Item.ElemType = ElemTy->getValueAsString(FieldName: "Name");
450 bool Is16Bit = Ctx.Uses16BitType || ElemTy->getValueAsBit(FieldName: "Is16Bit");
451 bool IsCond16Bit = Ctx.UsesConditionally16BitType ||
452 ElemTy->getValueAsBit(FieldName: "IsConditionally16Bit");
453 SetAvailability(Item, Is16Bit, IsCond16Bit);
454 Worklist.push_back(Elt: Item);
455 }
456}
457
458/// Emit a Doxygen documentation comment from the Doc field.
459static void emitDocComment(raw_ostream &OS, const Record *R) {
460 StringRef Doc = R->getValueAsString(FieldName: "Doc");
461 if (Doc.empty())
462 return;
463 Doc = Doc.trim();
464 SmallVector<StringRef> DocLines;
465 Doc.split(A&: DocLines, Separator: '\n');
466 for (StringRef Line : DocLines) {
467 if (Line.empty())
468 OS << "///\n";
469 else
470 OS << "/// " << Line << "\n";
471 }
472}
473
474/// Process the worklist: emit all shape variants for each type with
475/// availability annotations and #ifdef guards.
476static void emitWorklistOverloads(raw_ostream &OS, const OverloadContext &Ctx,
477 ArrayRef<TypeWorkItem> Worklist,
478 bool EmitScalarOverload,
479 ArrayRef<int64_t> VectorSizes,
480 ArrayRef<const Record *> MatrixDimensions) {
481 bool InIfdef = false;
482 for (const TypeWorkItem &Item : Worklist) {
483 if (Item.NeedsIfdefGuard && !InIfdef) {
484 OS << "#ifdef __HLSL_ENABLE_16_BIT\n";
485 InIfdef = true;
486 }
487
488 auto EmitAvail = [&]() {
489 if (!Item.Availability.empty())
490 emitAvailability(OS, Version: Item.Availability, Use16Bit: Item.Use16BitAvail);
491 };
492
493 if (EmitScalarOverload) {
494 EmitAvail();
495 emitScalarOverload(Ctx, ElemType: Item.ElemType);
496 }
497 for (int64_t N : VectorSizes) {
498 EmitAvail();
499 emitVectorOverload(Ctx, ElemType: Item.ElemType, VecSize: N);
500 }
501 for (const Record *MD : MatrixDimensions) {
502 EmitAvail();
503 emitMatrixOverload(Ctx, ElemType: Item.ElemType, Rows: MD->getValueAsInt(FieldName: "Rows"),
504 Cols: MD->getValueAsInt(FieldName: "Cols"));
505 }
506
507 if (InIfdef) {
508 bool NextIsUnguarded =
509 (&Item == &Worklist.back()) || !(&Item + 1)->NeedsIfdefGuard;
510 if (NextIsUnguarded) {
511 OS << "#endif\n";
512 InIfdef = false;
513 }
514 }
515
516 OS << "\n";
517 }
518}
519
520/// Emit all overloads for a single HLSLBuiltin record.
521static void emitBuiltinOverloads(raw_ostream &OS, const Record *R) {
522 OverloadContext Ctx(OS);
523 buildOverloadContext(R, Ctx);
524
525 SmallVector<TypeWorkItem> Worklist;
526 buildWorklist(R, Worklist, Ctx);
527
528 emitDocComment(OS, R);
529 OS << "// " << Ctx.FuncName << " overloads\n";
530
531 // Emit a scalar overload if a scalar Varying overload was requested.
532 // If no Varying types are used at all, emit a scalar overload to handle
533 // emitting a single overload for fixed-typed args or arg-less functions.
534 bool EmitScalarOverload = R->getValueAsBit(FieldName: "VaryingScalar") ||
535 R->getValueAsListOfDefs(FieldName: "VaryingTypes").empty();
536
537 std::vector<int64_t> VectorSizes = R->getValueAsListOfInts(FieldName: "VaryingVecSizes");
538 std::vector<const Record *> MatrixDimensions =
539 R->getValueAsListOfDefs(FieldName: "VaryingMatDims");
540
541 // Sort vector sizes and matrix dimensions for consistent output order.
542 llvm::sort(C&: VectorSizes);
543 llvm::sort(C&: MatrixDimensions, Comp: [](const Record *A, const Record *B) {
544 int RowA = A->getValueAsInt(FieldName: "Rows"), RowB = B->getValueAsInt(FieldName: "Rows");
545 if (RowA != RowB)
546 return RowA < RowB;
547 return A->getValueAsInt(FieldName: "Cols") < B->getValueAsInt(FieldName: "Cols");
548 });
549
550 emitWorklistOverloads(OS, Ctx, Worklist, EmitScalarOverload, VectorSizes,
551 MatrixDimensions);
552}
553
554/// Emit alias overloads for a single HLSLBuiltin record.
555/// Skips records that have inline bodies (DetailFunc or Body).
556static void emitAliasBuiltin(raw_ostream &OS, const Record *R) {
557 if (!R->getValueAsString(FieldName: "DetailFunc").empty() ||
558 !R->getValueAsString(FieldName: "Body").empty())
559 return;
560 emitBuiltinOverloads(OS, R);
561}
562
563/// Emit inline overloads for a single HLSLBuiltin record.
564/// Skips records that are pure alias declarations.
565static void emitInlineBuiltin(raw_ostream &OS, const Record *R) {
566 if (R->getValueAsString(FieldName: "DetailFunc").empty() &&
567 R->getValueAsString(FieldName: "Body").empty())
568 return;
569 emitBuiltinOverloads(OS, R);
570}
571
572void clang::EmitHLSLAliasIntrinsics(const RecordKeeper &Records,
573 raw_ostream &OS) {
574 OS << "// This file is auto-generated by clang-tblgen from "
575 "HLSLIntrinsics.td.\n";
576 OS << "// Do not edit this file directly.\n\n";
577
578 for (const Record *R : Records.getAllDerivedDefinitions(ClassName: "HLSLBuiltin"))
579 emitAliasBuiltin(OS, R);
580}
581
582void clang::EmitHLSLInlineIntrinsics(const RecordKeeper &Records,
583 raw_ostream &OS) {
584 OS << "// This file is auto-generated by clang-tblgen from "
585 "HLSLIntrinsics.td.\n";
586 OS << "// Do not edit this file directly.\n\n";
587
588 for (const Record *R : Records.getAllDerivedDefinitions(ClassName: "HLSLBuiltin"))
589 emitInlineBuiltin(OS, R);
590}
591