Dear Richard and GCC list, I am working on a proposal to standardize interval arithmetic in C++. (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1843.pdf)
In order to implement it efficiently, one typically needs to use the FPU rounding modes (e.g. using fegetround and fesetround from C99). Typically, this boils down to something like: struct interval { double lower; double upper; }; and functions like: interval operator+(interval a, interval b) { int backup = fegetround(); // save current rounding mode fesetround(FE_UPWARD); // set rounding mode to +infinity double upper = a.upper + b.upper; double lower = - (-a.lower - b.lower); // trick to avoid round to -inf fesetround(backup); // restore default rounding mode return interval(lower, upper); } Of course, there is some C++ syntactic sugar on top of this (templates, plus you isolate the rounding mode restoration as the destructor of a local object...), but this is not my point here as I assume proper inlining. My question now is related to the capacity of the compilers in general, and GCC in particular, to optimize away some of useless rounding mode function calls. Consider for example a sequence of operations like: interval a, b, c; ... interval d = a+b+c; You can also imagine loops, which are quite common to sum arrays of intervals. Once operator+() calls are inlined, the code will look like: fegetround ; // save current rounding mode fesetround ; // set rounding mode to +infinity double tmp_upper = a.upper + b.upper; double tmp_lower = -(-a.lower - b.lower); fesetround ; // restore default rounding mode fegetround ; // save current rounding mode fesetround ; // set rounding mode to +infinity double upper = tmp_upper + c.upper; double lower = -(-tmp_lower - c.lower); fesetround ; // restore default rounding mode return interval(lower, upper); This can safely be optimized to (squeezing the 3 middle lines): fegetround ; // save current rounding mode fesetround ; // set rounding mode to +infinity double tmp_upper = a.upper + b.upper; double tmp_lower = -(-a.lower - b.lower); double upper = tmp_upper + c.upper; double lower = -(-tmp_lower - c.lower); fesetround ; // restore default rounding mode return interval(lower, upper); As far as the std::interval C++ proposal is concerned, there are 2 choices to obtain this optimization (which is fundamental): 1- hide the rounding mode function calls from the API, and let the compiler perform the optimizations 2- make it appear in the interface, in terms of a policy-based design or something similar, which forces to have a separate type and in general complexifies the standard proposal. I would very much prefer to go for the option #1. My question is to know if you think this is a reasonnable assumption to make in general, for GCC, and in practice concretely how could this be implemented in GCC ? For GCC, would this just boild down to defining builtins mimicing fesetround and fegetround, have them expose their properties to the optimizers, and let the generic optimizers remove the calls ? The properties needed on the builtins to perform the optimizations I think are : - two calls to fesetround which are not separated by floating point computations can be simplified by removing the first call. - if a call to fesetround is followed by a call fegetround with no intermediate call to fesetround, then the call to fegetround can be replaced by taking the argument passed to fesetround. - if two calls to fesetround with the same argument are not separated by some other call to fesetround (or other operation manipulating the FPU rounding mode register), the second call can be removed. -- Sylvain