Skip to content
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

[HLSL] Make HLSLAttributedResourceType canonical and add code paths to convert HLSL types to DirectX target types #110327

Merged
merged 14 commits into from
Oct 15, 2024

Conversation

hekota
Copy link
Member

@hekota hekota commented Sep 27, 2024

Translates RWBuffer and StructuredBuffer resources buffer types to DirectX target types dx.TypedBuffer and dx.RawBuffer.

Includes a change of HLSLAttributesResourceType from 'sugar' type to full canonical type. This is required for codegen and other clang infrastructure to work property on HLSL resource types.

Fixes #95952 (part 2/2)

@hekota hekota changed the title [HLSL] Make HLSLAttributesResourceType cannonical and add code paths to convert HLSL types to DirectX target types [HLSL] Make HLSLAttributedResourceType canonical and add code paths to convert HLSL types to DirectX target types Sep 27, 2024
@hekota hekota marked this pull request as ready for review September 27, 2024 20:55
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen backend:DirectX HLSL HLSL Language Support labels Sep 27, 2024
@llvmbot
Copy link

llvmbot commented Sep 27, 2024

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-backend-directx

Author: Helena Kotas (hekota)

Changes

Translates RWBuffer and StructuredBuffer resources buffer types to DirectX target types dx.TypedBuffer and dx.RawBuffer.

Includes a change of HLSLAttributesResourceType from 'sugar' type to full canonical type. This is required for codegen and other clang infrastructure to work property on HLSL resource types.

Depends on PR llvm/llvm-project#110079 (test will fail until merged).

Fixes #95952 (part 2/2)


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

27 Files Affected:

  • (modified) clang/include/clang/AST/Type.h (+23-11)
  • (modified) clang/include/clang/Basic/TypeNodes.td (+1-1)
  • (modified) clang/lib/AST/ASTContext.cpp (+23-2)
  • (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+2-13)
  • (modified) clang/lib/AST/DeclCXX.cpp (+3-3)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+24)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+26)
  • (modified) clang/lib/AST/Type.cpp (+5)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+1)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+3)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+6)
  • (modified) clang/lib/CodeGen/Targets/DirectX.cpp (+39-10)
  • (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (-2)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+3)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+17)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+7)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+11)
  • (modified) clang/test/AST/HLSL/RWBuffer-AST.hlsl (-2)
  • (modified) clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl (+14)
  • (modified) clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl (+14)
  • (modified) clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl (+50-6)
  • (modified) clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl (+5-8)
  • (modified) clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl (+3-6)
  • (modified) clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl (+3-6)
  • (modified) clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl (+6-11)
  • (modified) clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl (-2)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index dc87b84153e74a..f97217dead2139 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2659,6 +2659,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
 #include "clang/Basic/HLSLIntangibleTypes.def"
   bool isHLSLSpecificType() const; // Any HLSL specific type
   bool isHLSLIntangibleType() const; // Any HLSL intangible type
+  bool isHLSLAttributedResourceType() const;
 
   /// Determines if this type, which must satisfy
   /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -6180,6 +6181,14 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
         : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
 
     Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
+
+    friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
+      return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
+             std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
+    }
+    friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
+      return !(LHS == RHS);
+    }
   };
 
 private:
@@ -6189,18 +6198,19 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
   QualType ContainedType;
   const Attributes Attrs;
 
-  HLSLAttributedResourceType(QualType Canon, QualType Wrapped,
-                             QualType Contained, const Attributes &Attrs)
-      : Type(HLSLAttributedResource, Canon, Wrapped->getDependence()),
+  HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
+                             const Attributes &Attrs)
+      : Type(HLSLAttributedResource, QualType(), Wrapped->getDependence()),
         WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}
 
 public:
   QualType getWrappedType() const { return WrappedType; }
   QualType getContainedType() const { return ContainedType; }
+  bool hasContainedType() const { return !ContainedType.isNull(); }
   const Attributes &getAttrs() const { return Attrs; }
 
