[clang] [HLSL] add IsLineVectorLayoutCompatible type trait (PR #113730)

Joshua Batista via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 25 14:01:56 PDT 2024


https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/113730

>From a915def0c7cb69d8c910c697aa610fa37278d032 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 25 Oct 2024 12:33:05 -0700
Subject: [PATCH 1/2] add type trait

---
 .../clang/AST/CXXRecordDeclDefinitionBits.def |   5 +
 clang/include/clang/AST/DeclCXX.h             |   5 +
 clang/include/clang/AST/Type.h                |   8 ++
 clang/include/clang/Basic/TokenKinds.def      |   1 +
 clang/include/clang/Sema/SemaHLSL.h           |   1 +
 clang/lib/AST/DeclCXX.cpp                     |   6 +-
 clang/lib/Sema/SemaExprCXX.cpp                |  10 ++
 clang/lib/Sema/SemaHLSL.cpp                   |  43 ++++++++
 .../IsLineVectorLayoutCompatibleType.hlsl     | 101 ++++++++++++++++++
 ...IsLineVectorLayoutCompatibleTypeErros.hlsl |  10 ++
 10 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleType.hlsl
 create mode 100644 clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl

diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
index 6620840df0ced2..0411b244ed5eef 100644
--- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
+++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
@@ -253,4 +253,9 @@ FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE)
 /// type that is intangible). HLSL only.
 FIELD(IsHLSLIntangible, 1, NO_MERGE)
 
+/// Whether the record type is line vector layout compatible (that is,
+/// it has at most 4 elements, does not exceed 16 bytes, is homogenous,
+/// and does not contain any bool or enum types)
+FIELD(IsHLSLLineVectorLayoutCompatible, 1, NO_MERGE)
+
 #undef FIELD
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 2693cc0e95b4b2..e2e4ed78195a81 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1551,6 +1551,11 @@ class CXXRecordDecl : public RecordDecl {
   /// a field or in base class.
   bool isHLSLIntangible() const { return data().IsHLSLIntangible; }
 
+  /// Returns true if the class is line vector layout compatible
+  bool isHLSLLineVectorLayoutCompatible() const {
+    return data().IsHLSLLineVectorLayoutCompatible;
+  }
+
   /// If the class is a local class [class.local], returns
   /// the enclosing function declaration.
   const FunctionDecl *isLocalClass() const {
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 40e617bf8f3b8d..1f2d5cecde4e18 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2662,6 +2662,8 @@ 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 isHLSLLineVectorLayoutCompatibleType()
+      const; // Any HLSL line vector layout compatible type
   bool isHLSLAttributedResourceType() const;
 
   /// Determines if this type, which must satisfy
@@ -8457,6 +8459,12 @@ inline bool Type::isHLSLIntangibleType() const {
       isHLSLAttributedResourceType();
 }
 
+inline bool Type::isHLSLLineVectorLayoutCompatibleType() const {
+#define HLSL_LINE_VECTOR_LAYOUT_COMPATIBLE_TYPE(Name, Id, SingletonId)         \
+  is##Id##Type() ||
+  return isHLSLAttributedResourceType();
+}
+
 inline bool Type::isHLSLSpecificType() const {
   return isHLSLIntangibleType() || isa<HLSLAttributedResourceType>(this);
 }
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fdfb35de9cf287..0e4e2a8e45b810 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -662,6 +662,7 @@ KEYWORD(out                         , KEYHLSL)
 // HLSL Type traits
 TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
 TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
+TYPE_TRAIT_1(__builtin_hlsl_is_line_vector_layout_compatible, IsLineVectorLayoutCompatibleType, KEYHLSL)
 
 // OpenMP Type Traits
 UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 4f1fc9a31404c6..142f816768de8f 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -133,6 +133,7 @@ class SemaHLSL : public SemaBase {
   // HLSL Type trait implementations
   bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
   bool IsIntangibleType(QualType T1);
+  bool IsLineVectorLayoutCompatibleType(QualType T1);
 
   bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
 
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 34bb200e43360c..16ff6325d53960 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -109,7 +109,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
       HasDeclaredCopyAssignmentWithConstParam(false),
-      IsAnyDestructorNoReturn(false), IsHLSLIntangible(false), IsLambda(false),
+      IsAnyDestructorNoReturn(false), IsHLSLIntangible(false),
+      IsHLSLLineVectorLayoutCompatible(false), IsLambda(false),
       IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
       HasODRHash(false), Definition(D) {}
 
@@ -434,6 +435,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
     if (BaseClassDecl->isHLSLIntangible())
       data().IsHLSLIntangible = true;
 
+    if (BaseClassDecl->isHLSLLineVectorLayoutCompatible())
+      data().IsHLSLLineVectorLayoutCompatible = true;
+
     // C++11 [class.copy]p18:
     //   The implicitly-declared copy assignment operator for a class X will
     //   have the form 'X& X::operator=(const X&)' if each direct base class B
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e19016ab23abe7..27a731364de379 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5032,6 +5032,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   case UTT_IsScalar:
   case UTT_IsCompound:
   case UTT_IsMemberPointer:
+  case UTT_IsLineVectorLayoutCompatibleType:
     // Fall-through
 
     // These traits are modeled on type predicates in C++0x [meta.unary.prop]
@@ -5714,6 +5715,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
                                   tok::kw___builtin_hlsl_is_intangible))
       return false;
     return Self.HLSL().IsIntangibleType(T);
+
+  case UTT_IsLineVectorLayoutCompatibleType:
+    assert(Self.getLangOpts().HLSL &&
+           "line vector layout compatible types are HLSL-only feature");
+    if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
+                                 diag::err_incomplete_type))
+      return false;
+
+    return Self.HLSL().IsLineVectorLayoutCompatibleType(T);
   }
 }
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c6627b0e993226..e38eb07c567b0f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2189,6 +2189,49 @@ static void BuildFlattenedTypeList(QualType BaseTy,
   }
 }
 
