mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Damian McGuckin <damianm@esi.com.au>
To: musl@lists.openwall.com
Subject: Re: [musl] Considering x86-64 fenv.s to C
Date: Sun, 26 Jan 2020 14:28:17 +1100 (AEDT)	[thread overview]
Message-ID: <alpine.LRH.2.02.2001261420060.4568@key0.esi.com.au> (raw)
In-Reply-To: <20200125001100.GY30412@brightrain.aerifal.cx>


Latest below - Apologies if I missed anything about which we spoke.

*	Lots more comments about architecture.

*	better explanation about dealing with those PowerPC issues.

*	some naming is improved

I will shortly post some guesses at what I think some hardware specific 
versions of fenv.c need to be.

Not sure how best to handle these because the way used currently is to 
pull in a template from directory above as seen in

 	.../musl-1.1.24/src/fenv/arm/fenv.c

which just does

 	#include "../fenv.c"

which includes the most trivial of fenv(3) implementations possible.

The following passes 'splint'.

/*
  * fenv-generic.c:
  *
  * All generic architectures are assumed to have
  *
  * a)	a status register in which the exception flags exist
  * b)	a control register in which the rounding mode exists
  * c)	an environment structure, fenv_t
  *
  * Routines must be provided with the architecture specific fenv.c routines
  * to both store (copy) these register into memory and load them from memory.
  *
  * If the control & status registers are distinct, then the declaration
  *
  *	static unsigned int fe_get_sr_arch() { ... }
  *	static void fe_set_sr_arch(unsigned int) { ... }
  *	static unsigned int fe_get_cr_arch() { ... }
  *	static void fe_set_cr_arch(unsigned int) { ... }
  *
  * and the macros that use these internal routines
  *
  *	#define fe_get_sr	fe_get_sr_arch
  *	#define fe_set_sr	fe_set_sr_arch
  *	#define fe_get_cr	fe_get_cr_arch
  *	#define fe_set_cr	fe_set_cr_arch
  *
  * need to be provided.
  *
  * If the control & status register are one and the same, then the declaration
  *
  *	static unsigned int fe_get_csr_arch() { ... }
  *	static void fe_set_csr_arch(unsigned int) { ... }
  *
  * needs to be provided. Those fe_[gs]et_[sc] macros are auto-created.
  *
  * Also needed are definitions that respectively
  *
  * a) allows a (memory) fenv_t object *e to be filled with the contents
  *    of the current floating point environment, and
  * b) allows the current floating point environment to mirror the state
  *    of the contents of some (memory) fenv_t object *e.
  *
  *	#define fe_get_e(e)	...
  *	#define fe_set_e(e)	...
  *
  * The default state of the floating point environment must be defined as
  *
  *	#define FE_DFL_ENV_DATA	....
  *
  * Where an architecture like a PowerPC64 supports a list of causes for an
  * INVALID exceptions, the bit mask encapsulating all those causes must be
  * defined, FE_ALL_VALID_CAUSES, as well as the bit field associated with
  * an FE_INVALID exception being caused 'by (an explicit software) request'.
  * They will commonly be defined using the existing ABI as:
  *
  *	#define FE_ALL_INVALID_CAUSES	FE_ALL_INVALID
  *	#define FE_INVALID_BY_REQUEST	FE_INVALID_SOFTWARE
  *
  * Where no causes exist, the above 2 lines must NEVER be defined!
  *
  * Once the above inline functions and appropriate macros have been defined
  * within an 'fenv.c' for a given architecture, the ''fenv.c' should pull
  * this file into its compilation space following existing practice like
  *
  *	#include	"../fenv-generic.c"
  */

/*
  * default inspection and modification of FPU status and control registers
  */
