From d65537301277de04bcec3a133e76127b0877bfe1 Mon Sep 17 00:00:00 2001 From: DanielZhao0432 Date: Fri, 30 Oct 2026 17:08:23 +0800 Subject: [PATCH 1/2] DSP: make C_PACK optional; fall back to reference LAPACK zhegvx Since #8097, USE_DSP hard-requires MT_CPACK_DIR and DiagoLapack always calls cpack_zhegvx_driver under __DSP, coupling every DSP build to C_PACK even though only the serial generalized eigensolver uses it. Make MT_CPACK_DIR optional: when set, link libc_pack.a as before; when unset, compile the new cpack_zhegvx_fallback.cpp, which provides cpack_zhegvx_driver by forwarding to the reference zhegvx_. The two implementations are selected by CMake source-file selection, so no new compile-time macro is introduced and they can never be linked together. Fixes #8247 --- source/CMakeLists.txt | 32 ++++++---- source/source_hsolver/CMakeLists.txt | 8 +++ .../source_hsolver/cpack_zhegvx_fallback.cpp | 64 +++++++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 source/source_hsolver/cpack_zhegvx_fallback.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d849396a7d0..5bbd54cbcb5 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -157,21 +157,25 @@ target_link_libraries(abacus_link_libs INTERFACE abacus::feature_libs set(_abacus_linalg_libs) set(_abacus_linalg_include_dirs) +# C_PACK is optional for DSP builds. With MT_CPACK_DIR set, the serial +# generalized eigensolver is offloaded to cpack_zhegvx_driver from libc_pack.a; +# otherwise the fallback in source_hsolver/cpack_zhegvx_fallback.cpp forwards it +# to the reference LAPACK zhegvx_ (see issue #8247). if(USE_DSP) - if(NOT MT_CPACK_DIR) - message( - FATAL_ERROR - "USE_DSP requires MT_CPACK_DIR to be set to the DSP C_PACK install prefix " - "(the directory containing lib/libc_pack.a).") - endif() - set(_abacus_cpack_library "${MT_CPACK_DIR}/lib/libc_pack.a") - if(NOT EXISTS "${_abacus_cpack_library}") - message( - FATAL_ERROR - "MT_CPACK_DIR is set to '${MT_CPACK_DIR}' but '${_abacus_cpack_library}' does not exist." - ) - endif() - list(APPEND _abacus_linalg_libs ${_abacus_cpack_library}) + if(MT_CPACK_DIR) + set(_abacus_cpack_library "${MT_CPACK_DIR}/lib/libc_pack.a") + if(NOT EXISTS "${_abacus_cpack_library}") + message( + FATAL_ERROR + "MT_CPACK_DIR is set to '${MT_CPACK_DIR}' but '${_abacus_cpack_library}' does not exist." + ) + endif() + list(APPEND _abacus_linalg_libs ${_abacus_cpack_library}) + else() + message(STATUS + "USE_DSP without MT_CPACK_DIR: C_PACK disabled, the serial generalized " + "eigensolver falls back to reference LAPACK (zhegvx).") + endif() endif() if(USE_KML) diff --git a/source/source_hsolver/CMakeLists.txt b/source/source_hsolver/CMakeLists.txt index e7adc3fb5ad..7aed14ef5a3 100644 --- a/source/source_hsolver/CMakeLists.txt +++ b/source/source_hsolver/CMakeLists.txt @@ -46,6 +46,14 @@ if(ENABLE_LCAO) ) endif () + # DSP build without C_PACK: provide the zhegvx_ fallback for + # cpack_zhegvx_driver (used by diago_lapack.cpp under __DSP). + if(USE_DSP AND NOT MT_CPACK_DIR) + list(APPEND objects + cpack_zhegvx_fallback.cpp + ) + endif() + if(USE_CUDA) set(cuda_objects ./kernels/hegvd_op.cpp diff --git a/source/source_hsolver/cpack_zhegvx_fallback.cpp b/source/source_hsolver/cpack_zhegvx_fallback.cpp new file mode 100644 index 00000000000..adbbe393966 --- /dev/null +++ b/source/source_hsolver/cpack_zhegvx_fallback.cpp @@ -0,0 +1,64 @@ +// Fallback for DSP builds without C_PACK (MT_CPACK_DIR unset). +// +// diago_lapack.cpp calls cpack_zhegvx_driver under __DSP. The symbol normally +// comes from libc_pack.a; when C_PACK is not linked, this translation unit +// provides it by forwarding to the reference LAPACK zhegvx_. CMake adds this +// file only when USE_DSP is on and MT_CPACK_DIR is unset, so it never coexists +// with libc_pack.a. See issue #8247. + +#include "source_base/module_external/lapack_connector.h" + +#ifdef __DSP + +void cpack_zhegvx_driver(const int* itype, + const char* jobz, + const char* range, + const char* uplo, + const int* n, + std::complex* a, + const int* lda, + std::complex* b, + const int* ldb, + const double* vl, + const double* vu, + const int* il, + const int* iu, + const double* abstol, + int* m, + double* w, + std::complex* z, + const int* ldz, + std::complex* work, + const int* lwork, + double* rwork, + int* iwork, + int* ifail, + int* info) +{ + zhegvx_(itype, + jobz, + range, + uplo, + n, + a, + lda, + b, + ldb, + vl, + vu, + il, + iu, + abstol, + m, + w, + z, + ldz, + work, + lwork, + rwork, + iwork, + ifail, + info); +} + +#endif From 073b3ae606c8c759597e0305d6c2bc2e53eac6d0 Mon Sep 17 00:00:00 2001 From: DanielZhao0432 Date: Mon, 2 Nov 2026 10:49:41 +0800 Subject: [PATCH 2/2] Address review: wire fallback into hsolver unittest, add complex lapack case - MODULE_HSOLVER_LCAO compiles diago_lapack.cpp directly, so DSP builds without C_PACK need cpack_zhegvx_fallback.cpp there too. - Add a complex ks_solver=lapack case to the DiagoKPointsTest instantiation; the complex LAPACK path (zhegvx_once) had no registered coverage. - Wording: zhegvx_ comes from the configured LAPACK provider, not necessarily Netlib reference LAPACK. --- source/CMakeLists.txt | 4 ++-- source/source_hsolver/cpack_zhegvx_fallback.cpp | 2 +- source/source_hsolver/unittests/CMakeLists.txt | 9 +++++++-- source/source_hsolver/unittests/test_diago_lcao.cpp | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 748a0067c2a..61a8c2bccbe 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -160,7 +160,7 @@ set(_abacus_linalg_include_dirs) # C_PACK is optional for DSP builds. With MT_CPACK_DIR set, the serial # generalized eigensolver is offloaded to cpack_zhegvx_driver from libc_pack.a; # otherwise the fallback in source_hsolver/cpack_zhegvx_fallback.cpp forwards it -# to the reference LAPACK zhegvx_ (see issue #8247). +# to the configured LAPACK provider's zhegvx_ (see issue #8247). if(USE_DSP) if(MT_CPACK_DIR) set(_abacus_cpack_library "${MT_CPACK_DIR}/lib/libc_pack.a") @@ -174,7 +174,7 @@ if(USE_DSP) else() message(STATUS "USE_DSP without MT_CPACK_DIR: C_PACK disabled, the serial generalized " - "eigensolver falls back to reference LAPACK (zhegvx).") + "eigensolver falls back to the configured LAPACK provider (zhegvx).") endif() endif() diff --git a/source/source_hsolver/cpack_zhegvx_fallback.cpp b/source/source_hsolver/cpack_zhegvx_fallback.cpp index adbbe393966..25bc6f20bfe 100644 --- a/source/source_hsolver/cpack_zhegvx_fallback.cpp +++ b/source/source_hsolver/cpack_zhegvx_fallback.cpp @@ -2,7 +2,7 @@ // // diago_lapack.cpp calls cpack_zhegvx_driver under __DSP. The symbol normally // comes from libc_pack.a; when C_PACK is not linked, this translation unit -// provides it by forwarding to the reference LAPACK zhegvx_. CMake adds this +// provides it by forwarding to the configured LAPACK provider's zhegvx_. CMake adds this // file only when USE_DSP is on and MT_CPACK_DIR is unset, so it never coexists // with libc_pack.a. See issue #8247. diff --git a/source/source_hsolver/unittests/CMakeLists.txt b/source/source_hsolver/unittests/CMakeLists.txt index d013a06ed42..ab88294e70b 100644 --- a/source/source_hsolver/unittests/CMakeLists.txt +++ b/source/source_hsolver/unittests/CMakeLists.txt @@ -69,17 +69,22 @@ if (ENABLE_MPI) ) if(ENABLE_LCAO) + # DSP build without C_PACK: diago_lapack.cpp then needs the zhegvx_ + # fallback for cpack_zhegvx_driver. + if(USE_DSP AND NOT MT_CPACK_DIR) + set(_dsp_cpack_fallback_src ../cpack_zhegvx_fallback.cpp) + endif() if(TARGET ELPA::ELPA) AddTest( TARGET MODULE_HSOLVER_LCAO LIBS parameter ELPA::ELPA base genelpa psi device - SOURCES test_diago_lcao.cpp ../diago_elpa.cpp ../diago_elpa_native.cpp ../diago_scalapack.cpp ../diago_lapack.cpp + SOURCES test_diago_lcao.cpp ../diago_elpa.cpp ../diago_elpa_native.cpp ../diago_scalapack.cpp ../diago_lapack.cpp ${_dsp_cpack_fallback_src} ) else() AddTest( TARGET MODULE_HSOLVER_LCAO LIBS parameter base psi device - SOURCES test_diago_lcao.cpp ../diago_scalapack.cpp ../diago_lapack.cpp + SOURCES test_diago_lcao.cpp ../diago_scalapack.cpp ../diago_lapack.cpp ${_dsp_cpack_fallback_src} ) endif() diff --git a/source/source_hsolver/unittests/test_diago_lcao.cpp b/source/source_hsolver/unittests/test_diago_lcao.cpp index d61f0e0a44b..956b3752464 100644 --- a/source/source_hsolver/unittests/test_diago_lcao.cpp +++ b/source/source_hsolver/unittests/test_diago_lcao.cpp @@ -491,6 +491,7 @@ INSTANTIATE_TEST_SUITE_P( DiagoPrepare>(0, 0, 1, 0, "genelpa", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), #endif // DiagoPrepare>(0, 0, 32, 0, "genelpa", "H-KPoints-Si64.dat", "S-KPoints-Si64.dat"), + DiagoPrepare>(0, 0, 1, 0, "lapack", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), DiagoPrepare>(0, 0, 1, 0, "scalapack_gvx", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), DiagoPrepare>(0, 0, 32, 0, "scalapack_gvx", "H-KPoints-Si64.dat", "S-KPoints-Si64.dat")));