+bool SemaHLSL::IsLineVectorLayoutCompatibleType(clang::QualType QT) {
+  if (QT.isNull())
+    return false;
+
+  llvm::SmallVector<QualType, 16> QTTypes;
+  BuildFlattenedTypeList(QT, QTTypes);
+
+  QualType FirstQT = QTTypes[0];
+
+  // element count cannot exceed 4
+  if (QTTypes.size() > 4)
+    return false;
+
+  // check if the outer type was an array type
+  if (llvm::isa<clang::ArrayType>(QT.getTypePtr()))
+    return false;
+
+  for (QualType TempQT : QTTypes) {
+    // ensure homogeneity
+    if (TempQT != FirstQT)
+      return false;
+
+    if (const BuiltinType *BT = TempQT->getAs<BuiltinType>()) {
+      if (BT->getKind() == BuiltinType::Bool ||
+          BT->getKind() == BuiltinType::Enum)
+        return false;
+
+      // Check if it is an array type.
+      if (llvm::isa<clang::ArrayType>(TempQT.getTypePtr()))
+        return false;
+    }
+  }
+
+  // if the loop above completes without returning, then
+  // we've guaranteed homogeneity
+  int TotalSizeInBytes =
+      (SemaRef.Context.getTypeSize(FirstQT) / 8) * QTTypes.size();
+  if (TotalSizeInBytes > 16)
+    return false;
+
+  return true;
+}
+
 bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
   if (T1.isNull() || T2.isNull())
     return false;