#ifndef	fe_get_cr
#define	fe_get_cr	fe_get_csr_arch
#endif
#ifndef	fe_set_cr
#define	fe_set_cr	fe_set_csr_arch
#endif
#ifndef	fe_get_sr
#define	fe_get_sr	fe_get_csr_arch
#endif
#ifndef	fe_set_sr
#define	fe_set_sr	fe_set_csr_arch
#endif
/*
  * Compute the rounding mask with some rigid logic
  */
#ifndef	FE_TONEAREST
#define	FE_TONEAREST	0
#define	ROUND_MASK	((unsigned int) 0)
#else
#ifndef	FE_TOWARDZERO
#define	ROUND_MASK	((unsigned int) 0)
#else
#ifdef	FE_DOWNWARD
#ifdef	FE_UPWARD
#define	ROUND_MASK	((unsigned int) (FE_DOWNWARD|FE_UPWARD|FE_TOWARDZERO))
#else
#define	ROUND_MASK	UNSUPPORTED rounding
#endif
#else
#ifdef	FE_UPWARD
#define	ROUND_MASK	UNSUPPORTED rounding
#else
#define	ROUND_MASK	((unsigned int) (FE_TOWARDZERO))
#endif
#endif
#endif
#endif

/*
  * The PowerPC architecture has the concept of an INVALID exception cause,
  * basically the reason why an FE_INVALID exception has occurred. There are
  * nine such causes, encapsulated in a non-contiguous mask of 9 bits, the
  * macro called (herein) FE_ALL_INVALID_CAUSES for clarity. Instructions
  * which involve invalid operations will set the CAUSE bit first, that
  * action implicitly raising the FE_INVALID exception, i.e. an FE_INVALID
  * implies the existence of a CAUSE bit, and vica versa.  Even on this a
  * PowerPC, MUSL supports only one of those 9 hardware causes, the macro
  * called (herein)  FE_INVALID_BY_REQUEST. These nomenclature is used to
  * document that not only do these macros refer to some cause, but that the
  * FE_INVALID exception has been caused 'by (an explicit software) request'.
  *
  * On any other architecture, no such definitions will exist of the mask of
  * all such causes, the macro FE_ALL_INVALID_CAUSES, nor will the macro
  * FE_INVALID_BY_REQUEST exist. In that case, the former is just defined as
  * zero, implying that there are NO causes, while the latter will be just
  * defined as FE_INVALID to keep the compiler happy (as it is never used
  * in any logic).  See fenv.c for the PowerPC64 for more detailed words on
  * this interesting, useful, fascinating, but highly non-standard feature.
  *
  * The above is important because ignoring it stabs MUSL in the back. When
  * it is desired that an FE_INVALID exception be cleared on an architecture
  * with a bit mask of causes as to why any FE_INVALID occurred, any CAUSE
  * bit field must also to be cleared. If this is not done, any set CAUSE
  * bit, i.e. one left uncleared, will cause an FE_INVALID exception to be
  * re-raised when the register image containing those uncleared bits is
  * fed back into 'fe_set_sr' where the instruction * 'Move to FPSCR' is
  * used. The single line of code following doing such handling is avoided
  * on architectures which do not need it because the zero value of the
  * FE_ALL_INVALID_CAUSE mask should mean that this line of code disappears
  * into oblivion by compile-time optimization.
  *
  * On architectures where a raised FE_INVALID exception implies some CAUSE
  * bit is also raised (or set), consistently is provided by saying that the
  * FE_INVALID is caused 'by (an explicit software) request', the bit named
  * (herein) as FE_INVALID_BY_REQUEST.  The single line of code doing such
  * handling is again avoided on architectures which do not need it because
  * the zero value of the FE_ALL_INVALID_CAUSE mask should mean that this
  * line of code is optimized into oblivion at compile-time. To keep the
  * compiler happy, FE_INVALID_BY_REQUEST is simply set to FE_INVALID.
  */
#ifndef	FE_ALL_INVALID_CAUSES
#define	FE_ALL_INVALID_CAUSES	0
#define	FE_INVALID_BY_REQUEST	FE_INVALID
#endif

