[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -5980,6 +5987,64 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return Ret; } +static bool endsWithRoundingModeSuffix(StringRef FuncName) { + size_t Underscore = FuncName.find_last_of("_"); + if (Underscore == StringRef::npos || Underscore < 2) +return false; + StringRef Suffix = FuncName.substr(Underscore + 1); + static const StringRef RMSuffixes[] = {"rtz", "rte", "rtp", "rtn", "rhaz", + "rz", "rn", "ru", "rd"}; + for (auto RM : RMSuffixes) { +if (Suffix == RM) + return true; + } + return false; +} + +bool CodeGenFunction::requiresDynamicRounding(const CGCallee &Callee) { + if (Callee.isOrdinary()) { +const Decl *CalleeDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl(); +if (const FunctionDecl *FD = dyn_cast_or_null(CalleeDecl)) { + IdentifierInfo *FuncNameII = FD->getDeclName().getAsIdentifierInfo(); + if (FuncNameII) { +StringRef FuncName = FuncNameII->getName(); +// If a reserved identifier ends with rounding mode suffix preceded by +// underscore, this function does not need the previous dynamic rounding +// mode to be set. +if (isReservedInAllContexts( +FuncNameII->isReserved(getContext().getLangOpts( { + if (endsWithRoundingModeSuffix(FuncName)) +return false; +} + } +} + } + return true; +} + +/// Sets dynamic rounding mode for the function called in the region where +/// pragma FENV_ROUND is in effect. +void CodeGenFunction::setRoundingModeForCall(const CGCallee &Callee) { + if (Target.hasStaticRounding() || Callee.isBuiltin() || + !requiresDynamicRounding(Callee)) +return; + if (!CurrentRoundingIsStatic || !DynamicRoundingMode) +return; + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::set_rounding), + DynamicRoundingMode); + CurrentRoundingIsStatic = false; jcranmer-intel wrote: I'm not seeing logic here to effect the proper handling of, e.g., `sqrt`. Is this planned in a future patch? If so, add in a TODO note. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -5980,6 +5987,64 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return Ret; } +static bool endsWithRoundingModeSuffix(StringRef FuncName) { + size_t Underscore = FuncName.find_last_of("_"); + if (Underscore == StringRef::npos || Underscore < 2) +return false; + StringRef Suffix = FuncName.substr(Underscore + 1); + static const StringRef RMSuffixes[] = {"rtz", "rte", "rtp", "rtn", "rhaz", + "rz", "rn", "ru", "rd"}; + for (auto RM : RMSuffixes) { +if (Suffix == RM) + return true; + } + return false; +} + +bool CodeGenFunction::requiresDynamicRounding(const CGCallee &Callee) { + if (Callee.isOrdinary()) { +const Decl *CalleeDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl(); +if (const FunctionDecl *FD = dyn_cast_or_null(CalleeDecl)) { + IdentifierInfo *FuncNameII = FD->getDeclName().getAsIdentifierInfo(); + if (FuncNameII) { +StringRef FuncName = FuncNameII->getName(); +// If a reserved identifier ends with rounding mode suffix preceded by +// underscore, this function does not need the previous dynamic rounding +// mode to be set. jcranmer-intel wrote: Where is this rule coming from? https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -1232,6 +1232,14 @@ class TargetInfo : public TransferrableTargetInfo, return true; } + /// Returns true, if an operations that depends on rounding mode can be + /// implemented without changing FP environment. In this case the rounding + /// mode is encoded in the bits of implementing instruction. jcranmer-intel wrote: I'm not sure we actually have any (non-target-specific) IR constructs at the moment that actually implement static rounding mode. The documentation for constrained intrinsics says: > For values other than “round.dynamic” optimization passes may assume that the > actual runtime rounding mode (as defined in a target-specific manner) matches > the specified rounding mode, but this is not guaranteed. It's also the case that static rounding mode may be a less-than-global decision. X86 AVX512/AVX10 has static rounding mode, which is a subtarget consideration, but even then, it's not entirely clear that they would be absolutely preferred. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/jcranmer-intel commented: Sorry for just thinking of this now, but we should also have tests for some of the builtins like `__builtin_fma` or `__builtin_sqrt`. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/jcranmer-intel edited https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
spavloff wrote: > 7.6.2p4 does clearly state that floating constants need to be evaluated > according to the standard rounding mode, so that the constant 0.1 evaluates > to a different value in FE_DOWNWARD versus FE_UPWARD. Treatment of floating-point constants is fixed in https://github.com/llvm/llvm-project/pull/90877. > I'm not seeing from the tests how the code is handling calls to functions. > Calls to all functions outside of a finite list (see same paragraph) need to > restore the saved dynamic rounding mode for the duration of the call. The latest update to this PR fixes this. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff edited https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/89617 >From ec8838685fb7af618445c3ff1bae953778996c37 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 14 Apr 2022 18:00:14 +0700 Subject: [PATCH 1/3] Implementation of '#pragma STDC FENV_ROUND' This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- clang/include/clang/AST/Stmt.h| 9 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Basic/LangOptions.h | 6 + clang/lib/CodeGen/CGStmt.cpp | 56 ++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/ParsePragma.cpp | 3 - clang/test/CodeGen/complex-strictfp.c | 60 --- clang/test/CodeGen/math-errno.c | 6 +- clang/test/CodeGen/pragma-fenv_access.c | 45 - clang/test/CodeGen/pragma-fenv_round.c| 160 ++ clang/test/Parser/pragma-fenv_round.c | 1 - 11 files changed, 315 insertions(+), 37 deletions(-) create mode 100644 clang/test/CodeGen/pragma-fenv_round.c diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 9cd7a364cd3f1..6eceecd93e59c 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1658,6 +1658,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 44bc4e0e130de..c9b0c0e616c71 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1266,9 +1266,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index e2a2aa71b880b..53c498f1c4017 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -846,6 +846,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic() const { +return (getConstRoundingMode() == RoundingMode::Dynamic) && + (getAllowFEnvAccess() || getRoundingMath()); + } + RoundingMode getRoundingMode() const { RoundingMode RM = getConstRoundingMode(); if (RM == RoundingMode::Dynamic) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 576fe2f7a2d46..4fbc906afaeed 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, return true; } +namespace { +/// Cleanup action that restores floating-point control modes upon leaving +/// a scope. +struct FPControlModesCleanup final : EHScopeStack::Cleanup { + llvm::Value *PreviousModes; + FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { +CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {}, +{PreviousModes}); + } +}; +} // namespace
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/jcranmer-intel requested changes to this pull request. I haven't fully tested the changes yet, so right now I'm looking at the test to figure out how much is supported. Nevertheless, I can already tell that this is not complete support. 7.6.2p4 does clearly state that floating constants need to be evaluated according to the standard rounding mode, so that the constant `0.1` evaluates to a different value in `FE_DOWNWARD` versus `FE_UPWARD`. I'm not seeing from the tests how the code is handling calls to functions. Calls to all functions outside of a finite list (see same paragraph) need to restore the saved dynamic rounding mode for the duration of the call. I'd like to see tests covering casts and conversions better. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/89617 >From 0fc5c57264ecf51f8b9fe8303520a51cb1fee40e Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 14 Apr 2022 18:00:14 +0700 Subject: [PATCH 1/2] Implementation of '#pragma STDC FENV_ROUND' This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- clang/include/clang/AST/Stmt.h| 9 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Basic/LangOptions.h | 6 + clang/lib/CodeGen/CGStmt.cpp | 56 ++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/ParsePragma.cpp | 3 - clang/test/CodeGen/complex-strictfp.c | 60 --- clang/test/CodeGen/math-errno.c | 6 +- clang/test/CodeGen/pragma-fenv_access.c | 45 - clang/test/CodeGen/pragma-fenv_round.c| 160 ++ clang/test/Parser/pragma-fenv_round.c | 1 - 11 files changed, 315 insertions(+), 37 deletions(-) create mode 100644 clang/test/CodeGen/pragma-fenv_round.c diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 9cd7a364cd3f1d..6eceecd93e59c2 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1658,6 +1658,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 38174cf3549f14..329af794405998 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index ae4715921d1665..28164f564e907d 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -839,6 +839,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic() const { +return (getConstRoundingMode() == RoundingMode::Dynamic) && + (getAllowFEnvAccess() || getRoundingMath()); + } + RoundingMode getRoundingMode() const { RoundingMode RM = getConstRoundingMode(); if (RM == RoundingMode::Dynamic) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 576fe2f7a2d46f..4fbc906afaeed5 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, return true; } +namespace { +/// Cleanup action that restores floating-point control modes upon leaving +/// a scope. +struct FPControlModesCleanup final : EHScopeStack::Cleanup { + llvm::Value *PreviousModes; + FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { +CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {}, +{PreviousModes}); + } +}; +} // n
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -0,0 +1,160 @@ +// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | \ +// RUN: FileCheck %s --implicit-check-not "call void @llvm.set.rounding" --implicit-check-not "call i32 @llvm.get.rounding" + +float func_rz_ru(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_UPWARD +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_ru +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 2) +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) + + +float func_rz_rz(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_TOWARDZERO +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_rz +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) + +float func_rne_rne(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TONEAREST + float result = x * y; + { +#pragma STDC FENV_ROUND FE_TONEAREST +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rne_rne +// CHECK: fmul +// CHECK: fadd +// CHECK: fsub + +float func_rz_dyn_noacc(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_DYNAMIC +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_dyn_noacc +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") jcranmer-intel wrote: 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. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either zahiraam wrote: This comment can be removed I think. https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
@@ -0,0 +1,160 @@ +// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | \ +// RUN: FileCheck %s --implicit-check-not "call void @llvm.set.rounding" --implicit-check-not "call i32 @llvm.get.rounding" + +float func_rz_ru(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_UPWARD +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_ru +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 2) +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) + + +float func_rz_rz(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_TOWARDZERO +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_rz +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) + +float func_rne_rne(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TONEAREST + float result = x * y; + { +#pragma STDC FENV_ROUND FE_TONEAREST +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rne_rne +// CHECK: fmul +// CHECK: fadd +// CHECK: fsub + +float func_rz_dyn_noacc(float w, float x, float y, float z) { + #pragma STDC FENV_ROUND FE_TOWARDZERO + float result = x * y; + { +#pragma STDC FENV_ROUND FE_DYNAMIC +result += z; + } + return result - w; +} + +// CHECK-LABEL: @func_rz_dyn_noacc +// CHECK: call void @llvm.set.rounding(i32 0) +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +// CHECK: call void @llvm.set.rounding(i32 1) +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore") zahiraam wrote: Shouldn't the `result += z` be dynamic here? https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
zahiraam wrote: How about adding `pragma STDC FENV_ROUND` at file scope and some C++ tests (with default argument in functions). https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/89617 >From 0fc5c57264ecf51f8b9fe8303520a51cb1fee40e Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 14 Apr 2022 18:00:14 +0700 Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND' This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- clang/include/clang/AST/Stmt.h| 9 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Basic/LangOptions.h | 6 + clang/lib/CodeGen/CGStmt.cpp | 56 ++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/ParsePragma.cpp | 3 - clang/test/CodeGen/complex-strictfp.c | 60 --- clang/test/CodeGen/math-errno.c | 6 +- clang/test/CodeGen/pragma-fenv_access.c | 45 - clang/test/CodeGen/pragma-fenv_round.c| 160 ++ clang/test/Parser/pragma-fenv_round.c | 1 - 11 files changed, 315 insertions(+), 37 deletions(-) create mode 100644 clang/test/CodeGen/pragma-fenv_round.c diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 9cd7a364cd3f1d..6eceecd93e59c2 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1658,6 +1658,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 38174cf3549f14..329af794405998 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1257,9 +1257,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index ae4715921d1665..28164f564e907d 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -839,6 +839,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic() const { +return (getConstRoundingMode() == RoundingMode::Dynamic) && + (getAllowFEnvAccess() || getRoundingMath()); + } + RoundingMode getRoundingMode() const { RoundingMode RM = getConstRoundingMode(); if (RM == RoundingMode::Dynamic) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 576fe2f7a2d46f..4fbc906afaeed5 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, return true; } +namespace { +/// Cleanup action that restores floating-point control modes upon leaving +/// a scope. +struct FPControlModesCleanup final : EHScopeStack::Cleanup { + llvm::Value *PreviousModes; + FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { +CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {}, +{PreviousModes}); + } +}; +} // names
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/89617 >From fc7aab600c25b39b2df039c0cbcf517719736311 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 14 Apr 2022 18:00:14 +0700 Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND' This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- clang/include/clang/AST/Stmt.h| 9 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Basic/LangOptions.h | 6 + clang/lib/CodeGen/CGStmt.cpp | 56 ++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/ParsePragma.cpp | 3 - clang/test/CodeGen/complex-strictfp.c | 60 --- clang/test/CodeGen/math-errno.c | 2 +- clang/test/CodeGen/pragma-fenv_access.c | 45 - clang/test/CodeGen/pragma-fenv_round.c| 160 ++ clang/test/Parser/pragma-fenv_round.c | 1 - 11 files changed, 313 insertions(+), 35 deletions(-) create mode 100644 clang/test/CodeGen/pragma-fenv_round.c diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 1b9c9231047717..0ee9c13df75e41 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1663,6 +1663,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index bb9ca2a50cc06c..cbda8975717d2e 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 24b109e32cdd3e..ae8c7b2ead8ee2 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -834,6 +834,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic() const { +return (getConstRoundingMode() == RoundingMode::Dynamic) && + (getAllowFEnvAccess() || getRoundingMath()); + } + RoundingMode getRoundingMode() const { RoundingMode RM = getConstRoundingMode(); if (RM == RoundingMode::Dynamic) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 576fe2f7a2d46f..4fbc906afaeed5 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, return true; } +namespace { +/// Cleanup action that restores floating-point control modes upon leaving +/// a scope. +struct FPControlModesCleanup final : EHScopeStack::Cleanup { + llvm::Value *PreviousModes; + FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { +CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {}, +{PreviousModes}); + } +}; +} // names
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 37b7207651b44743909a427b5509bed5e6c21b59 58adf3643828272d071fd49195cfcf0b2164eb70 -- clang/test/CodeGen/pragma-fenv_round.c clang/include/clang/AST/Stmt.h clang/include/clang/Basic/LangOptions.h clang/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Parse/ParsePragma.cpp clang/test/CodeGen/complex-strictfp.c clang/test/CodeGen/math-errno.c clang/test/CodeGen/pragma-fenv_access.c clang/test/Parser/pragma-fenv_round.c `` View the diff from clang-format here. ``diff diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 2ec642e25d..ae8c7b2ead 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -837,7 +837,7 @@ public: /// Checks if the rounding mode is unknown at compile-time. bool isRoundingModeDynamic() const { return (getConstRoundingMode() == RoundingMode::Dynamic) && - (getAllowFEnvAccess() || getRoundingMath()); + (getAllowFEnvAccess() || getRoundingMath()); } RoundingMode getRoundingMode() const { `` https://github.com/llvm/llvm-project/pull/89617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
llvmbot wrote: @llvm/pr-subscribers-clang-codegen Author: Serge Pavlov (spavloff) Changes This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- Patch is 33.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89617.diff 11 Files Affected: - (modified) clang/include/clang/AST/Stmt.h (+9) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (-3) - (modified) clang/include/clang/Basic/LangOptions.h (+6) - (modified) clang/lib/CodeGen/CGStmt.cpp (+56) - (modified) clang/lib/CodeGen/CodeGenFunction.h (+3) - (modified) clang/lib/Parse/ParsePragma.cpp (-3) - (modified) clang/test/CodeGen/complex-strictfp.c (+39-21) - (modified) clang/test/CodeGen/math-errno.c (+1-1) - (modified) clang/test/CodeGen/pragma-fenv_access.c (+39-6) - (added) clang/test/CodeGen/pragma-fenv_round.c (+160) - (modified) clang/test/Parser/pragma-fenv_round.c (-1) ``diff diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 1b9c9231047717..0ee9c13df75e41 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1663,6 +1663,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index bb9ca2a50cc06c..cbda8975717d2e 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 24b109e32cdd3e..2ec642e25ddcc6 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -834,6 +834,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic() const { +return (getConstRoundingMode() == RoundingMode::Dynamic) && + (getAllowFEnvAccess() || getRoundingMath()); + } + RoundingMode getRoundingMode() const { RoundingMode RM = getConstRoundingMode(); if (RM == RoundingMode::Dynamic) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 576fe2f7a2d46f..4fbc906afaeed5 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -486,6 +486,56 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, return true; } +namespace { +/// Cleanup action that restores floating-point control modes upon leaving +/// a scope. +struct FPControlModesCleanup final : EHScopeStack::Cleanup { + llvm::Value *PreviousModes; + FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {} + void Emit(CodeGenFunction &CGF, Flags flags) override { +CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {}, +{PreviousModes}); + } +}; +} // namespace + +void CodeGenFunction::emitSetFPControlModes(FPOptions NewFP) { + if (NewFP == CurFPFeatures) +return; + + // For now only rounding
[clang] Implementation of '#pragma STDC FENV_ROUND' (PR #89617)
https://github.com/spavloff created https://github.com/llvm/llvm-project/pull/89617 This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. >From 58adf3643828272d071fd49195cfcf0b2164eb70 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 14 Apr 2022 18:00:14 +0700 Subject: [PATCH] Implementation of '#pragma STDC FENV_ROUND' This pragma is introduced by forthcoming C2x standard and can be used to set particular rounding mode without need to call 'fesetmode' or accessing control mode registers directly. Previously this pragma was implemented in clang partially, only for the purpose of using in constant expressions and making tests. This change implements the pragma according to the standard draft. It sets up dynamic rounding mode in the compound statement where the pragma acts. This is inevitable for targets that set rounding mode by changing some control register. Targets that support static rounding mode encoded in instructions can have more efficient implementation, it is not implemented in this change. The implementation uses intrinsic functions 'get_rounding' and 'set_rounding' to save/restore dynamic rounding mode. In some cases using functions that operate entire set of control modes or even FP environment may give more efficient implementation. This optimization is not a part of this change. --- clang/include/clang/AST/Stmt.h| 9 + .../clang/Basic/DiagnosticParseKinds.td | 3 - clang/include/clang/Basic/LangOptions.h | 6 + clang/lib/CodeGen/CGStmt.cpp | 56 ++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/ParsePragma.cpp | 3 - clang/test/CodeGen/complex-strictfp.c | 60 --- clang/test/CodeGen/math-errno.c | 2 +- clang/test/CodeGen/pragma-fenv_access.c | 45 - clang/test/CodeGen/pragma-fenv_round.c| 160 ++ clang/test/Parser/pragma-fenv_round.c | 1 - 11 files changed, 313 insertions(+), 35 deletions(-) create mode 100644 clang/test/CodeGen/pragma-fenv_round.c diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 1b9c9231047717..0ee9c13df75e41 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1663,6 +1663,15 @@ class CompoundStmt final return *getTrailingObjects(); } + /// Get FPOptions inside this statement. They may differ from the outer + /// options due to pragmas. + /// \param CurFPOptions FPOptions outside this statement. + FPOptions getNewFPOptions(FPOptions CurFPOptions) const { +return hasStoredFPFeatures() + ? getStoredFPFeatures().applyOverrides(CurFPOptions) + : CurFPOptions; + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index bb9ca2a50cc06c..cbda8975717d2e 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1255,9 +1255,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def warn_stdc_fenv_round_not_supported : - Warning<"pragma STDC FENV_ROUND is not supported">, - InGroup; def warn_stdc_unknown_rounding_mode : Warning< "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">, InGroup; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 24b109e32cdd3e..2ec642e25ddcc6 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -834,6 +834,12 @@ class FPOptions { getAllowFEnvAccess(); } + /// Checks if the rounding mode is unknown at compile-time. + bool isRoundingModeDynamic