aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend/CompilerInvocation.cpp
diff options
context:
space:
mode:
authorYaxun (Sam) Liu <yaxun.liu@amd.com>2020-10-23 16:24:48 -0400
committerYaxun (Sam) Liu <yaxun.liu@amd.com>2020-11-24 08:10:06 -0500
commitcb08558caa3bad69213b08e6361586491232c745 (patch)
tree59456c7d0475ae1ad9191d93b21568c7e40d72cb /clang/lib/Frontend/CompilerInvocation.cpp
parent38236656ab4a4bea5e582f709929003abfa1ddcd (diff)
downloadllvm-cb08558caa3bad69213b08e6361586491232c745.zip
llvm-cb08558caa3bad69213b08e6361586491232c745.tar.gz
llvm-cb08558caa3bad69213b08e6361586491232c745.tar.bz2
[HIP] Fix regressions due to fp contract change
Recently HIP toolchain made a change to use clang instead of opt/llc to do compilation (https://reviews.llvm.org/D81861). The intention is to make HIP toolchain canonical like other toolchains. However, this change introduced an unintentional change regarding backend fp fuse option, which caused regressions in some HIP applications. Basically before the change, HIP toolchain used clang to generate bitcode, then use opt/llc to optimize bitcode and generate ISA. As such, the amdgpu backend takes the default fp fuse mode which is 'Standard'. This mode respect contract flag of fmul/fadd instructions and do not fuse fmul/fadd instructions without contract flag. However, after the change, HIP toolchain now use clang to generate IR, do optimization, and generate ISA as one process. Now amdgpu backend fp fuse option is determined by -ffp-contract option, which is 'fast' by default. And this -ffp-contract=fast language option is translated to 'Fast' fp fuse option in backend. Suddenly backend starts to fuse fmul/fadd instructions without contract flag. This causes wrong result for some device library functions, e.g. tan(-1e20), which should return 0.8446, now returns -0.933. What is worse is that since backend with 'Fast' fp fuse option does not respect contract flag, there is no way to use #pragma clang fp contract directive to enforce fp contract requirements. This patch fixes the regression by introducing a new value 'fast-honor-pragmas' for -ffp-contract and use it for HIP by default. 'fast-honor-pragmas' is equivalent to 'fast' in frontend but let the backend to use 'Standard' fp fuse option. 'fast-honor-pragmas' is useful since 'Fast' fp fuse option in backend does not honor contract flag, it is of little use to HIP applications since all code with #pragma STDC FP_CONTRACT or any IR from a source compiled with -ffp-contract=on is broken. Differential Revision: https://reviews.llvm.org/D90174
Diffstat (limited to 'clang/lib/Frontend/CompilerInvocation.cpp')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp17
1 files changed, 15 insertions, 2 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 35025a9..f4b7f68 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2424,9 +2424,20 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.HIP = IK.getLanguage() == Language::HIP;
Opts.CUDA = IK.getLanguage() == Language::CUDA || Opts.HIP;
- if (Opts.CUDA)
- // Set default FP_CONTRACT to FAST.
+ if (Opts.HIP) {
+ // HIP toolchain does not support 'Fast' FPOpFusion in backends since it
+ // fuses multiplication/addition instructions without contract flag from
+ // device library functions in LLVM bitcode, which causes accuracy loss in
+ // certain math functions, e.g. tan(-1e20) becomes -0.933 instead of 0.8446.
+ // For device library functions in bitcode to work, 'Strict' or 'Standard'
+ // FPOpFusion options in backends is needed. Therefore 'fast-honor-pragmas'
+ // FP contract option is used to allow fuse across statements in frontend
+ // whereas respecting contract flag in backend.
+ Opts.setDefaultFPContractMode(LangOptions::FPM_FastHonorPragmas);
+ } else if (Opts.CUDA) {
+ // Allow fuse across statements disregarding pragmas.
Opts.setDefaultFPContractMode(LangOptions::FPM_Fast);
+ }
Opts.RenderScript = IK.getLanguage() == Language::RenderScript;
if (Opts.RenderScript) {
@@ -3343,6 +3354,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.setDefaultFPContractMode(LangOptions::FPM_On);
else if (Val == "off")
Opts.setDefaultFPContractMode(LangOptions::FPM_Off);
+ else if (Val == "fast-honor-pragmas")
+ Opts.setDefaultFPContractMode(LangOptions::FPM_FastHonorPragmas);
else
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
}