[Cfp-interest] Background: How IEEE Exceptions Might have been Implemented

David Hough CFP pcfp at oakapple.net
Tue Jun 10 16:53:59 PDT 2014


In preparation for Thursday's teleconference I have gathered a number of
my notes here:

http://www.validlab.com/cfp/



For background I have outlined my understanding of how IEEE
exceptions were originally intended to work:




Background: How IEEE Exceptions Might have been Implemented

According to Prof. Kahan, the hardware exception flag bits and trap enable
or mask bits of early 754 implementations were never intended to be mapped
directly into facilities for application writers.    They were intended
to be implementation mechanisms for features that applications could use.

>From the point of view of 754-1985 chapter 8, 
each exception has only two handling modes: 

 * default result, record details in a "flag", and continue
 * non-default result, record no details in a "flag", and continue

The "detail record" was perhaps unwisely called a flag.
The purpose of the flag was to record the first instance of a particular
exception that was handled by default - 
and therefore might not have been anticipated by the programmer,
and therefore the default handling might have been an error - and that's
why some compilers I worked on used to issue retrospective diagnostics 
for flags left standing at the end of a program.     The flag was intended
to convey more details about the exception than just one bit -
and these details should appear in the retrospective diagnostic information.

754-1985 describes trap handlers that return a non-default result and
continue.    That result might have been computed before or after
the trap actually arose.    754-1985 does not describe trap handlers
that transfer control and do not continue.

What happened is that flags and non-default-exception enablers
are just one-bit hardware exception flags and trap enables.
Trap handlers are extremely difficult to write for one platform;
and impossible to write to be both portable and efficient - this is the
job of the system implementer, not the application writer.
Hardware trap enable bits are typically used to generate SIGFPE's,
and the only portable use for a SIGFPE trap handler is to abort or 
long jump.

There are on-going cross-currents among C programmers.
On the one hand, they would like to write portable application code in C.
On the other hand, they would like to write system-specific code in C
as well.

One can imagine the original idea being implemented by having all
hardware trap enable bits on all the time.      There would be a table
of actions to be taken for all floating-point traps.
Possible actions would be "default" and "substitute".     (754-2008 adds
"control transfer").     This table is the floating-point 
exception environment.

 "default" action on an exception is to compute the specified default result,
 automatically create a detail record (= "raise a flag") 
 IF none exists for that exception
 AND the exception is not an exact underflow, then continue.

 "substitute" action is to retrieve or compute the desired result and continue.
 Because this exception was anticipated, there is no need to automatically
 create a detail-record - the programmer could do it if needed.
 The problem here is determining what the "destination" is - not to mention
 the operation and operands in a portable way.

 "control transfer" action is to transfer control to another location.
 No result need be computed because something else is going to be done.
 Because this exception was anticipated, there is no need to automatically
 create a detail-record - the programmer could do it if needed.

The flag is not the exception.    The trap is not the exception.    They
are consequences of the exception.

Now the foregoing sounds very inefficient - taking a hardware trap on every
rounding error?      But there's an obvious optimization available -
once the detail record has been created/flag has been raised, there's no
need to take a trap to implement the default exception handling - just
compute the default result and continue.    And this is what almost all
hardware does almost all the time.



There are interesting questions of scope here.     How much of the
exception environment does the callee inherit down from the caller?
How much of the callee changes - to exception handling and detail records -
should propagate up to the caller?

There's a familiar conflict here, like that between static and dynamic
rounding specifications.     If the programmer for a particular function
feels that he has correctly and explicitly
handled all possible instances of overflow, then
he does not want that handling overwritten by a more global abort-on-overflow
specification inserted for debugging purposes.     On the other hand the
programmer of the more global function may not agree that overflow has been
correctly handled and might want a convenient way to find out where it
occurred without recompiling source code that he doesn't have access to
anyway.


More information about the Cfp-interest mailing list