Skip to content

[HLSL] Implement '__builtin_hlsl_is_intangible' type trait #104544

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 20 commits into from
Sep 4, 2024

Conversation

hekota
Copy link
Member

@hekota hekota commented Aug 16, 2024

Implements __builtin_hlsl_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

@hekota hekota marked this pull request as ready for review August 16, 2024 05:27
@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 Aug 16, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 16, 2024

@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-clang

Author: Helena Kotas (hekota)

Changes

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


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

6 Files Affected:

  • (modified) clang/include/clang/Basic/TokenKinds.def (+3)
  • (modified) clang/include/clang/Sema/SemaHLSL.h (+6)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+9)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+70-1)
  • (added) clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl (+61)
  • (added) clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl (+11)
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..663dea12880d1b 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -62,6 +62,12 @@ class SemaHLSL : public SemaBase {
   void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+  // HLSL Type trait implementations
+  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 5356bcf172f752..94132a4823e305 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"
@@ -5098,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;
 
@@ -5683,6 +5685,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 false;
+    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..09d4d6e7f13c72 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -10,8 +10,10 @@
 
 #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"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TargetInfo.h"
@@ -27,7 +29,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,
@@ -1154,3 +1156,70 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
   }
   return false;
 }
+
+static bool calculateIsIntangibleType(QualType Ty) {
+  Ty = Ty->getCanonicalTypeUnqualified();
+  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->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()->getCanonicalTypeUnqualified();
+      if (ElTy->isBuiltinType())
+        return ElTy->isHLSLSpecificType();
+      TypesToScan.push_back(ElTy);
+      continue;
+    }
+
+    if (const auto *VT = dyn_cast<VectorType>(T)) {
+      QualType ElTy = VT->getElementType()->getCanonicalTypeUnqualified();
+      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()->getCanonicalTypeUnqualified();
+        if (FieldTy->isBuiltinType()) {
+          if (FieldTy->isHLSLSpecificType())
+            return true;
+        } else {
+          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;
+    }
+  }
+  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;
+}
diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
new file mode 100644
index 00000000000000..f7ef7f543bfb5e
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
@@ -0,0 +1,61 @@
+// 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]), "");
+
+class Simple {
+    int a;
+};
+
+class MyClass3 : MyClass2, Simple {
+    half h;
+};
+_Static_assert(__builtin_is_intangible(MyClass3), "");
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

@hekota hekota changed the title [HLSL] Implement '__builtin_is_intangible' type trait [HLSL] Implement '__builtin_hlsl_is_intangible' type trait Aug 19, 2024
Copy link

github-actions bot commented Aug 19, 2024

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

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.

Looks good overall. I have some areas where I still feel confused though

Copy link

@pow3clk pow3clk left a comment

Choose a reason for hiding this comment

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

One more question, but it looks good to me!

@pow2clk pow2clk requested a review from pow3clk August 27, 2024 23:49
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.

Oops. I approved on my underprivileged laptop account 😳

@pow2clk pow2clk removed the request for review from pow3clk August 27, 2024 23:50
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.

I left an inline comment about this, but rather than keeping a side map in the SemaHLSL object we should take a bit in the RecordDecl bitfield to signify if the type is intangible.

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.

Overall looks good. I think that in the places outside SemaHLSL we should try to refer to the trait as HLSLIntangible to make it clear that it is a language-mode specific feature. We don't need to repeat HLSL a million times in SemaHLSL because that would just be noisy and redundant.

@hekota hekota merged commit 9efe377 into llvm:main Sep 4, 2024
8 checks passed
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 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.

7 participants