[clang] [HLSL] Implement '__builtin_is_intangible' type trait (PR #104544)

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 15 22:27:06 PDT 2024


https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/104544

>From 6d5f8991a4ef9e79bc1bed30addf7b29b7ed0d2e Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 19:03:29 -0700
Subject: [PATCH 1/6] Implement `__builtin_is_intangible`

---
 clang/include/clang/Basic/TokenKinds.def |  3 ++
 clang/include/clang/Sema/SemaHLSL.h      |  3 ++
 clang/lib/Sema/SemaExprCXX.cpp           |  8 ++++
 clang/lib/Sema/SemaHLSL.cpp              | 49 ++++++++++++++++++++++++
 4 files changed, 63 insertions(+)

diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index d683106bb0e298..f4fc7c321d9c5a 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -660,6 +660,9 @@ KEYWORD(out                         , KEYHLSL)
 #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
 #include "clang/Basic/HLSLIntangibleTypes.def"
 
+// HLSL Type traits
+TYPE_TRAIT_1(__builtin_is_intangible, IsIntangibleType, 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 d60cb2a57d4918..13e75a79ec6bf0 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -62,6 +62,9 @@ class SemaHLSL : public SemaBase {
   void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+  // HLSL Type trait implementations
+  bool IsIntangibleType(QualType T1) const;
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5356bcf172f752..f3f8d511a6e568 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaLambda.h"
 #include "clang/Sema/SemaObjC.h"
@@ -5683,6 +5684,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
         return true;
     return false;
   }
+  case UTT_IsIntangibleType:
+    if (!T->isVoidType() && !T->isIncompleteArrayType())
+      if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
+                                   diag::err_incomplete_type))
+        return true;
+    DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___builtin_is_intangible);
+    return Self.HLSL().IsIntangibleType(T);
   }
 }
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index e3e926465e799e..5978c14399ba32 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TargetInfo.h"
@@ -1154,3 +1155,51 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   }
   return false;
 }
+
+bool SemaHLSL::IsIntangibleType(QualType Ty) const {
+  if (Ty.isNull())
+    return false;
+
+  Ty = Ty.getCanonicalType().getUnqualifiedType();
+  if (Ty->isBuiltinType())
+    return Ty->isHLSLSpecificType();
+
+  llvm::SmallVector<QualType, 8> TypesToScan;
+  TypesToScan.push_back(Ty);
+  while (!TypesToScan.empty()) {
+    QualType T = TypesToScan.pop_back_val();
+    assert(T == T.getCanonicalType().getUnqualifiedType() && "expected sugar-free type");
+    assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
+
+    if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
+      QualType ElTy = AT->getElementType().getCanonicalType().getUnqualifiedType();
+      if (ElTy->isBuiltinType())
+        return ElTy->isHLSLSpecificType();
+      TypesToScan.push_back(ElTy);
+      continue; 
+    }
+
+    if (const auto *VT = dyn_cast<VectorType>(T)) {
+      QualType ElTy = VT->getElementType().getCanonicalType().getUnqualifiedType();
+      assert(ElTy->isBuiltinType() && "vectors can only contain builtin types");
+      if (ElTy->isHLSLSpecificType())
+        return true;
+      continue;
+    }
+
+    if (const auto *RT = dyn_cast<RecordType>(T)) {
+      const RecordDecl *RD = RT->getDecl();
+      for (const auto *FD : RD->fields()) {
+        QualType FieldTy = FD->getType().getCanonicalType().getUnqualifiedType();
+        if (FieldTy->isBuiltinType()) {
+          if (FieldTy->isHLSLSpecificType())
+            return true;
+        } else {
+          TypesToScan.push_back(FieldTy); 
+        }
+      }
+      continue;
+    }
+  }
+  return false;
+}

>From d21ca2e2891acbd6c89864b57d864d881a8a8b96 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 20:52:24 -0700
Subject: [PATCH 2/6] add caching

