Skip to content

[HLSL] Add empty struct test cases to __builtin_hlsl_is_typed_resource_element_compatible test file #115045

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 7 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 20 additions & 27 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2200,47 +2200,40 @@ static void BuildFlattenedTypeList(QualType BaseTy,
}

bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
if (QT.isNull())
// null and array types are not allowed.
if (QT.isNull() || QT->isArrayType())
return false;

// check if the outer type was an array type
if (QT->isArrayType())
// UDT types are not allowed
if (QT->isRecordType())
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 = SemaRef.Context.getCanonicalType(QTTypes[0]);

// element count cannot exceed 4
if (QTTypes.size() > 4)
if (QT->isBooleanType() || QT->isEnumeralType())
return false;

for (QualType TempQT : QTTypes) {
// ensure homogeneity
if (!getASTContext().hasSameUnqualifiedType(FirstQT, TempQT))
// the only other valid builtin types are scalars or vectors
if (QT->isArithmeticType()) {
if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
return false;
return true;
}

if (const BuiltinType *BT = FirstQT->getAs<BuiltinType>()) {
if (BT->isBooleanType() || BT->isEnumeralType())
if (const VectorType *VT = QT->getAs<VectorType>()) {
int ArraySize = VT->getNumElements();

if (ArraySize > 4)
return false;

// Check if it is an array type.
if (FirstQT->isArrayType())
QualType ElTy = VT->getElementType();
if (ElTy->isBooleanType())
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;
if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
return false;
return true;
}

return true;
return false;
}

bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
Expand Down
111 changes: 27 additions & 84 deletions clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
Original file line number Diff line number Diff line change
@@ -1,109 +1,52 @@
// 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>), "");

struct s {
int x;
};

// arrays not allowed
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");
struct Empty {};

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;
template<typename T> struct TemplatedVector {
vector<T, 4> v;
};
_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), "");
// structs not allowed
Copy link
Collaborator

Choose a reason for hiding this comment

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

This change may be a little too aggressive at removing test cases. All the struct cases should return false, but we could maybe test a few different struct formations. Some key ones to cover: forward declaration (incomplete), empty structure, template struct, template struct containing a vector that would be valid.

_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(s), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(Empty), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedBuffer<int>), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedVector<int>), "");

template<typename T> struct SimpleTemplate {
T a;
};
// arrays not allowed
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");

// 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>), "");
typedef vector<int, 8> int8;
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should also have typedef tests that fail, the only one you have right now is a successful case.

What about arrays?

_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(float[3]), "");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The typedef test that I have right now does return false when evaluated by the builtin, it's a typedef of 8 ints in a vector. I also test for arrays with half[4]. Are these sufficient?

// too many elements
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(int8), "");

_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<float>), "");
typedef int MyInt;
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(MyInt), "");

// bool and enums not allowed
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(bool), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(vector<bool, 2>), "");

typedef int myInt;
enum numbers { one, two, three };

struct TypeDefTest {
int x;
myInt y;
};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(numbers), "");

// size exceeds 16 bytes, and exceeds element count limit after splitting 64 bit types into 32 bit types
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(double3), "");

_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(TypeDefTest), "");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to remove all these tests, or just update them to expect false results?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They could be left in and switched to false, but it doesn't seem valuable. All structs are disallowed, so I think just one struct test would suffice.

Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// 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), "");
_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), "");

Loading