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

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 15 21:16:02 PDT 2024


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

Implements `__builtin_is_intangible` type trait.

HLSL intangible types are special implementation-defined types such as resource handles or samplers. Any class that is an array of intangible type or contains base class or members of intangible types is also an intangible type. 

Fixes #[102954](https://github.com/llvm/llvm-project/issues/102954)

>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/3] 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/3] 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/3] 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;
   }
 



More information about the cfe-commits mailing list