[clang] 6021cbe - Add option 'exceptions' to pragma clang fp
Serge Pavlov via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 31 03:37:33 PDT 2020
Author: Serge Pavlov
Date: 2020-10-31T17:36:12+07:00
New Revision: 6021cbea4d346d8ff059f8dd74ba7d520646be03
URL: https://github.com/llvm/llvm-project/commit/6021cbea4d346d8ff059f8dd74ba7d520646be03
DIFF: https://github.com/llvm/llvm-project/commit/6021cbea4d346d8ff059f8dd74ba7d520646be03.diff
LOG: Add option 'exceptions' to pragma clang fp
Pragma 'clang fp' is extended to support a new option, 'exceptions'. It
allows to specify floating point exception behavior more flexibly.
Differential Revision: https://reviews.llvm.org/D89849
Added:
clang/test/CodeGen/pragma-fp-exc.cpp
Modified:
clang/docs/LanguageExtensions.rst
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParsePragma.cpp
clang/lib/Sema/SemaAttr.cpp
clang/test/Parser/pragma-fp.cpp
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index a90485d9f799..e17e4e1c46a7 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3182,7 +3182,7 @@ The pragma can take two values: ``on`` and ``off``.
float f(float x, float y, float z)
{
// Enable floating point reassociation across statements
- #pragma fp reassociate(on)
+ #pragma clang fp reassociate(on)
float t = x + y;
float v = t + z;
}
@@ -3211,6 +3211,31 @@ The pragma can also be used with ``off`` which turns FP contraction off for a
section of the code. This can be useful when fast contraction is otherwise
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
+
+``#pragma clang fp exceptions`` specifies floating point exception behavior. It
+may take one the the values: ``ignore``, ``maytrap`` or ``strict``. Meaning of
+these values is same as for `constrained floating point intrinsics <http://llvm.org/docs/LangRef.html#constrained-floating-point-intrinsics>`_.
+
+.. code-block:: c++
+
+ {
+ // Preserve floating point exceptions
+ #pragma clang fp exceptions(strict)
+ z = x + y;
+ if (fetestexcept(FE_OVERFLOW))
+ ...
+ }
+
+A ``#pragma clang fp`` pragma may contain any number of options:
+
+.. code-block:: c++
+
+ void func(float *dest, float a, float b) {
+ #pragma clang fp exceptions(maytrap) contract(fast) reassociate(on)
+ ...
+ }
+
+
The ``#pragma float_control`` pragma allows precise floating-point
semantics and floating-point exception behavior to be specified
for a section of the source code. This pragma can only appear at file scope or
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 0fd4eb5323de..c0a5a2b4c144 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1388,12 +1388,13 @@ def err_pragma_loop_invalid_option : Error<
"pipeline, pipeline_initiation_interval, vectorize_predicate, or distribute">;
def err_pragma_fp_invalid_option : Error<
- "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract' or 'reassociate'">;
+ "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate' or 'exceptions'">;
def err_pragma_fp_invalid_argument : Error<
- "unexpected argument '%0' to '#pragma clang fp %1'; "
+ "unexpected argument '%0' to '#pragma clang fp %1'; expected "
"%select{"
- "expected 'fast' or 'on' or 'off'|"
- "expected 'on' or 'off'}2">;
+ "'fast' or 'on' or 'off'|"
+ "'on' or 'off'|"
+ "'ignore', 'maytrap' or 'strict'}2">;
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4be3c23652e1..3afd417bb2a2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9896,6 +9896,10 @@ class Sema final {
/// \#pragma STDC FENV_ACCESS
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
+ /// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
+ void ActOnPragmaFPExceptions(SourceLocation Loc,
+ LangOptions::FPExceptionModeKind);
+
/// Called to set constant rounding mode for floating point operations.
void setRoundingMode(SourceLocation Loc, llvm::RoundingMode);
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 278e6f50deba..64de2cf5d7f1 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -2858,11 +2858,12 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
namespace {
/// Used as the annotation value for tok::annot_pragma_fp.
struct TokFPAnnotValue {
- enum FlagKinds { Contract, Reassociate };
+ enum FlagKinds { Contract, Reassociate, Exceptions };
enum FlagValues { On, Off, Fast };
- FlagKinds FlagKind;
- FlagValues FlagValue;
+ llvm::Optional<LangOptions::FPModeKind> ContractValue;
+ llvm::Optional<LangOptions::FPModeKind> ReassociateValue;
+ llvm::Optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
};
} // end anonymous namespace
@@ -2879,6 +2880,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
return;
}
+ auto *AnnotValue = new (PP.getPreprocessorAllocator()) TokFPAnnotValue;
while (Tok.is(tok::identifier)) {
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
@@ -2887,6 +2889,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
OptionInfo->getName())
.Case("contract", TokFPAnnotValue::Contract)
.Case("reassociate", TokFPAnnotValue::Reassociate)
+ .Case("exceptions", TokFPAnnotValue::Exceptions)
.Default(None);
if (!FlagKind) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
@@ -2905,25 +2908,49 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName()
- << (FlagKind == TokFPAnnotValue::Reassociate);
+ << static_cast<int>(*FlagKind);
return;
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
- auto FlagValue =
- llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
- II->getName())
- .Case("on", TokFPAnnotValue::On)
- .Case("off", TokFPAnnotValue::Off)
- .Case("fast", TokFPAnnotValue::Fast)
- .Default(llvm::None);
-
- if (!FlagValue || (FlagKind == TokFPAnnotValue::Reassociate &&
- FlagValue == TokFPAnnotValue::Fast)) {
- PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
- << PP.getSpelling(Tok) << OptionInfo->getName()
- << (FlagKind == TokFPAnnotValue::Reassociate);
- return;
+ if (FlagKind == TokFPAnnotValue::Contract) {
+ AnnotValue->ContractValue =
+ llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
+ II->getName())
+ .Case("on", LangOptions::FPModeKind::FPM_On)
+ .Case("off", LangOptions::FPModeKind::FPM_Off)
+ .Case("fast", LangOptions::FPModeKind::FPM_Fast)
+ .Default(llvm::None);
+ if (!AnnotValue->ContractValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+ return;
+ }
+ } else if (FlagKind == TokFPAnnotValue::Reassociate) {
+ AnnotValue->ReassociateValue =
+ llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
+ II->getName())
+ .Case("on", LangOptions::FPModeKind::FPM_On)
+ .Case("off", LangOptions::FPModeKind::FPM_Off)
+ .Default(llvm::None);
+ if (!AnnotValue->ReassociateValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+ return;
+ }
+ } else if (FlagKind == TokFPAnnotValue::Exceptions) {
+ AnnotValue->ExceptionsValue =
+ llvm::StringSwitch<llvm::Optional<LangOptions::FPExceptionModeKind>>(
+ II->getName())
+ .Case("ignore", LangOptions::FPE_Ignore)
+ .Case("maytrap", LangOptions::FPE_MayTrap)
+ .Case("strict", LangOptions::FPE_Strict)
+ .Default(llvm::None);
+ if (!AnnotValue->ExceptionsValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+ return;
+ }
}
PP.Lex(Tok);
@@ -2933,17 +2960,6 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
return;
}
PP.Lex(Tok);
-
- auto *AnnotValue = new (PP.getPreprocessorAllocator())
- TokFPAnnotValue{*FlagKind, *FlagValue};
- // Generate the fp annotation token.
- Token FPTok;
- FPTok.startToken();
- FPTok.setKind(tok::annot_pragma_fp);
- FPTok.setLocation(PragmaName.getLocation());
- FPTok.setAnnotationEndLoc(PragmaName.getLocation());
- FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
- TokenList.push_back(FPTok);
}
if (Tok.isNot(tok::eod)) {
@@ -2952,6 +2968,14 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
return;
}
+ Token FPTok;
+ FPTok.startToken();
+ FPTok.setKind(tok::annot_pragma_fp);
+ FPTok.setLocation(PragmaName.getLocation());
+ FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+ FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+ TokenList.push_back(FPTok);
+
auto TokenArray = std::make_unique<Token[]>(TokenList.size());
std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
@@ -3019,24 +3043,16 @@ void Parser::HandlePragmaFP() {
auto *AnnotValue =
reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
- if (AnnotValue->FlagKind == TokFPAnnotValue::Reassociate)
- Actions.ActOnPragmaFPReassociate(
- Tok.getLocation(), AnnotValue->FlagValue == TokFPAnnotValue::On);
- else {
- LangOptions::FPModeKind FPC;
- switch (AnnotValue->FlagValue) {
- case TokFPAnnotValue::Off:
- FPC = LangOptions::FPM_Off;
- break;
- case TokFPAnnotValue::On:
- FPC = LangOptions::FPM_On;
- break;
- case TokFPAnnotValue::Fast:
- FPC = LangOptions::FPM_Fast;
- break;
- }
- Actions.ActOnPragmaFPContract(Tok.getLocation(), FPC);
- }
+ if (AnnotValue->ReassociateValue)
+ Actions.ActOnPragmaFPReassociate(Tok.getLocation(),
+ *AnnotValue->ReassociateValue ==
+ LangOptions::FPModeKind::FPM_On);
+ if (AnnotValue->ContractValue)
+ Actions.ActOnPragmaFPContract(Tok.getLocation(),
+ *AnnotValue->ContractValue);
+ if (AnnotValue->ExceptionsValue)
+ Actions.ActOnPragmaFPExceptions(Tok.getLocation(),
+ *AnnotValue->ExceptionsValue);
ConsumeAnnotationToken();
}
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index a7751707649a..920cbf5cab59 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1022,6 +1022,11 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
CurFPFeatures = NewFPFeatures.applyOverrides(LO);
}
+void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,
+ LangOptions::FPExceptionModeKind FPE) {
+ setExceptionMode(Loc, FPE);
+}
+
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
SourceLocation Loc) {
// Visibility calculations will consider the namespace's visibility.
diff --git a/clang/test/CodeGen/pragma-fp-exc.cpp b/clang/test/CodeGen/pragma-fp-exc.cpp
new file mode 100644
index 000000000000..c51b7e63204c
--- /dev/null
+++ b/clang/test/CodeGen/pragma-fp-exc.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEF %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
+
+float func_01(float x, float y, float z) {
+ float res = x + y;
+ {
+#pragma clang fp exceptions(maytrap)
+ res += z;
+ }
+ return res;
+}
+// CHECK-DEF-LABEL: @_Z7func_01fff
+// CHECK-DEF: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// CHECK-DEF: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
+
+// CHECK-STRICT-LABEL: @_Z7func_01fff
+// CHECK-STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// CHECK-STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
diff --git a/clang/test/Parser/pragma-fp.cpp b/clang/test/Parser/pragma-fp.cpp
index 400cafb29de8..0377a1b259f4 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' or 'reassociate'}} */
+/* expected-error at +1 {{missing option; expected 'contract', 'reassociate' 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' or 'reassociate'}} */
+/* expected-error at +1 {{invalid option 'blah'; expected 'contract', 'reassociate' or 'exceptions'}} */
#pragma clang fp blah
for (int i = 0; i < Length; i++) {
List[i] = i;
@@ -62,3 +62,14 @@ void test_8(int *List, int Length) {
#pragma clang fp contract(fast)
}
}
+
+void test_9(float *dest, float a, float b) {
+/* expected-error at +1 {{unexpected argument 'on' to '#pragma clang fp exceptions'; expected 'ignore', 'maytrap' or 'strict'}} */
+#pragma clang fp exceptions(on)
+ *dest = a + b;
+}
+
+void test_10(float *dest, float a, float b) {
+#pragma clang fp exceptions(maytrap) contract(fast) reassociate(on)
+ *dest = a + b;
+}
More information about the cfe-commits
mailing list