Skip to content

[HLSL] add IsTypedResourceElementCompatible type trait #113730

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

Merged
merged 6 commits into from
Nov 4, 2024

Conversation

bob80905
Copy link
Contributor

@bob80905 bob80905 commented Oct 25, 2024

This PR implements a new type trait as a builtin, __builtin_hlsl_is_typed_resource_element_compatible
This type traits verifies that the given input type is suitable as a typed resource element type.
It checks that the given input type is homogeneous, has no more than 4 sub elements, does not exceed 16 bytes, and does not contain any arrays, booleans, or enums.
Fixes #113223

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" HLSL HLSL Language Support labels Oct 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 25, 2024

@llvm/pr-subscribers-clang-modules
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-hlsl

Author: Joshua Batista (bob80905)

Changes

This PR implements a new type trait as a builtin, __builtin_hlsl_is_line_vector_layout_compatible
This type traits verifies that the given input type is suitable as a typed resource element type.
It checks that the given input type is homogeneous, has no more than 4 sub elements, does not exceed 16 bytes, and does not contain any arrays, booleans, or enums.
Fixes #113223


Full diff: https://github.com/llvm/llvm-project/pull/113730.diff

10 Files Affected:

  • (modified) clang/include/clang/AST/CXXRecordDeclDefinitionBits.def (+5)
  • (modified) clang/include/clang/AST/DeclCXX.h (+5)
  • (modified) clang/include/clang/AST/Type.h (+8)
  • (modified) clang/include/clang/Basic/TokenKinds.def (+1)
  • (modified) clang/include/clang/Sema/SemaHLSL.h (+1)
  • (modified) clang/lib/AST/DeclCXX.cpp (+5-1)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+10)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+43)
  • (added) clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleType.hlsl (+101)
  • (added) clang/test/SemaHLSL/Types/Traits/IsLineVectorLayoutCompatibleTypeErros.hlsl (+10)
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@+1{{forward declaration of 'notComplete'}}
+struct notComplete;
+// expected-error@+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), "");

Copy link

github-actions bot commented Oct 25, 2024

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

@llvmbot llvmbot added the clang:modules C++20 modules and Clang Header Modules label Oct 25, 2024
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo in filename: TypeErros -> TypeErrors

llvm::SmallVector<QualType, 16> QTTypes;
BuildFlattenedTypeList(QT, QTTypes);

QualType FirstQT = QTTypes[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could add an assert on the vector size or a check with llvm_unreachable when size is 0

@bob80905 bob80905 force-pushed the add_builtin_line_vector_compatible branch from def3686 to 5403988 Compare October 25, 2024 23:21
Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

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

If you are going to store isHLSLLineVectorLayoutCompatibleType on a declaration you need to modify addMember to analyze newly added members. Then move the IsLineVectorLayoutCompatibleType implementation from SemaHLSL to Type and use the bit on the record type decl instead of building flattened type list.

@hekota
Copy link
Member

hekota commented Oct 31, 2024

If you are going to store isHLSLLineVectorLayoutCompatibleType on a declaration you need to modify addMember to analyze newly added members. Then move the IsLineVectorLayoutCompatibleType implementation from SemaHLSL to Type and use the bit on the record type decl instead of building flattened type list.

On the other hand, it is probably not worth caching the bit on the decl because it also needs to make sure the size is within limits, which would more involved to have on the decl than we'd probably like.

@bob80905
Copy link
Contributor Author

If you are going to store isHLSLLineVectorLayoutCompatibleType on a declaration you need to modify addMember to analyze newly added members. Then move the IsLineVectorLayoutCompatibleType implementation from SemaHLSL to Type and use the bit on the record type decl instead of building flattened type list.

On the other hand, it is probably not worth caching the bit on the decl because it also needs to make sure the size is within limits, which would more involved to have on the decl than we'd probably like.

Agreed, I got rid of the bit and the associated functions.

@bob80905 bob80905 changed the title [HLSL] add IsLineVectorLayoutCompatible type trait [HLSL] add IsTypedResourceElementCompatible type trait Oct 31, 2024
Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

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

LGTM! Please remove the whitespace-only change in clang/include/clang/AST/Type.h.

@bob80905 bob80905 merged commit 4894c67 into llvm:main Nov 4, 2024
8 checks passed
bob80905 added a commit that referenced this pull request Nov 4, 2024
bob80905 added a commit that referenced this pull request Nov 4, 2024
)

Reverts #113730
Reverting because test compiler-rt default failed, with:
error: comparison of different enumeration types ('Kind' and
'clang::Type::TypeClass')
bob80905 added a commit that referenced this pull request Nov 5, 2024
This PR implements a new type trait as a builtin,
__builtin_hlsl_is_typed_resource_element_compatible
This type traits verifies that the given input type is suitable as a
typed resource element type.
It checks that the given input type is homogeneous, has no more than 4
sub elements, does not exceed 16 bytes, and does not contain any arrays,
booleans, or enums.
Fixes an issue in #113730 that
needed to cause that PR to be reverted.
Fixes #113223
PhilippRados pushed a commit to PhilippRados/llvm-project that referenced this pull request Nov 6, 2024
This PR implements a new type trait as a builtin,
`__builtin_hlsl_is_typed_resource_element_compatible`
This type traits verifies that the given input type is suitable as a
typed resource element type.
It checks that the given input type is homogeneous, has no more than 4
sub elements, does not exceed 16 bytes, and does not contain any arrays,
booleans, or enums.
Fixes llvm#113223
PhilippRados pushed a commit to PhilippRados/llvm-project that referenced this pull request Nov 6, 2024
…#114853)

Reverts llvm#113730
Reverting because test compiler-rt default failed, with:
error: comparison of different enumeration types ('Kind' and
'clang::Type::TypeClass')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[HLSL] Create __builtin_hlsl_is_typed_resource_element_compatible builtin
4 participants