[clang] [HLSL] Implement '__builtin_is_intangible' type trait (PR #104544)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 15 22:28:03 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Helena Kotas (hekota)
<details>
<summary>Changes</summary>
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)
---
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
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/104544
More information about the cfe-commits
mailing list