[PATCH] D126364: Fix interaction of pragma FENV_ACCESS with other pragmas

Serge Pavlov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu May 26 04:03:05 PDT 2022


sepavloff added a comment.

In D126364#3537964 <https://reviews.llvm.org/D126364#3537964>, @efriedma wrote:

> Could you lay out the expected interaction between "STDC FENV_ACCESS", "clang fp exceptions", "float_control", and "fenv_access"?  If there's some way to map everything to "#pragma clang fp", please lay that out; if that isn't possible, please explain why.

`pragma fenv_access` is same as `pragma STDC FENV_ACCESS`.
`pragma float_control(except, ...)` is same as `pragma clang fp exception` amended with possibility to maintain stack of the directives using `push` token.
So indeed, all cases can be mapped to the interaction of  `pragma STDC FENV_ACCESS` with `pragma clang fp exception`.
Possible combinations are:

1. No access to FP environment:

  	#pragma STDC FENV_ACCESS OFF
  	#pragma clang fp exception(ignore)  // maytrap or strict is not allowed

2. Strict exception mode:

  	#pragma STDC FENV_ACCESS ON
  	#pragma clang fp exception(strict)

3. MayTrap exception mode:

  	#pragma STDC FENV_ACCESS ON
  	#pragma clang fp exception(maytrap)

4. Ignore exception mode

  	#pragma STDC FENV_ACCESS ON
  	#pragma clang fp exception(ignore)

In this mode the code may change FP control modes, like rounding mode, but FP exceptions are ignored.
All of them must be supported.

> As far as I can tell, "STDC FENV_ACCESS" and "STDC FENV_ROUND" don't directly interact.  FENV_ROUND just overrides the rounding mode for specific floating-point operations; it doesn't impact whether environment access is allowed.  So the call to setRoundingModeOverride seems dubious.

According to the latest standard draft http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2731.pdf:

  7.6.2p2
  The FENV_ROUND pragma provides a means to specify a constant rounding direction for floating-point
  operations for standard floating types ...
  
  7.6.2p4
  ... Within the scope of an FENV_ROUND pragma establishing a mode other than FE_DYNAMIC, floating-point operators, implicit conversions ..., and invocations of functions indicated in the table below, ...  shall be evaluated according to the specified constant rounding mode (as though no constant mode was specified and the corresponding dynamic rounding mode had been established by a call to fesetround).

So indeed the pragmas are independent, with the exception:

  7.6.2p3
  ... If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off", the translator may assume that the default rounding mode is in effect.

If target allows specifying rounding mode in instruction (like RISCV), FENV_ROUND may be implemented without changing FP environment. However for targets, where change of rounding mode requires modification of a control register, there is no other way. The standard explicitly allows it in:

  7.6.2p5
  NOTE Constant rounding modes (other than FE_DYNAMIC) could be implemented using dynamic rounding modes as
  illustrated in the following example:
  {
      #pragma STDC FENV_ROUND direction
      // compiler inserts:
      // #pragma STDC FENV_ACCESS ON
      // int __savedrnd;
      // __savedrnd = __swapround(direction);
      ... operations affected by constant rounding mode ...
      // compiler inserts:
      // __savedrnd = __swapround(__savedrnd);
      ... operations not affected by constant rounding mode ...
      // compiler inserts:
      // __savedrnd = __swapround(__savedrnd);
      ... operations affected by constant rounding mode ...
      // compiler inserts:
      // __swapround(__savedrnd);
  }
  
  where __swapround is defined by:
  
  static inline int __swapround(const int new) {
      const int old = fegetround();
      fesetround(new);
      return old;
  }

As it follows from the standard, FENV_ROUND in general case changes FP environment (sets rounding mode). Also it affects any FP operation in the scope of the pragma, which is modelled as current rounding mode in clang. So the call to setRoundingModeOverride seems necessary.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126364/new/

https://reviews.llvm.org/D126364



More information about the cfe-commits mailing list