-  bool isSugared() const { return true; }
-  QualType desugar() const { return getWrappedType(); }
+  bool isSugared() const { return false; }
+  QualType desugar() const { return QualType(this, 0); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
     Profile(ID, WrappedType, ContainedType, Attrs);
@@ -8344,17 +8354,19 @@ inline bool Type::isOpenCLSpecificType() const {
   }
 #include "clang/Basic/HLSLIntangibleTypes.def"
 
-inline bool Type::isHLSLSpecificType() const {
+inline bool Type::isHLSLIntangibleType() const {
 #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
   return
 #include "clang/Basic/HLSLIntangibleTypes.def"
-      false; // end boolean or operation
+      isHLSLAttributedResourceType();
 }
 
-inline bool Type::isHLSLIntangibleType() const {
-  // All HLSL specific types are currently intangible type as well, but that
-  // might change in the future.
-  return isHLSLSpecificType();
+inline bool Type::isHLSLSpecificType() const {
+  return isHLSLIntangibleType() || isa<HLSLAttributedResourceType>(this);
+}
+
+inline bool Type::isHLSLAttributedResourceType() const {
+  return isa<HLSLAttributedResourceType>(this);
 }
 
 inline bool Type::isTemplateTypeParmType() const {
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index 8cca392cddc174..7e550ca2992f35 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -93,7 +93,7 @@ def EnumType : TypeNode<TagType>, LeafType;
 def ElaboratedType : TypeNode<Type>, NeverCanonical;
 def AttributedType : TypeNode<Type>, NeverCanonical;
 def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
-def HLSLAttributedResourceType : TypeNode<Type>, NeverCanonical;
+def HLSLAttributedResourceType : TypeNode<Type>;
 def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
 def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
 def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cda8b02cc8499a..b41620505a0b16 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3437,6 +3437,9 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
     OS << II->getLength() << II->getName();
     return;
   }
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
+    break;
   case Type::DeducedTemplateSpecialization:
   case Type::Auto:
 #define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
@@ -4108,6 +4111,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
   case Type::BitInt:
   case Type::DependentBitInt:
   case Type::ArrayParameter:
+  case Type::HLSLAttributedResource:
     llvm_unreachable("type should never be variably-modified");
 
   // These types can be variably-modified but should never need to
@@ -5233,9 +5237,8 @@ QualType ASTContext::getHLSLAttributedResourceType(
   if (Ty)
     return QualType(Ty, 0);
 
-  QualType Canon = getCanonicalType(Wrapped);
   Ty = new (*this, alignof(HLSLAttributedResourceType))
-      HLSLAttributedResourceType(Canon, Wrapped, Contained, Attrs);
+      HLSLAttributedResourceType(Wrapped, Contained, Attrs);
 
   Types.push_back(Ty);
   HLSLAttributedResourceTypes.InsertNode(Ty, InsertPos);
@@ -9106,6 +9109,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
   case Type::DeducedTemplateSpecialization:
     return;
 
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("unexpected type");
+
   case Type::ArrayParameter:
   case Type::Pipe:
 #define ABSTRACT_TYPE(KIND, BASE)
@@ -11533,6 +11539,18 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
       return {};
     return LHS;
   }
+  case Type::HLSLAttributedResource: {
+    const HLSLAttributedResourceType *LHSTy =
+        LHS->castAs<HLSLAttributedResourceType>();
+    const HLSLAttributedResourceType *RHSTy =
+        RHS->castAs<HLSLAttributedResourceType>();
+
+    if (LHSTy->getWrappedType() == RHSTy->getWrappedType() &&
+        LHSTy->getContainedType() == RHSTy->getContainedType() &&
+        LHSTy->getAttrs() == RHSTy->getAttrs())
+      return LHS;
+    return {};
+  }
   }
 
   llvm_unreachable("Invalid Type::Class!");
@@ -13672,6 +13690,9 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
         TX->getDepth(), TX->getIndex(), TX->isParameterPack(),
         getCommonDecl(TX->getDecl(), TY->getDecl()));
   }
+  case Type::HLSLAttributedResource: {
+    llvm_unreachable("not yet implemented");
+  }
   }
   llvm_unreachable("Unknown Type Class");
 }
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 21f0562f9d72ae..120ddc0f26c0d7 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -802,16 +802,6 @@ static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
   return true;
 }
 
-// Determine structural equivalence of two instances of
-// HLSLAttributedResourceType::Attributes
-static bool
-IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
-                         const HLSLAttributedResourceType::Attributes &Attrs1,
-                         const HLSLAttributedResourceType::Attributes &Attrs2) {
-  return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) ==
-         std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer);
-}
-
 /// Determine structural equivalence of two types.
 static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
                                      QualType T1, QualType T2) {
@@ -1115,9 +1105,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
             Context, cast<HLSLAttributedResourceType>(T1)->getContainedType(),
             cast<HLSLAttributedResourceType>(T2)->getContainedType()))
       return false;
-    if (!IsStructurallyEquivalent(
-            Context, cast<HLSLAttributedResourceType>(T1)->getAttrs(),
-            cast<HLSLAttributedResourceType>(T2)->getAttrs()))
+    if (cast<HLSLAttributedResourceType>(T1)->getAttrs() !=
+        cast<HLSLAttributedResourceType>(T2)->getAttrs())
       return false;
     break;
 
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 01143391edab40..8d0b5171fc9ae3 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1411,10 +1411,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
         Ty = Ty->getArrayElementTypeNoTypeQual();
 
       Ty = Ty->getUnqualifiedDesugaredType();
-      if (Ty->isBuiltinType())
-        data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
-      else if (const RecordType *RT = dyn_cast<RecordType>(Ty))
+      if (const RecordType *RT = dyn_cast<RecordType>(Ty))
         data().IsHLSLIntangible |= RT->getAsCXXRecordDecl()->isHLSLIntangible();
+      else
+        data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
     }
   }
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 960eae36ed1f51..dab54133248393 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12163,6 +12163,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
   case Type::ObjCInterface:
   case Type::ObjCObjectPointer:
   case Type::Pipe:
