diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1278,12 +1278,29 @@ // pragma, or by using the /fp:precise or /fp:strict compiler options if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fenv_requires_precise); + // Enabling FENV access sets the RoundingMode to Dynamic + // and ExceptionBehavior to Strict unless they are already overwritten. + if (!NewFPFeatures.hasRoundingModeOverride()) + NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic); + else if (NewFPFeatures.getRoundingModeOverride() == + llvm::RoundingMode::NearestTiesToEven) { + if (NewFPFeatures.hasAllowFEnvAccessOverride()) + NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic); + } + if (!NewFPFeatures.hasFPExceptionModeOverride()) + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); + else if (NewFPFeatures.getFPExceptionModeOverride() == + LangOptions::FPE_Ignore) { + if (NewFPFeatures.hasAllowFEnvAccessOverride()) + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); + } NewFPFeatures.setAllowFEnvAccessOverride(true); - // Enabling FENV access sets the RoundingMode to Dynamic. - // and ExceptionBehavior to Strict - NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic); - NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); } else { + if (CurFPFeatures.getRoundingMode() == llvm::RoundingMode::Dynamic) + NewFPFeatures.setRoundingModeOverride( + llvm::RoundingMode::NearestTiesToEven); + if (CurFPFeatures.getFPExceptionMode() != LangOptions::FPE_Ignore) + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore); NewFPFeatures.setAllowFEnvAccessOverride(false); } FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); diff --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c --- a/clang/test/CodeGen/pragma-fenv_access.c +++ b/clang/test/CodeGen/pragma-fenv_access.c @@ -20,7 +20,7 @@ return x + y; } // CHECK-LABEL: @func_02 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") float func_03(float x, float y) { @@ -41,7 +41,7 @@ return x + y; } // CHECK-LABEL: @func_04 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// CHECK: fadd float float func_05(float x, float y) { @@ -57,7 +57,7 @@ return x + y; } // CHECK-LABEL: @func_06 -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore") +// CHECK: fadd float float func_07(float x, float y) { @@ -69,6 +69,58 @@ return y + 4; } // CHECK-LABEL: @func_07 -// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") // CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") -// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") + + +float func_08(float x, float y) { + #pragma STDC FENV_ROUND FE_UPWARD + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_08 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict") + + +float func_09(float x, float y) { + #pragma clang fp exceptions(maytrap) + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_09 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap") + +float func_10(float x, float y) { + #pragma clang fp exceptions(maytrap) + #pragma STDC FENV_ROUND FE_UPWARD + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_10 +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap") + +float func_11(float x, float y, float z) { + #pragma STDC FENV_ACCESS ON + float res = x * y; + { + #pragma STDC FENV_ACCESS OFF + return res + z; + } +} +// CHECK-LABEL: @func_11 +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") + +float func_12(float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + #pragma STDC FENV_ACCESS ON + float res = x * y; + { + #pragma STDC FENV_ACCESS OFF + return res + z; + } +} +// CHECK-LABEL: @func_12 +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")