static inline void
__cleargeneric(int excepts)
{
 	/*
 	 * Address where FE_INVALID is to be cleared on an architecture with a
 	 * matching CAUSE to say why that FE_INVALID occurred. To handle this,
 	 * every one of the CAUSE bits must also be cleared - see above.
 	 */
 	if (FE_ALL_INVALID_CAUSES != 0 && (excepts & FE_INVALID) != 0)
 		excepts |= FE_ALL_INVALID_CAUSES;

 	fe_set_sr(fe_get_sr() & ~excepts);
}

static inline void
__raisegeneric(int excepts)
{
 	/*
 	 * Address where FE_INVALID is to be raised on an architecture demanding
 	 * a matching CAUSE to say why the FE_INVALID is being raised. To handle
 	 * this, say it is caused 'By (Explicit Software) Request' - see above.
 	 */
 	if (FE_ALL_INVALID_CAUSES != 0 && (excepts & FE_INVALID) != 0)
 		excepts |= FE_INVALID_BY_REQUEST;

 	fe_set_sr(fe_get_sr() | excepts);
}

static inline void
__raisecleverly(int excepts)
{
 	/*
 	 * assume single OP is faster than double OP
 	 */
 	const float zero = (float) 0;
 	const float one = (float) 1;
 	const float large = 2.076919e+34; // 2^(+108)
 	const float small = 4.814826e-35; // 2^(-108)
 	volatile float x;
 	/*
 	 * if it is just a simple exception, arithmetic expressions are optimal
 	 */
 	switch(excepts)
 	{
 	case FE_INVALID:
 		x = zero, x /= x;
 		break;
 	case FE_DIVBYZERO:
 		x = zero, x = one / x;
 		break;
 	case FE_INEXACT:
 		x = small, x += one;
 		break;
 	case FE_OVERFLOW | FE_INEXACT:
 		x = large, x *= x;
 		break;
 	case FE_UNDERFLOW | FE_INEXACT:
 		x = small, x *= x;
 		break;
 	default:
 		/*
 		 * if more than one exception exists, a sledgehammer is viable
 		 */
 		__raisegeneric(excepts);
 		break;
 	}
}

int
feclearexcept(int excepts)
{
 	__cleargeneric(excepts & FE_ALL_EXCEPT);
 	return 0;
}

int
feraiseexcept(int excepts)
{
 	__raisecleverly(excepts & FE_ALL_EXCEPT);
 	return 0;
}

int
fetestexcept(int excepts)
{
 	return (int) (fe_get_sr() & (excepts & FE_ALL_EXCEPT));
}

int
fegetround(void)
{
 	return (int) (fe_get_cr() & ROUND_MASK);
}

int
fesetround(int rounding_mode)
{
 	if ((rounding_mode & ~ROUND_MASK) != 0)
 		return -1;

 	fe_set_cr((fe_get_cr() & ~ROUND_MASK) | (rounding_mode & ROUND_MASK));
 	return 0;
}

int
fegetenv(fenv_t *envp)
{
 	fe_get_e(envp);
 	return 0;
}

int
fesetenv(fenv_t *envp)
{
 	const fenv_t envpd = FE_DFL_ENV_DATA;
 	const fenv_t *e = envp == FE_DFL_ENV ? &envpd : envp;

 	fe_set_e(e);
 	return 0;
}

Regards - Damian

Pacific Engineering Systems International, 277-279 Broadway, Glebe NSW 2037
Ph:+61-2-8571-0847 .. Fx:+61-2-9692-9623 | unsolicited email not wanted here
Views & opinions here are mine and not those of any past or present employer

  reply	other threads:[~2020-01-26  3:28 UTC|newest]