+  case Type::HLSLAttributedResource:
     // Classify all other types that don't fit into the regular
     // classification the same way.
     return GCCTypeClass::None;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b6e1da0c3192da..9bda078d9fac81 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4488,6 +4488,30 @@ void CXXNameMangler::mangleType(const ArrayParameterType *T) {
   mangleType(cast<ConstantArrayType>(T));
 }
 
+void CXXNameMangler::mangleType(const HLSLAttributedResourceType *T) {
+  mangleType(T->getWrappedType());
+  const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
+  switch (Attrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+    Out << 'U';
+    break;
+  case llvm::dxil::ResourceClass::SRV:
+    Out << 'T';
+    break;
+  case llvm::dxil::ResourceClass::CBuffer:
+    Out << 'C';
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    Out << 'S';
+    break;
+  }
+  mangleNumber(Attrs.IsROV);
+  mangleNumber(Attrs.RawBuffer);
+
+  if (!T->hasContainedType())
+    mangleType(T->getContainedType());
+}
+
 void CXXNameMangler::mangleIntegerLiteral(QualType T,
                                           const llvm::APSInt &Value) {
   //  <expr-primary> ::= L <type> <value number> E # integer literal
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 7b069c66aed598..16df5c99c623ce 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -32,6 +32,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/CRC.h"
+#include "llvm/Support/DXILABI.h"
 #include "llvm/Support/MD5.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/StringSaver.h"
@@ -3753,6 +3754,31 @@ void MicrosoftCXXNameMangler::mangleType(const DependentBitIntType *T,
   Error(Range.getBegin(), "DependentBitInt type") << Range;
 }
 
+void MicrosoftCXXNameMangler::mangleType(const HLSLAttributedResourceType *T,
+                                         Qualifiers, SourceRange Range) {
+  mangleType(T->getWrappedType(), SourceRange(), QMM_Escape);
+  const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
+  switch (Attrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+    Out << 'U';
+    break;
+  case llvm::dxil::ResourceClass::SRV:
+    Out << 'T';
+    break;
+  case llvm::dxil::ResourceClass::CBuffer:
+    Out << 'C';
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    Out << 'S';
+    break;
+  }
+  mangleNumber(Attrs.IsROV);
+  mangleNumber(Attrs.RawBuffer);
+
+  if (T->hasContainedType())
+    mangleType(T->getContainedType(), SourceRange(), QMM_Escape);
+}
+
 // <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
 //                       <virtual-adjustment>
 // <no-adjustment>      ::= A # private near
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a55e6c8bf02611..99fc3c676c2c98 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4575,6 +4575,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
     return Cache::get(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return Cache::get(cast<PipeType>(T)->getElementType());
+  case Type::HLSLAttributedResource:
+    return Cache::get(cast<HLSLAttributedResourceType>(T)->getWrappedType());
   }
 
   llvm_unreachable("unhandled type class");
@@ -4664,6 +4666,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
     return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm_unreachable("unhandled type class");
@@ -4846,6 +4850,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
   case Type::BitInt:
   case Type::DependentBitInt:
   case Type::ArrayParameter:
+  case Type::HLSLAttributedResource:
     return false;
   }
   llvm_unreachable("bad type kind!");
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index eda96f3e352ce3..ddbd5e2f1aa311 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -296,6 +296,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
     case Type::ObjCObject:
     case Type::ObjCInterface:
     case Type::ArrayParameter:
+    case Type::HLSLAttributedResource:
       return TEK_Aggregate;
 
     // We operate on atomic values according to their underlying type.
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 77c1b27cebf401..bacb0a04cb7c86 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -742,6 +742,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
     ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
     break;
   }
+  case Type::HLSLAttributedResource:
+    ResultType = CGM.getHLSLRuntime().convertHLSLSpecificType(Ty);
+    break;
   }
 
   assert(ResultType && "Didn't convert a type?");
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index dcc35d5689831e..8533ccb2129c34 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3943,6 +3943,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
     // abi::__pointer_to_member_type_info.
     VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
     break;
+
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm::Constant *VTable = nullptr;
@@ -4205,6 +4208,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
   case Type::Atomic:
     // No fields, at least for the moment.
     break;
