C_LAPACK: take the float format from <float.h> in dlamch/slamch - #5982
Merged
martin-frbg merged 1 commit intoAug 18, 2026
Merged
Conversation
INSTALL/dlamch.c and INSTALL/slamch.c are f2c translations of the deprecated
dlamchf77.f and slamchf77.f, which determine the floating point format at run
time by probing in dlamc1/dlamc2 rather than reading it from the environment.
The current dlamch.f and slamch.f use the Fortran 90 inquiry intrinsics
(EPSILON, TINY, HUGE, DIGITS, MINEXPONENT, MAXEXPONENT, RADIX) instead, but f2c
cannot translate those, so the C LAPACK selected by NOFORTRAN=1 has been left
with the older probing implementation.
The probe is only correct if double intermediates are genuinely rounded to
double. That does not hold on x87. Building 32 bit for a target without SSE2,
so with -mfpmath=387, and with gcc 16, the intermediates stay in registers and
the probe measures the 80 bit register format: it reports emin/emax as
-16381/16384, and a mantissa width that follows the caller's x87 precision
control bits (64 at extended precision, 53 at double). Written back as doubles,
rmin underflows to 0 and rmax overflows to +Inf, so dlamch('S') and dlamch('U')
return 0 and dlamch('O') returns +Inf.
Everything that scales by those values is then wrong, mostly silently. The
first symptom to surface was a floating point exception rather than a wrong
answer: dsbevx computes
safmin = dlamch('S')
eps = dlamch('P')
smlnum = safmin / eps
bignum = 1 / smlnum
so a zero safe minimum makes smlnum zero and the next line divides by zero.
Callers that unmask the divide by zero exception get a hard failure there;
callers that do not get whatever the wrong scaling produces.
Replace the probe with the <float.h> constants, mirroring the values the
current dlamch.f and slamch.f return. This fixes two lesser problems at the
same time: rmach was left uninitialised when cmach matched nothing, where
dlamch.f returns zero; and the cached static results made both routines
unsafe to call concurrently on first use.
dlamc1-dlamc5 and slamc1-slamc5 are left in place. They become unreachable
from dlamch/slamch, but dlamc3 and slamc3 have callers of their own in dlaed3,
dlaed9, dlals0, dlasd3, dlasd8 and their complex equivalents, where they serve
as optimiser barriers.
Collaborator
|
Ah right, thanks - the big f2c'ing was mostly a hack to keep the LAPACK parts available on Android after the NDK switched away from GCC (and also for the people who insist on compiling with plain MSVC under Windows...). I had meant to revise it at some point, if only to remove the remaining compiler warnings. In the not too distant future, it might make sense to replace it with ilayn 's semicolon-lapack that is a complete C11 rewrite of the latest Reference-LAPACK rather than a half-baked machine translation of something resembling 3.9.0 |
Contributor
Author
|
Thanks for merging, and yes replacing the f2c version with semicolon-lapack does sound like a better option. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
lapack-netlib/INSTALL/dlamch.candslamch.care f2c translations of the deprecateddlamchf77.f/slamchf77.f, which determine the floating point format at run time byprobing in
dlamc1/dlamc2. The currentdlamch.fuses the Fortran 90 inquiryintrinsics instead, but f2c cannot translate those, so the C LAPACK selected by
NOFORTRAN=1was left with the older probing implementation.The probe is only correct if double intermediates are genuinely rounded to double. That
does not hold on x87, where they stay in 80 bit registers and the probe measures the
register format instead of the storage format.
This affects stock 32 bit builds, not just unusual ones
Makefile.x86adds-msse2but never-mfpmath=sse, and on 32 bit x86-msse2enablesthe instructions without changing the FP math default away from 387. With gcc 16.1.0:
So a stock 32 bit
NOFORTRAN=1build compilesdlamch.cwith x87 double arithmetic,which is exactly the condition that breaks the probe.
Reproduction
Linking
INSTALL/dlamch.candINSTALL/slamch.cfrom currentdevelopagainst a testprogram that compares every
cmachagainst<float.h>, built with the stock 32 bitflags
-O2 -msse2, 16 of the 20 constants are wrong:dlamch('E')dlamch('S')dlamch('N')dlamch('M')dlamch('L')dlamch('O')slamch('S')slamch('N')slamch('O')Note that
slamchreports the 80 bit format too, and that the mantissa width follows thecaller's x87 precision control bits rather than being a property of the type at all.
It is not always a silent wrong answer. With the x87 control word
0x1332(extendedprecision, overflow unmasked, which is what Delphi sets) the unpatched code terminates
with
STATUS_FLOAT_OVERFLOW(0xC0000091) insidedlamchitself.Where the values are merely wrong rather than fatal, everything that scales by them is
wrong. The first symptom we saw was
dsbevx, which computesso a zero safe minimum makes
smlnumzero and the next line divides by zero. Callers thatunmask the divide by zero exception get a hard failure there; callers that do not get
whatever the wrong scaling produces.
With this patch all 20 constants are correct, at the default control word and at
0x1332and
0x037F.x86_64 is not affected by this part, since
-mfpmath=sseis the default there and theprobe measures the right format. I have verified that separately.
Two further problems fixed at the same time, on all architectures
These are not x87 specific and apply to every
NOFORTRAN=1build, x86_64 included:rmachwas left uninitialised whencmachmatched nothing, wheredlamch.freturnszero.
staticresults made both routines unsafe to call concurrently on firstuse.
What the patch does
Replaces the probe with the
<float.h>constants, mirroring the values the currentdlamch.fandslamch.freturn via the F90 intrinsics.dlamc1-dlamc5andslamc1-slamc5are deliberately left in place. They becomeunreachable from
dlamch/slamch, butdlamc3/slamc3have callers of their own indlaed3,dlaed9,dlals0,dlasd3,dlasd8and their complex equivalents, where theyserve as optimiser barriers. Happy to remove the genuinely dead
dlamc1/2/4/5in afollow-up if you would prefer.
Regenerating these files from the modern
dlamch.fis not an option, since f2c cannottranslate the F90 inquiry intrinsics — which is how the C path came to be stuck on the
deprecated version in the first place.
These two
.cfiles are OpenBLAS's own artifacts, added in #3539 and hand maintainedsince (#3605,
4041b7fb4); Reference-LAPACK ships only the.f, and itsdlamch.fisalready correct. So this does not need to go to Reference-LAPACK, and will not be
clobbered by a future re-sync.
gcc -Wallreports no new warnings; the patch removes one of the five that currentdevelopproduces for this file.This has been running in production in our fork since 0.3.34.
🤖 Generated with Claude Code