CBLAS: use the shared XERBLA helper in the xerbla sources
Switch cblas_xerbla(), F77_xerbla_base() and the test harness over to
cblas_xerbla_internal.h. Two diagnostic bugs go away with the duplicated
code:
- the row-major remap keyed off strstr(rout, "gemm"), which also
matches gemmtr and so wrongly swapped its arguments 4 and 5;
- the six-character name buffer truncated cblas_sgemmtr and
cblas_sskewsyr2k in the library, while the harness used an
eleven-character buffer and did not, so the two disagreed about the
same routine.
The Fortran entry points now take FCHAR and read the argument number
through F77_INT consistently, honour the hidden string length instead of
assuming six characters, and carry doxygen comments.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bfadf61f2f
commit
e2fd85389f
+27
-57
@@ -1,72 +1,42 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "cblas.h"
|
||||
#include "cblas_f77.h"
|
||||
#include "cblas_xerbla_internal.h"
|
||||
|
||||
void
|
||||
#ifdef HAS_ATTRIBUTE_WEAK_SUPPORT
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
API_SUFFIX(cblas_xerbla)(CBLAS_INT info, const char *rout, const char *form, ...)
|
||||
/**
|
||||
* \brief CBLAS error handler: report an invalid argument and terminate.
|
||||
*
|
||||
* Remaps \p info to the CBLAS argument position for row-major calls, writes
|
||||
* the diagnostic to stderr and exits; it does not return to its caller.
|
||||
*
|
||||
* \param[in] info CBLAS argument number, or 0 to report only \p form.
|
||||
* \param[in] rout Routine name, e.g. "cblas_dgemm".
|
||||
* \param[in] form printf-style format for further detail, followed by the
|
||||
* values it refers to.
|
||||
*/
|
||||
void CBLAS_WEAK_SYMBOL API_SUFFIX(cblas_xerbla)(CBLAS_INT info,
|
||||
const char *rout,
|
||||
const char *form, ...)
|
||||
{
|
||||
extern int RowMajorStrg;
|
||||
char empty[1] = "";
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, form);
|
||||
|
||||
if (RowMajorStrg)
|
||||
{
|
||||
if (strstr(rout,"gemm") != 0)
|
||||
{
|
||||
if (info == 5 ) info = 4;
|
||||
else if (info == 4 ) info = 5;
|
||||
else if (info == 11) info = 9;
|
||||
else if (info == 9 ) info = 11;
|
||||
}
|
||||
else if (strstr(rout,"symm") != 0 || strstr(rout,"hemm") != 0)
|
||||
{
|
||||
if (info == 5 ) info = 4;
|
||||
else if (info == 4 ) info = 5;
|
||||
}
|
||||
else if (strstr(rout,"trmm") != 0 || strstr(rout,"trsm") != 0)
|
||||
{
|
||||
if (info == 7 ) info = 6;
|
||||
else if (info == 6 ) info = 7;
|
||||
}
|
||||
else if (strstr(rout,"gemv") != 0)
|
||||
{
|
||||
if (info == 4) info = 3;
|
||||
else if (info == 3) info = 4;
|
||||
}
|
||||
else if (strstr(rout,"gbmv") != 0)
|
||||
{
|
||||
if (info == 4) info = 3;
|
||||
else if (info == 3) info = 4;
|
||||
else if (info == 6) info = 5;
|
||||
else if (info == 5) info = 6;
|
||||
}
|
||||
else if (strstr(rout,"ger") != 0)
|
||||
{
|
||||
if (info == 3) info = 2;
|
||||
else if (info == 2) info = 3;
|
||||
else if (info == 8) info = 6;
|
||||
else if (info == 6) info = 8;
|
||||
}
|
||||
else if ( (strstr(rout,"her2") != 0 || strstr(rout,"hpr2") != 0)
|
||||
&& strstr(rout,"her2k") == 0 )
|
||||
{
|
||||
if (info == 8) info = 6;
|
||||
else if (info == 6) info = 8;
|
||||
}
|
||||
info = cblas_xerbla_map_info(info, rout, RowMajorStrg);
|
||||
if (info) {
|
||||
fprintf(stderr, "Parameter %" CBLAS_IFMT " to routine %s was incorrect\n",
|
||||
info, rout);
|
||||
}
|
||||
if (info)
|
||||
fprintf(stderr, "Parameter %" CBLAS_IFMT " to routine %s was incorrect\n", info, rout);
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, form);
|
||||
vfprintf(stderr, form, argptr);
|
||||
va_end(argptr);
|
||||
if (info && !info)
|
||||
|
||||
if (info && !info) {
|
||||
F77_xerbla(empty, &info); /* Force link of our F77 error handler */
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
+47
-36
@@ -1,50 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cblas.h"
|
||||
#include "cblas_f77.h"
|
||||
#include "cblas_xerbla_internal.h"
|
||||
|
||||
#define XerblaStrLen 6
|
||||
#define XerblaStrLen1 7
|
||||
|
||||
void
|
||||
#ifdef HAS_ATTRIBUTE_WEAK_SUPPORT
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
F77_xerbla_base
|
||||
#ifdef F77_CHAR
|
||||
(F77_CHAR F77_srname, void *vinfo
|
||||
#else
|
||||
(char *srname, void *vinfo
|
||||
#endif
|
||||
/**
|
||||
* \brief XERBLA implementation linked in together with the CBLAS library.
|
||||
*
|
||||
* An error raised beneath a CBLAS wrapper is forwarded to cblas_xerbla()
|
||||
* under the CBLAS spelling of the routine name, with the argument number
|
||||
* shifted by one to account for the extra layout argument. Errors from
|
||||
* direct Fortran calls are reported under the Fortran name instead.
|
||||
*
|
||||
* \param[in] F77_srname Routine name reported by the Fortran BLAS, blank
|
||||
* padded and not NUL terminated.
|
||||
* \param[in] vinfo Pointer to the Fortran argument number.
|
||||
* \param[in] len Hidden Fortran length of \p F77_srname, on
|
||||
* compilers that pass string lengths at the end of
|
||||
* the argument list.
|
||||
*/
|
||||
void CBLAS_WEAK_SYMBOL F77_xerbla_base(FCHAR F77_srname, void *vinfo
|
||||
#ifdef BLAS_FORTRAN_STRLEN_END
|
||||
, FORTRAN_STRLEN len
|
||||
,
|
||||
FORTRAN_STRLEN len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef F77_CHAR
|
||||
char *srname;
|
||||
#endif
|
||||
|
||||
char rout[] = {'c','b','l','a','s','_','\0','\0','\0','\0','\0','\0','\0'};
|
||||
|
||||
int *info=vinfo;
|
||||
int i;
|
||||
|
||||
extern int CBLAS_CallFromC;
|
||||
|
||||
#ifdef F77_CHAR
|
||||
srname = F2C_STR(F77_srname, XerblaStrLen);
|
||||
size_t srname_len;
|
||||
#ifdef BLAS_FORTRAN_STRLEN_END
|
||||
srname_len = len > 0 ? (size_t)len : 0;
|
||||
#else
|
||||
srname_len = 6;
|
||||
#endif
|
||||
|
||||
if (CBLAS_CallFromC)
|
||||
{
|
||||
for(i=0; i != XerblaStrLen; i++) rout[i+6] = tolower(srname[i]);
|
||||
rout[XerblaStrLen+6] = '\0';
|
||||
API_SUFFIX(cblas_xerbla)(*info+1,rout,"");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Parameter %d to routine %s was incorrect\n",
|
||||
*info, srname);
|
||||
char *srname;
|
||||
#ifdef F77_CHAR
|
||||
srname = F2C_STR(F77_srname, srname_len);
|
||||
#else
|
||||
srname = F77_srname;
|
||||
#endif
|
||||
|
||||
F77_INT *info = (F77_INT *)vinfo;
|
||||
CBLAS_INT cblas_info = (CBLAS_INT)*info;
|
||||
|
||||
if (CBLAS_CallFromC) {
|
||||
char rout[CBLAS_XERBLA_ROUT_BUFFER_SIZE];
|
||||
cblas_xerbla_make_rout(rout, sizeof(rout), srname, srname_len);
|
||||
API_SUFFIX(cblas_xerbla)(cblas_info + 1, rout, "");
|
||||
} else {
|
||||
size_t display_len = cblas_xerbla_trimmed_length(srname, srname_len);
|
||||
|
||||
fprintf(stderr, "Parameter %" CBLAS_IFMT " to routine ", cblas_info);
|
||||
if (display_len > 0) {
|
||||
fwrite(srname, 1, display_len, stderr);
|
||||
}
|
||||
fputs(" was incorrect\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
+63
-96
@@ -1,16 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cblas.h"
|
||||
#include "cblas_test.h"
|
||||
#include "cblas_xerbla_internal.h"
|
||||
|
||||
void API_SUFFIX(cblas_xerbla)(CBLAS_INT info, const char *rout, const char *form, ...)
|
||||
/**
|
||||
* \brief Test-harness stand-in for the CBLAS error handler.
|
||||
*
|
||||
* Rather than terminating, checks the reported routine name and argument
|
||||
* number against the values the calling tester put in cblas_rout and
|
||||
* cblas_info, and records the outcome in cblas_ok and cblas_lerr.
|
||||
*
|
||||
* \param[in] info CBLAS argument number reported by the caller.
|
||||
* \param[in] rout Routine name, e.g. "cblas_dgemm".
|
||||
* \param[in] form Unused; kept so the signature matches the library's.
|
||||
*/
|
||||
void API_SUFFIX(cblas_xerbla)(CBLAS_INT info, const char *rout,
|
||||
const char *form, ...)
|
||||
{
|
||||
extern CBLAS_INT cblas_lerr, cblas_info, cblas_ok;
|
||||
extern CBLAS_INT link_xerbla;
|
||||
extern char *cblas_rout;
|
||||
|
||||
(void)form;
|
||||
|
||||
/* Initially, c__3chke may call this routine with
|
||||
* global variable link_xerbla=1, and F77_xerbla will set link_xerbla=0.
|
||||
* This is done to fool the linker into loading these subroutines first
|
||||
@@ -18,120 +34,71 @@ void API_SUFFIX(cblas_xerbla)(CBLAS_INT info, const char *rout, const char *form
|
||||
*/
|
||||
if (link_xerbla) return;
|
||||
|
||||
if (cblas_rout != NULL && strcmp(cblas_rout, rout) != 0){
|
||||
printf("***** XERBLA WAS CALLED WITH SRNAME = <%s> INSTEAD OF <%s> *******\n", rout, cblas_rout);
|
||||
if (cblas_rout != NULL && strcmp(cblas_rout, rout) != 0) {
|
||||
printf(
|
||||
"***** XERBLA WAS CALLED WITH SRNAME = <%s> INSTEAD OF <%s> *******\n",
|
||||
rout, cblas_rout);
|
||||
cblas_ok = FALSE;
|
||||
}
|
||||
|
||||
if (RowMajorStrg)
|
||||
{
|
||||
/* To properly check leading dimension problems in cblas__gemm, we
|
||||
* need to do the following trick. When cblas__gemm is called with
|
||||
* CblasRowMajor, the arguments A and B switch places in the call to
|
||||
* f77__gemm. Thus when we test for bad leading dimension problems
|
||||
* for A and B, lda is in position 11 instead of 9, and ldb is in
|
||||
* position 9 instead of 11.
|
||||
*/
|
||||
if (strstr(rout,"gemm") != 0 && strstr(rout, "gemmtr") == 0)
|
||||
{
|
||||
if (info == 5 ) info = 4;
|
||||
else if (info == 4 ) info = 5;
|
||||
else if (info == 11) info = 9;
|
||||
else if (info == 9 ) info = 11;
|
||||
} else if (strstr(rout, "gemmtr") != 0)
|
||||
{
|
||||
if (info == 11) info = 9;
|
||||
else if (info == 9 ) info = 11;
|
||||
}
|
||||
info = cblas_xerbla_map_info(info, rout, RowMajorStrg);
|
||||
|
||||
else if (strstr(rout,"symm") != 0 || strstr(rout,"skewsymm") != 0 || strstr(rout,"hemm") != 0)
|
||||
{
|
||||
if (info == 5 ) info = 4;
|
||||
else if (info == 4 ) info = 5;
|
||||
}
|
||||
else if (strstr(rout,"trmm") != 0 || strstr(rout,"trsm") != 0)
|
||||
{
|
||||
if (info == 7 ) info = 6;
|
||||
else if (info == 6 ) info = 7;
|
||||
}
|
||||
else if (strstr(rout,"gemv") != 0)
|
||||
{
|
||||
if (info == 4) info = 3;
|
||||
else if (info == 3) info = 4;
|
||||
}
|
||||
else if (strstr(rout,"gbmv") != 0)
|
||||
{
|
||||
if (info == 4) info = 3;
|
||||
else if (info == 3) info = 4;
|
||||
else if (info == 6) info = 5;
|
||||
else if (info == 5) info = 6;
|
||||
}
|
||||
else if (strstr(rout,"ger") != 0)
|
||||
{
|
||||
if (info == 3) info = 2;
|
||||
else if (info == 2) info = 3;
|
||||
else if (info == 8) info = 6;
|
||||
else if (info == 6) info = 8;
|
||||
}
|
||||
else if ( ( strstr(rout,"her2") != 0 || strstr(rout,"hpr2") != 0 )
|
||||
&& strstr(rout,"her2k") == 0 )
|
||||
{
|
||||
if (info == 8) info = 6;
|
||||
else if (info == 6) info = 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (info != cblas_info){
|
||||
printf("***** XERBLA WAS CALLED WITH INFO = %" CBLAS_IFMT " INSTEAD OF %d in %s *******\n",info, (int) cblas_info, rout);
|
||||
if (info != cblas_info) {
|
||||
printf("***** XERBLA WAS CALLED WITH INFO = %" CBLAS_IFMT
|
||||
" INSTEAD OF %d in %s *******\n",
|
||||
info, (int)cblas_info, rout);
|
||||
cblas_lerr = PASSED;
|
||||
cblas_ok = FALSE;
|
||||
} else cblas_lerr = FAILED;
|
||||
} else {
|
||||
cblas_lerr = FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef F77_Char
|
||||
void F77_xerbla(F77_Char F77_srname, void *vinfo
|
||||
#else
|
||||
void F77_xerbla(char *srname, void *vinfo
|
||||
#endif
|
||||
/**
|
||||
* \brief Test-harness XERBLA that redirects Fortran errors to cblas_xerbla().
|
||||
*
|
||||
* \param[in] F77_srname Routine name reported by the Fortran BLAS, blank
|
||||
* padded and not NUL terminated.
|
||||
* \param[in] vinfo Pointer to the Fortran argument number.
|
||||
* \param[in] len Hidden Fortran length of \p F77_srname, on
|
||||
* compilers that pass string lengths at the end.
|
||||
*/
|
||||
void F77_xerbla(FCHAR F77_srname, void *vinfo
|
||||
#ifdef BLAS_FORTRAN_STRLEN_END
|
||||
, FORTRAN_STRLEN srname_len
|
||||
,
|
||||
FORTRAN_STRLEN len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef F77_Char
|
||||
char *srname;
|
||||
#endif
|
||||
|
||||
char rout[] = {'c','b','l','a','s','_','\0','\0','\0','\0','\0','\0','\0', '\0', '\0', '\0', '\0', '\0'};
|
||||
|
||||
#ifdef F77_Integer
|
||||
F77_Integer *info=vinfo;
|
||||
F77_Integer i;
|
||||
extern F77_Integer link_xerbla;
|
||||
#else
|
||||
CBLAS_INT *info=vinfo;
|
||||
CBLAS_INT i;
|
||||
extern CBLAS_INT link_xerbla;
|
||||
#endif
|
||||
#ifdef F77_Char
|
||||
srname = F2C_STR(F77_srname, XerblaStrLen);
|
||||
#endif
|
||||
|
||||
/* See the comment in API_SUFFIX(cblas_xerbla)() above */
|
||||
if (link_xerbla)
|
||||
{
|
||||
extern CBLAS_INT link_xerbla;
|
||||
if (link_xerbla) {
|
||||
link_xerbla = 0;
|
||||
return;
|
||||
}
|
||||
#ifndef BLAS_FORTRAN_STRLEN_END
|
||||
const int srname_len = 6;
|
||||
|
||||
size_t srname_len;
|
||||
#ifdef BLAS_FORTRAN_STRLEN_END
|
||||
srname_len = len > 0 ? (size_t)len : 0;
|
||||
#else
|
||||
srname_len = 6;
|
||||
#endif
|
||||
|
||||
for(i=0; i < srname_len; i++) rout[i+6] = tolower(srname[i]);
|
||||
for(i=16; i >= 9; i--) if (rout[i] == ' ') rout[i] = '\0';
|
||||
char *srname;
|
||||
#ifdef F77_CHAR
|
||||
srname = F2C_STR(F77_srname, srname_len);
|
||||
#else
|
||||
srname = F77_srname;
|
||||
#endif
|
||||
|
||||
F77_INT *info = (F77_INT *)vinfo;
|
||||
CBLAS_INT cblas_info = (CBLAS_INT)*info;
|
||||
|
||||
char rout[CBLAS_XERBLA_ROUT_BUFFER_SIZE];
|
||||
cblas_xerbla_make_rout(rout, sizeof(rout), srname, srname_len);
|
||||
|
||||
/* We increment *info by 1 since the CBLAS interface adds one more
|
||||
* argument to all level 2 and 3 routines.
|
||||
*/
|
||||
API_SUFFIX(cblas_xerbla)(*info+1,rout,"");
|
||||
API_SUFFIX(cblas_xerbla)(cblas_info + 1, rout, "");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user