[clang] clang: Add pragma clang fp reciprocal (PR #68267)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 4 15:22:08 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
<details>
<summary>Changes</summary>
Just follow allow with the reassociate pragma. This allows locally setting the arcp fast math flag. Previously you could only access this through the global -freciprocal-math.
---
Full diff: https://github.com/llvm/llvm-project/pull/68267.diff
8 Files Affected:
- (modified) clang/docs/LanguageExtensions.rst (+16)
- (modified) clang/docs/ReleaseNotes.rst (+2)
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+1)
- (modified) clang/include/clang/Sema/Sema.h (+4)
- (modified) clang/lib/Parse/ParsePragma.cpp (+20-9)
- (modified) clang/lib/Sema/SemaAttr.cpp (+7)
- (added) clang/test/CodeGen/fp-reciprocal-pragma.cpp (+130)
- (modified) clang/test/Parser/pragma-fp-contract.c (+15)
``````````diff
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index b9466b5a0bc2087..49678240cb55f07 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -4609,6 +4609,22 @@ The pragma can take two values: ``on`` and ``off``.
float v = t + z;
}
+``#pragma clang fp reciprocal`` allows control over using reciprocal
+approximations in floating point expressions. When enabled, this
+pragma allows the expression ``x / y`` to be approximated as ``x *
+(1.0 / y)``. This pragma can be used to disable reciprocal
+approximation when it is otherwise enabled for the translation unit
+with the ``-fallow-reciprocal`` flag. The pragma can take two values:
+``on`` and ``off``.
+
+.. code-block:: c++
+
+ float f(float x, float y)
+ {
+ // Enable floating point reciprocal approximation
+ #pragma clang fp reciprocal(on)
+ return x / y;
+ }
``#pragma clang fp contract`` specifies whether the compiler should
contract a multiply and an addition (or subtraction) into a fused FMA
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6f410c48bd1ffe9..d412e2334c4bbc3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -144,6 +144,8 @@ C23 Feature Support
Non-comprehensive list of changes in this release
-------------------------------------------------
+* Added ``#pragma clang fp reciprocal``.
+
New Compiler Flags
------------------
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 178761bdcf4d5e3..27385487b55bce0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1566,6 +1566,7 @@ def err_pragma_fp_invalid_argument : Error<
"%select{"
"'fast' or 'on' or 'off'|"
"'on' or 'off'|"
+ "'on' or 'off'|"
"'ignore', 'maytrap' or 'strict'|"
"'source', 'double' or 'extended'}2">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index bb05c45391b5473..49b4c836c7451ab 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10950,6 +10950,10 @@ class Sema final {
/// \#pragma clang fp reassociate
void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled);
+ /// Called on well formed
+ /// \#pragma clang fp reciprocal
+ void ActOnPragmaFPReciprocal(SourceLocation Loc, bool IsEnabled);
+
/// ActOnPragmaFenvAccess - Called on well formed
/// \#pragma STDC FENV_ACCESS
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index b3178aef64d72d7..d5ebb9d994a819a 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -3191,11 +3191,12 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
namespace {
/// Used as the annotation value for tok::annot_pragma_fp.
struct TokFPAnnotValue {
- enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod };
+ enum FlagKinds { Contract, Reassociate, Reciprocal, Exceptions, EvalMethod };
enum FlagValues { On, Off, Fast };
std::optional<LangOptions::FPModeKind> ContractValue;
std::optional<LangOptions::FPModeKind> ReassociateValue;
+ std::optional<LangOptions::FPModeKind> ReciprocalValue;
std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
};
@@ -3225,6 +3226,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
.Case("reassociate", TokFPAnnotValue::Reassociate)
.Case("exceptions", TokFPAnnotValue::Exceptions)
.Case("eval_method", TokFPAnnotValue::EvalMethod)
+ .Case("reciprocal", TokFPAnnotValue::Reciprocal)
.Default(std::nullopt);
if (!FlagKind) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
@@ -3264,14 +3266,17 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
return;
}
- } else if (FlagKind == TokFPAnnotValue::Reassociate) {
- AnnotValue->ReassociateValue =
- llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
- II->getName())
- .Case("on", LangOptions::FPModeKind::FPM_On)
- .Case("off", LangOptions::FPModeKind::FPM_Off)
- .Default(std::nullopt);
- if (!AnnotValue->ReassociateValue) {
+ } else if (FlagKind == TokFPAnnotValue::Reassociate ||
+ FlagKind == TokFPAnnotValue::Reciprocal) {
+ auto &Value = FlagKind == TokFPAnnotValue::Reassociate
+ ? AnnotValue->ReassociateValue
+ : AnnotValue->ReciprocalValue;
+ Value = llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
+ II->getName())
+ .Case("on", LangOptions::FPModeKind::FPM_On)
+ .Case("off", LangOptions::FPModeKind::FPM_Off)
+ .Default(std::nullopt);
+ if (!Value) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
return;
@@ -3398,6 +3403,12 @@ void Parser::HandlePragmaFP() {
Actions.ActOnPragmaFPReassociate(Tok.getLocation(),
*AnnotValue->ReassociateValue ==
LangOptions::FPModeKind::FPM_On);
+
+ if (AnnotValue->ReciprocalValue)
+ Actions.ActOnPragmaFPReciprocal(Tok.getLocation(),
+ *AnnotValue->ReciprocalValue ==
+ LangOptions::FPModeKind::FPM_On);
+
if (AnnotValue->ContractValue)
Actions.ActOnPragmaFPContract(Tok.getLocation(),
*AnnotValue->ContractValue);
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 6dadf01ead4441b..a7eb25e72a63547 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1309,6 +1309,13 @@ void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
+void Sema::ActOnPragmaFPReciprocal(SourceLocation Loc, bool IsEnabled) {
+ FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+ NewFPFeatures.setAllowReciprocalOverride(IsEnabled);
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+}
+
void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) {
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
NewFPFeatures.setConstRoundingModeOverride(FPR);
diff --git a/clang/test/CodeGen/fp-reciprocal-pragma.cpp b/clang/test/CodeGen/fp-reciprocal-pragma.cpp
new file mode 100644
index 000000000000000..db93550301bf23c
--- /dev/null
+++ b/clang/test/CodeGen/fp-reciprocal-pragma.cpp
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,DEFAULT %s
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -freciprocal-math -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,FLAG %s
+
+float base(float a, float b, float c) {
+// CHECK-LABEL: _Z4basefff
+// FLAG: %[[A:.+]] = fdiv arcp float %b, %c
+// FLAG: %[[M:.+]] = fdiv arcp float %[[A]], %b
+// FLAG-NEXT: fadd arcp float %[[M]], %c
+
+// DEFAULT: %[[A:.+]] = fdiv float %b, %c
+// DEFAULT: %[[M:.+]] = fdiv float %[[A]], %b
+// DEFAULT-NEXT: fadd float %[[M]], %c
+ a = b / c;
+ return a / b + c;
+}
+
+// Simple case
+float fp_recip_simple(float a, float b, float c) {
+// CHECK-LABEL: _Z15fp_recip_simplefff
+// CHECK: %[[A:.+]] = fdiv arcp float %b, %c
+// CHECK: %[[M:.+]] = fdiv arcp float %[[A]], %b
+// CHECK-NEXT: fadd arcp float %[[M]], %c
+#pragma clang fp reciprocal(on)
+ a = b / c;
+ return a / b + c;
+}
+
+// Test interaction with -freciprocal-math
+float fp_recip_disable(float a, float b, float c) {
+// CHECK-LABEL: _Z16fp_recip_disablefff
+// CHECK: %[[A:.+]] = fdiv float %b, %c
+// CHECK: %[[M:.+]] = fdiv float %[[A]], %b
+// CHECK-NEXT: fadd float %[[M]], %c
+#pragma clang fp reciprocal(off)
+ a = b / c;
+ return a / b + c;
+}
+
+float fp_recip_with_reassoc_simple(float a, float b, float c) {
+// CHECK-LABEL: _Z28fp_recip_with_reassoc_simplefff
+// CHECK: %[[A:.+]] = fmul reassoc arcp float %b, %c
+// CHECK: %[[M:.+]] = fdiv reassoc arcp float %b, %[[A]]
+// CHECK-NEXT: fadd reassoc arcp float %[[M]], %c
+#pragma clang fp reciprocal(on) reassociate(on)
+ a = b / c;
+ return a / b + c;
+}
+
+// arcp pragma should only apply to its scope
+float fp_recip_scoped(float a, float b, float c) {
+ // CHECK-LABEL: _Z15fp_recip_scopedfff
+ // DEFAULT: %[[M:.+]] = fdiv float %a, %b
+ // DEFAULT-NEXT: fadd float %[[M]], %c
+ // FLAG: %[[M:.+]] = fdiv arcp float %a, %b
+ // FLAG-NEXT: fadd arcp float %[[M]], %c
+ {
+#pragma clang fp reciprocal(on)
+ }
+ return a / b + c;
+}
+
+// arcp pragma should apply to templates as well
+class Foo {};
+Foo operator+(Foo, Foo);
+template <typename T>
+T template_recip(T a, T b, T c) {
+#pragma clang fp reciprocal(on)
+ return ((a / b) - c) + c;
+}
+
+float fp_recip_template(float a, float b, float c) {
+ // CHECK-LABEL: _Z17fp_recip_templatefff
+ // CHECK: %[[A1:.+]] = fdiv arcp float %a, %b
+ // CHECK-NEXT: %[[A2:.+]] = fsub arcp float %[[A1]], %c
+ // CHECK-NEXT: fadd arcp float %[[A2]], %c
+ return template_recip<float>(a, b, c);
+}
+
+// File Scoping should work across functions
+#pragma clang fp reciprocal(on)
+float fp_file_scope_on(float a, float b, float c) {
+ // CHECK-LABEL: _Z16fp_file_scope_onfff
+ // CHECK: %[[M1:.+]] = fdiv arcp float %a, %c
+ // CHECK-NEXT: %[[M2:.+]] = fdiv arcp float %b, %c
+ // CHECK-NEXT: fadd arcp float %[[M1]], %[[M2]]
+ return (a / c) + (b / c);
+}
+
+// Inner pragma has precedence
+float fp_file_scope_stop(float a, float b, float c) {
+ // CHECK-LABEL: _Z18fp_file_scope_stopfff
+ // CHECK: %[[A:.+]] = fdiv arcp float %a, %a
+ // CHECK: %[[M1:.+]] = fdiv float %[[A]], %c
+ // CHECK-NEXT: %[[M2:.+]] = fdiv float %b, %c
+ // CHECK-NEXT: fsub float %[[M1]], %[[M2]]
+ a = a / a;
+ {
+#pragma clang fp reciprocal(off)
+ return (a / c) - (b / c);
+ }
+}
+
+#pragma clang fp reciprocal(off)
+float fp_recip_off(float a, float b, float c) {
+ // CHECK-LABEL: _Z12fp_recip_offfff
+ // CHECK: %[[D1:.+]] = fdiv float %a, %c
+ // CHECK-NEXT: %[[D2:.+]] = fdiv float %b, %c
+ // CHECK-NEXT: fadd float %[[D1]], %[[D2]]
+ return (a / c) + (b / c);
+}
+
+// Takes latest flag
+float fp_recip_many(float a, float b, float c) {
+// CHECK-LABEL: _Z13fp_recip_manyfff
+// CHECK: %[[D1:.+]] = fdiv arcp float %a, %c
+// CHECK-NEXT: %[[D2:.+]] = fdiv arcp float %b, %c
+// CHECK-NEXT: fadd arcp float %[[D1]], %[[D2]]
+#pragma clang fp reciprocal(off) reciprocal(on)
+ return (a / c) + (b / c);
+}
+
+// Pragma does not propagate through called functions
+float helper_func(float a, float b, float c) { return a + b + c; }
+float fp_recip_call_helper(float a, float b, float c) {
+// CHECK-LABEL: _Z20fp_recip_call_helperfff
+// CHECK: %[[S1:.+]] = fadd float %a, %b
+// CHECK-NEXT: fadd float %[[S1]], %c
+#pragma clang fp reciprocal(on)
+ return helper_func(a, b, c);
+}
diff --git a/clang/test/Parser/pragma-fp-contract.c b/clang/test/Parser/pragma-fp-contract.c
index 3230a23792af3fc..788fffc00d70d17 100644
--- a/clang/test/Parser/pragma-fp-contract.c
+++ b/clang/test/Parser/pragma-fp-contract.c
@@ -38,3 +38,18 @@ float fp_reassoc_no_fast(float a, float b) {
#pragma clang fp reassociate(fast)
return a - b;
}
+
+float fp_recip_fail(float a, float b) {
+ // CHECK-LABEL: fp_recip_fail
+ // expected-error at +2{{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}}
+ float c = a + b;
+#pragma clang fp reciprocal(off)
+ return c - b;
+}
+
+float fp_recip_no_fast(float a, float b) {
+// CHECK-LABEL: fp_recip_no_fast
+// expected-error at +1{{unexpected argument 'fast' to '#pragma clang fp reciprocal'; expected 'on' or 'off'}}
+#pragma clang fp reciprocal(fast)
+ return a - b;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/68267
More information about the cfe-commits
mailing list