Index: SingleSource/UnitTests/CMakeLists.txt =================================================================== --- SingleSource/UnitTests/CMakeLists.txt +++ SingleSource/UnitTests/CMakeLists.txt @@ -42,4 +42,13 @@ ms_struct_pack_layout-1.c ) endif() + +# Enable matrix types extension tests for Clang versions supporting it. +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND + CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 11.0) + set_property(SOURCE matrix-types-spec.cpp PROPERTY COMPILE_FLAGS -fenable-matrix) +else() + list(REMOVE_ITEM Source matrix-types-spec.cpp) +endif() + llvm_singlesource() Index: SingleSource/UnitTests/matrix-types-spec.cpp =================================================================== --- /dev/null +++ SingleSource/UnitTests/matrix-types-spec.cpp @@ -0,0 +1,167 @@ +// Runtime tests to ensure the Matrix Type extension implementation matches the +// specification. + +#include +#include +#include + +#define EXPECT_MATRIX_EQ(A, B, R, C) \ + do { \ + for (unsigned r = 0; r < R; r++) \ + for (unsigned c = 0; c < C; c++) \ + if (A[r + c * R] != B[r + c * R]) { \ + std::cerr << "mismatch at " << r << ":" << c << "\n"; \ + exit(1); \ + } \ + } while (false) + +template +void zeroMatrix(EltTy *M, unsigned Rows, unsigned Cols) { + for (unsigned r = 0; r < Rows; r++) + for (unsigned c = 0; c < Cols; c++) + M[r + c * Rows] = 0; +} + +template void print(EltTy *X, unsigned Rows, unsigned Cols) { + for (int r = 0; r < Rows; r++) { + for (int c = 0; c < Cols; c++) + std::cout << X[r + c * Rows] << ", "; + std::cout << "\n"; + } +} + +template void initRandom(Ty *A, unsigned Rows, unsigned Cols) { + std::default_random_engine generator; + std::uniform_int_distribution distribution(-10.0, 10.0); + auto random_double = std::bind(distribution, generator); + + for (unsigned i = 0; i < Rows * Cols; i++) + A[i] = random_double(); +} + +template +void transposeBuiltin(EltTy *ResPtr, EltTy *SrcPtr) { + auto M = __builtin_matrix_column_major_load(SrcPtr, R, C, R); + __builtin_matrix_column_major_store(__builtin_matrix_transpose(M), ResPtr, C); +} + +template +void transposeSpec(EltTy *ResPtr, EltTy *SrcPtr) { + using matrix_trans_t = EltTy __attribute__((matrix_type(C, R))); + auto M = __builtin_matrix_column_major_load(SrcPtr, R, C, R); + matrix_trans_t Res; + for (int c = 0; c < C; ++c) + for (int r = 0; r < R; ++r) + Res[c][r] = M[r][c]; + __builtin_matrix_column_major_store(Res, ResPtr, C); +} + +template +static void transposeBase(Ty *Res, Ty *Src, unsigned R0, unsigned C0) { + for (unsigned r = 0; r < R0; r++) { + for (unsigned c = 0; c < C0; c++) + Res[c + r * C0] = Src[r + c * R0]; + } +} + +template void testTranspose() { + EltTy X[R0 * C0]; + EltTy ResBase[R0 * C0]; + EltTy ResSpec[R0 * C0]; + EltTy ResBuiltin[R0 * C0]; + + initRandom(X, R0, C0); + zeroMatrix(ResBase, C0, R0); + zeroMatrix(ResSpec, C0, R0); + zeroMatrix(ResBuiltin, C0, R0); + + transposeBase(ResBase, X, R0, C0); + transposeSpec(ResSpec, X); + transposeBuiltin(ResBuiltin, X); + + EXPECT_MATRIX_EQ(ResBase, ResBuiltin, R0, C0); + EXPECT_MATRIX_EQ(ResBase, ResSpec, C0, R0); +} + +template +void multiplyBuiltin(EltTy *Res, EltTy *Matrix1, EltTy *Matrix2) { + using res_t = EltTy __attribute__((matrix_type(R0, C1))); + + auto A = __builtin_matrix_column_major_load(Matrix1, R0, C0, R0); + auto B = __builtin_matrix_column_major_load(Matrix2, C0, C1, C0); + res_t C = A * B; + __builtin_matrix_column_major_store(C, Res, R0); +} + +template +void multiplySpec(EltTy *Res, EltTy *Matrix1, EltTy *Matrix2) { + using res_t = EltTy __attribute__((matrix_type(R0, C1))); + + auto A = __builtin_matrix_column_major_load(Matrix1, R0, C0, R0); + auto B = __builtin_matrix_column_major_load(Matrix2, C0, C1, C0); + res_t ResM; + for (int C = 0; C < C1; ++C) { + for (int R = 0; R < R0; ++R) { + EltTy Elt = 0; + for (int K = 0; K < C0; K++) + Elt += A[R][K] * B[K][C]; + ResM[R][C] = Elt; + } + } + __builtin_matrix_column_major_store(ResM, Res, R0); +} + +template +static void BaseMatrixMult(Ty *A, Ty *B, Ty *C, unsigned R0, unsigned C0, + unsigned R1, unsigned C1) { + for (unsigned i = 0; i < R0; i++) + for (unsigned j = 0; j < C1; j++) + for (unsigned c = 0; c < C0; c++) + C[i + j * R0] += A[i + c * R0] * B[c + j * R1]; +} + +template +static void multiplyBase(EltTy *C, EltTy *A, EltTy *B) { + for (unsigned i = 0; i < R0; i++) + for (unsigned j = 0; j < C1; j++) + for (unsigned c = 0; c < C0; c++) { + C[i + j * R0] += A[i + c * R0] * B[c + j * C0]; + } +} + +template +void testMultiply() { + EltTy X[R0 * C0]; + EltTy Y[C0 * C1]; + EltTy ResBase[R0 * C1]; + EltTy ResSpec[R0 * C1]; + EltTy ResBuiltin[R0 * C1]; + + initRandom(X, R0, C0); + initRandom(Y, C0, C1); + zeroMatrix(ResBase, R0, C1); + zeroMatrix(ResSpec, R0, C1); + zeroMatrix(ResBuiltin, R0, C1); + + multiplyBase(ResBase, X, Y); + multiplySpec(ResSpec, X, Y); + multiplyBuiltin(ResBuiltin, X, Y); + + EXPECT_MATRIX_EQ(ResSpec, ResBuiltin, R0, C1); + EXPECT_MATRIX_EQ(ResBase, ResBuiltin, R0, C1); + EXPECT_MATRIX_EQ(ResBase, ResSpec, R0, C1); +} + +int main(void) { + testTranspose(); + testTranspose(); + testTranspose(); + testTranspose(); + testTranspose(); + + testMultiply(); + testMultiply(); + testMultiply(); + + return 0; +} Index: SingleSource/UnitTests/matrix-types-spec.reference_output =================================================================== --- /dev/null +++ SingleSource/UnitTests/matrix-types-spec.reference_output @@ -0,0 +1 @@ +exit 0