RfD: IEEE-FP Exceptions

17 views
Skip to first unread message

David N. Williams

unread,
Oct 4, 2009, 7:38:24 PM10/4/09
to
I spent about a month going around with exceptions (well, not
*just* that), especially IEEE alternate fp handling. I started
out pretty much from scratch, having never written any signal
handling code. I'm far from ready to declare myself an expert,
but I do know quite a bit more than I used to.

Early on, Andrew warned me about the basic imprecision problem
with handling interrupts:

Andrew Haley wrote (private message):
> [...]
>
> Assuming you can persuade the kernel to convert that interrupt into a
> signal, sure. But on some systems the interrupt can be imprecise,
> i.e. delayed by many instructions, and you will have no idea which
> actual instruction it referred to. So, if you have a catch region the
> program counter may be outside it by the time you see a signal. So
> what possible use would this be?

Nevertheless, I think it's feasible if all you want to do is
interrupt program flow with a somewhat useful message.

It took a lot of effort to reach the point where I could do
that, but in the end, the code is straightforward. Some of what
I've learned about enabling and handling fp exceptions for Mac
OS X ppc and intel cpu's, and Linux, is contained in the
following C example file:

http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c

That file revealed a bug in OS X Leopard's implementation of
sigaction() for intel, which I'm told is fixed in Snow Leopard.

It was really annoying to deal with the differences among OS X
ppc and intel, and Linux, in order to do a pfe implementation,
but it finally does work. The following has both assembly
language and C versions of enabling, as well as quite a bit of
other stuff:

http://www-personal.umich.edu/~williams/archive/forth/pfe/ieeefp/

For anybody who wants to look at the code, I suggest looking
first at ieeefp-words.txt, because the source, although
commented, is not organized yet to make clear what goes with the
IEEE-FP proposal and what's for development purposes. The
ttester regression tests in ieeefp-ext-test.fs so far include
FNEXTUP/FNEXTDOWN, rounding, and default exceptions.

This doesn't run properly yet with production pfe, because it
needs an interpreter mod to avoid clobbering the fp state. The
problem is inherited from the original Zoller pfe, and Guido is
on the case. If somebody wants to try out my fix, let me know
and I'll provide more info.

Here's an alternate exception handling session.

----------
goldenaxe% pfe
\ Portable Forth Environment 0.33.70 (Sep 27 2009 16:14:13)
Copyright (C) Dirk Uwe Zoller 1993 - 1995.
Copyright (C) Tektronix, Inc. 1998 - 2003.
Copyright (C) Guido U. Draheim 2005 - 2008.
ANS/ffa ITC Forth - Please enter LICENSE and WARRANTY.
Running on i686 linux-gnu - to quit say BYE. ok
loadm ieeefp ok
get-fhandler . 1075828272 ok
' throw . 1075828272 ok
1e 0e f/ f. inf ok
0e 0e f/ f. nan ok
FDIVBYZERO fenable ok
1e 0e f/ f.
Error: floating-point divide by zero
\ Terminal input: "f/"
1e 0e f/ f.
^^^ ok
0e 0e f/ f. nan ok
FDIVBYZERO fdisable ok
1e 0e f/ f. inf ok
----------

The words proposed below are the result of a few implementation
iterations. I didn't provide an IEEE-FP proposal version
number, because only the subsections for exceptions are
presented.

I don't want to particularly emphasize alternate exception
handling, but at least there's a proof of concept. Default
handling is the spirit of IEEE floating-point, and I much prefer
it.

So let the flames begin! :-)

-- David

------------------------------------------------------------------
IEEE-FP EXCEPTIONS (EXPERIMENTAL)
--dnw 04-Oct-09

9 IEEE FLOATING-POINT EXTENSION WORDS

This is an optional word set.

9.1 FLOATING-POINT EXCEPTIONS

All words have normal interpretation and compilation semantics.

