Skip to content

[HLSL] Implement SpirvType and SpirvOpaqueType #134034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

cassiebeckley
Copy link
Member

This implements the design proposed by Representing SpirvType in Clang's Type System. It creates HLSLInlineSpirvType as a new Type subclass, and __hlsl_spirv_type as a new builtin type template to create such a type.

This new type is lowered to the spirv.Type target extension type, as described in Target Extension Types for Inline SPIR-V and Decorated Types.

This implements the design proposed by [Representing SpirvType in
Clang's Type System](llvm/wg-hlsl#181). It
creates `HLSLInlineSpirvType` as a new `Type` subclass, and
`__hlsl_spirv_type` as a new builtin type template to create such a
type.

This new type is lowered to the `spirv.Type` target extension type, as
described in [Target Extension Types for Inline SPIR-V and Decorated
Types](https://github.com/llvm/wg-hlsl/blob/main/proposals/0017-inline-spirv-and-decorated-types.md).
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:modules C++20 modules and Clang Header Modules clang:codegen IR generation bugs: mangling, exceptions, etc. clang:as-a-library libclang and C++ API debuginfo HLSL HLSL Language Support labels Apr 2, 2025
@cassiebeckley
Copy link
Member Author

@s-perron @Keenuts

@llvmbot
Copy link
Member

llvmbot commented Apr 2, 2025

@llvm/pr-subscribers-debuginfo
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-hlsl
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-x86

Author: Cassandra Beckley (cassiebeckley)

Changes

This implements the design proposed by Representing SpirvType in Clang's Type System. It creates HLSLInlineSpirvType as a new Type subclass, and __hlsl_spirv_type as a new builtin type template to create such a type.

This new type is lowered to the spirv.Type target extension type, as described in Target Extension Types for Inline SPIR-V and Decorated Types.


Patch is 74.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134034.diff

51 Files Affected:

  • (modified) clang/include/clang-c/Index.h (+2-1)
  • (modified) clang/include/clang/AST/ASTContext.h (+5)
  • (modified) clang/include/clang/AST/ASTNodeTraverser.h (+18)
  • (modified) clang/include/clang/AST/PropertiesBase.td (+1)
  • (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+11)
  • (modified) clang/include/clang/AST/Type.h (+141-1)
  • (modified) clang/include/clang/AST/TypeLoc.h (+19)
  • (modified) clang/include/clang/AST/TypeProperties.td (+18)
  • (modified) clang/include/clang/Basic/BuiltinTemplates.td (+15-3)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
  • (modified) clang/include/clang/Basic/TypeNodes.td (+1)
  • (modified) clang/include/clang/Serialization/ASTRecordReader.h (+2)
  • (modified) clang/include/clang/Serialization/ASTRecordWriter.h (+14)
  • (modified) clang/include/clang/Serialization/TypeBitCodes.def (+1)
  • (modified) clang/lib/AST/ASTContext.cpp (+59)
  • (modified) clang/lib/AST/ASTImporter.cpp (+42)
  • (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+17)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+39-1)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+5)
  • (modified) clang/lib/AST/Type.cpp (+14)
  • (modified) clang/lib/AST/TypePrinter.cpp (+48)
  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+8)
  • (modified) clang/lib/CodeGen/CGDebugInfo.h (+1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+2)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+6)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+2)
  • (modified) clang/lib/CodeGen/Targets/SPIR.cpp (+89-1)
  • (modified) clang/lib/Headers/CMakeLists.txt (+1)
  • (modified) clang/lib/Headers/hlsl.h (+4)
  • (added) clang/lib/Headers/hlsl/hlsl_spirv.h (+30)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+1)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+19-2)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+102-1)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+2)
  • (modified) clang/lib/Sema/SemaType.cpp (+1)
  • (modified) clang/lib/Sema/TreeTransform.h (+7)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+9)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+4)
  • (added) clang/test/AST/HLSL/Inputs/pch_spirv_type.hlsl (+6)
  • (added) clang/test/AST/HLSL/ast-dump-SpirvType.hlsl (+27)
  • (added) clang/test/AST/HLSL/pch_spirv_type.hlsl (+17)
  • (modified) clang/test/AST/HLSL/vector-alias.hlsl (+52-53)
  • (added) clang/test/CodeGenHLSL/inline/SpirvType.alignment.hlsl (+16)
  • (added) clang/test/CodeGenHLSL/inline/SpirvType.dx.error.hlsl (+12)
  • (added) clang/test/CodeGenHLSL/inline/SpirvType.hlsl (+68)
  • (added) clang/test/CodeGenHLSL/inline/SpirvType.incomplete.hlsl (+14)
  • (added) clang/test/CodeGenHLSL/inline/SpirvType.literal.error.hlsl (+11)
  • (modified) clang/tools/libclang/CIndex.cpp (+5)
  • (modified) clang/tools/libclang/CXType.cpp (+1)
  • (modified) clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp (+59-13)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 38e2417dcd181..757f8a3afc758 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3034,7 +3034,8 @@ enum CXTypeKind {
 
   /* HLSL Types */
   CXType_HLSLResource = 179,
-  CXType_HLSLAttributedResource = 180
+  CXType_HLSLAttributedResource = 180,
+  CXType_HLSLInlineSpirv = 181
 };
 
 /**
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a24f30815e6b9..c62f9f7672010 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -260,6 +260,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
       DependentBitIntTypes;
   mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
   llvm::FoldingSet<HLSLAttributedResourceType> HLSLAttributedResourceTypes;
+  llvm::FoldingSet<HLSLInlineSpirvType> HLSLInlineSpirvTypes;
 
   mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;
 
@@ -1795,6 +1796,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
       QualType Wrapped, QualType Contained,
       const HLSLAttributedResourceType::Attributes &Attrs);
 
+  QualType getHLSLInlineSpirvType(uint32_t Opcode, uint32_t Size,
+                                  uint32_t Alignment,
+                                  ArrayRef<SpirvOperand> Operands);
+
   QualType
   getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
                                unsigned Index,
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index f086d8134a64b..fd9108221590e 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -450,6 +450,24 @@ class ASTNodeTraverser
     if (!Contained.isNull())
       Visit(Contained);
   }
+  void VisitHLSLInlineSpirvType(const HLSLInlineSpirvType *T) {
+    for (auto &Operand : T->getOperands()) {
+      using SpirvOperandKind = SpirvOperand::SpirvOperandKind;
+
+      switch (Operand.getKind()) {
+      case SpirvOperandKind::kConstantId:
+      case SpirvOperandKind::kLiteral:
+        break;
+
+      case SpirvOperandKind::kTypeId:
+        Visit(Operand.getResultType());
+        break;
+
+      default:
+        llvm_unreachable("Invalid SpirvOperand kind!");
+      }
+    }
+  }
   void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {}
   void
   VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 5171555008ac9..7d5e6671fec7d 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -147,6 +147,7 @@ def UInt64 : CountPropertyType<"uint64_t">;
 def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
 def VectorKind : EnumPropertyType<"VectorKind">;
 def TypeCoupledDeclRefInfo : PropertyType;
+def HLSLSpirvOperand : PropertyType<"SpirvOperand"> { let PassByReference = 1; }
 
 def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
   let BufferElementTypes = [ QualType ];
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 0530996ed20d3..255e39a46db09 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1154,6 +1154,14 @@ DEF_TRAVERSE_TYPE(BTFTagAttributedType,
 DEF_TRAVERSE_TYPE(HLSLAttributedResourceType,
                   { TRY_TO(TraverseType(T->getWrappedType())); })
 
+DEF_TRAVERSE_TYPE(HLSLInlineSpirvType, {
+  for (auto &Operand : T->getOperands()) {
+    if (Operand.isConstant() || Operand.isType()) {
+      TRY_TO(TraverseType(Operand.getResultType()));
+    }
+  }
+})
+
 DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); })
 
 DEF_TRAVERSE_TYPE(MacroQualifiedType,
@@ -1457,6 +1465,9 @@ DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
 DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType,
                      { TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
 
+DEF_TRAVERSE_TYPELOC(HLSLInlineSpirvType,
+                     { TRY_TO(TraverseType(TL.getType())); })
+
 DEF_TRAVERSE_TYPELOC(ElaboratedType, {
   if (TL.getQualifierLoc()) {
     TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index cfd417068abb7..f351e68d5297d 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2652,6 +2652,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   bool isHLSLSpecificType() const; // Any HLSL specific type
   bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type
   bool isHLSLAttributedResourceType() const;
+  bool isHLSLInlineSpirvType() const;
   bool isHLSLResourceRecord() const;
   bool isHLSLIntangibleType()
       const; // Any HLSL intangible type (builtin, array, class)
@@ -6330,6 +6331,140 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
   findHandleTypeOnResource(const Type *RT);
 };
 
+/// Instances of this class represent operands to a SPIR-V type instruction.
+class SpirvOperand {
+public:
+  enum SpirvOperandKind : unsigned char {
+    kInvalid,    ///< Uninitialized.
+    kConstantId, ///< Integral value to represent as a SPIR-V OpConstant
+                 ///< instruction ID.
+    kLiteral,    ///< Integral value to represent as an immediate literal.
+    kTypeId,     ///< Type to represent as a SPIR-V type ID.
+
+    kMax,
+  };
+
+private:
+  SpirvOperandKind Kind = kInvalid;
+
+  QualType ResultType;
+  llvm::APInt Value; // Signedness of constants is represented by ResultType.
+
+public:
+  SpirvOperand() : Kind(kInvalid), ResultType() {}
+
+  SpirvOperand(SpirvOperandKind Kind, QualType ResultType, llvm::APInt Value)
+      : Kind(Kind), ResultType(ResultType), Value(Value) {}
+
+  SpirvOperand(const SpirvOperand &Other) { *this = Other; }
+  ~SpirvOperand() {}
+
+  SpirvOperand &operator=(const SpirvOperand &Other) {
+    this->Kind = Other.Kind;
+    this->ResultType = Other.ResultType;
+    this->Value = Other.Value;
+    return *this;
+  }
+
+  bool operator==(const SpirvOperand &Other) const {
+    return Kind == Other.Kind && ResultType == Other.ResultType &&
+           Value == Other.Value;
+  }
+
+  bool operator!=(const SpirvOperand &Other) const { return !(*this == Other); }
+
+  SpirvOperandKind getKind() const { return Kind; }
+
+  bool isValid() const { return Kind != kInvalid && Kind < kMax; }
+  bool isConstant() const { return Kind == kConstantId; }
+  bool isLiteral() const { return Kind == kLiteral; }
+  bool isType() const { return Kind == kTypeId; }
+
+  llvm::APInt getValue() const {
+    assert((isConstant() || isLiteral()) &&
+           "This is not an operand with a value!");
+    return Value;
+  }
+
+  QualType getResultType() const {
+    assert((isConstant() || isType()) &&
+           "This is not an operand with a result type!");
+    return ResultType;
+  }
+
+  static SpirvOperand createConstant(QualType ResultType, llvm::APInt Val) {
+    return SpirvOperand(kConstantId, ResultType, Val);
+  }
+
+  static SpirvOperand createLiteral(llvm::APInt Val) {
+    return SpirvOperand(kLiteral, QualType(), Val);
+  }
+
+  static SpirvOperand createType(QualType T) {
+    return SpirvOperand(kTypeId, T, llvm::APSInt());
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(Kind);
+    ID.AddPointer(ResultType.getAsOpaquePtr());
+    Value.Profile(ID);
+  }
+};
+
+/// Represents an arbitrary, user-specified SPIR-V type instruction.
+class HLSLInlineSpirvType final
+    : public Type,
+      public llvm::FoldingSetNode,
+      private llvm::TrailingObjects<HLSLInlineSpirvType, SpirvOperand> {
+  friend class ASTContext; // ASTContext creates these
+  friend TrailingObjects;
+
+private:
+  uint32_t Opcode;
+  uint32_t Size;
+  uint32_t Alignment;
+  size_t NumOperands;
+
+  HLSLInlineSpirvType(uint32_t Opcode, uint32_t Size, uint32_t Alignment,
+                      ArrayRef<SpirvOperand> Operands)
+      : Type(HLSLInlineSpirv, QualType(), TypeDependence::None), Opcode(Opcode),
+        Size(Size), Alignment(Alignment), NumOperands(Operands.size()) {
+    for (size_t I = 0; I < NumOperands; I++) {
+      getTrailingObjects<SpirvOperand>()[I] = Operands[I];
+    }
+  }
+
+public:
+  uint32_t getOpcode() const { return Opcode; }
+  uint32_t getSize() const { return Size; }
+  uint32_t getAlignment() const { return Alignment; }
+  ArrayRef<SpirvOperand> getOperands() const {
+    return {getTrailingObjects<SpirvOperand>(), NumOperands};
+  }
+
+  bool isSugared() const { return false; }
+  QualType desugar() const { return QualType(this, 0); }
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, Opcode, Size, Alignment, getOperands());
+  }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, uint32_t Opcode,
+                      uint32_t Size, uint32_t Alignment,
+                      ArrayRef<SpirvOperand> Operands) {
+    ID.AddInteger(Opcode);
+    ID.AddInteger(Size);
+    ID.AddInteger(Alignment);
+    for (auto &Operand : Operands) {
+      Operand.Profile(ID);
+    }
+  }
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == HLSLInlineSpirv;
+  }
+};
+
 class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
   friend class ASTContext; // ASTContext creates these
 
@@ -8458,13 +8593,18 @@ inline bool Type::isHLSLBuiltinIntangibleType() const {
 }
 
 inline bool Type::isHLSLSpecificType() const {
-  return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType();
+  return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType() ||
+         isHLSLInlineSpirvType();
 }
 
 inline bool Type::isHLSLAttributedResourceType() const {
   return isa<HLSLAttributedResourceType>(this);
 }
 
+inline bool Type::isHLSLInlineSpirvType() const {
+  return isa<HLSLInlineSpirvType>(this);
+}
+
 inline bool Type::isTemplateTypeParmType() const {
   return isa<TemplateTypeParmType>(CanonicalType);
 }
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 92661b8b13fe0..53c7ea8c65df2 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -973,6 +973,25 @@ class HLSLAttributedResourceTypeLoc
   }
 };
 
+struct HLSLInlineSpirvTypeLocInfo {
+  SourceLocation Loc;
+}; // Nothing.
+
+class HLSLInlineSpirvTypeLoc
+    : public ConcreteTypeLoc<UnqualTypeLoc, HLSLInlineSpirvTypeLoc,
+                             HLSLInlineSpirvType, HLSLInlineSpirvTypeLocInfo> {
+public:
+  SourceLocation getSpirvTypeLoc() const { return getLocalData()->Loc; }
+  void setSpirvTypeLoc(SourceLocation loc) const { getLocalData()->Loc = loc; }
+
+  SourceRange getLocalSourceRange() const {
+    return SourceRange(getSpirvTypeLoc(), getSpirvTypeLoc());
+  }
+  void initializeLocal(ASTContext &Context, SourceLocation loc) {
+    setSpirvTypeLoc(loc);
+  }
+};
+
 struct ObjCObjectTypeLocInfo {
   SourceLocation TypeArgsLAngleLoc;
   SourceLocation TypeArgsRAngleLoc;
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 391fd26a086f7..784c2104f1bb2 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -719,6 +719,24 @@ let Class = HLSLAttributedResourceType in {
   }]>;
 }
 
+let Class = HLSLInlineSpirvType in {
+  def : Property<"opcode", UInt32> {
+    let Read = [{ node->getOpcode() }];
+  }
+  def : Property<"size", UInt32> {
+    let Read = [{ node->getSize() }];
+  }
+  def : Property<"alignment", UInt32> {
+    let Read = [{ node->getAlignment() }];
+  }
+  def : Property<"operands", Array<HLSLSpirvOperand>> {
+    let Read = [{ node->getOperands() }];
+  }
+  def : Creator<[{
+    return ctx.getHLSLInlineSpirvType(opcode, size, alignment, operands);
+  }]>;
+}
+
 let Class = DependentAddressSpaceType in {
   def : Property<"pointeeType", QualType> {
     let Read = [{ node->getPointeeType() }];
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5b9672b395955 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -28,25 +28,37 @@ class BuiltinNTTP<string type_name> : TemplateArg<""> {
 }
 
 def SizeT : BuiltinNTTP<"size_t"> {}
+def Uint32T: BuiltinNTTP<"uint32_t"> {}
 
 class BuiltinTemplate<list<TemplateArg> template_head> {
   list<TemplateArg> TemplateHead = template_head;
 }
 
+class CPlusPlusBuiltinTemplate<list<TemplateArg> template_head> : BuiltinTemplate<template_head>;
+
+class HLSLBuiltinTemplate<list<TemplateArg> template_head> : BuiltinTemplate<template_head>;
+
 // template <template <class T, T... Ints> IntSeq, class T, T N>
-def __make_integer_seq : BuiltinTemplate<
+def __make_integer_seq : CPlusPlusBuiltinTemplate<
   [Template<[Class<"T">, NTTP<"T", "Ints", /*is_variadic=*/1>], "IntSeq">, Class<"T">, NTTP<"T", "N">]>;
 
 // template <size_t, class... T>
