[clang] [llvm] [HLSL] Implement '__builtin_hlsl_is_intangible' type trait (PR #104544)
Helena Kotas via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 27 12:30:15 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/9] 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/9] 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/9] 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/9] 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/9] 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/9] 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);
}
>From 4bbf083bd75de42c82e4b2068b541241fcd492fd Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 19 Aug 2024 15:04:58 -0700
Subject: [PATCH 7/9] Rename to `__builtin_hlsl_is_intangible`
---
clang/include/clang/Basic/TokenKinds.def | 2 +-
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
.../Types/Traits/IsIntangibleType.hlsl | 32 +++++++++----------
.../Types/Traits/IsIntangibleTypeErrors.hlsl | 6 ++--
4 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index f4fc7c321d9c5a..1b36d799f13f46 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -661,7 +661,7 @@ KEYWORD(out , KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"
// HLSL Type traits
-TYPE_TRAIT_1(__builtin_is_intangible, IsIntangibleType, KEYHLSL)
+TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 94132a4823e305..55366bfd20b100 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5690,7 +5690,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
diag::err_incomplete_type))
return false;
- DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___builtin_is_intangible);
+ DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___builtin_hlsl_is_intangible);
return Self.HLSL().IsIntangibleType(T);
}
}
diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
index f7ef7f543bfb5e..39a912f99d3896 100644
--- a/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleType.hlsl
@@ -2,30 +2,30 @@
// 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), "");
+_Static_assert(__builtin_hlsl_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]), "");
+_Static_assert(!__builtin_hlsl_is_intangible(int), "");
+_Static_assert(!__builtin_hlsl_is_intangible(float3), "");
+_Static_assert(!__builtin_hlsl_is_intangible(half[4]), "");
typedef __hlsl_resource_t Res;
-_Static_assert(__builtin_is_intangible(const Res), "");
+_Static_assert(__builtin_hlsl_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]), "");
+_Static_assert(__builtin_hlsl_is_intangible(ABuffer), "");
+_Static_assert(__builtin_hlsl_is_intangible(ABuffer[10]), "");
struct MyStruct {
half2 h2;
int3 i3;
};
-_Static_assert(!__builtin_is_intangible(MyStruct), "");
-_Static_assert(!__builtin_is_intangible(MyStruct[10]), "");
+_Static_assert(!__builtin_hlsl_is_intangible(MyStruct), "");
+_Static_assert(!__builtin_hlsl_is_intangible(MyStruct[10]), "");
class MyClass {
int3 ivec;
@@ -33,23 +33,23 @@ class MyClass {
MyStruct ms;
ABuffer buf;
};
-_Static_assert(__builtin_is_intangible(MyClass), "");
-_Static_assert(__builtin_is_intangible(MyClass[2]), "");
+_Static_assert(__builtin_hlsl_is_intangible(MyClass), "");
+_Static_assert(__builtin_hlsl_is_intangible(MyClass[2]), "");
union U {
double d[4];
Res buf;
};
-_Static_assert(__builtin_is_intangible(U), "");
-_Static_assert(__builtin_is_intangible(U[100]), "");
+_Static_assert(__builtin_hlsl_is_intangible(U), "");
+_Static_assert(__builtin_hlsl_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]), "");
+_Static_assert(__builtin_hlsl_is_intangible(MyClass2), "");
+_Static_assert(__builtin_hlsl_is_intangible(MyClass2[5]), "");
class Simple {
int a;
@@ -58,4 +58,4 @@ class Simple {
class MyClass3 : MyClass2, Simple {
half h;
};
-_Static_assert(__builtin_is_intangible(MyClass3), "");
+_Static_assert(__builtin_hlsl_is_intangible(MyClass3), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl
index bfb654de0dcfca..bbf2a1682e3f05 100644
--- a/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/IsIntangibleTypeErrors.hlsl
@@ -1,11 +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}}
+_Static_assert(!__builtin_hlsl_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-error@#vla {{variable length arrays are not supported in '__builtin_hlsl_is_intangible'}}
// expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
- _Static_assert(!__builtin_is_intangible(int[X]), ""); // #vla
+ _Static_assert(!__builtin_hlsl_is_intangible(int[X]), ""); // #vla
}
\ No newline at end of file
>From 6fd1bf74d532160338bf8b091a15e06369c37027 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 19 Aug 2024 17:52:07 -0700
Subject: [PATCH 8/9] clang-format
---
clang/lib/Sema/SemaExprCXX.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 55366bfd20b100..49942944c37806 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5690,7 +5690,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
diag::err_incomplete_type))
return false;
- DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___builtin_hlsl_is_intangible);
+ DiagnoseVLAInCXXTypeTrait(Self, TInfo,
+ tok::kw___builtin_hlsl_is_intangible);
return Self.HLSL().IsIntangibleType(T);
}
}
>From 7f29d6fe8f7ca5fac9dfb475fc256b82b3b64048 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 27 Aug 2024 12:29:29 -0700
Subject: [PATCH 9/9] Address code review feedback
---
clang/include/clang/AST/Type.h | 7 ++
clang/include/clang/Sema/SemaHLSL.h | 6 +-
clang/lib/Sema/SemaExprCXX.cpp | 1 +
clang/lib/Sema/SemaHLSL.cpp | 19 ++--
particle_life.hlsl | 147 ++++++++++++++++++++++++++++
5 files changed, 171 insertions(+), 9 deletions(-)
create mode 100644 particle_life.hlsl
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 575f3c17a3f691..d19e353967fa8b 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2656,6 +2656,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
#include "clang/Basic/HLSLIntangibleTypes.def"
bool isHLSLSpecificType() const; // Any HLSL specific type
+ bool isHLSLIntangibleType() const; // Any HLSL intangible type
/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -8286,6 +8287,12 @@ inline bool Type::isHLSLSpecificType() const {
false; // end boolean or operation
}
+inline bool Type::isHLSLIntangibleType() const {
+ // All HLSL specific types are currently intangible type as well, but that
+ // might change in the future.
+ return isHLSLSpecificType();
+}
+
inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType);
}
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index e923df60b91458..cae3a502c73cf0 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -62,12 +62,12 @@ class SemaHLSL : public SemaBase {
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
-private:
- llvm::DenseMap<const Type *, bool> IsIntangibleTypeCache;
-
// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) 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 7e179bc9939cdd..4c7c6bfdb2db9d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5697,6 +5697,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return false;
}
case UTT_IsIntangibleType:
+ assert(Self.getLangOpts().HLSL && "intangible types are HLSL-only feature");
if (!T->isVoidType() && !T->isIncompleteArrayType())
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
diag::err_incomplete_type))
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index e939fca1411a5d..f7cf18be195f3f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -29,7 +29,7 @@
using namespace clang;
-SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S), IsIntangibleTypeCache(8) {}
+SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S), IsIntangibleTypeCache() {}
Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
SourceLocation KwLoc, IdentifierInfo *Ident,
@@ -1528,11 +1528,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
static bool calculateIsIntangibleType(QualType Ty) {
- Ty = Ty->getCanonicalTypeUnqualified();
- if (Ty->isBuiltinType())
- return Ty->isHLSLSpecificType();
+ assert(!Ty.getCanonicalType().getUnqualifiedType()->isBuiltinType() &&
+ "builtin types should be taken care of in IsIntangibleType");
- llvm::SmallVector<QualType, 8> TypesToScan;
+ llvm::SmallVector<QualType> TypesToScan;
TypesToScan.push_back(Ty);
while (!TypesToScan.empty()) {
QualType T = TypesToScan.pop_back_val();
@@ -1582,6 +1581,12 @@ bool SemaHLSL::IsIntangibleType(const clang::QualType Ty) {
if (Ty.isNull())
return false;
+ // check if it's a builtin type first (simple check, no need to cache it)
+ QualType CT = Ty->getCanonicalTypeUnqualified();
+ if (CT->isBuiltinType())
+ return CT->isHLSLIntangibleType();
+
+ // more complex type -> check if we already have it in the cache
const auto CachedEntry = IsIntangibleTypeCache.find(Ty.getTypePtr());
if (CachedEntry != IsIntangibleTypeCache.end()) {
assert(CachedEntry->second == calculateIsIntangibleType(Ty) &&
@@ -1589,9 +1594,12 @@ bool SemaHLSL::IsIntangibleType(const clang::QualType Ty) {
return CachedEntry->second;
}
+ // calculate and add to cache
bool IsIntangible = calculateIsIntangibleType(Ty);
IsIntangibleTypeCache[Ty.getTypePtr()] = IsIntangible;
return IsIntangible;
+}
+
static void BuildFlattenedTypeList(QualType BaseTy,
llvm::SmallVectorImpl<QualType> &List) {
llvm::SmallVector<QualType, 16> WorkList;
@@ -1673,4 +1681,3 @@ bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
return SemaRef.IsLayoutCompatible(LHS, RHS);
});
}
-}
diff --git a/particle_life.hlsl b/particle_life.hlsl
new file mode 100644
index 00000000000000..4cffbdb04e1b60
--- /dev/null
+++ b/particle_life.hlsl
@@ -0,0 +1,147 @@
+#define ROOT_SIGNATURE \
+ "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)," \
+ "CBV(b0)," \
+ "SRV(t0)," \
+ "SRV(t1)," \
+ "UAV(u0)," \
+ "UAV(u1)"
+
+
+cbuffer CONSTANTS : register(b0) {
+ uint ParticleTypeMax;
+ uint NumParticles;
+ float2 WorldSize;
+ float Friction;
+ float ForceMultipler;
+}
+
+struct Rule {
+ float force;
+ float min_distance;
+ float max_distance;
+};
+
+struct Particle {
+ float2 position;
+ float2 velocity;
+ uint type;
+};
+
+struct Vertex {
+ float2 position;
+ uint color;
+};
+
+StructuredBuffer<Rule> Rules : register(t0);
+StructuredBuffer<Particle> OldParticles : register(t1);
+RWStructuredBuffer<Particle> NewParticles : register(u0);
+RWStructuredBuffer<Vertex> Vertices : register(u1);
+
+
+float3 particle_type_to_color(uint type);
+uint float_to_abgr(float3 rgb);
+
+
+[numthreads(32, 1, 1)]
+void main(uint3 dispatch_thread_id : SV_DispatchThreadID) {
+ uint particle_id = dispatch_thread_id.x;
+
+ Particle particle = OldParticles[particle_id];
+
+ // Accumulate forces
+ float2 force = float2(0,0);
+ float hit = 0;
+
+ for (uint i = 0; i < NumParticles; ++i) {
+ if (i == particle_id)
+ continue;
+
+ Particle other_particle = OldParticles[i];
+
+ Rule rule = Rules[particle.type * ParticleTypeMax + other_particle.type];
+
+ float2 direction = other_particle.position - particle.position;
+
+ // wrapping
+ if (direction.x > WorldSize.x * 0.5f)
+ direction.x -= WorldSize.x;
+ if (direction.x < WorldSize.x * -0.5f)
+ direction.x += WorldSize.x;
+ if (direction.y > WorldSize.y * 0.5f)
+ direction.y -= WorldSize.y;
+ if (direction.y < WorldSize.y * -0.5f)
+ direction.y += WorldSize.y;
+
+ // apply rule
+ float distance = length(direction);
+ direction = normalize(direction);
+
+ if (distance < rule.min_distance) {
+ float repulsive_amount = abs(rule.force) * (1.0f - (distance / rule.min_distance)) * -3.0f;
+ force += direction * repulsive_amount;
+ }
+
+ if (distance < rule.max_distance) {
+ float attract_amount = rule.force * (1.0f - (distance / rule.max_distance));
+ force += direction * attract_amount;
+ hit += 0.01f;
+ }
+ }
+
+ float2 velocity = particle.velocity;
+ velocity += force * ForceMultipler;
+ velocity *= Friction;
+
+ particle.position = particle.position + velocity;
+
+ if (particle.position.x < 0)
+ particle.position.x += WorldSize.x;
+
+ if (particle.position.x > WorldSize.x)
+ particle.position.x -= WorldSize.x;
+
+ if (particle.position.y < 0)
+ particle.position.y += WorldSize.y;
+
+ if (particle.position.y > WorldSize.y)
+ particle.position.y -= WorldSize.y;
+
+
+ particle.velocity = velocity;
+
+ Vertices[particle_id].position = particle.position;
+
+ float3 color = particle_type_to_color(particle.type);
+
+ color = lerp(color, color * 0.1f, 1-saturate(hit));
+
+ Vertices[particle_id].color = float_to_abgr(color);
+
+ NewParticles[particle_id] = particle;
+}
+
+
+
+// from https://chilliant.com/rgb2hsv.html
+float3 hue2rgb(float H) {
+ float R = abs(H * 6 - 3) - 1;
+ float G = 2 - abs(H * 6 - 2);
+ float B = 2 - abs(H * 6 - 4);
+ return saturate(float3(R,G,B));
+}
+
+float3 particle_type_to_color(uint type) {
+ float hue = (float)type / float(ParticleTypeMax);
+ return hue2rgb(hue);
+}
+
+uint float_to_abgr(float3 rgb) {
+ rgb *= 255.0;
+
+ uint r = rgb.x;
+ uint g = rgb.y;
+ uint b = rgb.z;
+ uint a = 255;
+
+ return (a << 24) | (b << 16) | (g << 8) | r;
+}
\ No newline at end of file
More information about the cfe-commits
mailing list