-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[HLSL] add IsTypedResourceElementCompatible type trait #114864
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
[HLSL] add IsTypedResourceElementCompatible type trait #114864
Conversation
@llvm/pr-subscribers-hlsl Author: Joshua Batista (bob80905) ChangesThis PR implements a new type trait as a builtin, __builtin_hlsl_is_typed_resource_element_compatible Full diff: https://github.com/llvm/llvm-project/pull/114864.diff 6 Files Affected:
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fdfb35de9cf287..2c692c999bdff5 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -662,6 +662,7 @@ KEYWORD(out , KEYHLSL)
// HLSL Type traits
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
+TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, 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 e30acd87f77218..06c541dec08cc8 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -132,6 +132,7 @@ class SemaHLSL : public SemaBase {
// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
+ bool IsTypedResourceElementCompatible(QualType T1);
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 50c1b24fce6da7..0001e343da84be 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5032,6 +5032,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsScalar:
case UTT_IsCompound:
case UTT_IsMemberPointer:
+ case UTT_IsTypedResourceElementCompatible:
// Fall-through
// These traits are modeled on type predicates in C++0x [meta.unary.prop]
@@ -5714,6 +5715,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
tok::kw___builtin_hlsl_is_intangible))
return false;
return T->isHLSLIntangibleType();
+
+ case UTT_IsTypedResourceElementCompatible:
+ assert(Self.getLangOpts().HLSL &&
+ "line vector layout compatible types are HLSL-only feature");
+ if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
+ diag::err_incomplete_type))
+ return false;
+
+ return Self.HLSL().IsTypedResourceElementCompatible(T);
}
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1f6c5b8d4561bc..b4cd4aa9c85afd 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2163,6 +2163,50 @@ static void BuildFlattenedTypeList(QualType BaseTy,
}
}
+bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
+ if (QT.isNull())
+ return false;
+
+ // check if the outer type was an array type
+ if (QT->isArrayType())
+ return false;
+
+ llvm::SmallVector<QualType, 4> QTTypes;
+ BuildFlattenedTypeList(QT, QTTypes);
+
+ assert(QTTypes.size() > 0 &&
+ "expected at least one constituent type from non-null type");
+ QualType FirstQT = QTTypes[0];
+
+ // element count cannot exceed 4
+ if (QTTypes.size() > 4)
+ return false;
+
+ for (QualType TempQT : QTTypes) {
+ // ensure homogeneity
+ if (TempQT != FirstQT)
+ return false;
+
+ if (const BuiltinType *BT = TempQT->getAs<BuiltinType>()) {
+ if (BT->isBooleanType() || BT->isEnumeralType())
+ return false;
+
+ // Check if it is an array type.
+ if (TempQT->isArrayType())
+ return false;
+ }
+ }
+
+ // if the loop above completes without returning, then
+ // we've guaranteed homogeneity
+ int TotalSizeInBytes =
+ (SemaRef.Context.getTypeSize(FirstQT) / 8) * QTTypes.size();
+ if (TotalSizeInBytes > 16)
+ return false;
+
+ return true;
+}
+
bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
if (T1.isNull() || T2.isNull())
return false;
diff --git a/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
new file mode 100644
index 00000000000000..669c03ea39c8f7
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+struct oneInt {
+ int i;
+};
+
+struct twoInt {
+ int aa;
+ int ab;
+};
+
+struct threeInts {
+ oneInt o;
+ twoInt t;
+};
+
+struct oneFloat {
+ float f;
+};
+struct depthDiff {
+ int i;
+ oneInt o;
+ oneFloat f;
+};
+
+struct notHomogenous{
+ int i;
+ float f;
+};
+
+struct EightElements {
+ twoInt x[2];
+ twoInt y[2];
+};
+
+struct EightHalves {
+half x[8];
+};
+
+struct intVec {
+ int2 i;
+};
+
+struct oneIntWithVec {
+ int i;
+ oneInt i2;
+ int2 i3;
+};
+
+struct weirdStruct {
+ int i;
+ intVec iv;
+};
+
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(int), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float4), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(double2), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneInt), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneFloat), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(twoInt), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(threeInts), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notHomogenous), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(depthDiff), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightElements), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightHalves), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneIntWithVec), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(weirdStruct), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(RWBuffer<int>), "");
+
+
+// arrays not allowed
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");
+
+template<typename T> struct TemplatedBuffer {
+ T a;
+ __hlsl_resource_t h;
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedBuffer<int>), "");
+
+struct MyStruct1 : TemplatedBuffer<float> {
+ float x;
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct1), "");
+
+struct MyStruct2 {
+ const TemplatedBuffer<float> TB[10];
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct2), "");
+
+template<typename T> struct SimpleTemplate {
+ T a;
+};
+
+// though the element type is incomplete, the type trait should still technically return true
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<__hlsl_resource_t>), "");
+
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<float>), "");
+
+
diff --git a/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl
new file mode 100644
index 00000000000000..167a5be6e93843
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+
+// types must be complete
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(__hlsl_resource_t), "");
+
+// expected-note@+1{{forward declaration of 'notComplete'}}
+struct notComplete;
+// expected-error@+1{{incomplete type 'notComplete' where a complete type is required}}
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notComplete), "");
+
|
@llvm/pr-subscribers-clang Author: Joshua Batista (bob80905) ChangesThis PR implements a new type trait as a builtin, __builtin_hlsl_is_typed_resource_element_compatible Full diff: https://github.com/llvm/llvm-project/pull/114864.diff 6 Files Affected:
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fdfb35de9cf287..2c692c999bdff5 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -662,6 +662,7 @@ KEYWORD(out , KEYHLSL)
// HLSL Type traits
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
+TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, 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 e30acd87f77218..06c541dec08cc8 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -132,6 +132,7 @@ class SemaHLSL : public SemaBase {
// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
+ bool IsTypedResourceElementCompatible(QualType T1);
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 50c1b24fce6da7..0001e343da84be 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5032,6 +5032,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsScalar:
case UTT_IsCompound:
case UTT_IsMemberPointer:
+ case UTT_IsTypedResourceElementCompatible:
// Fall-through
// These traits are modeled on type predicates in C++0x [meta.unary.prop]
@@ -5714,6 +5715,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
tok::kw___builtin_hlsl_is_intangible))
return false;
return T->isHLSLIntangibleType();
+
+ case UTT_IsTypedResourceElementCompatible:
+ assert(Self.getLangOpts().HLSL &&
+ "line vector layout compatible types are HLSL-only feature");
+ if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
+ diag::err_incomplete_type))
+ return false;
+
+ return Self.HLSL().IsTypedResourceElementCompatible(T);
}
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1f6c5b8d4561bc..b4cd4aa9c85afd 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2163,6 +2163,50 @@ static void BuildFlattenedTypeList(QualType BaseTy,
}
}
+bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
+ if (QT.isNull())
+ return false;
+
+ // check if the outer type was an array type
+ if (QT->isArrayType())
+ return false;
+
+ llvm::SmallVector<QualType, 4> QTTypes;
+ BuildFlattenedTypeList(QT, QTTypes);
+
+ assert(QTTypes.size() > 0 &&
+ "expected at least one constituent type from non-null type");
+ QualType FirstQT = QTTypes[0];
+
+ // element count cannot exceed 4
+ if (QTTypes.size() > 4)
+ return false;
+
+ for (QualType TempQT : QTTypes) {
+ // ensure homogeneity
+ if (TempQT != FirstQT)
+ return false;
+
+ if (const BuiltinType *BT = TempQT->getAs<BuiltinType>()) {
+ if (BT->isBooleanType() || BT->isEnumeralType())
+ return false;
+
+ // Check if it is an array type.
+ if (TempQT->isArrayType())
+ return false;
+ }
+ }
+
+ // if the loop above completes without returning, then
+ // we've guaranteed homogeneity
+ int TotalSizeInBytes =
+ (SemaRef.Context.getTypeSize(FirstQT) / 8) * QTTypes.size();
+ if (TotalSizeInBytes > 16)
+ return false;
+
+ return true;
+}
+
bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
if (T1.isNull() || T2.isNull())
return false;
diff --git a/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
new file mode 100644
index 00000000000000..669c03ea39c8f7
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+struct oneInt {
+ int i;
+};
+
+struct twoInt {
+ int aa;
+ int ab;
+};
+
+struct threeInts {
+ oneInt o;
+ twoInt t;
+};
+
+struct oneFloat {
+ float f;
+};
+struct depthDiff {
+ int i;
+ oneInt o;
+ oneFloat f;
+};
+
+struct notHomogenous{
+ int i;
+ float f;
+};
+
+struct EightElements {
+ twoInt x[2];
+ twoInt y[2];
+};
+
+struct EightHalves {
+half x[8];
+};
+
+struct intVec {
+ int2 i;
+};
+
+struct oneIntWithVec {
+ int i;
+ oneInt i2;
+ int2 i3;
+};
+
+struct weirdStruct {
+ int i;
+ intVec iv;
+};
+
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(int), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float4), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(double2), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneInt), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneFloat), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(twoInt), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(threeInts), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notHomogenous), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(depthDiff), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightElements), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightHalves), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneIntWithVec), "");
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(weirdStruct), "");
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(RWBuffer<int>), "");
+
+
+// arrays not allowed
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");
+
+template<typename T> struct TemplatedBuffer {
+ T a;
+ __hlsl_resource_t h;
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedBuffer<int>), "");
+
+struct MyStruct1 : TemplatedBuffer<float> {
+ float x;
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct1), "");
+
+struct MyStruct2 {
+ const TemplatedBuffer<float> TB[10];
+};
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct2), "");
+
+template<typename T> struct SimpleTemplate {
+ T a;
+};
+
+// though the element type is incomplete, the type trait should still technically return true
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<__hlsl_resource_t>), "");
+
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<float>), "");
+
+
diff --git a/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl
new file mode 100644
index 00000000000000..167a5be6e93843
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatibleErrors.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+
+// types must be complete
+_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(__hlsl_resource_t), "");
+
+// expected-note@+1{{forward declaration of 'notComplete'}}
+struct notComplete;
+// expected-error@+1{{incomplete type 'notComplete' where a complete type is required}}
+_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notComplete), "");
+
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few additional test cases to add:
- Empty struct types
- typedef element types to something else, and mix the typedef and original type
clang/lib/Sema/SemaExprCXX.cpp
Outdated
|
||
case UTT_IsTypedResourceElementCompatible: | ||
assert(Self.getLangOpts().HLSL && | ||
"line vector layout compatible types are HLSL-only feature"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"line vector layout compatible types are HLSL-only feature"); | |
"typed resource element compatible types are HLSL-only feature"); |
llvm::SmallVector<QualType, 4> QTTypes; | ||
BuildFlattenedTypeList(QT, QTTypes); | ||
|
||
assert(QTTypes.size() > 0 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this assert fire if QT
is an empty struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When QT is an empty struct (like struct notComplete;
in clang\test\SemaHLSL\Types\Traits\IsTypedResourceElementCompatibleErrors.hlsl
)
the assert is never hit, the function is never entered.
clang\lib\Sema\SemaExprCXX.cpp::EvaluateUnaryTypeTrait
won't call IsTypedResourceElementCompatible
because there's an early return, that is executed when RequireCompleteType
returns false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an incomplete type, not an empty struct. What about something like:
struct EmptyStruct {};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EmptyStruct), "");
struct EmptyDerived : EmptyStruct {};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EmptyDerived), "");
struct EmptyBase : EmptyStruct {
int4 V;
};
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(EmptyBase), "");
We frequently find bugs in DXC with cases of empty structs, empty base classes, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #115045
clang/lib/Sema/SemaHLSL.cpp
Outdated
if (TempQT != FirstQT) | ||
return false; | ||
|
||
if (const BuiltinType *BT = TempQT->getAs<BuiltinType>()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than doing this in the loop for each type, you could do this after the loop on FirstQT, since all types need to be the same.
clang/lib/Sema/SemaHLSL.cpp
Outdated
|
||
for (QualType TempQT : QTTypes) { | ||
// ensure homogeneity | ||
if (TempQT != FirstQT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a call to hasSameUnqualifiedType
not a direct comparison.
clang/lib/Sema/SemaHLSL.cpp
Outdated
|
||
assert(QTTypes.size() > 0 && | ||
"expected at least one constituent type from non-null type"); | ||
QualType FirstQT = QTTypes[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll want to de-sugar this:
QualType FirstQT = QTTypes[0]; | |
QualType FirstQT = SemaRef.Context.getCanonicalType(QTTypes[0]); |
This PR implements a new type trait as a builtin, __builtin_hlsl_is_typed_resource_element_compatible
This type traits verifies that the given input type is suitable as a typed resource element type.
It checks that the given input type is homogeneous, has no more than 4 sub elements, does not exceed 16 bytes, and does not contain any arrays, booleans, or enums.
Fixes an issue in #113730 that needed to cause that PR to be reverted.
Fixes #113223