+
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 13da2c630629d7..cf6ac849777369 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -29,19 +29,48 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
 
 llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
                                                   const Type *Ty) const {
-  auto *BuiltinTy = dyn_cast<BuiltinType>(Ty);
-  if (!BuiltinTy || BuiltinTy->getKind() != BuiltinType::HLSLResource)
+  auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
+  if (!ResType)
     return nullptr;
 
   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
-  // FIXME: translate __hlsl_resource_t to target("dx.TypedBuffer", <4 x float>,
-  // 1, 0, 0) only for now (RWBuffer<float4>); more work us needed to determine
-  // the target ext type and its parameters based on the handle type
-  // attributes (not yet implemented)
-  llvm::FixedVectorType *ElemType =
-      llvm::FixedVectorType::get(llvm::Type::getFloatTy(Ctx), 4);
-  unsigned Flags[] = {/*IsWriteable*/ 1, /*IsROV*/ 0, /*IsSigned*/ 0};
-  return llvm::TargetExtType::get(Ctx, "dx.TypedBuffer", {ElemType}, Flags);
+  const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
+  switch (ResAttrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+  case llvm::dxil::ResourceClass::SRV: {
+    // convert element type
+    QualType ContainedTy = ResType->getContainedType();
+    llvm::Type *ElemType = nullptr;
+    if (!ContainedTy.isNull())
+      ElemType = CGM.getTypes().ConvertType(ContainedTy);
+
+    if (ResAttrs.RawBuffer) {
+      // RawBuffer needs element type
+      if (ContainedTy.isNull())
+        return nullptr;
+      return llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {ElemType},
+                                      {/*IsWriteable*/ ResAttrs.ResourceClass ==
+                                           llvm::dxil::ResourceClass::UAV,
+                                       /*IsROV*/ ResAttrs.IsROV});
+    }
+
+    // TypedBuffer needs element type
+    if (ContainedTy.isNull())
+      return nullptr;
+    return llvm::TargetExtType::get(
+        Ctx, "dx.TypedBuffer", {ElemType},
+        {/*IsWriteable*/ ResAttrs.ResourceClass ==
+             llvm::dxil::ResourceClass::UAV,
+         /*IsROV*/ ResAttrs.IsROV,
+         /*IsSigned*/ ContainedTy->isSignedIntegerType()});
+  }
+  case llvm::dxil::ResourceClass::CBuffer:
+    llvm_unreachable("dx.CBuffer handles are not implemented yet");
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    llvm_unreachable("dx.Sampler handles are not implemented yet");
+    break;
+  }
 }
 
 } // namespace
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index ca521dc0bcd26b..d2f032dfd5e9ba 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -211,8 +211,6 @@ struct BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
     if (Record->isCompleteDefinition())
       return *this;
-    assert(Fields.count("h") > 0 &&
-           "Subscript operator must be added after the handle.");
 
     FieldDecl *Handle = Fields["h"];
     ASTContext &AST = Record->getASTContext();
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index f3f62474d06441..e5db11369221a4 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
     // Array parameter types are treated as fundamental types.
     case Type::ArrayParameter:
       break;
+
+    case Type::HLSLAttributedResource:
+      T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
     }
 
     if (Queue.empty())
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0c1e054f7c30a4..16c2d0f74a3d34 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1785,6 +1785,23 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
     return ICS;
   }
 
+  if (S.getLangOpts().HLSL && ToType->isHLSLAttributedResourceType() &&
+      FromType->isHLSLAttributedResourceType()) {
+    auto *ToResType = cast<HLSLAttributedResourceType>(ToType);
+    auto *FromResType = cast<HLSLAttributedResourceType>(FromType);
+    if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
+                                         FromResType->getWrappedType()) &&
+        S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
+                                         FromResType->getContainedType()) &&
+        ToResT...
[truncated]

@llvmbot
Copy link

llvmbot commented Sep 27, 2024

@llvm/pr-subscribers-clang

Author: Helena Kotas (hekota)

Changes

Translates RWBuffer and StructuredBuffer resources buffer types to DirectX target types dx.TypedBuffer and dx.RawBuffer.

Includes a change of HLSLAttributesResourceType from 'sugar' type to full canonical type. This is required for codegen and other clang infrastructure to work property on HLSL resource types.

Depends on PR llvm/llvm-project#110079 (test will fail until merged).

Fixes #95952 (part 2/2)


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

27 Files Affected:

  • (modified) clang/include/clang/AST/Type.h (+23-11)
  • (modified) clang/include/clang/Basic/TypeNodes.td (+1-1)
  • (modified) clang/lib/AST/ASTContext.cpp (+23-2)
  • (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+2-13)
  • (modified) clang/lib/AST/DeclCXX.cpp (+3-3)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+24)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+26)
  • (modified) clang/lib/AST/Type.cpp (+5)
  • (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+1)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+3)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+6)
  • (modified) clang/lib/CodeGen/Targets/DirectX.cpp (+39-10)
  • (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (-2)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+3)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+17)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+7)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+11)
  • (modified) clang/test/AST/HLSL/RWBuffer-AST.hlsl (-2)
  • (modified) clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl (+14)
  • (modified) clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl (+14)
  • (modified) clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl (+50-6)
  • (modified) clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl (+5-8)
  • (modified) clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl (+3-6)
  • (modified) clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl (+3-6)
  • (modified) clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl (+6-11)
  • (modified) clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl (-2)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index dc87b84153e74a..f97217dead2139 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2659,6 +2659,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
 #include "clang/Basic/HLSLIntangibleTypes.def"
   bool isHLSLSpecificType() const; // Any HLSL specific type
   bool isHLSLIntangibleType() const; // Any HLSL intangible type
+  bool isHLSLAttributedResourceType() const;
 
   /// Determines if this type, which must satisfy
   /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -6180,6 +6181,14 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
         : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
 
     Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
+
+    friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
+      return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
+             std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
+    }
+    friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
+      return !(LHS == RHS);
+    }
   };
 
 private:
@@ -6189,18 +6198,19 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
   QualType ContainedType;
   const Attributes Attrs;
 
