summaryrefslogtreecommitdiffstats
path: root/tests/language-feature
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2025-08-29 15:52:34 -0700
committerGitHub <noreply@github.com>2025-08-29 22:52:34 +0000
commit7758625d3fea67e55e98e7e4103d56c9918365be (patch)
tree2ed40aeb4d16262866e5540dad1a519951b5f772 /tests/language-feature
parent450ef7934c1adfdf4a3a3c72967de3c5798a020d (diff)
[CBP] Pointer frontend changes + groupshared pointer support (#7848)
Resolves #7628 Resolves: #8197 Primary Goals: 1. Add `Access` to pointer 2. AddressSpace::GroupShared support for pointers (SPIR-V) 3. Add `__getAddress()` to replace `&` * `&` is not updated to `require(cpu)` since slangpy uses `&`. This means we must: (1) merge PR; (2) replace `&` with `__getAddress()`; (3) add `require(cpu)` to `&` Changes: * Added to `Ptr` the `Access` generic argument & logic (for `Access::Read`). * Moved the generic argument `AddressSpace` from `Ptr` to the end of the type. * Added pointer casting support between any `Ptr` as long as the `AddressSpace` is the same * Disallow globallycoherent T* and coherent T* * Disallow const T*, T const*, and const T* * Fixed .natvis display of `ConstantValue` `ValOperandNode` * Support generic resolution of type-casted integers * Added `VariablePointer` emitting for spirv + other minor logic needed for groupshared pointers Breaking Changes: * Anyone using the `AddressSpace` of `Ptr` will now have to account for the `Access` argument * we disallow various syntax paired with `Ptr` and `T*` --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'tests/language-feature')
-rw-r--r--tests/language-feature/bitfield/msvc-repr-mixed.slang13
-rw-r--r--tests/language-feature/capability/address-of.slang17
-rw-r--r--tests/language-feature/pointer/const-ptr-variations.slang40
-rw-r--r--tests/language-feature/pointer/get-address-validation.slang82
-rw-r--r--tests/language-feature/pointer/globallycoherent-ptr.slang20
-rw-r--r--tests/language-feature/pointer/groupshared-ptr-of-device.slang28
-rw-r--r--tests/language-feature/pointer/pointer-access/pointer-access-frontend.slang14
-rw-r--r--tests/language-feature/pointer/pointer-access/read-only-pointer-1.slang41
-rw-r--r--tests/language-feature/pointer/pointer-access/read-only-pointer-2.slang19
-rw-r--r--tests/language-feature/pointer/pointer-casting/pointer-casting-rules.slang51
-rw-r--r--tests/language-feature/pointer/pointer-self-reference.slang10
-rw-r--r--tests/language-feature/pointer/ptr-to-groupshared.slang30
12 files changed, 356 insertions, 9 deletions
diff --git a/tests/language-feature/bitfield/msvc-repr-mixed.slang b/tests/language-feature/bitfield/msvc-repr-mixed.slang
index 47f03ad1d..cf1925dd6 100644
--- a/tests/language-feature/bitfield/msvc-repr-mixed.slang
+++ b/tests/language-feature/bitfield/msvc-repr-mixed.slang
@@ -19,20 +19,23 @@ struct MixedSizes {
uint16_t d : 8; // Same backing field
};
+groupshared MixedSizes m;
+
+typealias GroupSharedPtr<T> = Ptr<T, Access::ReadWrite, AddressSpace::GroupShared>;
+
[numthreads(1, 1, 1)]
void computeMain()
{
- MixedSizes m;
m.a = 0xA;
m.b = 0xB;
m.c = 0xCD;
m.d = 0xEF;
// Read the two backing fields separately
- uint8_t* p8 = (uint8_t*)&m;
- uint16_t* p16 = (uint16_t*)((uint8_t*)&m + 2); // Skip uint8_t + padding
+ GroupSharedPtr<uint8_t> p8 = (GroupSharedPtr<uint8_t>)__getAddress(m);
+ GroupSharedPtr<uint16_t> p16 = (GroupSharedPtr<uint16_t>)( ((GroupSharedPtr<uint8_t>)__getAddress(m)) + 2); // Skip uint8_t + padding
- outputBuffer[0] = uint(*p8);
- outputBuffer[1] = uint(*p16);
+ outputBuffer[0] = (uint)*p8;
+ outputBuffer[1] = (uint)*p16;
}
diff --git a/tests/language-feature/capability/address-of.slang b/tests/language-feature/capability/address-of.slang
new file mode 100644
index 000000000..924312b0e
--- /dev/null
+++ b/tests/language-feature/capability/address-of.slang
@@ -0,0 +1,17 @@
+//TEST:SIMPLE(filecheck=CHECK_FAIL): -target glsl -entry computeMain -stage compute
+//TEST:SIMPLE(filecheck=CHECK_PASS): -target spirv -entry computeMain -stage compute
+
+// Test that __getAddress correctly reports capabilities.
+
+uniform int* outputBuffer;
+uniform int* buffer;
+
+// CHECK_PASS: OpEntryPoint
+// CHECK_PASS-NOT: error
+
+// CHECK_FAIL: ([[# @LINE+1]]): error 36107{{.*}}glsl
+void computeMain()
+{
+ // CHECK: ([[# @LINE+1]]): note: see using of '__getAddress'
+ outputBuffer[0] = *(__getAddress(buffer[0]));
+} \ No newline at end of file
diff --git a/tests/language-feature/pointer/const-ptr-variations.slang b/tests/language-feature/pointer/const-ptr-variations.slang
new file mode 100644
index 000000000..a2619d6c4
--- /dev/null
+++ b/tests/language-feature/pointer/const-ptr-variations.slang
@@ -0,0 +1,40 @@
+//TEST:SIMPLE(filecheck=CHECK_1):-stage compute -entry computeMain -target spirv -DT1
+//TEST:SIMPLE(filecheck=CHECK_2):-stage compute -entry computeMain -target spirv -DT2
+//TEST:SIMPLE(filecheck=CHECK_3):-stage compute -entry computeMain -target spirv -DT3
+//TEST:SIMPLE(filecheck=CHECK_4):-stage compute -entry computeMain -target spirv -DT4
+
+// Tests for invalid use of `const` with Ptr/T*
+// Due to bad syntax breaking the parser, it is more robust to use disjoint tests with
+// #define's.
+cbuffer Globals
+{
+ int* ptr;
+}
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ // disallowed syntax with modifier `const`
+#ifdef T1
+ // CHECK_1: ([[# @LINE+1]]): error
+ int const* ptr1 = ptr;
+#endif
+
+#ifdef T2
+ // CHECK_2: ([[# @LINE+1]]): error
+ int* const ptr2 = ptr;
+#endif
+
+#ifdef T3
+ // CHECK_3: ([[# @LINE+1]]): error 20017
+ const int* ptr3 = ptr;
+ // CHECK_3: ([[# @LINE+1]]): error 20018
+ Ptr<const int> ptr4 = ptr;
+#endif
+
+#ifdef T4
+ // CHECK_4: OpEntryPoint
+ // CHECK_4-NOT: error
+ const Ptr<int> ptr5 = ptr;
+#endif
+} \ No newline at end of file
diff --git a/tests/language-feature/pointer/get-address-validation.slang b/tests/language-feature/pointer/get-address-validation.slang
new file mode 100644
index 000000000..3931c13a2
--- /dev/null
+++ b/tests/language-feature/pointer/get-address-validation.slang
@@ -0,0 +1,82 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+// Tests for invalid/valid use of `__getAddress`
+
+struct DeviceStruct
+{
+ int data1;
+ int data2;
+}
+
+struct StructPtrInStruct
+{
+ DeviceStruct* ptr;
+}
+
+uniform int* bufferUserPointer;
+RWStructuredBuffer<int> bufferStorage;
+groupshared int bufferGroupShared[100];
+uniform DeviceStruct* bufferUserPointerStruct;
+uniform int2* bufferUserPointerVector;
+
+int* output;
+
+typealias GroupSharedPtr<T> = Ptr<T, Access::ReadWrite, AddressSpace::GroupShared>;
+
+GroupSharedPtr<T> paramGroupShared<T : __BuiltinIntegerType>(out groupshared T[100] ptr)
+{
+ // CHECK: ([[# @LINE+1]]): error 30019
+ T* ptr1 = __getAddress(ptr[5]);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ GroupSharedPtr<T> ptr2 = __getAddress(ptr[5]);
+
+ return ptr2;
+}
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ // CHECK: ([[# @LINE+1]]): error 31160
+ int* ptr1 = __getAddress(bufferStorage[id.x]);
+
+ // CHECK ([[# @LINE+1]]): error
+ int[100]* ptr2 = __getAddress(bufferGroupShared);
+
+ // CHECK: ([[# @LINE+1]]): error
+ int* ptr3 = __getAddress(bufferGroupShared[id.x]);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ int* ptr4 = __getAddress(bufferUserPointer[id.x]);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ GroupSharedPtr<int[100]> ptr5 = __getAddress(bufferGroupShared);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ GroupSharedPtr<int> ptr6 = __getAddress(bufferGroupShared[id.x]);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ GroupSharedPtr<int> ptr7 = paramGroupShared(bufferGroupShared);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ int* ptr8 = __getAddress(bufferUserPointerStruct.data1);
+
+ StructPtrInStruct structPtrInStruct;
+ structPtrInStruct.ptr = bufferUserPointerStruct;
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ int* ptr9 = __getAddress(structPtrInStruct.ptr[id.x].data1);
+
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ int* ptr10 = __getAddress(bufferUserPointerVector[0].x);
+
+ output[id] = ptr1[id];
+ output[id] = ptr2[id][0];
+ output[id] = ptr3[id];
+ output[id] = ptr4[id];
+ output[id] = ptr5[id];
+ output[id] = ptr6[id];
+ output[id] = ptr7[id];
+ output[id] = ptr8[id];
+ output[id] = ptr9[id];
+ output[id] = ptr10[id];
+}
diff --git a/tests/language-feature/pointer/globallycoherent-ptr.slang b/tests/language-feature/pointer/globallycoherent-ptr.slang
new file mode 100644
index 000000000..4909537d7
--- /dev/null
+++ b/tests/language-feature/pointer/globallycoherent-ptr.slang
@@ -0,0 +1,20 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+// Tests for invalid use of `globallycoherent` with Ptr/T*
+
+cbuffer Globals
+{
+ // CHECK: ([[# @LINE+1]]): error 30078
+ globallycoherent Ptr<int> ptr1;
+ // CHECK: ([[# @LINE+1]]): error 30078
+ globallycoherent int* ptr2;
+ // CHECK: ([[# @LINE+1]]): error 30078
+ coherent Ptr<int> ptr3;
+ // CHECK: ([[# @LINE+1]]): error 30078
+ coherent int* ptr4;
+}
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+}
diff --git a/tests/language-feature/pointer/groupshared-ptr-of-device.slang b/tests/language-feature/pointer/groupshared-ptr-of-device.slang
new file mode 100644
index 000000000..31703819e
--- /dev/null
+++ b/tests/language-feature/pointer/groupshared-ptr-of-device.slang
@@ -0,0 +1,28 @@
+//TEST:SIMPLE(filecheck=SPIRV):-stage compute -entry computeMain -target spirv -capability vk_mem_model+sm_6_0+spvGroupNonUniformBallot
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -output-using-type -emit-spirv-directly -capability vk_mem_model+sm_6_0+spvGroupNonUniformBallot
+
+// Tests if we pass-through and handle pointers via groupshared-memory correctly.
+// Ensure SPIRV emits coherent operations here
+// SPIRV: OpEntryPoint
+// SPIRV-NOT: error
+
+// CHECK: 1
+// CHECK-NEXT: 0
+// CHECK-NEXT: 2
+// CHECK-NEXT: 0
+// CHECK-NEXT: 3
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0], stride=4):out,name=outputBuffer
+uniform int* outputBuffer;
+
+groupshared int* sharedPtr[3];
+
+[numthreads(3, 1, 1)]
+void computeMain(uint3 group_thread_id: SV_GroupThreadID)
+{
+ sharedPtr[group_thread_id.x] = outputBuffer + group_thread_id.x;
+ sharedPtr[group_thread_id.x] = sharedPtr[group_thread_id.x]+group_thread_id.x;
+ GroupMemoryBarrierWithGroupSync();
+
+ *sharedPtr[group_thread_id.x] = group_thread_id.x+1;
+} \ No newline at end of file
diff --git a/tests/language-feature/pointer/pointer-access/pointer-access-frontend.slang b/tests/language-feature/pointer/pointer-access/pointer-access-frontend.slang
new file mode 100644
index 000000000..98a2a076d
--- /dev/null
+++ b/tests/language-feature/pointer/pointer-access/pointer-access-frontend.slang
@@ -0,0 +1,14 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+//CHECK: OpEntryPoint
+//CHECK-NOT: error
+
+int* processMemory;
+int* output;
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ Ptr<int, Access::ReadWrite, AddressSpace::Device> ptr1 = processMemory + id.x + 5;
+ Ptr<int> ptr2 = processMemory + id.x + 4;
+} \ No newline at end of file
diff --git a/tests/language-feature/pointer/pointer-access/read-only-pointer-1.slang b/tests/language-feature/pointer/pointer-access/read-only-pointer-1.slang
new file mode 100644
index 000000000..e7f1ad534
--- /dev/null
+++ b/tests/language-feature/pointer/pointer-access/read-only-pointer-1.slang
@@ -0,0 +1,41 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+// Writing with a read-only pointer should be an error
+
+int* processMemory;
+RWStructuredBuffer<int> output;
+
+typealias ReadPtr = Ptr<int, Access::Read, AddressSpace::Device>;
+
+void writeToReadOnlyPointer(ReadPtr ptr)
+{
+ // CHECK: ([[# @LINE+1]]): error 30011
+ ptr[0] = 1;
+}
+
+void writeToReadOnlyPointerOut(out int ptrVal)
+{
+ ptrVal = 1;
+}
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ ReadPtr ptr1 = ReadPtr(processMemory + id.x);
+
+ // CHECK: ([[# @LINE+1]]): error 30011
+ ptr1[id + 1] = 1;
+ // CHECK: ([[# @LINE+1]]): error 30011
+ *ptr1 = 1;
+
+ writeToReadOnlyPointer(ptr1);
+
+ // CHECK: ([[# @LINE+1]]): error 30047
+ writeToReadOnlyPointerOut(ptr1[1]);
+
+ // CHECK: ([[# @LINE+1]]): error 30047
+ writeToReadOnlyPointerOut(*(ptr1+2));
+
+ output[id] = ptr1[id];
+}
diff --git a/tests/language-feature/pointer/pointer-access/read-only-pointer-2.slang b/tests/language-feature/pointer/pointer-access/read-only-pointer-2.slang
new file mode 100644
index 000000000..c5288caba
--- /dev/null
+++ b/tests/language-feature/pointer/pointer-access/read-only-pointer-2.slang
@@ -0,0 +1,19 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+// Tests valid use of read-only pointer
+
+// CHECK: OpEntryPoint
+// CHECK-NOT: error
+
+int* processMemory;
+int* output;
+
+typealias ReadPtr = Ptr<int, Access::Read, AddressSpace::Device>;
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ ReadPtr ptr1 = ReadPtr(processMemory + id.x);
+
+ output[id] = ptr1[id];
+}
diff --git a/tests/language-feature/pointer/pointer-casting/pointer-casting-rules.slang b/tests/language-feature/pointer/pointer-casting/pointer-casting-rules.slang
new file mode 100644
index 000000000..d0a016fe5
--- /dev/null
+++ b/tests/language-feature/pointer/pointer-casting/pointer-casting-rules.slang
@@ -0,0 +1,51 @@
+//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv
+
+// Tests pointer casting rules: Only explicit casting is allowed between pointer types.
+// All implicit conversions between pointer types should fail.
+int* processMemory;
+RWStructuredBuffer<int> output;
+
+[numthreads(1, 1, 1)]
+void computeMain(int id : SV_DispatchThreadID)
+{
+ // regular address-of
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<int, Access::ReadWrite, AddressSpace::Device> rwPtr = processMemory + id.x;
+ // copying a pointer of T* syntax
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<int, Access::ReadWrite, AddressSpace::Device> copiedPtrOfLegacySyntax = processMemory;
+ // casting to Read ptr
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<int, Access::Read> rPtr = Ptr<int, Access::Read>(processMemory + id.x);
+
+ // casting to RW ptr from a R ptr
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<int, Access::ReadWrite, AddressSpace::Device> p1 = Ptr<int, Access::ReadWrite, AddressSpace::Device>(rPtr);
+ // casting to R ptr from a RW ptr
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<int, Access::Read, AddressSpace::Device> p2 = Ptr<int, Access::Read, AddressSpace::Device>(rwPtr);
+ // casting to ptr of different type
+ // CHECK-NOT: ([[# @LINE+1]]): error
+ Ptr<float, Access::ReadWrite, AddressSpace::Device> p3 = Ptr<float, Access::ReadWrite, AddressSpace::Device>(rPtr);
+
+ // Cannot implicit cast ptr's
+ // CHECK: ([[# @LINE+1]]): error 30019
+ Ptr<float, Access::ReadWrite, AddressSpace::Device> p4 = rPtr;
+ // cannot implcitly cast between different access qualifiers
+ // CHECK: ([[# @LINE+1]]): error 30019
+ Ptr<int, Access::Read> p5 = Ptr<int, Access::ReadWrite>(processMemory + id.x);
+ // cannot implcitly cast between different access qualifiers
+ // CHECK: ([[# @LINE+1]]): error 30019
+ Ptr<int, Access::ReadWrite> p6 = Ptr<int, Access::Read>(processMemory + id.x);
+
+ // TODO: Enable this when we allow user-defined group-shared address space, Issue #8173.
+ // Cannot cast between different address spaces.
+ // CHECK: ([[# @LINE+1]]): error
+ Ptr<float, Access::ReadWrite, AddressSpace::GroupShared> p7 = Ptr<float, Access::ReadWrite, AddressSpace::GroupShared>(rwPtr);
+ // CHECK: ([[# @LINE+1]]): error
+ Ptr<float, Access::ReadWrite, AddressSpace::GroupShared> p8 = Ptr<float, Access::ReadWrite, AddressSpace::GroupShared>(p1);
+ // CHECK: ([[# @LINE+1]]): error
+ Ptr<float, Access::ReadWrite, AddressSpace::GroupShared> p9 = rwPtr;
+
+ output[id] = *rwPtr;
+}
diff --git a/tests/language-feature/pointer/pointer-self-reference.slang b/tests/language-feature/pointer/pointer-self-reference.slang
index e78b70db0..75ff4e7a9 100644
--- a/tests/language-feature/pointer/pointer-self-reference.slang
+++ b/tests/language-feature/pointer/pointer-self-reference.slang
@@ -1,6 +1,8 @@
// pointer-self-reference.slang
-//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -output-using-type -shaderobj
+// We are disabling this test because '&' is intentionally not supported.
+// Design for pointers in Slang are not yet finalized.
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -output-using-type -shaderobj
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<int> outputBuffer;
@@ -18,13 +20,13 @@ void computeMain(int3 dispatchThreadID: SV_DispatchThreadID)
Thing things[2];
- things[0].next = &things[1];
+ things[0].next = __getAddress(things[1]);
things[0].value = 27;
- things[1].next = &things[0];
+ things[1].next = __getAddress(things[0]);
things[1].value = idx * idx;
- Ptr<Thing> cur = &things[0];
+ Ptr<Thing> cur = __getAddress(things[0]);
for (int i = 0; cur && i < idx; ++i)
{
diff --git a/tests/language-feature/pointer/ptr-to-groupshared.slang b/tests/language-feature/pointer/ptr-to-groupshared.slang
new file mode 100644
index 000000000..3ad4c5e0b
--- /dev/null
+++ b/tests/language-feature/pointer/ptr-to-groupshared.slang
@@ -0,0 +1,30 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -output-using-type -emit-spirv-directly
+
+// Tests if we handle passing groupshared address-space pointers correctly to a function
+// when that data-type needs legalization (Data -> Data_natural due to `lower-buffer-element-type`).
+// CHECK: 1
+// CHECK-NEXT: 2
+// CHECK-NEXT: 0
+
+struct Data
+{
+ int value1;
+ int value2;
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0], stride=4):out,name=outputBuffer
+uniform int* outputBuffer;
+groupshared Data shared;
+
+void foo(Ptr<Data, Access::ReadWrite, AddressSpace::GroupShared> ptr)
+{
+ outputBuffer[0] = ptr.value1;
+ outputBuffer[1] = ptr.value2;
+}
+
+[numthreads(3, 1, 1)]
+void computeMain(uint3 group_thread_id: SV_GroupThreadID)
+{
+ shared = Data(1, 2);
+ foo(__getAddress(shared));
+} \ No newline at end of file