A floating-point status flag is raised, but never lowered, as a
side effect of an fp operation. The default side effect also
provides a default fp datum and does not interrupt program flow.

The words that deal with the flags are:

GET-FFLAGS SET-FFLAGS CLEAR-FFLAGS

[**These words are an alternative to GET-FSTATUS and SET-FSTATUS
in version 0.5.5 of the IEEE-FP proposal. I find SET-FSTATUS
confusing, and the factors SET-FFLAGS and CLEAR-FFLAGS seem
clearer.]

IEEE also recommends the implementation of alternate fp
exception handling, with action to be specified by the language.
The words that deal with that are:

INSTALL-FHANDLING SET-FHANDLER GET-FHANDLER
FENABLE FDISABLE FENABLED

The next section lists constant exception masks used by both
sets of words.

9.1.1 Exception constants
-------------------------

FDIVBYZERO ( -- except )
FINEXACT ( -- except )
FINVALID ( -- except )
FOVERFLOW ( -- except )
FUNDERFLOW ( -- except )
ALL-FEXCEPTS ( -- excepts )

In the above words, each "except" (singular) is an
implementation-defined, constant flag mask, unique to the
corresponding IEEE fp exception. The individual masks may be
bitwise OR'd to define collective "excepts". ALL-FEXCEPTS
leaves the OR of all five individual masks.

See Section A.9.1.1 for more information.

9.1.2 Status flags
------------------

GET-FFLAGS ( excepts -- flags )

The flags output is the bitwise OR of the fp exception
constants corresponding to those flags that are both on in
the current fp state and present in excepts.

SET-FFLAGS ( excepts -- )

Turn on the fp exception status flags corresponding to the fp
exceptions present in excepts. It is implementation-dependent
whether the inexact fp flag is also set when the overflow or
underflow fp flags are set.

CLEAR-FFLAGS ( excepts -- )

Clear the fp exception status flags corresponding to the fp
exceptions present in excepts.

9.1.3 Alternate handling
------------------------

See Section A.9.1.3 for an overview of alternate fp exception
handling.

INSTALL-FHANDLING ( -- )

Establish the system handler for alternate floating-point
exceptions, and initialize the xt it executes to that of
THROW. Thereafter the handler shall fire on any of the five
IEEE floating-point exceptions for which alternate handling is
enabled. This word is to be executed when the IEEE-FP
Extensions word set is loaded. It may also be executed by an
application, which may be necessary to reestablish the handler
after an ABORT on some systems.

The system handler shall execute the xt of the current Forth
alternate fp handler, with the appropriate throw code topmost
on the data stack. A Forth fp handler shall have the
following stack effect:

( i*x n -- j*x ) ( f: r*x -- r'*x )

where i*x n and r*x are supplied by the system handler when it
does the callback to the Forth handler. Here the possibly
empty i*x and r*x contain implementation-dependent information
about the exception, and n is a Forth throw code, with the
corresponding IEEE exception and POSIX SIGFPE code shown in
Table XXX.

It is an ambiguous condition if the Forth handler terminates
neither with THROW nor with the equivalent of ABORT. See
Section A.9.1.3 for further information.

[**
Some fp exceptions raise more than one flag, as specified by
IEEE 754-2008. How that is dealt with is implementation
dependent.

In the experimental pfe implementation, INSTALL-FHANDLING
is in the ENVIRONMENT word set, which is not in the default
search order.
]


Table XXX: Floating-point exception codes

IEEE SIGFPE Forth THROW
-------------------------------------------------------------------
divideByZero FPE_FLTDIV -42 floating-point divide by zero
invalid FPE_FLTINV -46 floating-point invalid argument
overflow FPE_FLTOVF -43 floating-point result out of range
underflow FPE_FLTUND -54 floating-point underflow
inexact FPE_FLTRES -41 loss of precision
-55 floating point-unidentified fault
-------------------------------------------------------------------


SET-FHANDLER ( xt -- )

Set the execution token of the current Forth alternate fp
handler to xt. The old xt is not saved.

GET-FHANDLER ( -- xt )

Leave the execution token of the current Forth alternate fp
handler.

[**The above two words could be replaced by one if it were
practical to make the Forth handler vector a named, deferred
word, say FHANDLER. I didn't readily see how to make a pfe
system deferred word and do a callback on it in the experimental
implementation. Besides, the "SET-"/"GET-" style is traditional
in DPANS94.]

FENABLE ( excepts -- )
FDISABLE ( excepts -- )

FENABLE and FDISABLE first clear all fp exception flags.
They then turn alternate handling on/off, repectively, for
those fp exceptions present in excepts, without changing the
handling of those not present in the mask. When an exception
is turned off by FDISABLE, default IEEE handling for that
exception is restored. It is an ambiguous condition if
excepts is not the bitwise OR of a subset of the five
constants:

FDIVBYZERO FINEXACT FINVALID FOVERFLOW FUNDERFLOW

An ambiguous condition exists if an enabled exception occurs
when no Forth fp handler is installed.

FENABLED ( -- excepts )

The output excepts is the bitwise OR all fp exceptions for
which alternate handling is enabled.


A. RATIONALE (INFORMATIVE ANNEX)

A.9.1.1 Exception constants
---------------------------

The excepts data type serves a dual purpose. Underneath, it
gets translated as appropriate to manipulate either fpu
exception mask bits or status flag bits. The style of having
one data type for both enabling and flag masks is used by the
the GNU C Library. The same POSIX/C macros, FE_DIVBYZERO, etc.,
are used for both types of function.

A.9.1.3 Alternate handling
--------------------------

Alternate fp exception handling has several aspects.

At the lowest level, alternate handling for each of the five fp
exceptions generally has to be turned on by hardware
instructions. Otherwise cpu's like ppc and intel do IEEE 754
default handling. There is currently no POSIX interface for
this [**AFAIK]. The GNU C Library has three functions,
fegetexcept(), feenableexcept(), and fedisableexcept(), which do
the trick; but they are not universally present. For example,
they are present in GNU/Linux, but not implemented in OS X
Leopard.

To get alternate handling for enabled exceptions, a handler has
to be installed. There is a POSIX interface for installing
signal handlers, but the coding of a handler that does more than
report an error and abort is highly system dependent.

In the scheme proposed here, the handler furthermore needs to do
a callback on a Forth xt, which requires carnal knowledge of the
Forth implementation.

The basic idea is that there is a single system alternate
handler plus a vectored Forth alternate handler xt which the
system handler executes.

Ideally, the system handler needs to be installed only once; but
in fact that may be tricky. The system handler is called if and
only if an fp exception for which alternate handling is turned
on occurs. The system handler determines which of the five IEEE
exceptions invoked it, and executes the vectored xt with the
appropriate Forth throw code on the data stack.

Andrew Haley

unread,
Oct 5, 2009, 4:44:48 AM10/5/09
to
David N. Williams <will...@umich.edu> wrote:
> I spent about a month going around with exceptions (well, not
> *just* that), especially IEEE alternate fp handling. I started
> out pretty much from scratch, having never written any signal
> handling code. I'm far from ready to declare myself an expert,
> but I do know quite a bit more than I used to.

> Early on, Andrew warned me about the basic imprecision problem
> with handling interrupts:

> Andrew Haley wrote (private message):
> > [...]
> >
> > Assuming you can persuade the kernel to convert that interrupt
> > into a signal, sure. But on some systems the interrupt can be
> > imprecise, i.e. delayed by many instructions, and you will have no
> > idea which actual instruction it referred to. So, if you have a
> > catch region the program counter may be outside it by the time you
> > see a signal. So what possible use would this be?

> Nevertheless, I think it's feasible if all you want to do is
> interrupt program flow with a somewhat useful message.

> I don't want to particularly emphasize alternate exception


> handling, but at least there's a proof of concept. Default
> handling is the spirit of IEEE floating-point, and I much prefer
> it.

> So let the flames begin! :-)