-  HLSLAttributedResourceType(QualType Canon, QualType Wrapped,
-                             QualType Contained, const Attributes &Attrs)
-      : Type(HLSLAttributedResource, Canon, Wrapped->getDependence()),
+  HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
+                             const Attributes &Attrs)
+      : Type(HLSLAttributedResource, QualType(), Wrapped->getDependence()),
         WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}
 
 public:
   QualType getWrappedType() const { return WrappedType; }
   QualType getContainedType() const { return ContainedType; }
+  bool hasContainedType() const { return !ContainedType.isNull(); }
   const Attributes &getAttrs() const { return Attrs; }
 
-  bool isSugared() const { return true; }
-  QualType desugar() const { return getWrappedType(); }
+  bool isSugared() const { return false; }
+  QualType desugar() const { return QualType(this, 0); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
     Profile(ID, WrappedType, ContainedType, Attrs);
@@ -8344,17 +8354,19 @@ inline bool Type::isOpenCLSpecificType() const {
   }
 #include "clang/Basic/HLSLIntangibleTypes.def"
 
-inline bool Type::isHLSLSpecificType() const {
+inline bool Type::isHLSLIntangibleType() const {
 #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
   return
 #include "clang/Basic/HLSLIntangibleTypes.def"
-      false; // end boolean or operation
+      isHLSLAttributedResourceType();
 }
 
-inline bool Type::isHLSLIntangibleType() const {
-  // All HLSL specific types are currently intangible type as well, but that
-  // might change in the future.
-  return isHLSLSpecificType();
+inline bool Type::isHLSLSpecificType() const {
+  return isHLSLIntangibleType() || isa<HLSLAttributedResourceType>(this);
+}
+
+inline bool Type::isHLSLAttributedResourceType() const {
+  return isa<HLSLAttributedResourceType>(this);
 }
 
 inline bool Type::isTemplateTypeParmType() const {
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index 8cca392cddc174..7e550ca2992f35 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -93,7 +93,7 @@ def EnumType : TypeNode<TagType>, LeafType;
 def ElaboratedType : TypeNode<Type>, NeverCanonical;
 def AttributedType : TypeNode<Type>, NeverCanonical;
 def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
-def HLSLAttributedResourceType : TypeNode<Type>, NeverCanonical;
+def HLSLAttributedResourceType : TypeNode<Type>;
 def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
 def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
 def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cda8b02cc8499a..b41620505a0b16 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3437,6 +3437,9 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
     OS << II->getLength() << II->getName();
     return;
   }
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
+    break;
   case Type::DeducedTemplateSpecialization:
   case Type::Auto:
 #define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
@@ -4108,6 +4111,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
   case Type::BitInt:
   case Type::DependentBitInt:
   case Type::ArrayParameter:
+  case Type::HLSLAttributedResource:
     llvm_unreachable("type should never be variably-modified");
 
   // These types can be variably-modified but should never need to
@@ -5233,9 +5237,8 @@ QualType ASTContext::getHLSLAttributedResourceType(
   if (Ty)
     return QualType(Ty, 0);
 
-  QualType Canon = getCanonicalType(Wrapped);
   Ty = new (*this, alignof(HLSLAttributedResourceType))
-      HLSLAttributedResourceType(Canon, Wrapped, Contained, Attrs);
+      HLSLAttributedResourceType(Wrapped, Contained, Attrs);
 
   Types.push_back(Ty);
   HLSLAttributedResourceTypes.InsertNode(Ty, InsertPos);
@@ -9106,6 +9109,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
   case Type::DeducedTemplateSpecialization:
     return;
 
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("unexpected type");
+
   case Type::ArrayParameter:
   case Type::Pipe:
 #define ABSTRACT_TYPE(KIND, BASE)
@@ -11533,6 +11539,18 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
       return {};
     return LHS;
   }
+  case Type::HLSLAttributedResource: {
+    const HLSLAttributedResourceType *LHSTy =
+        LHS->castAs<HLSLAttributedResourceType>();
+    const HLSLAttributedResourceType *RHSTy =
+        RHS->castAs<HLSLAttributedResourceType>();
+
+    if (LHSTy->getWrappedType() == RHSTy->getWrappedType() &&
+        LHSTy->getContainedType() == RHSTy->getContainedType() &&
+        LHSTy->getAttrs() == RHSTy->getAttrs())
+      return LHS;
+    return {};
+  }
   }
 
   llvm_unreachable("Invalid Type::Class!");
@@ -13672,6 +13690,9 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
         TX->getDepth(), TX->getIndex(), TX->isParameterPack(),
         getCommonDecl(TX->getDecl(), TY->getDecl()));
   }
+  case Type::HLSLAttributedResource: {
+    llvm_unreachable("not yet implemented");
+  }
   }
   llvm_unreachable("Unknown Type Class");
 }
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 21f0562f9d72ae..120ddc0f26c0d7 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -802,16 +802,6 @@ static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
   return true;
 }
 
