[all-commits] [llvm/llvm-project] 4c4093: Introduce intrinsic llvm.isnan
Serge Pavlov via All-commits
all-commits at lists.llvm.org
Fri Aug 6 00:32:54 PDT 2021
Branch: refs/heads/main
Home: https://github.com/llvm/llvm-project
Commit: 4c4093e6e39fe6601f9c95a95a6bc242ef648cd5
https://github.com/llvm/llvm-project/commit/4c4093e6e39fe6601f9c95a95a6bc242ef648cd5
Author: Serge Pavlov <sepavloff at gmail.com>
Date: 2021-08-06 (Fri, 06 Aug 2021)
Changed paths:
M clang/lib/CodeGen/CGBuiltin.cpp
M clang/test/CodeGen/X86/strictfp_builtins.c
M clang/test/CodeGen/aarch64-strictfp-builtins.c
M clang/test/CodeGen/strictfp_builtins.c
M llvm/docs/LangRef.rst
M llvm/include/llvm/CodeGen/ISDOpcodes.h
M llvm/include/llvm/CodeGen/TargetLowering.h
M llvm/include/llvm/IR/Intrinsics.td
M llvm/lib/Analysis/ConstantFolding.cpp
M llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
M llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
M llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
M llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
M llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
M llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
M llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
M llvm/lib/CodeGen/TargetLoweringBase.cpp
M llvm/lib/Target/X86/X86ISelLowering.cpp
M llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
A llvm/test/CodeGen/AArch64/aarch64-fpclass.ll
A llvm/test/CodeGen/PowerPC/ppc-fpclass.ll
A llvm/test/CodeGen/X86/x86-fpclass.ll
A llvm/test/Transforms/InstCombine/fpclass.ll
A llvm/test/Transforms/InstSimplify/ConstProp/fpclassify.ll
Log Message:
-----------
Introduce intrinsic llvm.isnan
This is recommit of the patch 16ff91ebccda1128c43ff3cee104e2c603569fb2,
reverted in 0c28a7c990c5218d6aec47c5052a51cba686ec5e because it had
an error in call of getFastMathFlags (base type should be FPMathOperator
but not Instruction). The original commit message is duplicated below:
Clang has builtin function '__builtin_isnan', which implements C
library function 'isnan'. This function now is implemented entirely in
clang codegen, which expands the function into set of IR operations.
There are three mechanisms by which the expansion can be made.
* The most common mechanism is using an unordered comparison made by
instruction 'fcmp uno'. This simple solution is target-independent
and works well in most cases. It however is not suitable if floating
point exceptions are tracked. Corresponding IEEE 754 operation and C
function must never raise FP exception, even if the argument is a
signaling NaN. Compare instructions usually does not have such
property, they raise 'invalid' exception in such case. So this
mechanism is unsuitable when exception behavior is strict. In
particular it could result in unexpected trapping if argument is SNaN.
* Another solution was implemented in https://reviews.llvm.org/D95948.
It is used in the cases when raising FP exceptions by 'isnan' is not
allowed. This solution implements 'isnan' using integer operations.
It solves the problem of exceptions, but offers one solution for all
targets, however some can do the check in more efficient way.
* Solution implemented by https://reviews.llvm.org/D96568 introduced a
hook 'clang::TargetCodeGenInfo::testFPKind', which injects target
specific code into IR. Now only SystemZ implements this hook and it
generates a call to target specific intrinsic function.
Although these mechanisms allow to implement 'isnan' with enough
efficiency, expanding 'isnan' in clang has drawbacks:
* The operation 'isnan' is hidden behind generic integer operations or
target-specific intrinsics. It complicates analysis and can prevent
some optimizations.
* IR can be created by tools other than clang, in this case treatment
of 'isnan' has to be duplicated in that tool.
Another issue with the current implementation of 'isnan' comes from the
use of options '-ffast-math' or '-fno-honor-nans'. If such option is
specified, 'fcmp uno' may be optimized to 'false'. It is valid
optimization in general, but it results in 'isnan' always returning
'false'. For example, in some libc++ implementations the following code
returns 'false':
std::isnan(std::numeric_limits<float>::quiet_NaN())
The options '-ffast-math' and '-fno-honor-nans' imply that FP operation
operands are never NaNs. This assumption however should not be applied
to the functions that check FP number properties, including 'isnan'. If
such function returns expected result instead of actually making
checks, it becomes useless in many cases. The option '-ffast-math' is
often used for performance critical code, as it can speed up execution
by the expense of manual treatment of corner cases. If 'isnan' returns
assumed result, a user cannot use it in the manual treatment of NaNs
and has to invent replacements, like making the check using integer
operations. There is a discussion in https://reviews.llvm.org/D18513#387418,
which also expresses the opinion, that limitations imposed by
'-ffast-math' should be applied only to 'math' functions but not to
'tests'.
To overcome these drawbacks, this change introduces a new IR intrinsic
function 'llvm.isnan', which realizes the check as specified by IEEE-754
and C standards in target-agnostic way. During IR transformations it
does not undergo undesirable optimizations. It reaches instruction
selection, where is lowered in target-dependent way. The lowering can
vary depending on options like '-ffast-math' or '-ffp-model' so the
resulting code satisfies requested semantics.
Differential Revision: https://reviews.llvm.org/D104854
More information about the All-commits
mailing list