# Copyright Advanced Micro Devices, Inc., or its affiliates. # SPDX-License-Identifier: MIT find_package(GTest REQUIRED) include(GoogleTest) add_executable(tensilelite-tests) add_subdirectory(configs) set(TEST_DATA_DIR "${CMAKE_CURRENT_BINARY_DIR}/data") file(MAKE_DIRECTORY "${TEST_DATA_DIR}") foreach(FILE ${SOLUTION_LIBRARY_FILES}) if(EXISTS "${FILE}.gz") execute_process(COMMAND gzip --keep --decompress --force "${FILE}.gz") endif() file(COPY ${FILE} DESTINATION "${TEST_DATA_DIR}") endforeach() target_sources(tensilelite-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AlmostEqual_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ContractionSelectionLibrary_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CuCount_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/DataTypes_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/DataInit_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ExactLogicLibrary_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/GEMMKernelTest.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/GEMMKernelTest_impl.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/RunGEMMKernelTest.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/RunGEMMKernelTest_impl.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/TestData.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/TestUtils.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/MXScalePadding_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/PciChipId_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Predicates_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ReferenceFastPath_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RangeLibrary_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ResultComparison_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ReferenceMXFastPath_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/SolutionValidation_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TensorDescriptor_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TestData.cpp" ) # MasterSolutionLibraryMapping_test exercises TensileLite::LoadLibraryMapping, # which is only defined when MSGPACK is the active serialization format # (see tensilelite/src/Tensile.cpp). The test also writes msgpack mapping # files directly via , so it has no meaning in YAML builds. if(NOT HIPBLASLT_ENABLE_YAML) target_sources(tensilelite-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/MasterSolutionLibraryMapping_test.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CompressedLibraryLoad_test.cpp" ) endif() target_include_directories(tensilelite-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_include_directories(tensilelite-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../client/include") target_link_libraries(tensilelite-tests PUBLIC roc::tensilelite-host PRIVATE hip::device tensilelite::client-common ${CMAKE_DL_LIBS} ${hipblaslt_msgpack_target} ZLIB::ZLIB ) if(HIPBLASLT_ENABLE_MXDATAGENERATOR) target_sources(tensilelite-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/MXDataGen_test.cpp" ) target_link_libraries(tensilelite-tests PRIVATE hipblaslt::mxdatagen) endif() gtest_discover_tests(tensilelite-tests WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} TIMEOUT 60) target_link_libraries(tensilelite-tests PUBLIC GTest::gtest) if(HIPBLASLT_ENABLE_OPENMP) target_link_libraries(tensilelite-tests PRIVATE OpenMP::OpenMP_CXX) endif() enable_testing() ################################################# # Tests for cpu-gemm-driver # ################################################# function(add_cpu_gemm_test TEST_NAME) cmake_parse_arguments(ARG "" "" "ARGS" ${ARGN}) add_test( NAME "CPUGemm.${TEST_NAME}" COMMAND cpu-gemm-driver ${ARG_ARGS} ) endfunction() # Default test sizes. Non-tile-aligned to stress remainder handling. # f32, f64, and f16/bf16 use different sizes to increase coverage diversity. set(F32_SIZES -M 133 -N 147 -K 165) set(F64_SIZES -M 137 -N 149 -K 163) set(F16_SIZES -M 131 -N 141 -K 151) set(ADDITIONAL_SIZES -M 102 -N 103 -K 105) function(get_test_sizes TYPE OUT_SIZES) if("${TYPE}" STREQUAL "f32") set(${OUT_SIZES} ${F32_SIZES} PARENT_SCOPE) else() set(${OUT_SIZES} ${F16_SIZES} PARENT_SCOPE) endif() endfunction() # Helper: convert transpose tag (NN/TN/NT/TT) to flags macro(get_trans_flags TRANS OUT_FLAGS) set(${OUT_FLAGS} "") if("${TRANS}" MATCHES "^T") list(APPEND ${OUT_FLAGS} --transA) endif() if("${TRANS}" MATCHES "T$") list(APPEND ${OUT_FLAGS} --transB) endif() endmacro() # Run all tests against both fast and slow paths foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() # Basic sanity, transpose combos, odd sizes, type coverage add_cpu_gemm_test(${PATH}_F32_Sanity ARGS ${F32_SIZES} --type f32 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_F32_ADDITIONAL_SIZES ARGS ${ADDITIONAL_SIZES} --type f32 --validate ${PATH_FLAGS} ) foreach(TYPE f32 f16 bf16) get_test_sizes(${TYPE} SIZES) foreach(TRANS NN TN NT TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_${TYPE}_${TRANS} ARGS ${SIZES} ${TFLAGS} --type ${TYPE} --validate ${PATH_FLAGS} ) endforeach() endforeach() # Cross-validate: features per type foreach(TYPE f32 f16 bf16) get_test_sizes(${TYPE} SIZES) add_cpu_gemm_test(${PATH}_${TYPE}_Beta ARGS ${SIZES} --type ${TYPE} --beta 1.0 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_Bias ARGS ${SIZES} --type ${TYPE} --validate --bias ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_AllFeatures ARGS ${SIZES} --type ${TYPE} --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_TN_AllFeatures ARGS ${SIZES} --transA --type ${TYPE} --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) endforeach() # F32-only individual feature tests add_cpu_gemm_test(${PATH}_f32_Relu ARGS ${F32_SIZES} --type f32 --validate --activation relu ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f32_ScaleAlphaVec ARGS ${F32_SIZES} --type f32 --validate --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f32_Beta_AllFeatures ARGS ${F32_SIZES} --type f32 --beta 0.5 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f32_ScaleAlphaVec_ColN ARGS ${F32_SIZES} --type f32 --validate --scaleAlphaVec --factorDim 1 ${PATH_FLAGS} ) # Edge cases: dimensions at or below tile size (BLOCK_M=32, BLOCK_N=32, BLOCK_K=8) foreach(CASE "M1;1;147;165" "N1;133;1;165" "K1;133;147;1" "1x1;1;1;1" "ExactBlock;32;32;8") list(GET CASE 0 NAME) list(GET CASE 1 EM) list(GET CASE 2 EN) list(GET CASE 3 EK) add_cpu_gemm_test(${PATH}_f32_${NAME} ARGS -M ${EM} -N ${EN} -K ${EK} --type f32 --validate ${PATH_FLAGS} ) endforeach() # ScaleAB tests foreach(MODE Scalar Vector) foreach(TYPE f32 f16 bf16) get_test_sizes(${TYPE} SIZES) add_cpu_gemm_test(${PATH}_${TYPE}_ScaleAB_${MODE} ARGS ${SIZES} --type ${TYPE} --validate --useScaleAB ${MODE} ${PATH_FLAGS} ) endforeach() add_cpu_gemm_test(${PATH}_f32_ScaleAB_${MODE}_AllFeatures ARGS ${F32_SIZES} --type f32 --beta 0.5 --validate --useScaleAB ${MODE} --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) # ScaleAB with factorDim=1 (column-dimension ScaleAlphaVec) add_cpu_gemm_test(${PATH}_f32_ScaleAB_${MODE}_ColN ARGS ${F32_SIZES} --type f32 --validate --useScaleAB ${MODE} --scaleAlphaVec --factorDim 1 ${PATH_FLAGS} ) endforeach() endforeach() add_test( NAME "CPUGemm.validation_InjectedFailure_Rejected" COMMAND cpu-gemm-driver -M 8 -N 8 -K 8 --type f32 --validate --tryFastPath --injectValidationFailure ) set_tests_properties("CPUGemm.validation_InjectedFailure_Rejected" PROPERTIES WILL_FAIL TRUE) ################################################# # FP8 tests (fast & slow) # ################################################# if(NOT WIN32) foreach(TYPE f8 bf8 f8fnuz bf8fnuz) foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() # Transpose combos foreach(TRANS NN TN NT TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_${TYPE}_${TRANS} ARGS ${F16_SIZES} ${TFLAGS} --type ${TYPE} --validate ${PATH_FLAGS} ) endforeach() # Feature tests add_cpu_gemm_test(${PATH}_${TYPE}_Beta ARGS ${F16_SIZES} --type ${TYPE} --beta 1.0 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_Beta_Half ARGS ${F16_SIZES} --type ${TYPE} --beta 0.5 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_Bias ARGS ${F16_SIZES} --type ${TYPE} --validate --bias ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_AllFeatures ARGS ${F16_SIZES} --type ${TYPE} --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_${TYPE}_TN_AllFeatures ARGS ${F16_SIZES} --transA --type ${TYPE} --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) # ScaleAB tests foreach(MODE Scalar Vector) add_cpu_gemm_test(${PATH}_${TYPE}_ScaleAB_${MODE} ARGS ${F16_SIZES} --type ${TYPE} --validate --useScaleAB ${MODE} ${PATH_FLAGS} ) endforeach() endforeach() endforeach() endif() ################################################# # Mixed-input-type FP8 tests (fast & slow path).# # Reproduces production failure where A and B # # have different storage types but share a # # narrower MAC compute-input type (the kernel # # quantizes the wider operand for F8 MFMA). # # See: sk_f8ngemm_quick.yaml F8NH_F8NSS NN. # ################################################# if(NOT WIN32) foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() # A=F8N, B=Half, both quantized to F8N at the MAC. This is the exact # shape that failed in sk_f8ngemm_quick.yaml's F8NH_F8NSS NN test. # Pre-fix, the fast path skipped the B->F8N quantization while the slow # path applied it, and the two diverged. add_cpu_gemm_test(${PATH}_f8fnuz_x_h_macF8N ARGS ${F16_SIZES} --typeA f8fnuz --typeB f16 --computeInputB f8fnuz --validate ${PATH_FLAGS} ) # OCP F8 counterpart (same shape, non-fnuz storage). # NB: BFloat8_fnuz x Half is intentionally absent - the slow path # has no TypedGemm dispatch for that combination. add_cpu_gemm_test(${PATH}_f8_x_h_macF8 ARGS ${F16_SIZES} --typeA f8 --typeB f16 --computeInputB f8 --validate ${PATH_FLAGS} ) # Mirror cases - A is the wider operand and gets quantized to F8 at # the MAC. Exercises the symmetric A-side quantization path on both # the test driver init and the GEMM implementations. add_cpu_gemm_test(${PATH}_h_x_f8fnuz_macF8N ARGS ${F16_SIZES} --typeA f16 --typeB f8fnuz --computeInputA f8fnuz --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_h_x_f8_macF8 ARGS ${F16_SIZES} --typeA f16 --typeB f8 --computeInputA f8 --validate ${PATH_FLAGS} ) endforeach() endif() ################################################# # F64 (double precision) tests # ################################################# # F64 uses double storage and accumulation. foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() foreach(TRANS NN TN NT TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_f64_${TRANS} ARGS ${F64_SIZES} ${TFLAGS} --type f64 --validate ${PATH_FLAGS} ) endforeach() add_cpu_gemm_test(${PATH}_f64_Beta ARGS ${F64_SIZES} --type f64 --beta 1.0 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f64_Bias ARGS ${F64_SIZES} --type f64 --validate --bias ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f64_AllFeatures ARGS ${F64_SIZES} --type f64 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f64_TN_AllFeatures ARGS ${F64_SIZES} --transA --type f64 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) foreach(MODE Scalar Vector) add_cpu_gemm_test(${PATH}_f64_ScaleAB_${MODE} ARGS ${F64_SIZES} --type f64 --validate --useScaleAB ${MODE} ${PATH_FLAGS} ) endforeach() endforeach() ################################################# # TF32 (XFloat32 math-op) tests # ################################################# # TF32 uses float storage with XFloat32 truncation on multiply. foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() foreach(TRANS NN TN NT TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_tf32_${TRANS} ARGS ${F32_SIZES} ${TFLAGS} --type tf32 --validate ${PATH_FLAGS} ) endforeach() add_cpu_gemm_test(${PATH}_tf32_Beta ARGS ${F32_SIZES} --type tf32 --beta 1.0 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_tf32_Bias ARGS ${F32_SIZES} --type tf32 --validate --bias ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_tf32_AllFeatures ARGS ${F32_SIZES} --type tf32 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_tf32_TN_AllFeatures ARGS ${F32_SIZES} --transA --type tf32 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) foreach(MODE Scalar Vector) add_cpu_gemm_test(${PATH}_tf32_ScaleAB_${MODE} ARGS ${F32_SIZES} --type tf32 --validate --useScaleAB ${MODE} ${PATH_FLAGS} ) endforeach() endforeach() add_test( NAME "CPUGemm.tf32_MixedA_Rejected" COMMAND cpu-gemm-driver -M 16 -N 16 -K 16 --typeA tf32 --typeB f32 --validate ) set_tests_properties("CPUGemm.tf32_MixedA_Rejected" PROPERTIES WILL_FAIL TRUE) add_test( NAME "CPUGemm.tf32_MixedB_Rejected" COMMAND cpu-gemm-driver -M 16 -N 16 -K 16 --typeA f32 --typeB tf32 --validate ) set_tests_properties("CPUGemm.tf32_MixedB_Rejected" PROPERTIES WILL_FAIL TRUE) ################################################# # FP4 / MX Scale tests (fast & slow) # ################################################# if(NOT WIN32) # M/N similar to f32 tests; K must be a multiple of mxBlock (32). set(F4_SIZES_32 -M 133 -N 147 -K 160) set(F4_SIZES_64 -M 133 -N 147 -K 192) foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() # Basic F4 with MX scaling, all transpose combos foreach(TRANS NN TN NT TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_f4_MX32_${TRANS} ARGS ${F4_SIZES_32} ${TFLAGS} --type f4 --mxBlockA 32 --mxBlockB 32 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_K192_${TRANS} ARGS ${F4_SIZES_64} ${TFLAGS} --type f4 --mxBlockA 32 --mxBlockB 32 --validate ${PATH_FLAGS} ) endforeach() # F4 without MX (mxBlock=0, the default) add_cpu_gemm_test(${PATH}_f4_NoMX_NN ARGS -M 16 -N 16 -K 16 --type f4 --validate ${PATH_FLAGS} ) # F4 + MX + epilogue features add_cpu_gemm_test(${PATH}_f4_MX32_Bias ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --bias ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_Relu ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --activation relu ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_ScaleAlphaVec ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_AllFeatures ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --bias --activation relu --scaleAlphaVec ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_Beta ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --beta 1.0 --validate ${PATH_FLAGS} ) # F4 + MX + ScaleAB foreach(MODE Scalar Vector) add_cpu_gemm_test(${PATH}_f4_MX32_ScaleAB_${MODE} ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --useScaleAB ${MODE} ${PATH_FLAGS} ) endforeach() endforeach() # Fast-path-only: mxBlock=16 (tests non-hardcoded mxBlock; 16 % BLOCK_K=8 == 0) add_cpu_gemm_test(fast_f4_MX16_NN ARGS ${F4_SIZES_32} --type f4 --mxBlockA 16 --mxBlockB 16 --validate --tryFastPath ) # Batched mxfp4 (batchCount > 1) — exercises strideBatchMxsa/strideBatchMxsb # in the fast path's MX loop (the site of a previous .a / .b typo bug). foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() foreach(TRANS NN TT) get_trans_flags(${TRANS} TFLAGS) add_cpu_gemm_test(${PATH}_f4_MX32_Batched_${TRANS} ARGS ${F4_SIZES_32} ${TFLAGS} --type f4 --mxBlockA 32 --mxBlockB 32 --validate --batchCount 2 ${PATH_FLAGS} ) endforeach() endforeach() # Asymmetric MX (mxBlockA != mxBlockB). K must be a multiple of # lcm(mxBlockA, mxBlockB) — here lcm(32, 64) = 64, which F4_SIZES_64 # already satisfies (K=192). Fast path only: the production slow path # collapses the smaller side's per-segment scales (see driver rejection # in runGemm). add_cpu_gemm_test(fast_f4_MX_A32_B64_NN ARGS ${F4_SIZES_64} --type f4 --mxBlockA 32 --mxBlockB 64 --validate --tryFastPath ) add_cpu_gemm_test(fast_f4_MX_A64_B32_NN ARGS ${F4_SIZES_64} --type f4 --mxBlockA 64 --mxBlockB 32 --validate --tryFastPath ) # Negative test: slow path must reject asymmetric MX. add_test( NAME "CPUGemm.slow_f4_MX_A32_B64_Rejected" COMMAND cpu-gemm-driver ${F4_SIZES_64} --type f4 --mxBlockA 32 --mxBlockB 64 --validate ) set_tests_properties("CPUGemm.slow_f4_MX_A32_B64_Rejected" PROPERTIES WILL_FAIL TRUE) # Negative test: one-sided MX (only A or only B) must be rejected. add_test( NAME "CPUGemm.f4_MX_OneSided_Rejected" COMMAND cpu-gemm-driver ${F4_SIZES_32} --type f4 --mxBlockA 32 --validate ) set_tests_properties("CPUGemm.f4_MX_OneSided_Rejected" PROPERTIES WILL_FAIL TRUE) # Edge-size mxfp4 coverage: K equal to mxBlock (single MX block per row), # M=1 / N=1 strips, and alpha=0 short-circuit. Both fast and slow paths. foreach(PATH fast slow) if("${PATH}" STREQUAL "fast") set(PATH_FLAGS --tryFastPath) else() set(PATH_FLAGS "") endif() add_cpu_gemm_test(${PATH}_f4_MX32_K_eq_mxBlock ARGS -M 16 -N 16 -K 32 --type f4 --mxBlockA 32 --mxBlockB 32 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_M1 ARGS -M 1 -N 147 -K 160 --type f4 --mxBlockA 32 --mxBlockB 32 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_N1 ARGS -M 133 -N 1 -K 160 --type f4 --mxBlockA 32 --mxBlockB 32 --validate ${PATH_FLAGS} ) add_cpu_gemm_test(${PATH}_f4_MX32_Alpha0 ARGS ${F4_SIZES_32} --type f4 --mxBlockA 32 --mxBlockB 32 --alpha 0 --validate ${PATH_FLAGS} ) endforeach() # F4 with odd dimensions (M*K is odd) to exercise ShadowBuffer edge cases add_cpu_gemm_test(fast_f4_NoMX_OddDims ARGS -M 3 -N 5 -K 7 --type f4 --validate --tryFastPath ) # Negative tests: invalid K/mxBlock combos should fail with clear error add_test( NAME "CPUGemm.slow_f4_MX32_BadK_Unaligned" COMMAND cpu-gemm-driver -M 16 -N 16 -K 33 --type f4 --mxBlockA 32 --mxBlockB 32 --validate ) set_tests_properties("CPUGemm.slow_f4_MX32_BadK_Unaligned" PROPERTIES WILL_FAIL TRUE) add_test( NAME "CPUGemm.slow_f4_MX32_BadK_TooSmall" COMMAND cpu-gemm-driver -M 16 -N 16 -K 16 --type f4 --mxBlockA 32 --mxBlockB 32 --validate ) set_tests_properties("CPUGemm.slow_f4_MX32_BadK_TooSmall" PROPERTIES WILL_FAIL TRUE) # Negative test: non-power-of-2 mxBlock should be rejected add_test( NAME "CPUGemm.slow_f4_MX6_BadPow2" COMMAND cpu-gemm-driver -M 4 -N 4 -K 12 --type f4 --mxBlockA 6 --mxBlockB 6 --validate ) set_tests_properties("CPUGemm.slow_f4_MX6_BadPow2" PROPERTIES WILL_FAIL TRUE) # Negative test: mxBlock with non-FP4 types should be rejected add_test( NAME "CPUGemm.slow_f32_MX32_Rejected" COMMAND cpu-gemm-driver -M 16 -N 16 -K 32 --type f32 --mxBlockA 32 --mxBlockB 32 --validate ) set_tests_properties("CPUGemm.slow_f32_MX32_Rejected" PROPERTIES WILL_FAIL TRUE) endif()