[clang] clang: Add pragma clang fp reciprocal (PR #68267)
Matt Arsenault via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 3 01:13:54 PDT 2023
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/68267
>From db9b84992dbd6d75dc5c23b11d63c195400d5bc1 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 31 Aug 2023 17:33:35 -0400
Subject: [PATCH] clang: Add pragma clang fp reciprocal
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.
---
clang/docs/LanguageExtensions.rst | 16 +++
clang/docs/ReleaseNotes.rst | 2 +
.../clang/Basic/DiagnosticParseKinds.td | 3 +-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/include/clang/Basic/PragmaKinds.h | 9 ++
clang/include/clang/Sema/Sema.h | 5 +-
clang/lib/Parse/ParsePragma.cpp | 52 ++++---
clang/lib/Sema/SemaAttr.cpp | 18 ++-
clang/test/CodeGen/fp-reciprocal-pragma.cpp | 130 ++++++++++++++++++
clang/test/Parser/pragma-fp-contract.c | 15 ++
clang/test/Parser/pragma-fp.cpp | 4 +-
.../test/Sema/eval-method-with-unsafe-math.c | 32 +++++
12 files changed, 259 insertions(+), 29 deletions(-)
create mode 100644 clang/test/CodeGen/fp-reciprocal-pragma.cpp
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 30e288f986782fd..090600275956be0 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -4617,6 +4617,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 ``-freciprocal-math`` flag or other fast-math options. 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 4696836b3a00caa..ad28acf61226136 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -218,6 +218,8 @@ Non-comprehensive list of changes in this release
For scalable vectors, e.g., SVE or RISC-V V, the number of elements is not known at compile-time and is
determined at runtime.
+* 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 de180344fcc5c74..2f3bef33f936883 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1569,12 +1569,13 @@ def note_pragma_loop_invalid_vectorize_option : Note<
"vectorize_width(X, scalable) where X is an integer, or vectorize_width('fixed' or 'scalable')">;
def err_pragma_fp_invalid_option : Error<
- "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate' or 'exceptions'">;
+ "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate', 'reciprocal', or 'exceptions'">;
def err_pragma_fp_invalid_argument : Error<
"unexpected argument '%0' to '#pragma clang fp %1'; expected "
"%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/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 474afc2fb99c1f0..d23d3dd8b592ec9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6755,7 +6755,7 @@ def warn_floatingpoint_eq : Warning<
def err_setting_eval_method_used_in_unsafe_context : Error <
"%select{'#pragma clang fp eval_method'|option 'ffp-eval-method'}0 cannot be used with "
- "%select{option 'fapprox-func'|option 'mreassociate'|option 'freciprocal'|option 'ffp-eval-method'|'#pragma clang fp reassociate'}1">;
+ "%select{option 'fapprox-func'|option 'mreassociate'|option 'freciprocal'|option 'ffp-eval-method'|'#pragma clang fp reassociate'|'#pragma clang fp reciprocal'}1">;
def warn_remainder_division_by_zero : Warning<
"%select{remainder|division}0 by zero is undefined">,
diff --git a/clang/include/clang/Basic/PragmaKinds.h b/clang/include/clang/Basic/PragmaKinds.h
index 176bbc9ac7caaec..a4789ccde5ec3c1 100644
--- a/clang/include/clang/Basic/PragmaKinds.h
+++ b/clang/include/clang/Basic/PragmaKinds.h
@@ -34,6 +34,15 @@ enum PragmaFloatControlKind {
PFC_Push, // #pragma float_control(push)
PFC_Pop // #pragma float_control(pop)
};
+
+enum PragmaFPKind {
+ PFK_Contract, // #pragma clang fp contract
+ PFK_Reassociate, // #pragma clang fp reassociate
+ PFK_Reciprocal, // #pragma clang fp reciprocal
+ PFK_Exceptions, // #pragma clang fp exceptions
+ PFK_EvalMethod // #pragma clang fp eval_method
+};
+
}
#endif
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index daed24be0a86d11..8a6cb52736e6c0b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10998,7 +10998,10 @@ class Sema final {
/// Called on well formed
/// \#pragma clang fp reassociate
- void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled);
+ /// or
+ /// \#pragma clang fp reciprocal
+ void ActOnPragmaFPValueChangingOption(SourceLocation Loc, PragmaFPKind Kind,
+ bool IsEnabled);
/// ActOnPragmaFenvAccess - Called on well formed
/// \#pragma STDC FENV_ACCESS
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index b3178aef64d72d7..f0d366aaa134eb3 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -3191,11 +3191,11 @@ 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 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;
};
@@ -3219,12 +3219,13 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
auto FlagKind =
- llvm::StringSwitch<std::optional<TokFPAnnotValue::FlagKinds>>(
+ llvm::StringSwitch<std::optional<PragmaFPKind>>(
OptionInfo->getName())
- .Case("contract", TokFPAnnotValue::Contract)
- .Case("reassociate", TokFPAnnotValue::Reassociate)
- .Case("exceptions", TokFPAnnotValue::Exceptions)
- .Case("eval_method", TokFPAnnotValue::EvalMethod)
+ .Case("contract", PFK_Contract)
+ .Case("reassociate", PFK_Reassociate)
+ .Case("exceptions", PFK_Exceptions)
+ .Case("eval_method", PFK_EvalMethod)
+ .Case("reciprocal", PFK_Reciprocal)
.Default(std::nullopt);
if (!FlagKind) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
@@ -3240,7 +3241,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
}
PP.Lex(Tok);
bool isEvalMethodDouble =
- Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod;
+ Tok.is(tok::kw_double) && FlagKind == PFK_EvalMethod;
// Don't diagnose if we have an eval_metod pragma with "double" kind.
if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) {
@@ -3251,7 +3252,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
- if (FlagKind == TokFPAnnotValue::Contract) {
+ if (FlagKind == PFK_Contract) {
AnnotValue->ContractValue =
llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
II->getName())
@@ -3264,19 +3265,22 @@ 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 == PFK_Reassociate ||
+ FlagKind == PFK_Reciprocal) {
+ auto &Value = FlagKind == PFK_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;
}
- } else if (FlagKind == TokFPAnnotValue::Exceptions) {
+ } else if (FlagKind == PFK_Exceptions) {
AnnotValue->ExceptionsValue =
llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>(
II->getName())
@@ -3289,7 +3293,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
return;
}
- } else if (FlagKind == TokFPAnnotValue::EvalMethod) {
+ } else if (FlagKind == PFK_EvalMethod) {
AnnotValue->EvalMethodValue =
llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>(
II->getName())
@@ -3395,9 +3399,15 @@ void Parser::HandlePragmaFP() {
reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
if (AnnotValue->ReassociateValue)
- Actions.ActOnPragmaFPReassociate(Tok.getLocation(),
- *AnnotValue->ReassociateValue ==
- LangOptions::FPModeKind::FPM_On);
+ Actions.ActOnPragmaFPValueChangingOption(
+ Tok.getLocation(), PFK_Reassociate,
+ *AnnotValue->ReassociateValue == LangOptions::FPModeKind::FPM_On);
+
+ if (AnnotValue->ReciprocalValue)
+ Actions.ActOnPragmaFPValueChangingOption(
+ Tok.getLocation(), PFK_Reciprocal,
+ *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..79271c872627310 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1285,7 +1285,8 @@ void Sema::ActOnPragmaFPContract(SourceLocation Loc,
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
-void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
+void Sema::ActOnPragmaFPValueChangingOption(SourceLocation Loc,
+ PragmaFPKind Kind, bool IsEnabled) {
if (IsEnabled) {
// For value unsafe context, combining this pragma with eval method
// setting is not recommended. See comment in function FixupInvocation#506.
@@ -1301,10 +1302,21 @@ void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
Reason = 0;
if (Reason != -1)
Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context)
- << Reason << 4;
+ << Reason << (Kind == PFK_Reassociate ? 4 : 5);
}
+
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
- NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
+ switch (Kind) {
+ case PFK_Reassociate:
+ NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
+ break;
+ case PFK_Reciprocal:
+ NewFPFeatures.setAllowReciprocalOverride(IsEnabled);
+ break;
+ default:
+ llvm_unreachable("unhandled value changing pragma fp");
+ }
+
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
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;
+}
diff --git a/clang/test/Parser/pragma-fp.cpp b/clang/test/Parser/pragma-fp.cpp
index 0377a1b259f465c..737aee03f4bb015 100644
--- a/clang/test/Parser/pragma-fp.cpp
+++ b/clang/test/Parser/pragma-fp.cpp
@@ -1,14 +1,14 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
void test_0(int *List, int Length) {
-/* expected-error at +1 {{missing option; expected 'contract', 'reassociate' or 'exceptions'}} */
+/* expected-error at +1 {{missing option; expected 'contract', 'reassociate', 'reciprocal', or 'exceptions'}} */
#pragma clang fp
for (int i = 0; i < Length; i++) {
List[i] = i;
}
}
void test_1(int *List, int Length) {
-/* expected-error at +1 {{invalid option 'blah'; expected 'contract', 'reassociate' or 'exceptions'}} */
+/* expected-error at +1 {{invalid option 'blah'; expected 'contract', 'reassociate', 'reciprocal', or 'exceptions'}} */
#pragma clang fp blah
for (int i = 0; i < Length; i++) {
List[i] = i;
diff --git a/clang/test/Sema/eval-method-with-unsafe-math.c b/clang/test/Sema/eval-method-with-unsafe-math.c
index b68dc6e7505d379..eb61e1d9f3e6350 100644
--- a/clang/test/Sema/eval-method-with-unsafe-math.c
+++ b/clang/test/Sema/eval-method-with-unsafe-math.c
@@ -54,3 +54,35 @@ float f4(float a, float b, float c) {
#pragma clang fp reassociate(on)
return (a * c) - (b * c);
}
+
+float f4_reciprocal(float a, float b, float c) {
+#pragma clang fp eval_method(double)
+ // CHECK-FUNC: '#pragma clang fp eval_method' cannot be used with option 'fapprox-func'
+ // CHECK-ASSOC: '#pragma clang fp eval_method' cannot be used with option 'mreassociate'
+ // CHECK-RECPR: '#pragma clang fp eval_method' cannot be used with option 'freciprocal'
+ // CHECK-PRGM: '#pragma clang fp eval_method' cannot be used with '#pragma clang fp reciprocal'
+#pragma clang fp reciprocal(on)
+ return (a * c) / (b * c);
+}
+
+float f4_reciprocal_reassociate(float a, float b, float c) {
+#pragma clang fp eval_method(double)
+ // CHECK-FUNC: '#pragma clang fp eval_method' cannot be used with option 'fapprox-func'
+ // CHECK-ASSOC: '#pragma clang fp eval_method' cannot be used with option 'mreassociate'
+ // CHECK-RECPR: '#pragma clang fp eval_method' cannot be used with option 'freciprocal'
+ // CHECK-PRGM: '#pragma clang fp eval_method' cannot be used with '#pragma clang fp reassociate'
+ // CHECK-PRGM: '#pragma clang fp eval_method' cannot be used with '#pragma clang fp reciprocal'
+#pragma clang fp reciprocal(on) reassociate(on)
+ return (a * c) / (b * c);
+}
+
+float f2_reciprocal(float a, float b, float c) {
+ // CHECK-FFP-OPT: option 'ffp-eval-method' cannot be used with '#pragma clang fp reciprocal'
+#pragma clang fp reciprocal(on)
+ return (a + b) / c;
+}
+
+float f3_reciprocal(float a, float b, float c) {
+#pragma clang fp reciprocal(off)
+ return (a - b) / c;
+}
More information about the cfe-commits
mailing list