[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