I'm not going to flame you, but I don't think this should be required
by the IEEE FP proposal. Apart from the reasons of practicality,
i.e. it may not be possible to implement everywhere, there is AFIAA no
existing practice. Having said all that, it might be nice to have
something like this in the IEEE reference implementation.

Andrew.

David N. Williams

unread,
Oct 5, 2009, 8:12:25 AM10/5/09
to
Andrew Haley wrote:
> David N. Williams <will...@umich.edu> wrote:
> [...]

>
>> I don't want to particularly emphasize alternate exception
>> handling, but at least there's a proof of concept. Default
>> handling is the spirit of IEEE floating-point, and I much prefer
>> it.
>
>> So let the flames begin! :-)
>
> I'm not going to flame you, but I don't think this should be required
> by the IEEE FP proposal. Apart from the reasons of practicality,
> i.e. it may not be possible to implement everywhere, there is AFIAA no
> existing practice. Having said all that, it might be nice to have
> something like this in the IEEE reference implementation.

I'm assuming you're talking about the alternate exception
handling part -- not the default part. Back to default handling
in a moment.

Indeed, I was thinking alternate handlng should at best be
labeled a should. But I wouldn't object to having something
like it in the reference implementation.

As for existing practice, I hope we're getting close enough to
convergence to spawn experimental implementations, and get some
experience with them. There has been one for iForth since the
end of August, which I plan to play with. And now there's one
that's pretty far along for pfe.

I think it would be good if we could identify issues that are
hindering trial implementations.

As for default handling, which I believe *does* need to be
included in the extensions word set, there's a change from the
previous proposal.

Namely, before, besides the flag constants, there were two
words:

----------
GET-FSTATUS ( fmask -- fflags )

Return the bit-wise OR of the current fp status flags selected
by the nonzero bits of fmask, without changing the status. It
is an ambiguous condition if fmask is not the OR of a subset
of the five, named masks, or if the underlying system does not
support all five flags.

SET-FSTATUS ( fflags fmask -- )

Set the values of the fp status flags selected by fmask to the
values of the corresponding bits in fflags, without side
effects. It is an ambiguous condition if fmask is not the OR
of a subset of the five, named masks, or if the underlying
system does not support all five flags.
----------

Now there are three: GET-FFLAGS SET-FFLAGS CLEAR-FFLAGS

See the intro to the new Sec. 9.1 for a note about the reason,
and Sec. 9.1.2 for the specs.

For the constants, there should have been a note in the
rationale, A.9.1.1, like this:

----------
The constant ALL-FEXCEPTS can be defined as

FDIVBYZERO FINEXACT FINVALID OR OR
FOVERFLOW FUNDERFLOW OR OR CONSTANT ALL-FEXCEPTS
----------

Does this seem a reasonable glossary for default exceptions?

Finally, there's rounding, which I believe you are
contemplating. There are bare-bones rounding words in the
experimental pfe implementation, just C bindings, for which I
found it interesting to write tests in ieeefp-ext-test.fs.

-- David

Andrew Haley

unread,
Oct 5, 2009, 9:14:09 AM10/5/09
to
David N. Williams <will...@umich.edu> wrote:

> Does this seem a reasonable glossary for default exceptions?

I think so, but I need to study it more.

> Finally, there's rounding, which I believe you are
> contemplating.

I am, yes. I have tried writing code to handle closures in Standard
Forth, but there are some nasty corner cases. I haven't given up yet,
but I think the best solution is a word that does

( xt mode) EXECUTE-ROUNDING

but with hopefully a better name. That word will catch any Forth
exceptions and reset the rounding mode. However, we'll still need
something that people can use interpretively.

Andrew.

Reply all
Reply to author
Forward
0 new messages