-// Determine structural equivalence of two instances of
-// HLSLAttributedResourceType::Attributes
-static bool
-IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
-                         const HLSLAttributedResourceType::Attributes &Attrs1,
-                         const HLSLAttributedResourceType::Attributes &Attrs2) {
-  return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) ==
-         std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer);
-}
-
 /// Determine structural equivalence of two types.
 static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
                                      QualType T1, QualType T2) {
@@ -1115,9 +1105,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
             Context, cast<HLSLAttributedResourceType>(T1)->getContainedType(),
             cast<HLSLAttributedResourceType>(T2)->getContainedType()))
       return false;
-    if (!IsStructurallyEquivalent(
-            Context, cast<HLSLAttributedResourceType>(T1)->getAttrs(),
-            cast<HLSLAttributedResourceType>(T2)->getAttrs()))
+    if (cast<HLSLAttributedResourceType>(T1)->getAttrs() !=
+        cast<HLSLAttributedResourceType>(T2)->getAttrs())
       return false;
     break;
 
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 01143391edab40..8d0b5171fc9ae3 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1411,10 +1411,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
         Ty = Ty->getArrayElementTypeNoTypeQual();
 
       Ty = Ty->getUnqualifiedDesugaredType();
-      if (Ty->isBuiltinType())
-        data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
-      else if (const RecordType *RT = dyn_cast<RecordType>(Ty))
+      if (const RecordType *RT = dyn_cast<RecordType>(Ty))
         data().IsHLSLIntangible |= RT->getAsCXXRecordDecl()->isHLSLIntangible();
+      else
+        data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
     }
   }
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 960eae36ed1f51..dab54133248393 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12163,6 +12163,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
   case Type::ObjCInterface:
   case Type::ObjCObjectPointer:
   case Type::Pipe:
+  case Type::HLSLAttributedResource:
     // Classify all other types that don't fit into the regular
     // classification the same way.
     return GCCTypeClass::None;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b6e1da0c3192da..9bda078d9fac81 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4488,6 +4488,30 @@ void CXXNameMangler::mangleType(const ArrayParameterType *T) {
   mangleType(cast<ConstantArrayType>(T));
 }
 
+void CXXNameMangler::mangleType(const HLSLAttributedResourceType *T) {
+  mangleType(T->getWrappedType());
+  const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
+  switch (Attrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+    Out << 'U';
+    break;
+  case llvm::dxil::ResourceClass::SRV:
+    Out << 'T';
+    break;
+  case llvm::dxil::ResourceClass::CBuffer:
+    Out << 'C';
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    Out << 'S';
+    break;
+  }
+  mangleNumber(Attrs.IsROV);
+  mangleNumber(Attrs.RawBuffer);
+
+  if (!T->hasContainedType())
+    mangleType(T->getContainedType());
+}
+
 void CXXNameMangler::mangleIntegerLiteral(QualType T,
                                           const llvm::APSInt &Value) {
   //  <expr-primary> ::= L <type> <value number> E # integer literal
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 7b069c66aed598..16df5c99c623ce 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -32,6 +32,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/CRC.h"
+#include "llvm/Support/DXILABI.h"
 #include "llvm/Support/MD5.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/StringSaver.h"
@@ -3753,6 +3754,31 @@ void MicrosoftCXXNameMangler::mangleType(const DependentBitIntType *T,
   Error(Range.getBegin(), "DependentBitInt type") << Range;
 }
 
+void MicrosoftCXXNameMangler::mangleType(const HLSLAttributedResourceType *T,
+                                         Qualifiers, SourceRange Range) {
+  mangleType(T->getWrappedType(), SourceRange(), QMM_Escape);
+  const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
+  switch (Attrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+    Out << 'U';
+    break;
+  case llvm::dxil::ResourceClass::SRV:
+    Out << 'T';
+    break;
+  case llvm::dxil::ResourceClass::CBuffer:
+    Out << 'C';
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    Out << 'S';
+    break;
+  }
+  mangleNumber(Attrs.IsROV);
+  mangleNumber(Attrs.RawBuffer);
+
+  if (T->hasContainedType())
+    mangleType(T->getContainedType(), SourceRange(), QMM_Escape);
+}
+
 // <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
 //                       <virtual-adjustment>
 // <no-adjustment>      ::= A # private near
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a55e6c8bf02611..99fc3c676c2c98 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4575,6 +4575,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
     return Cache::get(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return Cache::get(cast<PipeType>(T)->getElementType());
+  case Type::HLSLAttributedResource:
+    return Cache::get(cast<HLSLAttributedResourceType>(T)->getWrappedType());
   }
 
   llvm_unreachable("unhandled type class");
@@ -4664,6 +4666,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
     return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm_unreachable("unhandled type class");
@@ -4846,6 +4850,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
   case Type::BitInt:
   case Type::DependentBitInt:
   case Type::ArrayParameter:
+  case Type::HLSLAttributedResource:
     return false;
   }
   llvm_unreachable("bad type kind!");
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index eda96f3e352ce3..ddbd5e2f1aa311 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -296,6 +296,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
     case Type::ObjCObject:
     case Type::ObjCInterface:
     case Type::ArrayParameter:
