From 48b6e2432ea28c06d04931fccd633e31eed6d995 Mon Sep 17 00:00:00 2001 From: venkataram-nv Date: Fri, 18 Jul 2025 09:38:00 -0700 Subject: Lower int/uint/bool matrices to arrays for SPIRV (#7687) * Add tests for expected behaviour * Allow matrix types in logical or/and * Legalize int/bool matrix types and construction with makeMatrix * Legalize uint matrices and operations * Limit testing to only SPIRV * Better tests for int and bool * Add test for uint * Remove GLSL tests * Remove old test for diagnosing int matrices * Emit SPIRV directly in tests * format code * Address PR comments * Improve testing * Address PR comments * format code * Add tests for matrix intrinsic operations * Move matrix lowering to dedicated legalization pass * Fix compiler warning * Remove signal again * Reorder matrix and vector legalization * Fix formatting * Add shift and comparison tests --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com> --- tests/compute/integer-matrix-diagnostic.slang | 22 --- tests/spirv/matrix-bool-lowering.slang | 114 ++++++++++++++++ tests/spirv/matrix-integer-lowering.slang | 189 ++++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 22 deletions(-) delete mode 100644 tests/compute/integer-matrix-diagnostic.slang create mode 100644 tests/spirv/matrix-bool-lowering.slang create mode 100644 tests/spirv/matrix-integer-lowering.slang (limited to 'tests') diff --git a/tests/compute/integer-matrix-diagnostic.slang b/tests/compute/integer-matrix-diagnostic.slang deleted file mode 100644 index bd69c28e4..000000000 --- a/tests/compute/integer-matrix-diagnostic.slang +++ /dev/null @@ -1,22 +0,0 @@ -// Check that using matrices with integer floating point type yields the correct diagnostic - -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target glsl -entry computeMain -stage compute -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target metal -entry computeMain -stage compute -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target spirv -entry computeMain -stage compute -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target wgsl -entry computeMain -stage compute - -cbuffer MatrixBuffer -{ - // CHECK: error 38202 - int4x4 iMatrix; -} - -//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out, name=outputBuffer -RWStructuredBuffer outputBuffer; - -[numthreads(4, 1, 1)] -void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - uint index = dispatchThreadID.x; - outputBuffer[index] = iMatrix[0][0]; -} \ No newline at end of file diff --git a/tests/spirv/matrix-bool-lowering.slang b/tests/spirv/matrix-bool-lowering.slang new file mode 100644 index 000000000..63b7caacf --- /dev/null +++ b/tests/spirv/matrix-bool-lowering.slang @@ -0,0 +1,114 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -compute -vk -shaderobj -xslang -emit-spirv-directly + +//TEST_INPUT:ubuffer(data=[1 0], stride=4):in,name inputBuffer +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer +RWStructuredBuffer inputBuffer; +RWStructuredBuffer outputBuffer; + +// Global bool constants to avoid constant folding +static bool trueVal; +static bool falseVal; + +struct matrixWrapper { + bool2x2 mat1 = bool2x2(falseVal, falseVal, falseVal, falseVal); + bool2x3 mat2 = bool2x3(trueVal, trueVal, falseVal, falseVal, falseVal, trueVal); +} + +bool elementAnd(bool2x2 matrix) +{ + return trueVal + && matrix[0][0] + && matrix[0][1] + && matrix[1][0] + && matrix[1][1]; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + // Load true/false values from input buffer to avoid constant folding + trueVal = inputBuffer[0] != 0; + falseVal = inputBuffer[1] != 0; + + // Test bool matrix construction + bool2x2 mat1 = bool2x2(trueVal, falseVal, falseVal, trueVal); + bool3x3 mat2 = bool3x3( + trueVal, falseVal, trueVal, + falseVal, trueVal, falseVal, + trueVal, falseVal, trueVal + ); + bool2x4 mat3 = bool2x4( + trueVal, falseVal, trueVal, falseVal, + trueVal, falseVal, trueVal, falseVal + ); + + // Test bool matrix element access + bool val1 = mat1[0][0]; + bool val2 = mat2[2][1]; + + // Test bool matrix row access + bool2 row = mat1[1]; + bool3 row3 = mat2[0]; + + // Test logical operations + bool2x2 not_mat = !mat1; + bool2x2 and_mat = mat1 && bool2x2(trueVal, trueVal, falseVal, falseVal); + + // Test element assignment + mat1[0][1] = trueVal; + mat2[1][2] = falseVal; + + // Test passing bool matrices to functions + bool anded = elementAnd(mat1); + + // Test structs with bool matrix fields + matrixWrapper wrapper = {}; + + // Test any/all operations + bool2x2 all_true = bool2x2(trueVal, trueVal, trueVal, trueVal); + bool2x2 all_false = bool2x2(falseVal, falseVal, falseVal, falseVal); + bool2x2 mixed = bool2x2(trueVal, falseVal, trueVal, falseVal); + + bool test_all_true = all(all_true); // all elements true -> true + bool test_all_false = all(all_false); // all elements false -> false + bool test_all_mixed = all(mixed); // some elements false -> false + bool test_any_true = any(all_true); // some elements true -> true + bool test_any_false = any(all_false); // no elements true -> false + bool test_any_mixed = any(mixed); // some elements true -> true + + // Store results + outputBuffer[0] = val1; + // CHECK: 1 + outputBuffer[1] = val2; + // CHECK-NEXT: 0 + outputBuffer[2] = row.x; + // CHECK-NEXT: 0 + outputBuffer[3] = row.y; + // CHECK-NEXT: 1 + outputBuffer[4] = row3.y; + // CHECK-NEXT: 0 + outputBuffer[5] = not_mat[0][0]; + // CHECK-NEXT: 0 + outputBuffer[6] = and_mat[0][0]; + // CHECK-NEXT: 1 + outputBuffer[7] = mat1[0][1]; + // CHECK-NEXT: 1 + outputBuffer[8] = mat3[0][1]; + // CHECK-NEXT: 0 + outputBuffer[9] = anded; + // CHECK-NEXT: 0 + outputBuffer[10] = wrapper.mat1[0][0] || wrapper.mat2[0][0]; + // CHECK-NEXT: 1 + outputBuffer[11] = test_all_true; + // CHECK-NEXT: 1 + outputBuffer[12] = test_all_false; + // CHECK-NEXT: 0 + outputBuffer[13] = test_all_mixed; + // CHECK-NEXT: 0 + outputBuffer[14] = test_any_true; + // CHECK-NEXT: 1 + outputBuffer[15] = test_any_false; + // CHECK-NEXT: 0 + outputBuffer[16] = test_any_mixed; + // CHECK-NEXT: 1 +} diff --git a/tests/spirv/matrix-integer-lowering.slang b/tests/spirv/matrix-integer-lowering.slang new file mode 100644 index 000000000..518d0f78b --- /dev/null +++ b/tests/spirv/matrix-integer-lowering.slang @@ -0,0 +1,189 @@ +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -output-using-type -compute -vk -shaderobj -xslang -emit-spirv-directly -xslang -DTYPE=int +//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -output-using-type -compute -vk -shaderobj -xslang -emit-spirv-directly -xslang -DTYPE=uint + +#ifndef TYPE +#define TYPE int +#endif + +typealias m2x2 = matrix; +typealias m2x3 = matrix; +typealias m3x3 = matrix; +typealias m2x4 = matrix; + +//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer +RWStructuredBuffer outputBuffer; + +struct matrixWrapper { + m2x2 mat1 = m2x2(1, 2, 3, 4); + m2x3 mat2 = m2x3(5, 6, 7, 8, 9, 10); +}; + +TYPE elementAdd(m2x2 matrix) +{ + return matrix[0][0] + + matrix[0][1] + + matrix[1][0] + + matrix[1][1]; +} + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + // Test matrix construction + m2x2 mat1 = m2x2(1, 2, 3, 4); + m3x3 mat2 = m3x3( + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ); + m2x4 mat3 = m2x4( + 10, 11, 12, 13, + 14, 15, 16, 17 + ); + + // Test matrix element access + TYPE val1 = mat1[0][0]; + TYPE val2 = mat2[2][1]; + + // Test matrix row access + vector row = mat1[1]; + vector row3 = mat2[0]; + + // Test arithmetic operations + m2x2 mat5 = m2x2(2, 4, 6, 7); + + m2x2 mat_scalar = 2 * mat1; + m2x2 mat_add = mat1 + mat5; + m2x2 mat_sub = mat5 - mat1; + m2x2 mat_mul = mat1 * mat5; + + // Test passing matrices to functions + TYPE added = elementAdd(mat1); + + // Test structs with matrix fields + matrixWrapper wrapper = {}; + + // Test matrix intrinsic operations + + // Test determinant for square matrices + m2x2 mat6 = m2x2(2, 1, 4, 3); + TYPE det2x2 = TYPE(determinant(mat6)); + TYPE det3x3 = TYPE(determinant(mat2)); + + // Test transpose + matrix trans2x2 = transpose(mat1); + matrix trans2x3 = transpose(wrapper.mat2); + + // Test element-wise min/max + m2x2 mat_min = min(mat1, mat5); + m2x2 mat_max = max(mat1, mat5); + + // Test all/any operations (these return bool, but we'll cast to TYPE for output) + m2x2 zero_mat = m2x2(0, 0, 0, 0); + m2x2 mixed_mat = m2x2(1, 0, 2, 0); + + TYPE all_nonzero = TYPE(all(mat1)); + TYPE all_zero = TYPE(all(zero_mat)); + TYPE any_nonzero = TYPE(any(mixed_mat)); + TYPE any_zero = TYPE(any(zero_mat)); + + // Test bit shift operations + m2x2 shift_mat = m2x2(1, 2, 4, 8); + m2x2 left_shift = shift_mat << 1; + m2x2 right_shift = shift_mat >> 1; + + // Test comparison operations (these return bool matrices, cast to TYPE for output) + m2x2 comp_mat1 = m2x2(1, 3, 2, 4); + m2x2 comp_mat2 = m2x2(2, 2, 3, 3); + + matrix less_than = comp_mat1 < comp_mat2; + matrix greater_than = comp_mat1 > comp_mat2; + matrix less_equal = comp_mat1 <= comp_mat2; + matrix greater_equal = comp_mat1 >= comp_mat2; + matrix equal_to = comp_mat1 == comp_mat2; + matrix not_equal = comp_mat1 != comp_mat2; + + // Store results + outputBuffer[0] = val1; + // CHECK: 1 + outputBuffer[1] = val2; + // CHECK-NEXT: 8 + outputBuffer[2] = row.x; + // CHECK-NEXT: 3 + outputBuffer[3] = row.y; + // CHECK-NEXT: 4 + outputBuffer[4] = row3.y; + // CHECK-NEXT: 2 + outputBuffer[5] = mat_scalar[0][0]; + // CHECK-NEXT: 2 + outputBuffer[6] = mat_add[0][0]; + // CHECK-NEXT: 3 + outputBuffer[7] = mat_sub[0][0]; + // CHECK-NEXT: 1 + outputBuffer[8] = mat_mul[1][1]; + // CHECK-NEXT: 28 + outputBuffer[9] = added; + // CHECK-NEXT: 10 + outputBuffer[10] = wrapper.mat1[0][0] * wrapper.mat2[0][0]; + // CHECK-NEXT: 5 + + // Matrix intrinsic operation results + outputBuffer[11] = det2x2; + // CHECK-NEXT: 2 + outputBuffer[12] = det3x3; + // CHECK-NEXT: 0 + outputBuffer[13] = mat_min[0][0]; + // CHECK-NEXT: 1 + outputBuffer[14] = mat_min[1][1]; + // CHECK-NEXT: 4 + outputBuffer[15] = mat_max[0][0]; + // CHECK-NEXT: 2 + outputBuffer[16] = mat_max[1][1]; + // CHECK-NEXT: 7 + outputBuffer[17] = all_nonzero; + // CHECK-NEXT: 1 + outputBuffer[18] = all_zero; + // CHECK-NEXT: 0 + outputBuffer[19] = any_nonzero; + // CHECK-NEXT: 1 + outputBuffer[20] = any_zero; + // CHECK-NEXT: 0 + outputBuffer[21] = trans2x2[0][0]; + // CHECK-NEXT: 1 + outputBuffer[22] = trans2x2[1][0]; + // CHECK-NEXT: 2 + outputBuffer[23] = trans2x3[0][0]; + // CHECK-NEXT: 5 + + // Bit shift operation results + outputBuffer[24] = left_shift[0][0]; + // CHECK-NEXT: 2 + outputBuffer[25] = left_shift[0][1]; + // CHECK-NEXT: 4 + outputBuffer[26] = right_shift[1][0]; + // CHECK-NEXT: 2 + outputBuffer[27] = right_shift[1][1]; + // CHECK-NEXT: 4 + + // Comparison operation results (bool matrices cast to TYPE) + outputBuffer[28] = TYPE(less_than[0][0]); + // CHECK-NEXT: 1 + outputBuffer[29] = TYPE(less_than[0][1]); + // CHECK-NEXT: 0 + outputBuffer[30] = TYPE(greater_than[0][1]); + // CHECK-NEXT: 1 + outputBuffer[31] = TYPE(greater_than[1][1]); + // CHECK-NEXT: 1 + outputBuffer[32] = TYPE(less_equal[0][0]); + // CHECK-NEXT: 1 + outputBuffer[33] = TYPE(less_equal[0][1]); + // CHECK-NEXT: 0 + outputBuffer[34] = TYPE(greater_equal[0][1]); + // CHECK-NEXT: 1 + outputBuffer[35] = TYPE(greater_equal[1][0]); + // CHECK-NEXT: 0 + outputBuffer[36] = TYPE(equal_to[0][0]); + // CHECK-NEXT: 0 + outputBuffer[37] = TYPE(not_equal[0][0]); + // CHECK-NEXT: 1 +} \ No newline at end of file -- cgit v1.2.3