Thread overview: 63+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-16  4:30 Damian McGuckin
2020-01-16 15:11 ` Markus Wichmann
2020-01-16 16:14 ` Rich Felker
2020-01-16 18:56   ` Damian McGuckin
2020-01-16 19:33     ` Rich Felker
2020-01-16 21:31       ` Damian McGuckin
2020-01-17  3:36       ` Damian McGuckin
2020-01-17  3:48         ` Damian McGuckin
2020-01-17  3:53         ` David Edelsohn
2020-01-17 14:13           ` Rich Felker
2020-01-17 14:19             ` David Edelsohn
2020-01-17 14:53         ` Rich Felker
2020-01-18  4:45           ` Damian McGuckin
2020-01-18  5:29             ` Rich Felker
2020-01-19  8:50               ` Damian McGuckin
2020-01-19  9:07           ` Damian McGuckin
2020-01-19 10:42             ` Szabolcs Nagy
2020-01-19 12:25               ` Damian McGuckin
2020-01-20  5:32           ` Damian McGuckin
2020-01-20 17:38             ` Rich Felker
2020-01-20 21:11               ` [musl] Triggering Overflow (or Underflow) without triggering Inexact on i386 Damian McGuckin
2020-01-20 22:32                 ` Szabolcs Nagy
2020-01-21  3:53           ` [musl] Considering x86-64 fenv.s to C Damian McGuckin
2020-01-21  4:22             ` Rich Felker
2020-01-21  4:46               ` Damian McGuckin
2020-01-21  7:26                 ` Damian McGuckin
2020-01-17 16:41         ` Markus Wichmann
2020-01-18  1:15           ` Szabolcs Nagy
2020-01-18  5:03             ` Damian McGuckin
2020-01-18  5:37               ` Rich Felker
2020-01-18  9:40                 ` Szabolcs Nagy
2020-01-24  0:42                   ` Damian McGuckin
2020-01-24  1:11                     ` Rich Felker
2020-01-24  4:13                       ` Damian McGuckin
2020-01-24  4:55                         ` Rich Felker
2020-01-24  6:08                           ` Damian McGuckin
2020-01-24 13:44                             ` Rich Felker
2020-01-24 14:45                               ` Damian McGuckin
2020-01-24 23:59                               ` Damian McGuckin
2020-01-25  0:11                                 ` Rich Felker
2020-01-26  3:28                                   ` Damian McGuckin [this message]
2020-01-26  3:28                                   ` Damian McGuckin
2020-01-26  3:30                                   ` Damian McGuckin
2020-01-26  3:32                                   ` Damian McGuckin
2020-01-26  5:25                                   ` Damian McGuckin
2020-01-27  3:32                                   ` Damian McGuckin
2020-01-27  5:39                                   ` Damian McGuckin
2020-02-02  0:47                                   ` Damian McGuckin
2020-02-03  0:54                                   ` Damian McGuckin
2020-02-03  2:09                                     ` Rich Felker
2020-02-03  2:12                                       ` Damian McGuckin
2020-02-22 20:17                                         ` Rich Felker
2020-02-22 20:53                                           ` Damian McGuckin
2020-02-23  5:41                                           ` Damian McGuckin
2020-02-23  6:25                                             ` Rich Felker
2020-02-23  8:35                                               ` Damian McGuckin
2020-02-07 21:25                                   ` Damian McGuckin
2020-02-07 21:38                                     ` Rich Felker
2020-02-07 23:53                                       ` Damian McGuckin
2020-02-09  5:04                                       ` Damian McGuckin
2020-01-24  7:10                           ` Damian McGuckin
2020-01-18  5:04             ` Markus Wichmann
2020-02-03 14:16 [musl] PPC64(LE) support in musl requires ALTIVEC Romain Naour
2020-02-03 14:50 ` Rich Felker
2020-02-05  1:32   ` [musl] Considering x86-64 fenv.s to C Damian McGuckin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.LRH.2.02.2001261420060.4568@key0.esi.com.au \
    --to=damianm@esi.com.au \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).