[Cfp-interest] draft of syntax discussion for C committee

Ian McIntosh ianm at ca.ibm.com
Fri Jun 6 18:20:37 PDT 2014


That's written nicely and describes the options well.  It did get me
thinking though, and I decided I disagree with one thing we've been
assuming, and that may affect our proposal.


Question 1:  Is there really any truly one pass compiler?
Here are some examples of things hard to compile in one pass:

   goto label;			/* At this point the address of label is unknown but must be
   branched to. */
   . . .
   label:

   for (i = 0; i < n; ++i)
   {
       . . .
       break;			/* At this point the address of the code after the loop is
   unknown but must be branched to. */
       . . .
   }

Answer:  The minimum is one pass plus fixups, or if it generates assembler
code, the compiler is a minimum of 2 passes (compiler plus assembler pass
one) plus fixups.


Question 2:  Can a try-catch be compiled in one pass plus fixups?

Answer:  Yes, if it's known to handle floating-point exceptions at the
beginning, and if the fixup mechanism is able to either patch a load
immediate instruction with the mask of exceptions to enable, or the mask is
put in a compiler-generated constant that's loaded at the beginning and
initialized after seeing the catches.


Question 3:  Can a try-catch be compiled in one pass plus fixups if it
isn't known at the beginning that it will be handling floating-point
exceptions?

Answer:  No.  If trapping is being used then the trapping mechanism must be
enabled at the beginning.  If conditional branches are being used to detect
exceptions then the compiler needs to know to generate them from the
beginning.

Alternate answer:  Yes, if the compiler generates a forward branch to try
block initialization that's generated after the catch clauses are seen, and
which branches back to the top, the equivalent of:

	goto  initialize_try_block;

	start_of_try_block:
	    . . . /* try block */
	end_of_try_block:
	    goto  after_catch_handlers;

	initialize_try_block:
	    . . . initialize try block exception handling; . . .
	    goto  start_of_try_block;

	catch_handler_1:
	    . . .
	catch_handler_2:
	    . . .

	after_catch_handlers:

That involves two extra unconditional branch instructions, but one pass
compilers are not designed to generate optimal code so that may be an
acceptable cost.

Additional answer:  Yes, always in C, at least for now, since the only kind
of try-catch in C would be to handle floating-point exceptions.  That means
even detecting exceptions by conditional branches would work.


Conclusion:  The catches can be put at the end of the try block if we think
that's the best place for them from a usability point of view, with only
limited extra cost for single pass compilers.

- Ian McIntosh          IBM Canada Lab         Compiler Back End Support
and Development



|------------>
| From:      |
|------------>
  >-----------------------------------------------------------------------------------------------------------------------------------------|
  |David Hough CFP <pcfp at oakapple.net>                                                                                                      |
  >-----------------------------------------------------------------------------------------------------------------------------------------|
|------------>
| To:        |
|------------>
  >-----------------------------------------------------------------------------------------------------------------------------------------|
  |cfp-interest at ucbtest.org,                                                                                                                |
  >-----------------------------------------------------------------------------------------------------------------------------------------|
|------------>
| Date:      |
|------------>
  >-----------------------------------------------------------------------------------------------------------------------------------------|
  |2014-06-05 07:27 PM                                                                                                                      |
  >-----------------------------------------------------------------------------------------------------------------------------------------|
|------------>
| Subject:   |
|------------>
  >-----------------------------------------------------------------------------------------------------------------------------------------|
  |[Cfp-interest] draft of syntax discussion for C committee                                                                                |
  >-----------------------------------------------------------------------------------------------------------------------------------------|
|------------>
| Sent by:   |
|------------>
  >-----------------------------------------------------------------------------------------------------------------------------------------|
  |cfp-interest-bounces at oakapple.net                                                                                                        |
  >-----------------------------------------------------------------------------------------------------------------------------------------|







Alternate Exception Handling Syntax


How fast you can drive a car depends on how fast you can stop


Alternate Exception Handling is specified in Chapter 8 of IEEE 754-2008.
It's a series of recommendations to programming environments about what
kinds of facilities to provide in languages for portable numeric
programming.      Some of these recommendations have to do with changes
of control flow, and the best syntax to propose for these is the subject
of this note.

The overall idea is that the normal case should go as fast as possible
for performance reasons, so testing for exceptional conditions should not
slow it down.    Likewise the normal case should terminate as quickly as
possible when exceptional conditions arise, lest (particularly in a loop
terminated by a floating-point conditional test) it get into an expensive
or infinite loop.

The previous IEEE 754-1985 recommended traps on exceptions.    These are
implemented in most IEEE 754 hardware systems, but they are so low level
that they are not used
much except for debugging, where they can be easily used to stop the
program altogether.    It is not possible to write portable code to
handle a hardware trap and continue in any useful way.
But if free testing for exceptions is built into the hardware without
slowing down the normal case, how can we make it available to the
application
programmer?

Thus 754-2008
recommends alternate exception handling at a level that is meaningful
to the application programmer, leaving the details of hardware trapping
to the compiler, run time library, and operating system.     It is also
possible to implement 754-2008 alternate exception handling without
hardware
traps, but with significant performance penalties for either the normal
case
or exceptional case.

