Proposal: New Intrinsic anyfloat @llvm.canonicalize(anyfloat)
Owen Anderson
resistor at mac.com
Fri Jul 10 11:22:07 PDT 2015
Hello all,
Below is a proposal for a new target-independent intrinsic @llvm.canonicalize, primarily intended for use in the implementation of numerically sensitive routines. Much thanks to Ian Ollmann and Steve Canon for providing input on this proposal.
—Owen
------------------
@llvm.canonicalize returns the platform specific canonical encoding of a floating point number. The canonical encoding is defined by IEEE-754-2008 to be:
2.1.8 canonical encoding: The preferred encoding of a floating-point representation
in a format. Applied to declets, significands of finite numbers, infinities,
and NaNs, especially in decimal formats.
This operation should be considered to be equivalent to the IEEE-754-2008 conversion of a floating-point value to the same format. NaNs are handled according to section 6.2.
Examples of non-canonical encodings:
x87 pseudo denormals, pseudo NaNs, pseudo Infinity, Unnormals. These are converted to canonical representation per hardware-specific protocol.
Many normal decimal floating-point numbers have non-canonical alternative encodings.
Some machines, like GPUs or ARMv7 in NEON mode, may not support subnormal values. These are treated as non-canonical encodings of zero and will be "flushed" to zero of the same sign by this operation.
Note: Per IEEE-754-2008 6.2, under default exception handling SNaNs signal an invalid exception and the function shall deliver a quiet NaN.
Rationale:
In some advanced floating-point functions it may be most efficient to manipulate the bits in a floating-point value directly. An example be the implementation of frexp(). In such cases, the code can be simplified if non-canonical encodings can be removed by hardware in advance.
The user can in principle do this himself by multiplying the value by 1.0. Unfortunately, that operation is typically removed by a compiler optimizer. @llvm.canonicalize is provided as a way to signal to the compiler that this operation shall not be optimized away.
Caution: This definition of ‘canonical’ varies between environments, so the result is non-portable.
Implementation notes:
This function should always be implementable as x 1.0, absent compiler optimization (removal) of the expression. IEEE-754 rules state that basic operations return the canonical result. Likewise, divide by 1 and possibly minNum(a,a), depending on implementation should work. In some circumstances, x + -0.0 will also work, provided that the machine is not in round to -infinity rounding mode, in which case 0.0 + -0.0 would return a non-conforming -0.0.
@llvm.canonicalize preserves the equality relation. That is:
(@llvm.canonicalize(x) == x) is equivalent to ( x == x )
@llvm.canonicalize(x) == @llvm.canonicalize(y) is equivalent to x == y.
In addition, the sign of 0 SHOULD be conserved:
@llvm.canonicalize(-0) = -0
@llvm.canonicalize(+0) = +0
This may educate which method is used to implement the function.
Per section 6.2 the NaN payload bits SHOULD be conserved, except that SNaNs are quieted per the usual methods or in environments in which all NaNs are canonicalized to a single payload.
The operation can be optimized away if:
The result is not used.
The input is known to be canonical. For example, it was produced by a floating-point operation which is required by standard to be canonical, such as any math library function or basic floating-point arithmetic operation.
The result is consumed only by (or fused with) other floating-point operations. That is, the bits of the floating-point value are not examined.
Since @llvm.canonicalize can raise the invalid floating-point exception, the operation can not be optimized away unless the implementation can prove that the argument is not a SNaN or the program is not monitoring floating point exceptions (e.g. #pragma STDC FENV_ACCESS OFF).
More information about the llvm-commits
mailing list