-def __type_pack_element : BuiltinTemplate<
+def __type_pack_element : CPlusPlusBuiltinTemplate<
   [SizeT, Class<"T", /*is_variadic=*/1>]>;
 
 // template <template <class... Args> BaseTemplate,
 //           template <class TypeMember> HasTypeMember,
 //           class HasNoTypeMember
 //           class... Ts>
-def __builtin_common_type : BuiltinTemplate<
+def __builtin_common_type : CPlusPlusBuiltinTemplate<
   [Template<[Class<"Args", /*is_variadic=*/1>], "BaseTemplate">,
    Template<[Class<"TypeMember">], "HasTypeMember">,
    Class<"HasNoTypeMember">,
    Class<"Ts", /*is_variadic=*/1>]>;
+
+// template <uint32_t Opcode,
+//           uint32_t Size,
+//           uint32_t Alignment,
+//           typename ...Operands>
+def __hlsl_spirv_type : HLSLBuiltinTemplate<
+[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 265bed2df43cf..287e139f02a2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12709,6 +12709,9 @@ def err_hlsl_expect_arg_const_int_one_or_neg_one: Error<
 def err_invalid_hlsl_resource_type: Error<
   "invalid __hlsl_resource_t type attributes">;
 
+def err_hlsl_spirv_only: Error<"%0 is only available for the SPIR-V target">;
+def err_hlsl_vk_literal_must_contain_constant: Error<"the argument to vk::Literal must be a vk::integral_constant">;
+
 // Layout randomization diagnostics.
 def err_non_designated_init_used : Error<
   "a randomized struct can only be initialized with a designated initializer">;
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index 7e550ca2992f3..567b8a5ca5a4d 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -94,6 +94,7 @@ def ElaboratedType : TypeNode<Type>, NeverCanonical;
 def AttributedType : TypeNode<Type>, NeverCanonical;
 def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
 def HLSLAttributedResourceType : TypeNode<Type>;
+def HLSLInlineSpirvType : TypeNode<Type>;
 def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
 def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
 def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h
index 7117b7246739b..79d33315d4fee 100644
--- a/clang/include/clang/Serialization/ASTRecordReader.h
+++ b/clang/include/clang/Serialization/ASTRecordReader.h
@@ -214,6 +214,8 @@ class ASTRecordReader
 
   TypeCoupledDeclRefInfo readTypeCoupledDeclRefInfo();
 
+  SpirvOperand readHLSLSpirvOperand();
+
   /// Read a declaration name, advancing Idx.
   // DeclarationName readDeclarationName(); (inherited)
   DeclarationNameLoc readDeclarationNameLoc(DeclarationName Name);
diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h
index 84d77e46016b7..9653b709d3ef5 100644
--- a/clang/include/clang/Serialization/ASTRecordWriter.h
+++ b/clang/include/clang/Serialization/ASTRecordWriter.h
@@ -151,6 +151,20 @@ class ASTRecordWriter
     writeBool(Info.isDeref());
   }
 