+    case Type::HLSLAttributedResource:
       return TEK_Aggregate;
 
     // We operate on atomic values according to their underlying type.
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 77c1b27cebf401..bacb0a04cb7c86 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -742,6 +742,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
     ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
     break;
   }
+  case Type::HLSLAttributedResource:
+    ResultType = CGM.getHLSLRuntime().convertHLSLSpecificType(Ty);
+    break;
   }
 
   assert(ResultType && "Didn't convert a type?");
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index dcc35d5689831e..8533ccb2129c34 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3943,6 +3943,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
     // abi::__pointer_to_member_type_info.
     VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
     break;
+
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm::Constant *VTable = nullptr;
@@ -4205,6 +4208,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
   case Type::Atomic:
     // No fields, at least for the moment.
     break;
+
+  case Type::HLSLAttributedResource:
+    llvm_unreachable("not yet implemented");
   }
 
   llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 13da2c630629d7..cf6ac849777369 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -29,19 +29,48 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
 
 llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
                                                   const Type *Ty) const {
-  auto *BuiltinTy = dyn_cast<BuiltinType>(Ty);
-  if (!BuiltinTy || BuiltinTy->getKind() != BuiltinType::HLSLResource)
+  auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
+  if (!ResType)
     return nullptr;
 
   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
-  // FIXME: translate __hlsl_resource_t to target("dx.TypedBuffer", <4 x float>,
-  // 1, 0, 0) only for now (RWBuffer<float4>); more work us needed to determine
-  // the target ext type and its parameters based on the handle type
-  // attributes (not yet implemented)
-  llvm::FixedVectorType *ElemType =
-      llvm::FixedVectorType::get(llvm::Type::getFloatTy(Ctx), 4);
-  unsigned Flags[] = {/*IsWriteable*/ 1, /*IsROV*/ 0, /*IsSigned*/ 0};
-  return llvm::TargetExtType::get(Ctx, "dx.TypedBuffer", {ElemType}, Flags);
+  const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
+  switch (ResAttrs.ResourceClass) {
+  case llvm::dxil::ResourceClass::UAV:
+  case llvm::dxil::ResourceClass::SRV: {
+    // convert element type
+    QualType ContainedTy = ResType->getContainedType();
+    llvm::Type *ElemType = nullptr;
+    if (!ContainedTy.isNull())
+      ElemType = CGM.getTypes().ConvertType(ContainedTy);
+
+    if (ResAttrs.RawBuffer) {
+      // RawBuffer needs element type
+      if (ContainedTy.isNull())
+        return nullptr;
+      return llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {ElemType},
+                                      {/*IsWriteable*/ ResAttrs.ResourceClass ==
+                                           llvm::dxil::ResourceClass::UAV,
+                                       /*IsROV*/ ResAttrs.IsROV});
+    }
+
+    // TypedBuffer needs element type
+    if (ContainedTy.isNull())
+      return nullptr;
+    return llvm::TargetExtType::get(
+        Ctx, "dx.TypedBuffer", {ElemType},
+        {/*IsWriteable*/ ResAttrs.ResourceClass ==
+             llvm::dxil::ResourceClass::UAV,
+         /*IsROV*/ ResAttrs.IsROV,
+         /*IsSigned*/ ContainedTy->isSignedIntegerType()});
+  }
+  case llvm::dxil::ResourceClass::CBuffer:
+    llvm_unreachable("dx.CBuffer handles are not implemented yet");
+    break;
+  case llvm::dxil::ResourceClass::Sampler:
+    llvm_unreachable("dx.Sampler handles are not implemented yet");
+    break;
+  }
 }
 
 } // namespace
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index ca521dc0bcd26b..d2f032dfd5e9ba 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -211,8 +211,6 @@ struct BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
     if (Record->isCompleteDefinition())
       return *this;
-    assert(Fields.count("h") > 0 &&
-           "Subscript operator must be added after the handle.");
 
     FieldDecl *Handle = Fields["h"];
     ASTContext &AST = Record->getASTContext();
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index f3f62474d06441..e5db11369221a4 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
     // Array parameter types are treated as fundamental types.
     case Type::ArrayParameter:
       break;
+
+    case Type::HLSLAttributedResource:
+      T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
     }
 
     if (Queue.empty())
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0c1e054f7c30a4..16c2d0f74a3d34 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1785,6 +1785,23 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
     return ICS;
   }
 
+  if (S.getLangOpts().HLSL && ToType->isHLSLAttributedResourceType() &&
+      FromType->isHLSLAttributedResourceType()) {
+    auto *ToResType = cast<HLSLAttributedResourceType>(ToType);
+    auto *FromResType = cast<HLSLAttributedResourceType>(FromType);
+    if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
+                                         FromResType->getWrappedType()) &&
+        S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
+                                         FromResType->getContainedType()) &&
+        ToResT...
[truncated]

clang/lib/AST/ItaniumMangle.cpp Show resolved Hide resolved
clang/lib/AST/ItaniumMangle.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/Targets/DirectX.cpp Show resolved Hide resolved
clang/lib/CodeGen/Targets/DirectX.cpp Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Sep 30, 2024

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

