[clang] [HLSL] Implement TableGen for builtin HLSL intrinsics (PR #187610)
Rahul Joshi via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 19 18:08:41 PDT 2026
================
@@ -0,0 +1,586 @@
+//===--- 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) {
----------------
jurahul wrote:
nit: no {} for single-statement if/else
https://github.com/llvm/llvm-project/pull/187610
More information about the cfe-commits
mailing list