+  void writeHLSLSpirvOperand(SpirvOperand Op) {
+    QualType ResultType;
+    llvm::APInt Value;
+
+    if (Op.isConstant() || Op.isType())
+      ResultType = Op.getResultType();
+    if (Op.isConstant() || Op.isLiteral())
+      Value = Op.getValue();
+
+    Record->push_back(Op.getKind());
+    writeQualType(ResultType);
+    writeAPInt(Value);
+  }
+
   /// Emit a source range.
   void AddSourceRange(SourceRange Range, LocSeq *Seq = nullptr) {
     return Writer->AddSourceRange(Range, *Record, Seq);
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def
index 3c78b87805010..b8cde2e370960 100644
--- a/clang/include/clang/Serialization/TypeBitCodes.def
+++ b/clang/include/clang/Serialization/TypeBitCodes.def
@@ -68,5 +68,6 @@ TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56)
 TYPE_BIT_CODE(CountAttributed, COUNT_ATTRIBUTED, 57)
 TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
 TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59)
+TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
 
 #undef TYPE_BIT_CODE
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 552b5823add36..fb6a7b5a34175 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2454,6 +2454,19 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
     return getTypeInfo(
         cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr());
 
+  case Type::HLSLInlineSpirv: {
+    const auto *ST = cast<HLSLInlineSpirvType>(T);
+    // Size is specified in bytes, convert to bits
+    Width = ST->getSize() * 8;
+    Align = ST->getAlignment();
+    if (Width == 0 && Align == 0) {
+      // We are defaulting to laying out opaque SPIR-V types as 32-bit ints.
+      Width = 32;
+      Align = 32;
+    }
+    break;
+  }
+
   case Type::Atomic: {
     // Start with the base type information.
     TypeInfo Info = getTypeInfo(cast<AtomicType>(T)->getValueType());
@@ -3458,6 +3471,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
     return;
   }
   case Type::HLSLAttributedResource:
+  case Type::HLSLInlineSpirv:
     llvm_unreachable("should never get here");
     break;
   case Type::DeducedTemplateSpecialization:
@@ -4179,6 +4193,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
   case Type::DependentBitInt:
   case Type::ArrayParameter:
   case Type::HLSLAttributedResource:
+  case Type::HLSLInlineSpirv:
     llvm_unreachable("type should never be variably-modified");
 
   // These types can be variably-modified but should never need to
@@ -5444,6 +5459,31 @@ QualType ASTContext::getHLSLAttributedResourceType(
 
   return QualType(Ty, 0);
 }
+
+QualType ASTContext::getHLSLInlineSpirvType(uint32_t Opcode, uint32_t Size,
+                                            uint32_t Alignment,
+                                            ArrayRef<SpirvOperand> Operands) {
+  llvm::FoldingSetNodeID ID;
+  HLSLInlineSpirvType::Profile(ID, Opcode, Size, Alignment, Operands);
+
+  void *InsertPos = nullptr;
+  HLSLInlineSpirvType *Ty =
+      HLSLInlineSpirvTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (Ty)
+    return QualType(Ty, 0);
+
+  unsigned size = sizeof(HLSLInlineSpirvType);
+  size += Operands.size() * sizeof(SpirvOperand);
+  void *mem = Allocate(size, alignof(HLSLInlineSpirvType));
+
+  Ty = new (mem) HLSLInlineSpirvType(Opcode, Size, Alignment, Operands);
+
+  Types.push_back(Ty);
+  HLSLInlineSpirvTypes.InsertNode(Ty, InsertPos);
+
+  return QualType(Ty, 0);
+}
+
 /// Retrieve a substitution-result type.
 QualType ASTContext::getSubstTemplateTypeParmType(
     QualType Replacement, Decl *AssociatedDecl, unsigned Index,
@@ -9335,6 +9375,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
     return;
 
   case Type::HLSLAttributedResource:
+  case Type::HLSLInlineSpirv:
...
[truncated]

Copy link

github-actions bot commented Apr 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@cassiebeckley
Copy link
Member Author

@philnik777 fyi for the changes to builtin templates

@llvm-beanz llvm-beanz self-assigned this Apr 7, 2025
@s-perron s-perron requested review from llvm-beanz and hekota April 16, 2025 18:18
Copy link
Contributor

@s-perron s-perron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some extra testing and playing with it. It seems to be working. However, I do not know enough about how things are done in clang to know if this is the best way to do it. It look reasonable to me. Others will have to review the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 clang:as-a-library libclang and C++ API clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category debuginfo HLSL HLSL Language Support
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

4 participants