Copy link
Contributor

@bogner bogner left a comment

Choose a reason for hiding this comment

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

This LGTM but I'm not familiar enough with the mangling aspects or the implications of adding a canonical type to be comfortable signing off on it.

Copy link
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

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

A few (mostly small) comments

clang/lib/AST/MicrosoftMangle.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/ItaniumCXXABI.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/ItaniumCXXABI.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/Targets/DirectX.cpp Outdated Show resolved Hide resolved
clang/lib/AST/ASTContext.cpp Show resolved Hide resolved
clang/lib/AST/ASTContext.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

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

I'm a bit out of my depth here, but I've been trying to understand Itanium mangling better and I think my suggestion to coalesce the vendor mangled portions is valid at least.

clang/lib/AST/ItaniumMangle.cpp Outdated Show resolved Hide resolved
clang/lib/AST/ItaniumMangle.cpp Outdated Show resolved Hide resolved
clang/lib/AST/ASTContext.cpp Outdated Show resolved Hide resolved
clang/lib/AST/ItaniumMangle.cpp Show resolved Hide resolved
Copy link
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

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

LGTM other than needing a rebase after #111632

@llvm-beanz llvm-beanz removed their assignment Oct 15, 2024
@hekota hekota merged commit 3b45120 into llvm:main Oct 15, 2024
8 checks passed
bricknerb pushed a commit to bricknerb/llvm-project that referenced this pull request Oct 16, 2024
…o convert HLSL types to DirectX target types (llvm#110327)

Translates `RWBuffer` and `StructuredBuffer` resources buffer types to
DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`.

Includes a change of `HLSLAttributesResourceType` from 'sugar' type to
full canonical type. This is required for codegen and other clang
infrastructure to work property on HLSL resource types.

Fixes llvm#95952 (part 2/2)
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
…o convert HLSL types to DirectX target types (llvm#110327)

Translates `RWBuffer` and `StructuredBuffer` resources buffer types to
DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`.

Includes a change of `HLSLAttributesResourceType` from 'sugar' type to
full canonical type. This is required for codegen and other clang
infrastructure to work property on HLSL resource types.

Fixes llvm#95952 (part 2/2)
bricknerb pushed a commit to bricknerb/llvm-project that referenced this pull request Oct 17, 2024
…o convert HLSL types to DirectX target types (llvm#110327)

Translates `RWBuffer` and `StructuredBuffer` resources buffer types to
DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`.

Includes a change of `HLSLAttributesResourceType` from 'sugar' type to
full canonical type. This is required for codegen and other clang
infrastructure to work property on HLSL resource types.

Fixes llvm#95952 (part 2/2)
hekota added a commit that referenced this pull request Oct 18, 2024
…11207)

Adds `@_init_resource_bindings()` function to module initialization that
includes `handle.fromBinding` intrinsic calls for simple resource
declarations. Arrays of resources or resources inside user defined types
are not supported yet.

While this unblocks our progress on [Compile a runnable shader from
clang](llvm/wg-hlsl#7) milestone, this is
probably not the way we would like to handle resource binding
initialization going forward. Ideally, it should be done via the
resource class constructors in order to support dynamic resource binding
or unbounded arrays if resources.

Depends on PRs #110327 and #111203.

Part 1 of #105076
bricknerb pushed a commit to bricknerb/llvm-project that referenced this pull request Oct 21, 2024
…vm#111207)

Adds `@_init_resource_bindings()` function to module initialization that
includes `handle.fromBinding` intrinsic calls for simple resource
declarations. Arrays of resources or resources inside user defined types
are not supported yet.

While this unblocks our progress on [Compile a runnable shader from
clang](llvm/wg-hlsl#7) milestone, this is
probably not the way we would like to handle resource binding
initialization going forward. Ideally, it should be done via the
resource class constructors in order to support dynamic resource binding
or unbounded arrays if resources.

Depends on PRs llvm#110327 and llvm#111203.

Part 1 of llvm#105076
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
…o convert HLSL types to DirectX target types (llvm#110327)

Translates `RWBuffer` and `StructuredBuffer` resources buffer types to
DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`.

Includes a change of `HLSLAttributesResourceType` from 'sugar' type to
full canonical type. This is required for codegen and other clang
infrastructure to work property on HLSL resource types.

Fixes llvm#95952 (part 2/2)
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
…vm#111207)

Adds `@_init_resource_bindings()` function to module initialization that
includes `handle.fromBinding` intrinsic calls for simple resource
declarations. Arrays of resources or resources inside user defined types
are not supported yet.

While this unblocks our progress on [Compile a runnable shader from
clang](llvm/wg-hlsl#7) milestone, this is
probably not the way we would like to handle resource binding
initialization going forward. Ideally, it should be done via the
resource class constructors in order to support dynamic resource binding
or unbounded arrays if resources.

Depends on PRs llvm#110327 and llvm#111203.

Part 1 of llvm#105076
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang:codegen clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

[HLSL] Add DirectXTargetCodeGenInfo and the code paths to convert HLSL types to DirectX target types
6 participants