The general programming paradigm as it might be naturally
expressed in many languages is

try {
 normal case code...
}
catch (floating-point exception-list) {
 exceptional case code...
}
 following code...

The normal case code is executed; if any of the exceptions in the list
arises,
the normal case code is interrupted as quickly as possible (and thus its
output variables may be in an indeterminate state) and the exceptional case
code is executed.      In either case, after the normal case terminates
normally or the exceptional case terminates, the "following code" is
executed.

There are versions of try/catch in standard C++, java, C#, perl, php,
python,
matlab.
There are try/catch extensions in at least two Fortran compilers
targeting .NET applications.
These are all very similar but each slightly different.

ruby has a somewhat
more different version; any begin/end compound statement may have one or
more rescue clauses corresponding to catch; there is no explicit try
keyword.

Naturally, for C, the closest analog is C++.
C++ catch clauses have as
arguments a parameter and its type.     The parameter is set by the system
for standard exceptions and by the programmer for programmer-defined
exceptions
generated with the throw() function; the catch clause is matched to the
throw by the type of the thrown object.     There is also a catch(...)
syntax to catch all unspecified exceptions.

Unlike most of the exceptions for which try/catch was designed, some
floating-point exceptions arise frequently - inexact especially and
underflow in some programs - and the default treatment of continuing
execution with a prescribed result and raising a flag should be in force
if no alternate treatment is called out in a catch clause.

So much of C++ exception handling is unneeded to support 754-2008
floating-point alternate exception handling:
 * no need to throw()
 * no need to catch(...) unspecified exceptions
 * catch clause is matched by exception rather than type -
   in standard C, exceptions receive names in <fenv.h> like FE_INVALID

Furthermore there is another difference important for performance:
whereas in C++ the code in the try clause is compiled without reference
to subsequent catch clauses, for floating-point purposes it is usually
desirable or necessary to know which exceptions are to be trapped.
If the implementation is to be by traps, a trap handler has to be set
up before the try clause and torn down on exit; if the implementation
is to be by conditional branches on operands and results, that code
has to be generated inline in the try clause.     As a consequence,
a strictly one-pass C
compiler that could not exploit hardware traps would not be able to
implement alternate exception handling fully and efficiently - it would
have to test exception flags at the end of the try clause, and rely
on the programmer to code in such a way that no expensive or infinite
loop arises in the try clause if an exception arises.
Furthermore, a little-appreciated but important requirement of 754-1985
and 754-2008 is that exact underflow conditions must be detected by
trapping (1985) or alternate exception handling (2008)
if enabled, even though the underflow flag is not raised (and thus can't be
used to detect exact underflow).

The point of this very long preamble is that, syntactically,  the catch
clause for floating-point exceptions should be seen before the try clause
rather than afterward as it is in most languages.    One can imagine
having the catch before, in which case the keyword should perhaps be
different:

catch_fe( exception-list) {
 exceptional case code...
}
try {
 normal case code...
}

or having it within the try clause:

try {
catch_fe( exception-list) {
 exceptional case code...
}
 normal case code...
}

or allowing an optional red-flag pragma to warn one-pass compilers:

try {
#pragma STDC FENV_CATCH_AHEAD exception-list
 normal case code...
}
catch_fe (floating-point exception-list) {
 exceptional case code...
}

But having to specify the same exception-list in two different places
seems error-prone.


One result of preserving some form of try/catch syntax is that
floating-point
exception handling could be added to C++ with minimal syntactic effort,
and most of
C++ exception handling could be added to C with minimal syntactic effort.
If that compatibility is deemed to be of low value,
then there are other alternatives.


First, since the explicit try clause is not really needed, one could
define catch_fe clauses for any compound statement delimited by curly
brackets, and instead of adding a catch_fe keyword, it could be a
variety of pragma:


{
{
#pragma STDC FENV_CATCH exception-list
 exceptional case code...
}
 normal case code...
}

It's exactly the same try/catch semantics as what we started with,
but in syntax not particularly close to C++ or anybody else's try/catch.
However it does match other #pragma's
having scope in compound statements or in files,
that are already in C,
or are already in
previous floating-point extension reports going through the approval
process, or that are being considered to control other aspects
of floating-point code generation.


While the C floating-point extensions discussion group could pursue any of
these directions and report the results to the C committee,
we'd appreciate early feedback and direction from the C committee
as to which seems the most acceptable, or whether there's some better
C-like way to express the semantics.    The semantic content is pretty
much the same with all, but the syntax possibilities vary widely.
_______________________________________________
Cfp-interest mailing list
Cfp-interest at oakapple.net
http://mailman.oakapple.net/mailman/listinfo/cfp-interest


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mailman.oakapple.net/pipermail/cfp-interest/attachments/20140606/4b6c2690/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: graycol.gif
Type: image/gif
Size: 105 bytes
Desc: not available
Url : http://mailman.oakapple.net/pipermail/cfp-interest/attachments/20140606/4b6c2690/attachment-0002.gif 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ecblank.gif
Type: image/gif
Size: 45 bytes
Desc: not available
Url : http://mailman.oakapple.net/pipermail/cfp-interest/attachments/20140606/4b6c2690/attachment-0003.gif 


More information about the Cfp-interest mailing list