From 69450a2be7575aa4f984b9ae2824da0e5634c9f0 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Wed, 5 Jul 2023 13:23:14 -0400 Subject: Initial sizeof/alignof implementation. (#2954) * Initial sizeof implementation. * Small macro improvement. * Fix some typos. * Refactor NaturalSize. Add more sizeof tests. * Use _makeParseExpr to add sizeof support. * Add size-of.slang diagnostic result. * Fix typo in folding with macro change. * Add a sizeof test of This. * Some more NaturalSize coverage. * Simple alignof support. * Testing for alignof. * Added 8 bit enum to check enums values are correctly sized. * Add alignof to completion. * Lower sizeof/alignof to IR. sizeof/alignof IR pass. Tests for simple generic scenarios. * Make append handle invalid properly. Improve comments. --------- Co-authored-by: Theresa Foley <10618364+tangent-vector@users.noreply.github.com> --- tests/compute/tagged-union.slang | 6 +- tests/diagnostics/size-of.slang | 8 +++ tests/diagnostics/size-of.slang.expected | 8 +++ tests/hlsl-intrinsic/size-of/align-of-2.slang | 47 ++++++++++++++ .../size-of/align-of-2.slang.expected.txt | 4 ++ tests/hlsl-intrinsic/size-of/align-of-3.slang | 72 ++++++++++++++++++++++ .../size-of/align-of-3.slang.expected.txt | 8 +++ .../hlsl-intrinsic/size-of/align-of-generic.slang | 36 +++++++++++ .../size-of/align-of-generic.slang.expected.txt | 4 ++ tests/hlsl-intrinsic/size-of/align-of.slang | 54 ++++++++++++++++ .../size-of/align-of.slang.expected.txt | 4 ++ tests/hlsl-intrinsic/size-of/size-of-2.slang | 51 +++++++++++++++ .../size-of/size-of-2.slang.expected.txt | 8 +++ tests/hlsl-intrinsic/size-of/size-of-3.slang | 72 ++++++++++++++++++++++ .../size-of/size-of-3.slang.expected.txt | 8 +++ tests/hlsl-intrinsic/size-of/size-of-generic.slang | 35 +++++++++++ .../size-of/size-of-generic.slang.expected.txt | 4 ++ tests/hlsl-intrinsic/size-of/size-of.slang | 54 ++++++++++++++++ .../size-of/size-of.slang.expected.txt | 4 ++ 19 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 tests/diagnostics/size-of.slang create mode 100644 tests/diagnostics/size-of.slang.expected create mode 100644 tests/hlsl-intrinsic/size-of/align-of-2.slang create mode 100644 tests/hlsl-intrinsic/size-of/align-of-2.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/align-of-3.slang create mode 100644 tests/hlsl-intrinsic/size-of/align-of-3.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/align-of-generic.slang create mode 100644 tests/hlsl-intrinsic/size-of/align-of-generic.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/align-of.slang create mode 100644 tests/hlsl-intrinsic/size-of/align-of.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/size-of-2.slang create mode 100644 tests/hlsl-intrinsic/size-of/size-of-2.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/size-of-3.slang create mode 100644 tests/hlsl-intrinsic/size-of/size-of-3.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/size-of-generic.slang create mode 100644 tests/hlsl-intrinsic/size-of/size-of-generic.slang.expected.txt create mode 100644 tests/hlsl-intrinsic/size-of/size-of.slang create mode 100644 tests/hlsl-intrinsic/size-of/size-of.slang.expected.txt (limited to 'tests') diff --git a/tests/compute/tagged-union.slang b/tests/compute/tagged-union.slang index 91f0cd101..e8c210288 100644 --- a/tests/compute/tagged-union.slang +++ b/tests/compute/tagged-union.slang @@ -10,7 +10,7 @@ // and without code changes. // We are going to define a dummy interface just for testing -// purposes, that can be used to see which implmentation +// purposes, that can be used to see which implementation // got invoked at runtime. // interface IFrobnicator @@ -18,7 +18,7 @@ interface IFrobnicator int frobnicate(int value); } -// Now we will define two different implemetnations that +// Now we will define two different implementations that // "frobnicate" values differently. The first will just // add to the value from a member variable. // @@ -87,7 +87,7 @@ void computeMain // since it was the second option in our `__TaggedUnion`. // // In the Vulkan case the size of both `A` and `B` is 16 bytes -// (because they round up structure sizes to their alignement) +// (because they round up structure sizes to their alignment) // and so the tag value will be the fifth 32-bit value. // We will thus set up the same data buffer to look like an `A` // value to Vulkan! diff --git a/tests/diagnostics/size-of.slang b/tests/diagnostics/size-of.slang new file mode 100644 index 000000000..63c55398e --- /dev/null +++ b/tests/diagnostics/size-of.slang @@ -0,0 +1,8 @@ +// sizeof.slang + +//DIAGNOSTIC_TEST:SIMPLE: + +int func() +{ + return sizeof(func); +} diff --git a/tests/diagnostics/size-of.slang.expected b/tests/diagnostics/size-of.slang.expected new file mode 100644 index 000000000..19c837799 --- /dev/null +++ b/tests/diagnostics/size-of.slang.expected @@ -0,0 +1,8 @@ +result code = -1 +standard error = { +tests/diagnostics/size-of.slang(7): error 30099: argument to sizeof is invalid + return sizeof(func); + ^~~~~~ +} +standard output = { +} diff --git a/tests/hlsl-intrinsic/size-of/align-of-2.slang b/tests/hlsl-intrinsic/size-of/align-of-2.slang new file mode 100644 index 000000000..93040722c --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-2.slang @@ -0,0 +1,47 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +// Check Enum without base type + +enum Enum +{ + A = 10, + B = 20, +}; + +enum Enum8 : uint8_t +{ + A = 20, + B = 19, +}; + +// Check type aliases + +typedef Enum EnumTypeDef; +typealias EnumTypeAlias = Enum; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int size = 0; + switch (idx) + { + default: + case 0: size = alignof(Enum); break; + case 1: size = alignof(EnumTypeDef); break; + case 2: size = alignof(EnumTypeAlias); break; + case 3: size = alignof(idx); break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/align-of-2.slang.expected.txt b/tests/hlsl-intrinsic/size-of/align-of-2.slang.expected.txt new file mode 100644 index 000000000..e785149d2 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-2.slang.expected.txt @@ -0,0 +1,4 @@ +4 +4 +4 +4 diff --git a/tests/hlsl-intrinsic/size-of/align-of-3.slang b/tests/hlsl-intrinsic/size-of/align-of-3.slang new file mode 100644 index 000000000..4a2eea3e2 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-3.slang @@ -0,0 +1,72 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + + +int getParamSize(inout uint3 v) +{ + return alignof(v); +} + +// On some targets inout might be passed via a pointer. +// With "natural" layout size must be the same across all targets. +// The parameter passing semantic is "value in/value out", so the size +// will always be the size of the *value* regardless. So uint3 in this case. +int getParamSizeWithDirection(inout uint3 v) +{ + return alignof(v); +} + +struct TestThis +{ + int getSize() + { + return alignof(This); + } + + float a; + int b[2]; +}; + +static const float4 staticConstValueA = float4(-1); + +[numthreads(8, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + double doub = 13.0; + uint16_t u16 = 10; + + uint3 vec = uint3(0); + + int size = 0; + switch (idx) + { + case 0: size = alignof(doub); break; + case 1: size = alignof(u16); break; + case 2: size = alignof(nullptr); break; + case 3: size = alignof(void); break; + + case 4: size = getParamSizeWithDirection(vec); break; + case 5: size = getParamSize(vec); break; + + case 6: size = alignof(staticConstValueA); break; + case 7: + { + TestThis t; + size = t.getSize(); + break; + } + default: size = -1; break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/align-of-3.slang.expected.txt b/tests/hlsl-intrinsic/size-of/align-of-3.slang.expected.txt new file mode 100644 index 000000000..8bc98f52f --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-3.slang.expected.txt @@ -0,0 +1,8 @@ +8 +2 +8 +1 +4 +4 +4 +4 diff --git a/tests/hlsl-intrinsic/size-of/align-of-generic.slang b/tests/hlsl-intrinsic/size-of/align-of-generic.slang new file mode 100644 index 000000000..c10c6c8ce --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-generic.slang @@ -0,0 +1,36 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +struct Thing +{ + T t; +}; + + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int size = 0; + + switch (idx) + { + + case 0: size = alignof(Thing); break; + case 1: size = alignof(Thing); break; + case 2: size = alignof(Thing>); break; + case 3: size = alignof(bool); break; + default: break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/align-of-generic.slang.expected.txt b/tests/hlsl-intrinsic/size-of/align-of-generic.slang.expected.txt new file mode 100644 index 000000000..186c1e94f --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of-generic.slang.expected.txt @@ -0,0 +1,4 @@ +4 +4 +4 +1 diff --git a/tests/hlsl-intrinsic/size-of/align-of.slang b/tests/hlsl-intrinsic/size-of/align-of.slang new file mode 100644 index 000000000..b9e18f17d --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of.slang @@ -0,0 +1,54 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +enum Enum : int8_t +{ +}; + +struct Hey +{ + double b; + Enum e; +}; + +struct Thing : Hey +{ + int a; + float b; +}; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int a = alignof(idx); + int b = alignof(int); + int c = alignof(1 + 1); + int d = alignof(Thing); + + float g[alignof(a)]; + + int f[alignof(Thing) + alignof(float2) + alignof(g)]; + + int size; + + switch (idx) + { + default: + case 0: size = alignof(float); break; + case 1: size = alignof(float3); break; + case 2: size = alignof(matrix); break; + case 3: size = alignof(idx); break; + } + + outputBuffer[idx] = size + a + b + c + d + alignof(f); +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/align-of.slang.expected.txt b/tests/hlsl-intrinsic/size-of/align-of.slang.expected.txt new file mode 100644 index 000000000..a654cc5c4 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/align-of.slang.expected.txt @@ -0,0 +1,4 @@ +1C +1C +1C +1C diff --git a/tests/hlsl-intrinsic/size-of/size-of-2.slang b/tests/hlsl-intrinsic/size-of/size-of-2.slang new file mode 100644 index 000000000..c2bad0526 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-2.slang @@ -0,0 +1,51 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +// Check Enum without base type + +enum Enum +{ + A = 10, + B = 20, +}; + +enum Enum8 : uint8_t +{ + A = 20, + B = 19, +}; + +// Check type aliases + +typedef Enum EnumTypeDef; +typealias EnumTypeAlias = Enum; + +[numthreads(8, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int size = 0; + switch (idx) + { + case 0: size = sizeof(Enum); break; + case 1: size = sizeof(EnumTypeDef); break; + case 2: size = sizeof(EnumTypeAlias); break; + case 3: size = sizeof(idx); break; + case 4: size = sizeof(Enum::A); break; + case 5: size = sizeof(Enum.B); break; + case 6: size = sizeof(Enum8::A); break; + case 7: size = sizeof(Enum8.B); break; + default: break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/size-of-2.slang.expected.txt b/tests/hlsl-intrinsic/size-of/size-of-2.slang.expected.txt new file mode 100644 index 000000000..0cca5f483 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-2.slang.expected.txt @@ -0,0 +1,8 @@ +4 +4 +4 +4 +4 +4 +1 +1 diff --git a/tests/hlsl-intrinsic/size-of/size-of-3.slang b/tests/hlsl-intrinsic/size-of/size-of-3.slang new file mode 100644 index 000000000..f632c6d83 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-3.slang @@ -0,0 +1,72 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + + +int getParamSize(inout uint3 v) +{ + return sizeof(v); +} + +// On some targets inout might be passed via a pointer. +// With "natural" layout size must be the same across all targets. +// The parameter passing semantic is "value in/value out", so the size +// will always be the size of the *value* regardless. So uint3 in this case. +int getParamSizeWithDirection(inout uint3 v) +{ + return sizeof(v); +} + +struct TestThis +{ + int getSize() + { + return sizeof(This); + } + + float a; + int b[2]; +}; + +static const float4 staticConstValueA = float4(-1); + +[numthreads(8, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + double doub = 13.0; + uint16_t u16 = 10; + + uint3 vec = uint3(0); + + int size = 0; + switch (idx) + { + case 0: size = sizeof(doub); break; + case 1: size = sizeof(u16); break; + case 2: size = sizeof(nullptr); break; + case 3: size = sizeof(void); break; + + case 4: size = getParamSizeWithDirection(vec); break; + case 5: size = getParamSize(vec); break; + + case 6: size = sizeof(staticConstValueA); break; + case 7: + { + TestThis t; + size = t.getSize(); + break; + } + default: size = -1; break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/size-of-3.slang.expected.txt b/tests/hlsl-intrinsic/size-of/size-of-3.slang.expected.txt new file mode 100644 index 000000000..4e01f0eb1 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-3.slang.expected.txt @@ -0,0 +1,8 @@ +8 +2 +8 +0 +C +C +10 +C diff --git a/tests/hlsl-intrinsic/size-of/size-of-generic.slang b/tests/hlsl-intrinsic/size-of/size-of-generic.slang new file mode 100644 index 000000000..ffdc0e210 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-generic.slang @@ -0,0 +1,35 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +struct Thing +{ + T t; +}; + + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int size = 0; + + switch (idx) + { + + case 0: size = sizeof(Thing); break; + case 1: size = sizeof(Thing); break; + case 2: size = sizeof(Thing>); break; + default: break; + } + + outputBuffer[idx] = size; +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/size-of-generic.slang.expected.txt b/tests/hlsl-intrinsic/size-of/size-of-generic.slang.expected.txt new file mode 100644 index 000000000..01b215ca4 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of-generic.slang.expected.txt @@ -0,0 +1,4 @@ +4 +C +18 +0 diff --git a/tests/hlsl-intrinsic/size-of/size-of.slang b/tests/hlsl-intrinsic/size-of/size-of.slang new file mode 100644 index 000000000..7e27bab0c --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of.slang @@ -0,0 +1,54 @@ + +//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -shaderobj +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj +//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer + +RWStructuredBuffer outputBuffer; + +enum Enum : int8_t +{ +}; + +struct Hey +{ + double b; + Enum e; +}; + +struct Thing : Hey +{ + int a; + float b; +}; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + const int idx = asint(dispatchThreadID.x); + + int a = sizeof(idx); + int b = sizeof(int); + int c = sizeof(1 + 1); + int d = sizeof(Thing); + + float g[sizeof(a)]; + + int f[sizeof(Thing) + sizeof(float2) + sizeof(g)]; + + int size; + + switch (idx) + { + default: + case 0: size = sizeof(float); break; + case 1: size = sizeof(float3); break; + case 2: size = sizeof(matrix); break; + case 3: size = sizeof(idx); break; + } + + outputBuffer[idx] = size + a + b + c + d + sizeof(f); +} \ No newline at end of file diff --git a/tests/hlsl-intrinsic/size-of/size-of.slang.expected.txt b/tests/hlsl-intrinsic/size-of/size-of.slang.expected.txt new file mode 100644 index 000000000..568b74489 --- /dev/null +++ b/tests/hlsl-intrinsic/size-of/size-of.slang.expected.txt @@ -0,0 +1,4 @@ +D4 +DC +E8 +D4 -- cgit v1.2.3