---
 clang/include/clang/Sema/SemaHLSL.h |  5 ++++-
 clang/lib/Sema/SemaExprCXX.cpp      |  1 +
 clang/lib/Sema/SemaHLSL.cpp         | 22 +++++++++++++++++-----
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 13e75a79ec6bf0..663dea12880d1b 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -64,7 +64,10 @@ class SemaHLSL : public SemaBase {
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
 
   // HLSL Type trait implementations
-  bool IsIntangibleType(QualType T1) const;
+  bool IsIntangibleType(const QualType T1);
+
+private:
+  llvm::DenseMap<const Type *, bool> IsIntangibleTypeCache;
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f3f8d511a6e568..d3964f5da01e00 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5099,6 +5099,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   case UTT_IsDestructible:
   case UTT_IsNothrowDestructible:
   case UTT_IsTriviallyDestructible:
+  case UTT_IsIntangibleType:
     if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
       return true;
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5978c14399ba32..e23240a380528d 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -28,7 +28,7 @@
 
 using namespace clang;
 
-SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {}
+SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S), IsIntangibleTypeCache(8) {}
 
 Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
                                  SourceLocation KwLoc, IdentifierInfo *Ident,
@@ -1156,10 +1156,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   return false;
 }
 
-bool SemaHLSL::IsIntangibleType(QualType Ty) const {
-  if (Ty.isNull())
-    return false;
-
+static bool calculateIsIntangibleType(QualType Ty) {
   Ty = Ty.getCanonicalType().getUnqualifiedType();
   if (Ty->isBuiltinType())
     return Ty->isHLSLSpecificType();
@@ -1203,3 +1200,18 @@ bool SemaHLSL::IsIntangibleType(QualType Ty) const {
   }
   return false;
 }
+
+bool SemaHLSL::IsIntangibleType(const clang::QualType Ty) {
+  if (Ty.isNull())
+    return false;
+
+  const auto CachedEntry = IsIntangibleTypeCache.find(Ty.getTypePtr());
+  if (CachedEntry != IsIntangibleTypeCache.end()) {
+    assert(CachedEntry->second == calculateIsIntangibleType(Ty) && "IsIntangibleType mismatch");
+    return CachedEntry->second;
+  }
+
+  bool IsIntangible = calculateIsIntangibleType(Ty);
+  IsIntangibleTypeCache[Ty.getTypePtr()] = IsIntangible;
+  return IsIntangible;
+}

>From d7e8bce2e27f894196691435d2379edfdd6cd906 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 20:56:40 -0700
Subject: [PATCH 3/6] clang-format

---
 clang/lib/Sema/SemaHLSL.cpp | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index e23240a380528d..5e5917c40bc1cc 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1165,19 +1165,22 @@ static bool calculateIsIntangibleType(QualType Ty) {
   TypesToScan.push_back(Ty);
   while (!TypesToScan.empty()) {
     QualType T = TypesToScan.pop_back_val();
-    assert(T == T.getCanonicalType().getUnqualifiedType() && "expected sugar-free type");
+    assert(T == T.getCanonicalType().getUnqualifiedType() &&
+           "expected sugar-free type");
     assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
 
     if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
-      QualType ElTy = AT->getElementType().getCanonicalType().getUnqualifiedType();
+      QualType ElTy =
+          AT->getElementType().getCanonicalType().getUnqualifiedType();
       if (ElTy->isBuiltinType())
         return ElTy->isHLSLSpecificType();
       TypesToScan.push_back(ElTy);
-      continue; 
+      continue;
     }
 
     if (const auto *VT = dyn_cast<VectorType>(T)) {
-      QualType ElTy = VT->getElementType().getCanonicalType().getUnqualifiedType();
+      QualType ElTy =
+          VT->getElementType().getCanonicalType().getUnqualifiedType();
       assert(ElTy->isBuiltinType() && "vectors can only contain builtin types");
       if (ElTy->isHLSLSpecificType())
         return true;
@@ -1187,12 +1190,13 @@ static bool calculateIsIntangibleType(QualType Ty) {
     if (const auto *RT = dyn_cast<RecordType>(T)) {
       const RecordDecl *RD = RT->getDecl();
       for (const auto *FD : RD->fields()) {
-        QualType FieldTy = FD->getType().getCanonicalType().getUnqualifiedType();
+        QualType FieldTy =
+            FD->getType().getCanonicalType().getUnqualifiedType();
         if (FieldTy->isBuiltinType()) {
           if (FieldTy->isHLSLSpecificType())
             return true;
         } else {
-          TypesToScan.push_back(FieldTy); 
+          TypesToScan.push_back(FieldTy);
         }
       }
       continue;
@@ -1207,7 +1211,8 @@ bool SemaHLSL::IsIntangibleType(const clang::QualType Ty) {
 
   const auto CachedEntry = IsIntangibleTypeCache.find(Ty.getTypePtr());
   if (CachedEntry != IsIntangibleTypeCache.end()) {
-    assert(CachedEntry->second == calculateIsIntangibleType(Ty) && "IsIntangibleType mismatch");
+    assert(CachedEntry->second == calculateIsIntangibleType(Ty) &&
+           "IsIntangibleType mismatch");
     return CachedEntry->second;
   }
 

>From 481c118d7d94f16c9cc9babbaaa794f951883088 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 21:16:19 -0700
Subject: [PATCH 4/6] add tests

---
 .../Types/Traits/IsIntangibleType.hlsl        | 52 +++++++++++++++++++
 .../Types/Traits/IsIntangibleTypeErrors.hlsl  | 11 ++++
 2 files changed, 63 insertions(+)
 create mode 100644 clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
 create mode 100644 clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl

diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
new file mode 100644
index 00000000000000..ae6da681d5100e
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+_Static_assert(__builtin_is_intangible(__hlsl_resource_t), "");
+// no need to check array of __hlsl_resource_t, arrays of sizeless types are not supported
+
+_Static_assert(!__builtin_is_intangible(int), "");
+_Static_assert(!__builtin_is_intangible(float3), "");
+_Static_assert(!__builtin_is_intangible(half[4]), "");
+
+typedef __hlsl_resource_t Res;
+_Static_assert(__builtin_is_intangible(const Res), "");
+// no need to check array of Res, arrays of sizeless types are not supported
+
+struct ABuffer {
+    const int i[10];
+    __hlsl_resource_t h;
+};
+_Static_assert(__builtin_is_intangible(ABuffer), "");
+_Static_assert(__builtin_is_intangible(ABuffer[10]), "");
+
+struct MyStruct {
+    half2 h2;
+    int3 i3;
+};
+_Static_assert(!__builtin_is_intangible(MyStruct), "");
+_Static_assert(!__builtin_is_intangible(MyStruct[10]), "");
+
+class MyClass {
+    int3 ivec;
+    float farray[12];
+    MyStruct ms;
+    ABuffer buf;
+};
+_Static_assert(__builtin_is_intangible(MyClass), "");
+_Static_assert(__builtin_is_intangible(MyClass[2]), "");
+
+union U {
+    double d[4];
+    Res buf;
+};
+_Static_assert(__builtin_is_intangible(U), "");
+_Static_assert(__builtin_is_intangible(U[100]), "");
+
+class MyClass2 {
+    int3 ivec;
+    float farray[12];
+    U u;
+};
+_Static_assert(__builtin_is_intangible(MyClass2), "");
+_Static_assert(__builtin_is_intangible(MyClass2[5]), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl
new file mode 100644
index 00000000000000..bfb654de0dcfca
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library  -finclude-default-header -verify %s
+
+struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
+_Static_assert(!__builtin_is_intangible(Undefined), ""); // expected-error{{incomplete type 'Undefined' used in type trait expression}}
+
+void fn(int X) {
+  // expected-error@#vla {{variable length arrays are not supported for the current target}}
+  // expected-error@#vla {{variable length arrays are not supported in '__builtin_is_intangible'}}
+  // expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
+  _Static_assert(!__builtin_is_intangible(int[X]), ""); // #vla
+}
\ No newline at end of file

>From 2df05761de1df378cedec49430c327a21f8ee089 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 21:56:28 -0700
Subject: [PATCH 5/6] base classes!

---
 clang/lib/Sema/SemaHLSL.cpp                   | 21 +++++++++++--------
 .../Types/Traits/IsIntangibleType.hlsl        |  9 ++++++++
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5e5917c40bc1cc..09d4d6e7f13c72 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -10,6 +10,7 @@
 
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -1157,7 +1158,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
 }
 
 static bool calculateIsIntangibleType(QualType Ty) {
-  Ty = Ty.getCanonicalType().getUnqualifiedType();
+  Ty = Ty->getCanonicalTypeUnqualified();
   if (Ty->isBuiltinType())
     return Ty->isHLSLSpecificType();
 
@@ -1165,13 +1166,11 @@ static bool calculateIsIntangibleType(QualType Ty) {
   TypesToScan.push_back(Ty);
   while (!TypesToScan.empty()) {
     QualType T = TypesToScan.pop_back_val();
-    assert(T == T.getCanonicalType().getUnqualifiedType() &&
-           "expected sugar-free type");
+    assert(T == T->getCanonicalTypeUnqualified() && "expected sugar-free type");
     assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
 
     if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
-      QualType ElTy =
-          AT->getElementType().getCanonicalType().getUnqualifiedType();
+      QualType ElTy = AT->getElementType()->getCanonicalTypeUnqualified();
       if (ElTy->isBuiltinType())
         return ElTy->isHLSLSpecificType();
       TypesToScan.push_back(ElTy);
@@ -1179,8 +1178,7 @@ static bool calculateIsIntangibleType(QualType Ty) {
     }
 
     if (const auto *VT = dyn_cast<VectorType>(T)) {
-      QualType ElTy =
-          VT->getElementType().getCanonicalType().getUnqualifiedType();
+      QualType ElTy = VT->getElementType()->getCanonicalTypeUnqualified();
       assert(ElTy->isBuiltinType() && "vectors can only contain builtin types");
       if (ElTy->isHLSLSpecificType())
         return true;
@@ -1190,8 +1188,7 @@ static bool calculateIsIntangibleType(QualType Ty) {
     if (const auto *RT = dyn_cast<RecordType>(T)) {
       const RecordDecl *RD = RT->getDecl();
       for (const auto *FD : RD->fields()) {
-        QualType FieldTy =
-            FD->getType().getCanonicalType().getUnqualifiedType();
+        QualType FieldTy = FD->getType()->getCanonicalTypeUnqualified();
         if (FieldTy->isBuiltinType()) {
           if (FieldTy->isHLSLSpecificType())
             return true;
@@ -1199,6 +1196,12 @@ static bool calculateIsIntangibleType(QualType Ty) {
           TypesToScan.push_back(FieldTy);
         }
       }
+
+      if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+        for (const CXXBaseSpecifier &B : CXXRD->bases()) {
+          TypesToScan.push_back(B.getType()->getCanonicalTypeUnqualified());
+        }
+      }
       continue;
     }
   }
diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
index ae6da681d5100e..f7ef7f543bfb5e 100644
--- a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
@@ -50,3 +50,12 @@ class MyClass2 {
 };
 _Static_assert(__builtin_is_intangible(MyClass2), "");
 _Static_assert(__builtin_is_intangible(MyClass2[5]), "");
+
+class Simple {
+    int a;
+};
+
+class MyClass3 : MyClass2, Simple {
+    half h;
+};
+_Static_assert(__builtin_is_intangible(MyClass3), "");

>From 227befd3ecff7899ef0088045176cead79aa8adc Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 15 Aug 2024 22:26:44 -0700
Subject: [PATCH 6/6] Update default for incomplete type

---
 clang/lib/Sema/SemaExprCXX.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d3964f5da01e00..94132a4823e305 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5689,7 +5689,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     if (!T->isVoidType() && !T->isIncompleteArrayType())
       if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
                                    diag::err_incomplete_type))
-        return true;
+        return false;
     DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___builtin_is_intangible);
     return Self.HLSL().IsIntangibleType(T);
   }



More information about the cfe-commits mailing list