diff --git a/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleType.hlsl b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleType.hlsl
new file mode 100644
index 00000000000000..9c97a5af39a36c
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleType.hlsl
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+struct oneInt {
+    int i;
+};
+
+struct twoInt {
+   int aa;
+   int ab;
+};
+
+struct threeInts {
+  oneInt o;
+  twoInt t;
+};
+
+struct oneFloat {
+    float f;
+};
+struct depthDiff {
+  int i;
+  oneInt o;
+  oneFloat f;
+};
+
+struct notHomogenous{     
+  int i;
+  float f;
+};
+
+struct EightElements {
+  twoInt x[2];
+  twoInt y[2];
+};
+
+struct EightHalves {
+half x[8]; 
+};
+
+struct intVec {
+  int2 i;
+};
+
+struct oneIntWithVec {
+  int i;
+  oneInt i2;
+  int2 i3;
+};
+
+struct weirdStruct {
+  int i;
+  intVec iv;
+};
+
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(int), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(float), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(float4), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(double2), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(oneInt), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(oneFloat), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(twoInt), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(threeInts), "");
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(notHomogenous), "");
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(depthDiff), "");
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(EightElements), "");
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(EightHalves), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(oneIntWithVec), "");
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(weirdStruct), "");
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(RWBuffer<int>), "");
+
+
+// arrays not allowed
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(half[4]), "");
+
+template<typename T> struct TemplatedBuffer {
+    T a;
+    __hlsl_resource_t h;
+};
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(TemplatedBuffer<int>), "");
+
+struct MyStruct1 : TemplatedBuffer<float> {
+    float x;
+};
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(MyStruct1), "");
+
+struct MyStruct2 {
+    const TemplatedBuffer<float> TB[10];
+};
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(MyStruct2), "");
+
+template<typename T> struct SimpleTemplate {
+    T a;
+};
+
+// though the element type is incomplete, the type trait should still technically return true
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(SimpleTemplate<__hlsl_resource_t>), "");
+
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(SimpleTemplate<float>), "");
+
+
diff --git a/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl
new file mode 100644
index 00000000000000..ae878202eeac9d
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+
+// expected-note at +1{{forward declaration of 'notComplete'}}
+struct notComplete;
+// expected-error at +1{{incomplete type 'notComplete' where a complete type is required}}
+_Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(notComplete), "");
+
+
+// types must be complete
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(__hlsl_resource_t), "");

>From 1d97b51642d170b7ab15936e5ae540e5600409df Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 25 Oct 2024 14:01:39 -0700
Subject: [PATCH 2/2] fix bug

---
 clang/include/clang/Sema/SemaHLSL.h                         | 1 -
 clang/include/clang/Serialization/ASTBitCodes.h             | 2 +-
 .../Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl | 6 +++---
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index ef3c54cbd88eae..4c92b6170078b7 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -134,7 +134,6 @@ class SemaHLSL : public SemaBase {
   bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
   bool IsLineVectorLayoutCompatibleType(QualType T1);
 
-
   bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
 
   ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg);
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 99232fd2135790..3ddbc5fcd26c44 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1149,7 +1149,7 @@ enum PredefinedTypeIDs {
 ///
 /// Type IDs for non-predefined types will start at
 /// NUM_PREDEF_TYPE_IDs.
-const unsigned NUM_PREDEF_TYPE_IDS = 512;
+const unsigned NUM_PREDEF_TYPE_IDS = 513;
 
 // Ensure we do not overrun the predefined types we reserved
 // in the enum PredefinedTypeIDs above.
diff --git a/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl
index ae878202eeac9d..2277649df54f79 100644
--- a/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl
@@ -1,10 +1,10 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
 
+// types must be complete
+_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(__hlsl_resource_t), "");
+
 // expected-note at +1{{forward declaration of 'notComplete'}}
 struct notComplete;
 // expected-error at +1{{incomplete type 'notComplete' where a complete type is required}}
 _Static_assert(!__builtin_hlsl_is_line_vector_layout_compatible(notComplete), "");
 
-
-// types must be complete
-_Static_assert(__builtin_hlsl_is_line_vector_layout_compatible(__hlsl_resource_t), "");



More information about the cfe-commits mailing list