[Cfp-interest] revised directives.txt
David Hough CFP
pcfp at oakapple.net
Wed May 21 16:45:34 PDT 2014
I'll be talking about this at a research meeting tomorrow in Berkeley
to get some additional feedback.
Directives Pragmas
========== 754-2008 chapter 4 specifies attributes:
4.1 Attribute specification
An attribute is logically associated with a program block to modify
its numerical and exception semantics. A user can specify a constant
value for an attribute parameter.
Some attributes have the effect of an implicit parameter to most
individual operations of this standard; language standards shall
specify
* rounding-direction attributes
and should specify
* alternate exception handling attributes
Other attributes change the mapping of language expressions into
operations of this standard; language standards that permit more than
one such mapping should provide support for:
* preferredWidth attributes
* value-changing optimization attributes
* reproducibility attributes
For attribute specification, the implementation shall provide
language-defined means, such as compiler directives, to specify a
constant value for the attribute parameter for all standard operations
in a block; the scope of the attribute value is the block with which
it is associated. Language standards shall provide for constant
specification of the default and each specific value of the
attribute.
==========
========== 754-2008 chapter 8 recommends that languages require
various types of alternate exception handling:
* default (raise flag)
Provide the default exception handling in the associated block
despite alternate exception
handling that might be in effect in wider scope.
* raiseNoFlag
Provide the default exception handling without raising the
corresponding status flag.
* mayRaiseFlag
Provide the default exception handling, except languages define
whether a flag is raised.
Languages may defer to implementations for performance.
* recordException
Provide the default exception handling and record the
corresponding exception whenever
Clause 7 specifies raising a flag.
Recording an exception means storing a description of the
exception,
including language-standard-defined details which might include
the current operation
and operands, and the location of the exception.
Language standards define operations to convert
exception descriptions to and from character sequences,
and to inspect, save, and restore exception descriptions.
* substitute(x)
Specifiable for any exception:
replace the default result of such an exceptional operation with a
variable or expression x.
The timing and scope in which x is evaluated is language-defined.
* substituteXor(x)
Specifiable for any exception arising from
multiplication or division operations: like substitute(x),
but replace the default result of such an exceptional operation
with |x| and, if |x| is not a NaN,
obtaining the sign bit from the XOR of the signs of the operands.
* abruptUnderflow
When underflow is signaled because a tiny non-zero result is detected,
replace the default result
with a zero of the same sign or
a minimum normal rounded result of the same sign, raise the
underflow flag, and signal the inexact exception.
* Immediate alternate exception handler block associated with a block:
if the indicated exception is
signaled, abandon execution of the associated block as soon as possible and
execute the handler block,
then continue execution where execution would have continued after
normal termination of the associated block,
according to the semantics of the language.
* Delayed alternate exception handler block associated with a block:
if the indicated exception is
signaled, handle it by default until the associated block terminates normally,
then execute the handler block,
then continue execution where execution would have continued after normal
termination of the associated block,
according to the semantics of the language.
Transfers:
* Immediate transfer associated with a block:
if the indicated exception is signaled, transfer control
as soon as possible; no return is possible.
* Delayed transfer associated with a block:
if the indicated exception is signaled, handle it by default
until the associated block terminates normally, then transfer control;
no return is possible.
A transfer is a language-specific idiom for non-resumable control transfer.
Language standards might require several transfer idioms such as:
* break: Abandon the associated block and continue execution where execution
would continue after normal termination of the associated block,
according to the semantics of the language.
* throw exceptionName: Causes an exceptionName not to be handled locally,
but rather signaled to
the next handling in scope,
perhaps the function that invoked the current subprogram, according to
the semantics of the language.
* goto label:
==========
========== ANSI-C 7.6 specifies exception names
FE_INEXACT
FE_UNDERFLOW
FE_OVERFLOW
FE_DIVBYZERO
FE_INVALID
FE_ALL_EXCEPT shorthand for all five
========== ANSI-C specifies standard pragmas:
6.10.6 Pragma directive
Semantics A preprocessing directive of the form
# pragma pp-tokensopt new-line where the preprocessing token STDC
does not immediately follow pragma in the directive (prior to any
macro replacement)174) causes the implementation to behave in an
implementation-defined manner. The behavior might cause translation to
fail or cause the translator or the resulting program to behave in a
non-conforming manner. Any such pragma that is not recognized by the
implementation is ignored.
If the preprocessing token STDC does immediately follow pragma in the
directive (prior to any macro replacement), then no macro replacement
is performed on the directive, and the directive shall have one of the
following forms175) whose meanings are described elsewhere:
#pragma STDC FP_CONTRACT on-off-switch
#pragma STDC FENV_ACCESS on-off-switch
#pragma STDC CX_LIMITED_RANGE on-off-switch
on-off-switch: one of
ON OFF DEFAULT
==========
========== ANSI-C 7.12.2 specifies scope for FP_CONTRACT
extendible to other standard pragmas:
Each FP_CONTRACT pragma can occur either outside external declarations
or preceding all explicit declarations and statements inside a
compound statement. When outside external declarations, the pragma
takes effect from its occurrence until another FP_CONTRACT pragma is
encountered, or until the end of the translation unit. When inside a
compound statement, the pragma takes effect from its occurrence until
another FP_CONTRACT pragma is encountered (including within a nested
compound statement), or until the end of the compound statement; at
the end of a compound statement the state for the pragma is restored
to its condition just before the compound statement. If this pragma is
used in any other context, the behavior is undefined.
========== ANSI-C specifies scope with respect to invoked subfunctions:
Functions affected by constant rounding modes and alternate exception
handling modes
Within the scope of an FENV directive establishing a constant rounding mode
or an alternate exception handling mode,
all floating-point operators,
implicit conversions (including the conversion of a value represented in a
format wider than its semantic types to its semantic type,
as done by classification macros), and
invocations of functions indicated in the table below,
for which macro replacement has not been
suppressed,
shall be evaluated according to the specified mode.
Invocations of functions for which macro replacement has
been suppressed and invocations of functions other than those indicated in the
table below shall not
be affected by constant rounding modes or alternate exception handling modes.
<Header> Function groups
<math.h> acos, asin, atan, atan2
<math.h> cos, sin, tan
<math.h> acosh, asinh, atanh
<math.h> cosh, sinh, tanh
<math.h> exp, exp2, expm1
<math.h> log, log10, log1p, log2
<math.h> scalbn, scalbln, ldexp
<math.h> cbrt, hypot, pow, sqrt
<math.h> erf, erfc
<math.h> lgamma, tgamma
<math.h> rint, nearbyint, lrint, llrint
<math.h> fdim
<math.h> fma
<math.h> fadd, daddl, fsub, dsubl, fmul, dmull, fdiv, ddivl, ffma, dfmal
<math.h> fsqrt, dsqrtl
<stdlib.h> atof, strfromd, strfromf, strfroml, strtod, strtof, strtold
<wchar.h> wcstod, wcstof, wcstold
<stdio.h> printf and scanf families
<wchar.h> wprintf and wscanf families
Each <math.h> functon listed in the table above indicates
the family of functions of all supported types
(for example, acosf and acosl as well as acos).
========== Existing standard pragmas
(ANSI-C)
#pragma STDC FP_CONTRACT on-off-switch
#pragma STDC FENV_ACCESS on-off-switch
#pragma STDC CX_LIMITED_RANGE on-off-switch
on-off-switch: one of
ON
OFF
DEFAULT
(Floating-point extensions for C - Part 1)
#pragma STDC FENV_ROUND bdirection
bdirection:
FE_DOWNWARD
FE_TONEAREST
FE_TOWARDZERO
FE_UPWARD
FE_DYNAMIC
(Floating-point extensions for C - Part 2)
#pragma STDC FENV_DEC_ROUND ddirection
ddirection:
FE_DEC_DOWNWARD
FE_DEC_TONEAREST
FE_DEC_TONEARESTFROMZERO
FE_DEC_TOWARDZERO
FE_DEC_UPWARD
FE_DEC_DYNAMIC
==========
========== Floating-point extensions for C - Part 3
expands the EVAL_METHOD macro definitions
(binary)
If FLT_RADIX is 2, the value of the macro FLT_EVAL_METHOD (5.2.4.2.2)
characterizes the use of
evaluation formats for standard floating types and for binary interchange
and extended floating types:
-1 indeterminable;
0 evaluate all operations and constants, whose semantic type has at most the range and
precision of float, to the range and precision of float; evaluate all other operations and
constants to the range and precision of the semantic type;
1 evaluate operations and constants, whose semantic type has at most the range and
precision of double, to the range and precision of double; evaluate all other operations
and constants to the range and precision of the semantic type;
2 evaluate operations and constants, whose semantic type has at most the range and
precision of long double, to the range and precision of long double; evaluate all other
operations and constants to the range and precision of the semantic type;
N, where _FloatN is a supported interchange floating type
evaluate operations and constants, whose semantic type has at most the range and
precision of the _FloatN type, to the range and precision of the _FloatN type; evaluate
all other operations and constants to the range and precision of the semantic type;
N + 1, where _FloatNx is a supported extended floating type
evaluate operations and constants, whose semantic type has at most the range and
precision of the _FloatNx type, to the range and precision of the _FloatNx type;
evaluate all other operations and constants to the range and precision of the semantic type.
(decimal)
The implementation-defined value of the macro DEC_EVAL_METHOD characterizes the use of
evaluation formats (see analogous FLT_EVAL_METHOD in 5.2.4.2.2) for decimal interchange and
extended floating types:
-1 indeterminable;
0 evaluate all operations and constants just to the range and precision of the type;
1 evaluate operations and constants, whose semantic type has at most the range and
precision of the _Decimal64 type, to the range and precision of the _Decimal64 type;
evaluate all other operations and constants to the range and precision of the semantic type;
2 evaluate operations and constants, whose semantic type has at most the range and
precision of the _Decimal128 type, to the range and precision of the _Decimal128 type;
evaluate all other operations and constants to the range and precision of the semantic type;
N, where _DecimalN is a supported interchange floating type
evaluate operations and constants, whose semantic type has at most the range and
precision of the _DecimalN type, to the range and precision of the _DecimalN type;
evaluate all other operations and constants to the range and precision of the semantic type;
N + 1, where _DecimalNx is a supported extended floating type
evaluate operations and constants, whose semantic type has at most the range and
precision of the _DecimalNx type, to the range and precision of the _DecimalNx type;
evaluate all other operations and constants to the range and precision of the semantic type;
==========================================================================
The foregoing pragma STDC syntax and scope will be extended to
encompass the attributes required by 754-2008.
Implementations are allowed to generate warnings for standard pragmas
that they don't implement; they are not allowed to silently ignore them.
==========================================================================
----- ALTERNATE EXCEPTION HANDLING proposals -----
A standard pragma FENV_EXCEPT will provide some alternate exception
handling capabilities mentioned by
754-2008.
To obtain maximum flexibility, standard macros will be specified as well:
FP_EXCEPTIONAL_FLAGS,
FP_EXCEPTIONAL_DETERMINISTIC,
and FP_EXCEPTIONAL_NONDETERMINISTIC.
Add the following subexceptions of invalid and divbyzero:
subexception:
FE_INVALID_SNAN 7.2a
FE_INVALID_MUL 7.2b
FE_INVALID_FMA 7.2c
FE_INVALID_ADD 7.2d
FE_INVALID_DIV 7.2e
FE_INVALID_REM 7.2f
FE_INVALID_SQRT 7.2g
FE_INVALID_QUANTIZE 7.2h
FE_INVALID_INT 7.2i
FE_INVALID_UNORDERED 7.2j
FE_INVALID_LOGB 7.2k
FE_INVALID_OTHER especially for 754 chapter 9 functions
FE_DIVBYZERO_DIVISOR 7.3 divisor zero
FE_DIVBYZERO_LOGB 7.3 logb(0)
FE_DIVBYZERO_OTHER especially for 754 chapter 9 functions
#pragma STDC FENV_EXCEPT exception-list action
exception list is a list of exceptions and subexceptions
separated by commas
This pragma's actions don't change control flow:
DEFAULT 754 default
NO_FLAG default result, but no flag raised
MAY_FLAG implementation may raise flag or not
ABRUPT underflow only, mandatory
RECORD record the exception in a "debugger"
and continue; same as default if
no debugger active
What about functions invoked within compound statements controlled by
an alternate exception handling pragma? To follow the lead of
FENV_ROUND, a list of functions corresponding to 754 operations
specifies those affected by rounding and alternate exception handling pragmas.
Inlining does not affect whether an operation is affected.
Exceptional Macros
FE_EXCEPTIONAL_FLAGS(
compound-statement)
FE_EXCEPTIONAL_DETERMINISTIC(
compound-statement, exception1, exception2, ...)
FE_EXCEPTIONAL_NONDETERMINISTIC(
compound-statement, exception1, exception2, ...)
are special macros, almost varargs functions.
FE_EXCEPTIONAL_FLAGS evaluates the compound-statement and returns an int
which is a mask of all the exception flags that would have been raised
during the execution of the compound-statement. It's equivalent to
s1 = save flags
clear flags
compound-statement
s2 = save flags
restore s1 flags
compound-statement value is s2 flags
The saving is in verbiage so the compound-statement isn't lost in a sea of
flag mechanism. A typical usage might be
if ( FE_EXCEPTIONAL_FLAGS( d=b*b-a*c ;) & (FE_OVERFLOW | FE_UNDERFLOW) ) {
/* normal case */
d = sqrt(d);
} else {
/* exceptional case - scale to avoid intermediate spill */
...
}
Execution of compound-statement continues to its end, even if exceptions
are detected early. Because it is based on 754 flags, detecting
subexceptions is not possible. Underflow detection is based upon
whether the underflow flag was raised, not whether the underflow exception
occurred.
FE_EXCEPTIONAL_DETERMINISTIC and FE_EXCEPTIONAL_NONDETERMINISTIC
evaluate the compound-statement,
and return a non-zero int if any of the listed exceptions arose in the
course of the computation, and a zero int otherwise.
The non-zero int might be an implementation-dependent encoding of the listed
exceptions that arose, taking into account sub-exceptions.
Flags and traps for the listed exceptions
are the same after execution as before.
Other side effects, including flags and traps for unlisted exceptions,
occur the same as if compound-statement were executed alone.
Subexceptions can be specified though that might imply a performance
penalty relative to specifying exceptions.
Underflow detection is based upon whether the underflow exception occurred,
not whether the underflow flag was raised.
FE_EXCEPTIONAL_DETERMINISTIC
finishes the compound-statement and then
sets the result value and continues execution.
Intermediate and final results are in a deterministic state.
FE_EXCEPTIONAL_NONDETERMINISTIC
is allowed to quit work on the compound-statement
as soon as it determines that a listed exception has occurred.
Intermediate results might not be in a deterministic state.
Listed exceptions that might have been encountered later might not be reported.
An example of an application is computing the sum of squares for a 2-norm:
one might have the fast obvious loop as the compound-statement,
with underflow and overflow as the exceptions to be tested for;
if either arise, the fast computation is discarded and a slower scaled
one undertaken.
Using the notation FE_EXCEPTIONAL to refer to either,
they are intended to be used like any other conditional expression,
if FE_EXCEPTIONAL(compound-statement, exception) {
exceptional-case-code
} else {
nonexceptional-case-code
}
FE_EXCEPTIONAL(compound-statement, exception)
? exceptional-case-code
: nonexceptional-case-code
switch FE_EXCEPTIONAL(compound-statement, exception1, exception2) {
case exception1: exceptional-case1-code
case exception2: exceptional-case2-code
case exception1|exception2: exceptional-case12-code
default: nonexceptional-case-code
}
The code in compound-statement and nonexceptional-case-code might well
overlap.
Optimizing compilers would be expected to handle these cases
without unnecessary recomputation.
FE_EXCEPTIONAL is intended to impart the flexibility of C++ try/catch without
damaging C syntax or supporting the full generality of C++ try/catch.
FE_EXCEPTIONAL is not a function; its arguments include a
compound-statement, and the compound-statement is not to be
evaluated outside the macro.
It seems much better to avoid scope issues by having
expressions and labels exist within normal
C syntax rather than somehow grafted onto pragmas.
We could note than a corresponding construct
FE_SIGNALING( compound-statement, signal1, signal2, ...)
could have commensurate benefits for non-numeric programs: hiding all
the complication of setting up, using, and tearing down local signal handlers
by making the compiler and operating system figure it out.
But that's not our case.
(By considering signals I came up with the name FE_SIGNALING and then
the name FE_EXCEPTIONAL, rather than FE_TRYCATCH,
but maybe somebody else has a better idea.)
----- OTHER DIRECTIVES under consideration -----
FENV_FLT_EVAL_METHOD and FENV_DEC_EVAL_METHOD
specify the minimum evaluation width for expressions involving
standard, or binary, or decimal floating-point types.
#pragma STDC FENV_FLT_EVAL_METHOD eval
eval is one of the integer constants available from FLT_EVAL_METHOD,
but not -1
This affects standard and binary floating-point types.
#pragma STDC FENV_DEC_EVAL_METHOD eval
eval is one of the integer constants available from DEC_EVAL_METHOD,
but not -1
This affects decimal floating-point types.
#pragma STDC FENV_VALUE_CHANGING_OPTIMIZATIONS switch
switch:
ON
OFF
DEFAULT
enables compilers to make value changing optimizations but doesn't require
them.
There will be specific optimizations under this umbrella, such as
#pragma STDC FENV_FAST_SUBNORMAL switch
enables but does not require abrupt underflow and
zero treatment of subnormal operands if faster, implementation defined
Compare to the ABRUPT alternate exception handling mode for underflow:
it is compulsory, even if slower, and is defined in 754.
#pragma STDC FENV_REPRODUCIBLE switch
ON
OFF
DEFAULT
requires compilers to generate code that avoids certain specified
sources of irreproducible results.
Implies FENV_FLT_EVAL_METHOD and FENV_DEC_EVAL_METHOD values 0.
There will be additional specific features under this umbrella...
More information about the Cfp-interest
mailing list