Re: [PATCH] libm/math: Use __math_xflow in obsolete math code
Szabolcs Nagy <[email protected]>
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <[email protected]> |
The 07/30/2020 16:42, Keith Packard via Newlib wrote: > C compilers may fold const values at compile time, so expressions > which try to elicit underflow/overflow by performing simple > arithemetic on suitable values will not generate the required > exceptions. > > Work around this by replacing code which does these arithmetic > operations with calls to the existing __math_xflow functions that are > designed to do this correctly. > > Signed-off-by: Keith Packard <[email protected]> this looks good. note1: i used c99 code when i wrote the new math code and currently the old math code can be compiled with older compilers, this change might prevent that. note2: xflow may also try to set errno, depending on the WANT_ERRNO setting (which is on by default). in the old style math functions errno is handled in wrappers but presumably this fix is for the case when error handling wrappers are not in use. in that case note that some compilers may model math functions as pure (no sideeffect) and apply optimizations accrodingly, this may create unexpected errno clobbers if math functions actually set errno. (-fno-math-errno behaviour in gcc) but this affects other libm implementations too and so far we haven't run into issues. > --- a/newlib/libm/math/ef_pow.c > +++ b/newlib/libm/math/ef_pow.c ... > @@ -219,14 +217,14 @@ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ > i = j&0x7fffffff; > if (j>0) { > if (i>FLT_UWORD_EXP_MAX) > - return s*huge*huge; /* overflow */ > + return s*__math_oflowf(0); /* overflow */ > else if (i==FLT_UWORD_EXP_MAX) > - if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ > + if(p_l+ovt>z-p_h) return s*__math_oflowf(0); /* overflow */ > } else { > if (i>FLT_UWORD_EXP_MIN) > - return s*tiny*tiny; /* underflow */ > + return s*__math_uflowf(0); /* underflow */ > else if (i==FLT_UWORD_EXP_MIN) > - if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ > + if(p_l<=z-p_h) return s*__math_uflowf(0); /* underflow */ this is suboptimal: the reason there is a 'sign' argument to these functions is that you don't need mul with the sign (which is wrong with upward or downward rounding: s*huge*huge != (s*huge)*huge but newlib may not care about rounding modes, however it also prevents the call to be a tail call and turns the math function into a non-leaf function) i think e.g. return __math_uflowf(s == -1.0f) would work better (but it's better to set a sign flag where s is set).